JFreeChart MouseListener не разрешает элементы диаграммы

У меня есть гистограмма с накоплением, где я хочу иметь возможность выбирать отдельные бары в стеке. Но ChartMouseListener не разрешает ChartMouseEvent в соответствующий ChartEntity. Вот фрагмент слушателя:

    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);
    }

Проблема в том, что event.getEntity() возвращает ноль, когда я, очевидно, нажимаю на некоторые из баров. Обратите внимание, что НЕ все стержни выходят из строя. Чем дальше я иду к правому концу графика, тем более очевидным становится смещение координат. Снимок ниже, показывающий, что выбранная полоса действительно появляется при нажатии за ее пределами. Я использую JFreeChart в составе SWT. Кто-нибудь может подтвердить, что это некорректное поведение или есть обходной путь?

введите описание изображения здесь

Ниже приведен полный обзор, после того, как вы запустите его и нажмете на панели - он будет отображаться мизинец. Затем измените размер окна и попробуйте выбрать бары - оно будет отсутствовать. И я думаю, что мисс это функция нового размера.

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();
    }
}

2 ответа

Решение

ОК, я нашел проблему. В SWT есть несколько конструкторов для создания ChartComposite, большинство из которых используют значения по умолчанию, которые определяют минимальную / максимальную ширину и высоту. В моем случае всякий раз, когда я увеличивал график выше DEFAULT_MAXIMUM_DRAW_WIDTH (800px) - координаты начинали запутываться. Таким образом, решение состоит в том, чтобы использовать полный конструктор и указать соответствующие границы для вашего дисплея. Это было трудно взломать... в основном из-за отсутствия надлежащей документации.

Ваш примерный рендерер имеет правильную геометрию при запуске из Swing, как показано ниже. Я не уверен, почему с SWT все не так, но этот результат может сузить поиск.

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();
            }
        });
    }
}
Другие вопросы по тегам