0

I have a JList of ChartPanels. When I'm trying to select elements I can't visually see what elements of the list actually are selected. On a program level listeners are working properly.

How to get visually selected my chart panels of the list? Or how to overlay these elements with opacity color?

Desired result: enter image description here

Here is the code based on this example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Random;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * @see https://stackoverflow.com/a/40445144/230513
 */

public class ThumbnailChartsJList{

public static JScrollPane scrollPane;
public static JList chartList;

private static final int W = 200;
private static final int H = W;
private static final int N = 100;
private static final int NumberCharts = 20;
private static final Random random = new Random();



public static void main(final String[] args) {

    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            JFrame f = new JFrame("Test");
            JPanel panel = new JPanel(new BorderLayout());

            ChartPanel chartp = createChart();

            DefaultListModel listModel = new DefaultListModel();
            for (int i=0; i<NumberCharts; i++){
                listModel.addElement(chartp);
            }


            chartList = new JList(listModel);
            chartList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
            chartList.setCellRenderer(new ListRenderer());
            chartList.setVisibleRowCount(0); //0 - dynamic rows
            chartList.setLayoutOrientation(JList.HORIZONTAL_WRAP);

            chartList.setSelectionForeground(Color.RED);

            scrollPane = new JScrollPane(chartList,
                    JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                    JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);


            panel.add(scrollPane, BorderLayout.CENTER);
            f.setPreferredSize(new Dimension(900,700));
            f.setContentPane(panel);
            f.pack();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setVisible(true);
        }
    });

}

private static ChartPanel createChart() {
    final XYSeries series = new XYSeries("Data");
    for (int i = 0; i < random.nextInt(N) + N; i++) {
        series.add(i, random.nextGaussian());
    }
    XYSeriesCollection dataset = new XYSeriesCollection(series);

    JFreeChart chart = ChartFactory.createXYLineChart("Random", "Domain",
        "Range", dataset, PlotOrientation.VERTICAL, false, false, false);
    ChartPanel chartPanel = new ChartPanel(chart, W, H, W, H, W, H,
            false, true, true, true, true, true){
        @Override
        public Dimension getPreferredSize() {
        return new Dimension(W, H);}
    };
    chartPanel.getChart().removeLegend();
    return chartPanel;

}

static class ListRenderer extends DefaultListCellRenderer {

    @Override
    public Component getListCellRendererComponent(JList chartList, Object
        value, int index, boolean isSelected, boolean cellHasFocus) {       
        return (ChartPanel) value;
    }

}

}
trashgod
  • 196,350
  • 25
  • 213
  • 918
Andrei Sh
  • 113
  • 10
  • Don't add components to a `JList`/`ListModel`, add the data you need represented and then use a `ListCellRenderer` to provide visualisation - Doing so will give you the control you need to render the selection – MadProgrammer Sep 25 '17 at 04:55
  • Add data to JList and visualize it in cell renderer? But why? What's advantages? – Andrei Sh Sep 25 '17 at 05:40
  • It's faster (generally) it can reduce the memory overhead and gives you control over how the elements are rendered in different states - it's also the way that the API was designed to be used – MadProgrammer Sep 25 '17 at 05:41
  • Okay, thank you. Will try it. – Andrei Sh Sep 25 '17 at 05:46
  • @AndreiSh: Please cite the [original](https://stackoverflow.com/a/40445144/230513), as [required](https://stackexchange.com/legal). – trashgod Sep 25 '17 at 11:11
  • @MadProgrammer: He's using a `ListCellRenderer`; the [original](https://stackoverflow.com/a/40445144/230513) used a `TableCellRenderer` – trashgod Sep 25 '17 at 11:12
  • Yep, original is about jtable, this one -- my jlist implementation. – Andrei Sh Sep 25 '17 at 11:16
  • The citation is [required](https://stackexchange.com/legal) by the terms of service. – trashgod Sep 25 '17 at 11:42
  • Okay, I'll keep in mind that for future. Thanks. – Andrei Sh Sep 25 '17 at 11:50
  • @trashgod Which is just passing back the chart component - better to model the data then use components this way - or base the cell render on a chart component itself – MadProgrammer Sep 25 '17 at 11:56
  • @MadProgrammer draws an important distinction: the [example cited](https://stackoverflow.com/a/40445144/230513) had been optimized for time, not space or flexibility; in contrast, [version 1](https://stackoverflow.com/revisions/40445144/1) stored only data in the `TableModel`. – trashgod Sep 25 '17 at 18:19
  • Why version 1 was revisited? Because cited example has better performance? – Andrei Sh Sep 25 '17 at 18:30
  • @AndreiSh: It just has different tradeoffs; compare to see. – trashgod Sep 25 '17 at 19:15
  • @trashgod I was thinking of maybe buffering the result in a BufferedImage, but it might be going beyond the scope of the question though – MadProgrammer Sep 25 '17 at 19:38
  • @MadProgrammer: Good idea; `JFreeChart::createBufferedImage` is available; you could render the live chart on the left in this [example](https://stackoverflow.com/a/25170471/230513). – trashgod Sep 25 '17 at 22:45

1 Answers1

1

In your ListCellRenderer, condition the background color based on the value of isSelected. It's also possible to change the chart itself. The fragment below updates the chart's background paint; alternatively, you can alter the plots's background alpha.

static class ListRenderer extends DefaultListCellRenderer {

    @Override
    public Component getListCellRendererComponent(JList chartList, Object
        value, int index, boolean isSelected, boolean cellHasFocus) {
        ChartPanel chartPanel = (ChartPanel) value;
        if (isSelected) {chartPanel.getChart().setBackgroundPaint(Color.red);}
        else {chartPanel.getChart().setBackgroundPaint(Color.white);}
        return chartPanel;
    }
}

image

trashgod
  • 196,350
  • 25
  • 213
  • 918