Search code examples
javaswingjtablebar-chartrenderer

Show BarChar In JTable Column In Java


I have JTable in that I need to Show Chart but i have tired several Code but not able to achieve waht i wanted to make. here what i have tried so far

http://www.jroller.com/Thierry/entry/swing_barchart_rendering_in_a

and i want to achieve according to this image

enter image description here

but how ever i dont get any Render-er for same. Please Any suggestion will be welcomed.

Example


Solution

  • Okay, here's an idea...

    Layout

    Instead of using a JTable, you could create a layout manager which would calculate the offsets and allow for elements to overlap "columns"

    Prototype example - !! DO NOT USE IN PRODUCTION !!

    enter image description here

    This is an EXAMPLE only and should be used to LEARN from, do not try using this in production, there is a lot that needs to improved, such as a proper event notification API

    This example makes use of the JIDE Common Layer API (the JideScrollPane in particular), you can get a copy from here

    import com.jidesoft.swing.JideScrollPane;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.FontMetrics;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.LayoutManager2;
    import java.awt.LinearGradientPaint;
    import java.awt.Point;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JViewport;
    import javax.swing.ScrollPaneConstants;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.border.Border;
    import javax.swing.border.EmptyBorder;
    import javax.swing.border.MatteBorder;
    
    public class WorkSheetReport {
    
        public static final Color WORKING_HOURS_COLOR = new Color(93, 89, 88);
        public static final Color LUNCH_HOURS_COLOR = new Color(215, 142, 27);
        public static final Color OTHER_HOURS_COLOR = new Color(30, 141, 213);
    
        public static void main(String[] args) {
            new WorkSheetReport();
        }
    
        public WorkSheetReport() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    DefaultTimeSheetReport report = new DefaultTimeSheetReport();
                    report.add(createTimeSheet(
                                    "NWD/Full"));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
                                    new DefaultTimeEntry(WorkType.LUNCH, 12.5, 13.25),
                                    new DefaultTimeEntry(WorkType.WORK, 13.25, 18),
                                    new DefaultTimeEntry(WorkType.OTHER, 18, 18.5),
                                    new DefaultTimeEntry(WorkType.WORK, 18.5, 20.5)));
                    report.add(createTimeSheet(
                                    "0.5UUPL",
                                    new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
                                    new DefaultTimeEntry(WorkType.LUNCH, 12.5, 17.75),
                                    new DefaultTimeEntry(WorkType.OTHER, 17.75, 18),
                                    new DefaultTimeEntry(WorkType.WORK, 18, 20)));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 11, 13),
                                    new DefaultTimeEntry(WorkType.LUNCH, 13, 13.5),
                                    new DefaultTimeEntry(WorkType.WORK, 13.5, 17.75),
                                    new DefaultTimeEntry(WorkType.OTHER, 17.75, 18),
                                    new DefaultTimeEntry(WorkType.WORK, 18, 20.5)));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 10, 12.75),
                                    new DefaultTimeEntry(WorkType.LUNCH, 12.75, 13.5),
                                    new DefaultTimeEntry(WorkType.WORK, 13.5, 17.5),
                                    new DefaultTimeEntry(WorkType.OTHER, 17.5, 17.75),
                                    new DefaultTimeEntry(WorkType.WORK, 17.75, 20.5)));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 9.75, 12),
                                    new DefaultTimeEntry(WorkType.LUNCH, 12, 12.5),
                                    new DefaultTimeEntry(WorkType.WORK, 12.5, 17.25),
                                    new DefaultTimeEntry(WorkType.OTHER, 17.25, 17.75),
                                    new DefaultTimeEntry(WorkType.WORK, 17.75, 20)));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 10, 11.75),
                                    new DefaultTimeEntry(WorkType.LUNCH, 11.75, 12.25),
                                    new DefaultTimeEntry(WorkType.WORK, 12.25, 17.5),
                                    new DefaultTimeEntry(WorkType.OTHER, 17.5, 18),
                                    new DefaultTimeEntry(WorkType.WORK, 18, 20.25)));
                    report.add(createTimeSheet(
                                    "NWD/Full"));
                    report.add(createTimeSheet(
                                    "Present",
                                    new DefaultTimeEntry(WorkType.WORK, 10, 12.5),
                                    new DefaultTimeEntry(WorkType.LUNCH, 12.5, 13.5),
                                    new DefaultTimeEntry(WorkType.WORK, 13.5, 18),
                                    new DefaultTimeEntry(WorkType.OTHER, 18, 18.5),
                                    new DefaultTimeEntry(WorkType.WORK, 18.5, 20.5)));
    
                    TimeSheetReportPane pane = new TimeSheetReportPane(report);
    
                    JFrame frame = new JFrame("Testing");
                    frame.getContentPane().setBackground(Color.BLACK);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
                    JideScrollPane sp = new JideScrollPane(pane);
                    sp.setColumnHeadersHeightUnified(true);
                    frame.add(sp);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
    
            });
        }
    
        protected TimeSheet createTimeSheet(String name, TimeEntry... entries) {
            DefaultTimeSheet ts = new DefaultTimeSheet(name);
            for (TimeEntry entry : entries) {
                ts.add(entry);
            }
            return ts;
        }
    
        protected static String format(double time) {
            time *= 60 * 60; // to seconds
            int hours = (int) Math.floor(time / (60 * 60));
            double remainder = time % (60 * 60);
            int mins = (int) Math.floor(remainder / 60);
            int secs = (int) Math.floor(time % 60);
            return hours + ":" + mins + ":" + secs;
        }
    
        public class TimeSheetReportPane extends JPanel {
    
            private TimeSheetReport report;
    
            private int columnWidth;
            private int rowHeight;
    
            public TimeSheetReportPane(TimeSheetReport report) {
                this.report = report;
                setLayout(new GridBagLayout());
                setBackground(Color.BLACK);
    
                FontMetrics fm = getFontMetrics(UIManager.getFont("Label.font"));
                columnWidth = fm.stringWidth("0000");
                rowHeight = fm.getHeight() + 8;
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.weightx = 1;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.insets = new Insets(0, 0, 1, 0);
    
                int count = 0;
                for (TimeSheet ts : report) {
    
                    Color color = getColorForSheet(count);
                    TimeSheetPane pane = new TimeSheetPane(this, ts);
                    pane.setBackground(color);
                    add(pane, gbc);
                    count++;
    
                }
    
                gbc.weighty = 1;
                JPanel fill = new JPanel();
                fill.setOpaque(false);
                add(fill, gbc);
    
            }
    
            public Color getColorForSheet(int index) {
                Color endColor = Color.GRAY;
                Color startColor = Color.DARK_GRAY;
                double progress = (double) index / (double) getReport().size();
                return blend(startColor, endColor, progress);
            }
    
            public TimeSheetReport getReport() {
                return report;
            }
    
            public int getRowHeight() {
                return rowHeight;
            }
    
            public int getColumnWidth() {
                return columnWidth;
            }
    
            @Override
            public void addNotify() {
                super.addNotify();
                configureEnclosingScrollPane();
            }
    
            protected void configureEnclosingScrollPane() {
                Container parent = getParent();
                if (parent instanceof JViewport) {
                    JViewport viewport = (JViewport) parent;
                    parent = viewport.getParent();
                    if (parent instanceof JideScrollPane) {
                        JideScrollPane sp = (JideScrollPane) parent;
                        sp.setRowFooterView(new RowFooter(this));
                    }
                    if (parent instanceof JScrollPane) {
                        JScrollPane sp = (JScrollPane) parent;
                        JLabel leftHeader = new JLabel("Status");
                        leftHeader.setForeground(Color.WHITE);
                        leftHeader.setBackground(Color.BLACK);
                        leftHeader.setOpaque(true);
                        leftHeader.setHorizontalAlignment(JLabel.CENTER);
                        leftHeader.setVerticalAlignment(JLabel.TOP);
                        leftHeader.setBorder(new EdgeBorder(EdgeBorder.Edge.RIGHT, Color.WHITE, Color.BLACK));
                        sp.setCorner(ScrollPaneConstants.UPPER_LEFT_CORNER, leftHeader);
    
                        JLabel rightHeader = new JLabel("Working Hr");
                        rightHeader.setForeground(Color.WHITE);
                        rightHeader.setBackground(Color.BLACK);
                        rightHeader.setOpaque(true);
                        rightHeader.setHorizontalAlignment(JLabel.CENTER);
                        rightHeader.setBorder(new EdgeBorder(EdgeBorder.Edge.LEFT, Color.WHITE, Color.BLACK));
                        sp.setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, rightHeader);
    
                        sp.setRowHeaderView(new RowHeader(this));
                        sp.setColumnHeaderView(new ColumnHeader(this));
                    }
                }
            }
    
        }
    
        public class ColumnHeader extends JPanel {
    
            private TimeSheetReportPane reportPane;
    
            public ColumnHeader(TimeSheetReportPane tsrp) {
                reportPane = tsrp;
                setBackground(Color.BLACK);
                setLayout(new GridBagLayout());
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridheight = GridBagConstraints.REMAINDER;
                gbc.weighty = 1;
                gbc.fill = GridBagConstraints.VERTICAL;
                gbc.ipady = 8;
                Border border = new MatteBorder(0, 0, 0, 1, Color.GRAY);
    
                for (int hour = 8; hour < 25; hour++) {
                    JLabel label = new JLabel(Integer.toString(hour)) {
    
                        @Override
                        public Dimension getPreferredSize() {
                            Dimension dim = super.getPreferredSize();
                            dim.width = reportPane.getColumnWidth();
                            return dim;
                        }
    
                        @Override
                        public Dimension getMinimumSize() {
                            return getPreferredSize();
                        }
    
                    };
                    label.setVerticalAlignment(JLabel.TOP);
                    label.setHorizontalAlignment(JLabel.CENTER);
                    label.setForeground(Color.WHITE);
                    label.setBorder(border);
                    add(label, gbc);
                }
                gbc.weightx = 1;
                JPanel fill = new JPanel();
                fill.setOpaque(false);
                add(fill, gbc);
    
            }
    
        }
    
        public class RowHeader extends JPanel {
    
            private TimeSheetReportPane reportPane;
    
            public RowHeader(TimeSheetReportPane tsrp) {
                reportPane = tsrp;
                setBackground(Color.BLACK);
                setLayout(new GridBagLayout());
                TimeSheetReport tsr = reportPane.getReport();
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.weightx = 1;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.ipadx = 16;
                gbc.ipady = 2;
                gbc.insets = new Insets(0, 0, 1, 0);
    
                int index = 0;
                for (TimeSheet ts : tsr) {
                    JLabel label = new JLabel(ts.getName()) {
    
                        @Override
                        public Dimension getPreferredSize() {
                            Dimension dim = super.getPreferredSize();
                            dim.height = reportPane.getRowHeight();
                            return dim;
                        }
    
                        @Override
                        public Dimension getMinimumSize() {
                            return getPreferredSize();
                        }
    
                    };
                    label.setHorizontalAlignment(JLabel.CENTER);
                    label.setForeground(Color.WHITE);
                    label.setBackground(reportPane.getColorForSheet(index));
                    label.setOpaque(true);
                    add(label, gbc);
                    index++;
                }
                gbc.weighty = 1;
                JPanel fill = new JPanel();
                fill.setOpaque(false);
                add(fill, gbc);
    
            }
    
        }
    
        public class RowFooter extends JPanel {
    
            private TimeSheetReportPane reportPane;
    
            public RowFooter(TimeSheetReportPane tsrp) {
                reportPane = tsrp;
                setBackground(Color.BLACK);
                setLayout(new GridBagLayout());
                TimeSheetReport tsr = reportPane.getReport();
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.weightx = 1;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.ipadx = 36;
                gbc.ipady = 2;
                gbc.insets = new Insets(0, 0, 1, 0);
    
                int index = 0;
                for (TimeSheet ts : tsr) {
                    double time = ts.getWorkingHours();
                    String workHrs = "";
                    if (time > 0) {
                        workHrs = format(time);
                    }
                    JLabel label = new JLabel(workHrs) {
    
                        @Override
                        public Dimension getPreferredSize() {
                            Dimension dim = super.getPreferredSize();
                            dim.height = reportPane.getRowHeight();
                            return dim;
                        }
    
                        @Override
                        public Dimension getMinimumSize() {
                            return getPreferredSize();
                        }
    
                    };
                    label.setHorizontalAlignment(JLabel.CENTER);
                    label.setForeground(Color.WHITE);
                    label.setBackground(reportPane.getColorForSheet(index));
                    label.setOpaque(true);
                    add(label, gbc);
                    index++;
                }
                gbc.weighty = 1;
                JPanel fill = new JPanel();
                fill.setOpaque(false);
                add(fill, gbc);
    
            }
    
        }
    
        public static class EdgeBorder implements Border {
    
            public enum Edge {
    
                LEFT,
                RIGHT
            }
    
            private Edge edge;
            private Color startColor;
            private Color endColor;
    
            public EdgeBorder(Edge edge, Color startColor, Color endColor) {
                this.edge = edge;
                this.startColor = startColor;
                this.endColor = endColor;
            }
    
            @Override
            public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
    
                int xPos = x;
                switch (edge) {
                    case RIGHT:
                        xPos = x + (width - 1);
                }
    
                LinearGradientPaint lgp = new LinearGradientPaint(
                                new Point(x, 0),
                                new Point(x, height),
                                new float[]{0, 1},
                                new Color[]{startColor, endColor});
    
                Graphics2D g2d = (Graphics2D) g;
                g2d.setPaint(lgp);
                g2d.drawLine(xPos, y, xPos, y + height);
            }
    
            @Override
            public Insets getBorderInsets(Component c) {
                int left = edge == Edge.LEFT ? 1 : 0;
                int right = edge == Edge.RIGHT ? 1 : 0;
                return new Insets(0, left, 0, right);
            }
    
            @Override
            public boolean isBorderOpaque() {
                return false;
            }
    
        }
    
        /**
         * Blend two colors.
         *
         * @param color1 First color to blend.
         * @param color2 Second color to blend.
         * @param ratio Blend ratio. 0.5 will give even blend, 1.0 will return color1,
         * 0.0 will return color2 and so on.
         * @return Blended color.
         */
        public static Color blend(Color color1, Color color2, double ratio) {
            float r = (float) ratio;
            float ir = (float) 1.0 - r;
    
            float rgb1[] = new float[3];
            float rgb2[] = new float[3];
    
            color1.getColorComponents(rgb1);
            color2.getColorComponents(rgb2);
    
            float red = rgb1[0] * r + rgb2[0] * ir;
            float green = rgb1[1] * r + rgb2[1] * ir;
            float blue = rgb1[2] * r + rgb2[2] * ir;
    
            if (red < 0) {
                red = 0;
            } else if (red > 255) {
                red = 255;
            }
            if (green < 0) {
                green = 0;
            } else if (green > 255) {
                green = 255;
            }
            if (blue < 0) {
                blue = 0;
            } else if (blue > 255) {
                blue = 255;
            }
    
            Color color = null;
            try {
    
                color = new Color(red, green, blue);
    
            } catch (IllegalArgumentException exp) {
                exp.printStackTrace();
            }
            return color;
        }
    
        public class TimeSheetPane extends JPanel {
    
            private final JPanel timeEntriesPane;
    
            public TimeSheetPane(TimeSheetReportPane reportPane, TimeSheet ts) {
    
                timeEntriesPane = new JPanel(new TimeSheetLayoutManager(reportPane.getColumnWidth(), reportPane.getRowHeight()));
                timeEntriesPane.setBackground(Color.BLACK);
    
                setBorder(new EmptyBorder(1, 0, 1, 0));
                setLayout(new BorderLayout());
                add(timeEntriesPane);
    
                for (TimeEntry te : ts) {
                    JLabel label = createLabel(te.getType().getColor());
                    String startTime = format(te.getStartTime());
                    String duration = format(te.getDuration());
                    label.setToolTipText("<html>StartTime: " + startTime + "<br>Duration: " + duration);
                    timeEntriesPane.add(label, te);
                }
    
            }
    
            protected JLabel createLabel(Color color) {
                JLabel label = new JLabel();
                label.setOpaque(true);
                label.setBackground(color);
                return label;
            }
    
        }
    
        public class TimeSheetLayoutManager implements LayoutManager2 {
    
            private Map<Component, TimeEntry> mapConstraints;
            private int colWidth;
            private int rowHeight;
    
            public TimeSheetLayoutManager(int colWidth, int rowHeight) {
                mapConstraints = new HashMap<>(25);
                this.colWidth = colWidth;
                this.rowHeight = rowHeight;
            }
    
            @Override
            public void addLayoutComponent(Component comp, Object constraints) {
                if (constraints instanceof TimeEntry) {
                    mapConstraints.put(comp, (TimeEntry) constraints);
                } else {
                    throw new IllegalArgumentException(
                                    constraints == null ? "Null is not a valid constraint"
                                    : constraints.getClass().getName() + " is not a valid TimeEntry constraint"
                    );
                }
            }
    
            @Override
            public Dimension maximumLayoutSize(Container target) {
                return preferredLayoutSize(target);
            }
    
            @Override
            public float getLayoutAlignmentX(Container target) {
                return 0.5f;
            }
    
            @Override
            public float getLayoutAlignmentY(Container target) {
                return 0.5f;
            }
    
            @Override
            public void invalidateLayout(Container target) {
            }
    
            @Override
            public void addLayoutComponent(String name, Component comp) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
    
            @Override
            public void removeLayoutComponent(Component comp) {
                mapConstraints.remove(comp);
            }
    
            @Override
            public Dimension preferredLayoutSize(Container parent) {
                return new Dimension(colWidth * (24 - 8), rowHeight);
            }
    
            @Override
            public Dimension minimumLayoutSize(Container parent) {
                return preferredLayoutSize(parent);
            }
    
            @Override
            public void layoutContainer(Container parent) {
                Insets insets = parent.getInsets();
                int width = parent.getWidth() - (insets.left + insets.right);
                int height = rowHeight;
    
                int hourWidth = colWidth;
                int offset = 8;
    
                for (Component comp : mapConstraints.keySet()) {
                    TimeEntry te = mapConstraints.get(comp);
                    double startTime = te.getStartTime();
                    double duration = te.getDuration();
    
                    startTime -= offset;
    
                    int x = (int) Math.round(startTime * hourWidth);
                    int unitWidth = (int) Math.round(duration * hourWidth);
                    comp.setLocation(x, insets.top);
                    comp.setSize(unitWidth, height);
                }
            }
    
        }
    
        public enum WorkType {
    
            WORK(WORKING_HOURS_COLOR),
            LUNCH(LUNCH_HOURS_COLOR),
            OTHER(OTHER_HOURS_COLOR);
    
            private Color color;
    
            private WorkType(Color color) {
                this.color = color;
            }
    
            public Color getColor() {
                return color;
            }
    
        }
    
        public interface TimeEntry {
    
            public WorkType getType();
    
            public double getStartTime();
    
            public double getDuration();
        }
    
        public interface TimeSheet extends Iterable<TimeEntry> {
    
            public String getName();
    
            public int size();
    
            public TimeEntry get(int index);
    
            public double getWorkingHours();
    
        }
    
        public interface TimeSheetReport extends Iterable<TimeSheet> {
    
            public int size();
    
            public TimeSheet get(int index);
    
        }
    
        public class DefaultTimeEntry implements TimeEntry {
    
            private final double startTime;
            private final double endTime;
            private final WorkType workType;
    
            public DefaultTimeEntry(WorkType type, double startTime, double endTime) {
                this.startTime = startTime;
                this.endTime = endTime;
                this.workType = type;
            }
    
            @Override
            public double getStartTime() {
                return startTime;
            }
    
            public double getEndTime() {
                return endTime;
            }
    
            @Override
            public double getDuration() {
                return endTime - startTime;
            }
    
            @Override
            public WorkType getType() {
                return workType;
            }
    
        }
    
        public class DefaultTimeSheet implements TimeSheet {
    
            private final List<TimeEntry> timeEntries;
            private final String name;
    
            public DefaultTimeSheet(String name) {
                this.name = name;
                timeEntries = new ArrayList<>(25);
            }
    
            public TimeSheet add(TimeEntry te) {
                timeEntries.add(te);
                return this;
            }
    
            @Override
            public Iterator<TimeEntry> iterator() {
                return timeEntries.iterator();
            }
    
            @Override
            public int size() {
                return timeEntries.size();
            }
    
            @Override
            public TimeEntry get(int index) {
                return timeEntries.get(index);
            }
    
            @Override
            public String getName() {
                return name;
            }
    
            @Override
            public double getWorkingHours() {
                double time = 0;
                for (TimeEntry te : this) {
                    switch (te.getType()) {
                        case WORK:
                            time += te.getDuration();
                            break;
                    }
                }
                return time;
            }
    
        }
    
        public class DefaultTimeSheetReport implements TimeSheetReport {
    
            private final List<TimeSheet> timeSheets;
    
            public DefaultTimeSheetReport() {
                timeSheets = new ArrayList<>(25);
            }
    
            public DefaultTimeSheetReport add(TimeSheet ts) {
                timeSheets.add(ts);
                return this;
            }
    
            @Override
            public int size() {
                return timeSheets.size();
            }
    
            @Override
            public TimeSheet get(int index) {
                return timeSheets.get(index);
            }
    
            @Override
            public Iterator<TimeSheet> iterator() {
                return timeSheets.iterator();
            }
    
        }
    
    }