JFreeChart MouseListener non risolve gli elementi del grafico

Ho un grafico a barre in pila dove voglio essere in grado di selezionare singole barre nello stack. Ma ChartMouseListener non risolve ChartMouseEvent in ChartEntity corrispondente. Ecco lo snippet listener:

public void chartMouseClicked(ChartMouseEvent event){ ChartEntity entity = event.getEntity(); if(entity != null && (entity instanceof XYItemEntity) ){ XYItemEntity item = (XYItemEntity)entity; renderer.select(item.getSeriesIndex(), item.getItem()); return; } // deselect renderer.select(-1,-1); } 

Il problema è che event.getEntity () restituisce null quando ovviamente clicco su alcune barre. Notare che NON tutte le barre falliscono. Più andrò all’estremità destra del grafico, più evidente è lo spostamento delle coordinate. Scatta una foto qui sotto mostrando che la barra selezionata viene effettivamente visualizzata quando fai clic al di fuori di essa. Sto usando JFreeChart all’interno del composito SWT. Qualcuno può confermare che questo è un comportamento bacato o c’è una soluzione ?

inserisci la descrizione dell'immagine qui

Di seguito è completo sscce , dopo averlo eseguito e fare clic su barre – apparirà pinky. Quindi ridimensiona la finestra e prova a selezionare le barre: mancherà. E penso che la mancanza sia la funzione della nuova dimensione.

 import java.awt.Color; import java.awt.Paint; import java.util.Random; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickMarkPosition; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.StackedXYBarRenderer; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.data.time.Day; import org.jfree.data.time.Hour; import org.jfree.data.time.TimeTableXYDataset; import org.jfree.data.xy.TableXYDataset; import org.jfree.experimental.chart.swt.ChartComposite; public class StackedChartSwt { private StackedRenderer renderer; private Color[] colors = new Color[]{ new Color(230,240,255), new Color(240,255,240), new Color(255,255,255), new Color(255,255,240), new Color(255,240,240), new Color(240,240,240) }; public StackedChartSwt(){ Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); JFreeChart chart = createStackedChart(createStackedDataset()); ChartComposite chartComposite = new ChartComposite(shell, SWT.NONE, chart, false, false, false, false, false); chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); chartComposite.setRangeZoomable(false); chartComposite.setMenu(null); chartComposite.addChartMouseListener(new ThisMouseListener()); shell.setSize(800, 600); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } display.dispose(); } private JFreeChart createStackedChart(TableXYDataset tablexydataset) { DateAxis dateaxis = new DateAxis(); dateaxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE); NumberAxis numberaxis = new NumberAxis("Event counts"); renderer = new StackedRenderer(); XYPlot plot = new XYPlot(tablexydataset, dateaxis, numberaxis, renderer); plot.setBackgroundPaint(Color.white); plot.setDomainGridlinePaint(Color.lightGray); plot.setDomainGridlinesVisible(true); plot.setRangeGridlinesVisible(true); plot.setRangeGridlinePaint(Color.lightGray); JFreeChart chart = new JFreeChart(null, plot); chart.setBackgroundPaint(Color.white); chart.setBorderVisible(false); chart.setBorderPaint(null); return chart; } class StackedRenderer extends StackedXYBarRenderer{ int selectedRow=-1, selectedCol=-1; public StackedRenderer(){ setDrawBarOutline(true); setBarPainter(new StandardXYBarPainter()); setShadowVisible(false); setSeriesPaint(0, Color.blue); setMargin(0.2); } public void select(int row, int col){ selectedRow = row; selectedCol = col; notifyListeners(new RendererChangeEvent(this)); } @Override public Paint getItemPaint(final int row, final int col){ if(row == selectedRow && col == selectedCol) return Color.pink; return colors[row]; } } class ThisMouseListener implements ChartMouseListener{ public void chartMouseMoved(ChartMouseEvent event){ } public void chartMouseClicked(ChartMouseEvent event){ ChartEntity entity = event.getEntity(); if(entity != null && (entity instanceof XYItemEntity) ){ XYItemEntity item = (XYItemEntity)entity; renderer.select(item.getSeriesIndex(), item.getItem()); return; } // deselect renderer.select(-1,-1); } } private TableXYDataset createStackedDataset(){ Random random = new Random(0); TimeTableXYDataset ds = new TimeTableXYDataset(); Day day = new Day(); for( int i = 0; i < 24; i++ ){ Hour hour = new Hour( i, day ); ds.add(hour, random.nextInt( 20 ), "A"); ds.add(hour, random.nextInt( 20 ), "B"); ds.add(hour, random.nextInt( 20 ), "C"); ds.add(hour, random.nextInt( 20 ), "D"); ds.add(hour, random.nextInt( 20 ), "E"); ds.add(hour, random.nextInt( 20 ), "F"); } return ds; } public static void main(String[] args){ new StackedChartSwt(); } } 

OK, ho trovato il problema. In SWT ci sono diversi costruttori per creare ChartComposite, la maggior parte delle impostazioni predefinite di utilizzo che specificano la larghezza e l’altezza min / max. Nel mio caso, ogni volta che ho ingrandito il grafico sopra DEFAULT_MAXIMUM_DRAW_WIDTH (800px) – le coordinate iniziano a diventare disordinate. Quindi, la soluzione è utilizzare full constructor e specificare i limiti rilevanti per il tuo display. È stato difficile da decifrare … principalmente a causa della mancanza di una documentazione adeguata.

Il tuo riproduttore esemplare ha la geometria corretta quando viene eseguito da Swing, come mostrato di seguito. Non sono sicuro del motivo per cui le cose non vanno bene con SWT, ma questo risultato potrebbe restringere la ricerca.

inserisci la descrizione dell'immagine qui

 import java.awt.Color; import java.awt.EventQueue; import java.awt.Paint; import java.util.Random; import javax.swing.JFrame; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickMarkPosition; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.entity.ChartEntity; import org.jfree.chart.entity.XYItemEntity; import org.jfree.chart.event.RendererChangeEvent; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.StackedXYBarRenderer; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.data.time.Day; import org.jfree.data.time.Hour; import org.jfree.data.time.TimeTableXYDataset; import org.jfree.data.xy.TableXYDataset; public class StackedChartSwing { private ChartPanel panel; private StackedRenderer renderer; private Color[] colors = new Color[]{ new Color(230, 240, 255), new Color(240, 255, 240), new Color(255, 255, 255), new Color(255, 255, 240), new Color(255, 240, 240), new Color(240, 240, 240) }; public StackedChartSwing() { JFreeChart chart = createStackedChart(createStackedDataset()); panel = new ChartPanel(chart); panel.addChartMouseListener(new ThisMouseListener()); } private JFreeChart createStackedChart(TableXYDataset tablexydataset) { DateAxis dateaxis = new DateAxis(); dateaxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE); NumberAxis numberaxis = new NumberAxis("Event counts"); renderer = new StackedRenderer(); XYPlot plot = new XYPlot(tablexydataset, dateaxis, numberaxis, renderer); plot.setBackgroundPaint(Color.white); plot.setDomainGridlinePaint(Color.lightGray); plot.setDomainGridlinesVisible(true); plot.setRangeGridlinesVisible(true); plot.setRangeGridlinePaint(Color.lightGray); JFreeChart chart = new JFreeChart(null, plot); chart.setBackgroundPaint(Color.white); chart.setBorderVisible(false); chart.setBorderPaint(null); return chart; } class StackedRenderer extends StackedXYBarRenderer { int selectedRow = -1, selectedCol = -1; public StackedRenderer() { setDrawBarOutline(true); setBarPainter(new StandardXYBarPainter()); setShadowVisible(false); setSeriesPaint(0, Color.blue); setMargin(0.2); } public void select(int row, int col) { selectedRow = row; selectedCol = col; notifyListeners(new RendererChangeEvent(this)); } @Override public Paint getItemPaint(final int row, final int col) { if (row == selectedRow && col == selectedCol) { return Color.pink; } return colors[row]; } } class ThisMouseListener implements ChartMouseListener { @Override public void chartMouseMoved(ChartMouseEvent event) { } @Override public void chartMouseClicked(ChartMouseEvent event) { ChartEntity entity = event.getEntity(); if (entity != null && (entity instanceof XYItemEntity)) { XYItemEntity item = (XYItemEntity) entity; renderer.select(item.getSeriesIndex(), item.getItem()); return; } // deselect renderer.select(-1, -1); } } private TableXYDataset createStackedDataset() { Random random = new Random(0); TimeTableXYDataset ds = new TimeTableXYDataset(); Day day = new Day(); for (int i = 0; i < 24; i++) { Hour hour = new Hour(i, day); ds.add(hour, random.nextInt(20), "A"); ds.add(hour, random.nextInt(20), "B"); ds.add(hour, random.nextInt(20), "C"); ds.add(hour, random.nextInt(20), "D"); ds.add(hour, random.nextInt(20), "E"); ds.add(hour, random.nextInt(20), "F"); } return ds; } private void display() { JFrame f = new JFrame("Test"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(panel); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new StackedChartSwing().display(); } }); } }