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 指向当前系列,并在滚动条中重复使用该系列,而不是每次都重新分配它。
这一点,在源中进行一些额外的范围和空检查,使测试应用程序在这里对我们来说是稳定的。
请注意,随着点不断到达,色带会变小;如果您继续添加点而不删除任何人并且不重新调整滚动条的底轴,它将以非常小且几乎无法使用的色带结束。示例中有一些代码注释过一段时间后删除了第一个点。
最后,我们建议以较慢的间隔添加点。不那么频繁地添加更多的点会不太流畅,但会让用户更容易捕捉色带、拖动它或调整它的大小。
我正在尝试动态更新主图表系列数据,但如果我移动 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 指向当前系列,并在滚动条中重复使用该系列,而不是每次都重新分配它。
这一点,在源中进行一些额外的范围和空检查,使测试应用程序在这里对我们来说是稳定的。
请注意,随着点不断到达,色带会变小;如果您继续添加点而不删除任何人并且不重新调整滚动条的底轴,它将以非常小且几乎无法使用的色带结束。示例中有一些代码注释过一段时间后删除了第一个点。
最后,我们建议以较慢的间隔添加点。不那么频繁地添加更多的点会不太流畅,但会让用户更容易捕捉色带、拖动它或调整它的大小。