TeeChart ScrollPager 实时更新

TeeChart ScrollPager realtime update

我正在尝试动态更新主图表系列数据,但如果我移动 ColorBand 或如果我在图表已经重新绘制并出现大量 ArrayOutOfIndex 异常时更新图表,ScrollPager 会冻结我的图表框架。我明白为什么会这样,但不知道如何将它与 TeeChart 一起正确使用。有什么解决方案可以让它同步吗?

这是我使用 volatile 的代码示例,它模拟用样本值填充序列的更新:

public class TestTeeChartCandle extends JFrame {

int sizeX = 500;
int sizeY = 500;

private TChart chart;
private Candle series;
private MyScrollPager scrollPager;

private volatile boolean updatingChart = false;
private volatile boolean updatingSubChart = false;

private volatile boolean updatingChartSeries = false;
private volatile boolean updatingSubChartSeries = false;

private volatile boolean updatingData = false;

private volatile boolean draggingSubChart = false;

public TestTeeChartCandle() {
    super();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(new Dimension(520, 520));

    chart = new TChart();
    chart.setPreferredSize(new Dimension(500, 500));

    series = new Candle(chart.getChart());
    series.fillSampleValues(500);

    scrollPager = new MyScrollPager(chart.getChart());

    ChangeEvent changeEvent = new ChangeEvent(null);
    scrollPager.dragMoving(changeEvent);

    MouseMoveListener mouseMoveListener = new MouseMoveListener();
    scrollPager.getColorBandTool().addMouseMotionListener(mouseMoveListener);

    this.addComponentListener(new ComponentListener() {
        public void componentResized(ComponentEvent e) {
            sizeX = e.getComponent().getWidth();
            sizeY = e.getComponent().getHeight();
            setPreferredSize(new Dimension(sizeX, sizeY));
        }

        public void componentMoved(ComponentEvent e) {
        }

        public void componentHidden(ComponentEvent e) {
        }

        public void componentShown(ComponentEvent e) {
        }
    });

    chart.addChartPaintListener(new ChartPaintAdapter() {
        @Override
        public void chartPainted(ChartDrawEvent e) {
            updatingChart = false;
        }

        @Override public void chartPainting(ChartDrawEvent e) {
            while (updatingData) ;
            updatingChart = true;
        }

        @Override public void seriesPainted(ChartDrawEvent e) {
            updatingChartSeries = false;
        }

        @Override public void seriesPainting(ChartDrawEvent e) {
            while (updatingData) ;
            updatingChartSeries = true;
        }
    });


    scrollPager.getSubChartTChart().addChartPaintListener(new ChartPaintAdapter() {
        @Override
        public void chartPainted(ChartDrawEvent e) {
            updatingSubChart = false;
        }

        @Override public void chartPainting(ChartDrawEvent e) {
            while (updatingData) ;
            updatingSubChart = true;
        }

        @Override public void seriesPainted(ChartDrawEvent e) {
            updatingSubChartSeries = false;
        }

        @Override public void seriesPainting(ChartDrawEvent e) {

            while (updatingData) ;
            updatingSubChartSeries = true;
        }
    });

    add(chart);
    pack();
    setVisible(true);

    threadSleep(500);
}

public void drawChart() {

    updatingData = true;

    while (updatingChart && updatingSubChart
            && updatingChartSeries && updatingSubChartSeries
            && draggingSubChart) ;

    scrollPager.getSubChartTChart().removeAllSeries();
    scrollPager.setSeries(null);

    series.beginUpdate();

    if (scrollPager.getSeries() != null)
        scrollPager.getSeries().beginUpdate();

    series.fillSampleValues(500);

    FastLine fl = new FastLine();
    for (int j = 0; j < series.getCount(); j++)
        fl.add(series.getDateValues().getValue(j), series.getCloseValues().getValue(j));

    scrollPager.setSeries(fl);

    series.endUpdate();

    if (scrollPager.getSeries() != null)
        scrollPager.getSeries().endUpdate();


    int lastVisibleId = series.getCount() - 1;
    if (lastVisibleId < 0)
        lastVisibleId = 0;

    int firstVisibleId = lastVisibleId - 100;
    if (firstVisibleId < 0)
        firstVisibleId = 0;

    double last = series.getDateValues().getValue(lastVisibleId);
    double first = series.getDateValues().getValue(firstVisibleId);

    scrollPager.getColorBandTool().setStart(first);
    scrollPager.getColorBandTool().setEnd(last);

    chart.getAxes().getBottom().setMinMax(first, last);

    updatingData = false;

    pack();

    while (updatingChart && updatingSubChart
            && updatingChartSeries && updatingSubChartSeries
            && draggingSubChart) ;

}

public static void main(String[] args) {

    TestTeeChartCandle testTeeChartCandle = new TestTeeChartCandle();

    while (true) {

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        testTeeChartCandle.drawChart();

    }


}

public void threadSleep(int ms) {
    try {
        Thread.sleep(ms);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}


public class MyScrollPager extends ScrollPager implements com.steema.teechart.events.DragListener {

    public MyScrollPager(com.steema.teechart.IBaseChart iBaseChart) {
        super(iBaseChart);
    }

    @Override
    public void dragFinished(com.steema.teechart.events.ChangeEvent changeEvent) {
        draggingSubChart = false;
    }

    @Override
    public void dragMoving(com.steema.teechart.events.ChangeEvent changeEvent) {
        while (updatingData) ;
        draggingSubChart = true;
    }

}

}

如果正在更新数据,当鼠标在图表上移动时暂停线程怎么办?

    tChart1.addMouseMotionListener(new MouseMotionAdapter() {

        @Override
        public void mouseMoved(MouseEvent e) {
             while (updatingData) ;
        }
    });

编辑 1:

我们一直在调查此事。
该示例重新填充系列的速度如此之快,以至于很容易重现问题;在真实情况下可能不会那么容易发生。

我们添加了 AllowMouse 属性(可通过相应的 getter 和 setter 公开访问),默认情况下 true 禁用任何当图表为 false 时将在图表上触发鼠标事件。此 属性 将允许您在修改图表之前禁用图表上的鼠标事件,因此 ScrollPager 工具中的 ColorBand 在您重新启用 AllowMouse 属性 再次,在您的修改例程结束时。


编辑 2:

我们制作了另一个测试演示,我们将与大家分享 here

请注意它不使用 AllowMouse 但它不会每次都清除该系列;相反,它 adds/appends 指向当前系列,并在滚动条中重复使用该系列,而不是每次都重新分配它。
这一点,在源中进行一些额外的范围和空检查,使测试应用程序在这里对我们来说是稳定的。

请注意,随着点不断到达,色带会变小;如果您继续添加点而不删除任何人并且不重新调整滚动条的底轴,它将以非常小且几乎无法使用的色带结束。示例中有一些代码注释过一段时间后删除了第一个点。

最后,我们建议以较慢的间隔添加点。不那么频繁地添加更多的点会不太流畅,但会让用户更容易捕捉色带、拖动它或调整它的大小。