Scroll JfreeChart限制显示的图例项目数
我负责维护一个可以使用JFreeChart绘制图形的应用程序。 该应用程序是用EclipseRCP和SWT编写的,并使用ChartComposite来显示图表 ChartComposite已被部分覆盖,以便根据所选内容自定义上下文菜单:Scroll JfreeChart限制显示的图例项目数,scroll,swt,eclipse-rcp,jfreechart,Scroll,Swt,Eclipse Rcp,Jfreechart,我负责维护一个可以使用JFreeChart绘制图形的应用程序。 该应用程序是用EclipseRCP和SWT编写的,并使用ChartComposite来显示图表 ChartComposite已被部分覆盖,以便根据所选内容自定义上下文菜单: @Override public void createPartControl(Composite parent) { super.createPartControl(parent); chart = createChart(timeS
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
chart = createChart(timeSeriesDataset);
chartComposite = new MyChartComposite(this, parent, SWT.NONE, chart, true);
chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
selectionProvider = new GenericObjectSelectionProvider();
getSite().setSelectionProvider(selectionProvider);
// add information to the status line:
selectionProvider.addSelectionChangedListener(statusLineListener);
addDropSupport();// add D'n D support for dropping TimeSeries
}
protected JFreeChart createChart(TimeSeriesCollection ptimeSeriesDataset) {
JFreeChart vChart = ChartFactory.createTimeSeriesChart(null, "time", "values", ptimeSeriesDataset, true,
false, false);
vChart.setBackgroundPaint(Color.white);
XYPlot plot = vChart.getXYPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
// plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);
plot.setRenderer(new /*OptimisedXYLineAndShapeRenderer()*/ StandardXYItemRendererFast());
XYItemRenderer renderer = plot.getRenderer();
renderer.setBaseToolTipGenerator(new MyXYSeriesToolTipGenerator());
renderer.setBaseItemLabelGenerator(new MyXYSeriesItemLabelGenerator());
renderer.setLegendItemLabelGenerator(new MyXYSeriesLegendItemLabelGenerator());
if (renderer instanceof XYLineAndShapeRenderer) {
XYLineAndShapeRenderer r = (XYLineAndShapeRenderer) renderer;
r.setBaseShapesVisible(false);
r.setBaseShapesFilled(true);
}
SimpleDateFormat dateFormat = getDateFormatAbscissa();
if (dateFormat != null){
DateAxis axis = (DateAxis) plot.getDomainAxis();
axis.setDateFormatOverride(dateFormat);
}
return vChart;
}
我的问题是,当向图表(TimeSeriesChart)中添加太多变量时,标题占用了太多空间,图形从视图中消失:
我试图创建一个ScrollComposite来在ChartComposite中滚动,结果要好一点;但它只能在图表再次消失之前在标题中添加更多项目:
ScrolledComposite scrollableChart = new ScrolledComposite(parent, SWT.BORDER|SWT.V_SCROLL);
chartComposite = new MyChartComposite(this, scrollableChart, SWT.NONE, chart, true);
//chartComposite = new MyChartComposite(this, parent, SWT.NONE, chart, true);
//chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
scrollableChart.setContent(chartComposite);
scrollableChart.setExpandVertical(true);
scrollableChart.setExpandHorizontal(true);
scrollableChart.setMinSize(ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH, ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH);
我的问题是:如何为ChartComposite提供一个真正的滚动条,以便在图形上绘制多个系列时保持图形?我能够使用ChartComosite和slider对象,通过使用FormData将滑块同步到SWT中的XYSeries。每次移动滑块时,我都会捕捉到该事件,并根据需要自行更新图表 我的用例可能与您的不同,但值得一看我的答案
如果您对该答案中描述的我的实现有任何疑问,请随时询问详细信息我能够使用ChartComosite和slider对象,通过使用FormData将slider同步到SWT中的XYSeries。每次移动滑块时,我都会捕捉到该事件,并根据需要自行更新图表 我的用例可能与您的不同,但值得一看我的答案
如果您对该答案中描述的我的实现有任何疑问,请随时询问详细信息。在多次尝试失败后,我决定限制图表上显示的
LegendItem
的数量
要更改要在LegendTitle
中显示的图例项,我使用了滑块。最困难的部分是在使用滑块时重新创建一个新的LegendTitle;我不确定我的解决方案是最优的还是优雅的,但至少它是有效的
为了实现这一点,我需要监听序列创建(ChartChangeEventType.DATASET\u UPDATED
)来刷新LegendTitle并设置滑块值
下面是代码:
public class MyExampleChartComposite extends ChartComposite {
// snip
/**
* A slider to choose the legend items to display
*/
private Slider legendSlider;
/**
* Number of legend items to display on the chart
*/
private final static int NUMBER_OF_LEGENDITEMS_TO_DISPLAY = 10;
private void createPartControl(Composite parent, int style) {
JFreeChart chart = createChart();
setChart(chart);
legendSlider = new Slider(parent, SWT.NONE|SWT.H_SCROLL);
legendSlider.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent arg0) {
refreshLegend();
}
});
private JFreeChart createChart() {
chart.addChangeListener(new ChartChangeListener() {
@Override
public void chartChanged(ChartChangeEvent e) {
if (e.getType().equals(ChartChangeEventType.DATASET_UPDATED)) {
refreshLegend();
}
}
});
}
/**
* Refresh the the LegendItems and the slider,
* according to slider selection.
*/
public void refreshLegend() {
// Display LegendItems according to the selection
// display the 10 nearest legend item (current selected element included)
int begin = legendSlider.getSelection() - (NUMBER_OF_LEGENDITEMS_TO_DISPLAY/2);
int end = legendSlider.getSelection() + (NUMBER_OF_LEGENDITEMS_TO_DISPLAY/2 -1);
int seriesEndIndex = Math.max(getSeriesCount()-1, 0);
// if begin is less than 0
// set it to 0, and increase end to display 10 items
if (begin < 0) {
begin = 0;
end = NUMBER_OF_LEGENDITEMS_TO_DISPLAY - 1;
}
// if end is greater than the number of series plotted
// set it to the max possible value and increase begin to
// display 10 items
if (end > seriesEndIndex) {
end = seriesEndIndex;
begin = seriesEndIndex - (NUMBER_OF_LEGENDITEMS_TO_DISPLAY - 1);
}
end = Math.min(seriesEndIndex, end);
begin = Math.max(begin, 0);
// Refresh only if begin != end
if (end != begin) {
refreshLegendItems(begin, end);
refreshLegendSlider();
} else {
// in this case no more series are plotted on the chart
// clear legend
getChart().clearSubtitles();
}
}
/**
* Refresh the LegendTitle.
* Display only LegendItems between beginIndex and toIndex,
* to preserve space for the chart.
* @param beginIndex index of the {@link LegendItemCollection} used as the beginning of the new {@link LegendTitle}
* @param endIndex index of the {@link LegendItemCollection} used as the end of the new {@link LegendTitle}
*/
private void refreshLegendItems(int beginIndex, int endIndex) {
// Last 10 items
final LegendItemCollection result = new LegendItemCollection();
// get the renderer to retrieve legend items
XYPlot plot = getChart().getXYPlot();
XYItemRenderer renderer = plot.getRenderer();
// Number of series displayed on the chart
// Construct the legend
for (int i = beginIndex; i <= endIndex; i++) {
LegendItem item = renderer.getLegendItem(0, i);
result.add(item);
}
// Because the only way to create a new LegendTitle is to
// create a LegendItemSource first
LegendItemSource source = new LegendItemSource() {
LegendItemCollection lic = new LegendItemCollection();
{lic.addAll(result);}
public LegendItemCollection getLegendItems() {
return lic;
}
};
// clear previous legend title
getChart().clearSubtitles();
// Create the new LegendTitle and set its position
LegendTitle legend = new LegendTitle(source);
legend.setHorizontalAlignment(HorizontalAlignment.CENTER);
legend.setVerticalAlignment(VerticalAlignment.CENTER);
legend.setPosition(RectangleEdge.BOTTOM);
legend.setBorder(1.0, 1.0, 1.0, 1.0);
legend.setVisible(true);
// Add the LegendTitle to the graph
getChart().addLegend(legend);
}
/**
* Set values of the slider according to the number of series
* plotted on the graph
*/
private void refreshLegendSlider() {
int max = getSeriesCount() -1;
int selection = Math.min(legendSlider.getSelection(), max);
legendSlider.setValues(selection, 0, max, 1, 1, 1);
}
}
公共类MyExampleChartComposite扩展了ChartComposite{
//剪断
/**
*用于选择要显示的图例项目的滑块
*/
私有滑块legendSlider;
/**
*要在图表上显示的图例项目数
*/
私有最终静态整数,从LEGENDITEMS到DISPLAY的整数=10;
私有void createPartControl(复合父级,int样式){
JFreeChart chart=createChart();
setChart(图表);
Legendslaider=新滑块(父级,SWT.NONE | SWT.H|u滚动);
legendSlider.addSelectionListener(新建SelectionListener(){
@凌驾
公共无效widgetSelected(SelectionEvent arg0){
刷新图例();
}
});
私有JFreeChart createChart(){
chart.addChangeListener(新的ChartChangeListener(){
@凌驾
公共无效图表更改(图表更改事件e){
if(e.getType().equals(ChartChangeEventType.DATASET_更新)){
刷新图例();
}
}
});
}
/**
*刷新LegendItems和滑块,
*根据滑块选择。
*/
公共空白刷新图例(){
//根据选择显示LegendItems
//显示最近的10个图例项(包括当前选定的图元)
int begin=legendSlider.getSelection()-(LEGENDITEMS到LEGENDITEMS的数量/2);
int end=legendsloider.getSelection()+(LEGENDITEMS到显示的数量/2-1);
int seriesendex=Math.max(getSeriesCount()-1,0);
//如果开始小于0
//将其设置为0,并增加“结束”以显示10项
如果(开始<0){
开始=0;
结束=要显示的项目的数量-1;
}
//如果end大于打印的系列数
//将其设置为最大可能值并开始增加
//显示10个项目
如果(结束>系列索引){
结束=系列索引;
begin=seriesEndIndex-(要显示的传奇项目的数量-1);
}
结束=数学最小值(序列索引,结束);
begin=Math.max(begin,0);
//仅当开始!=结束时刷新
如果(结束!=开始){
刷新LegendItems(开始、结束);
刷新LegendSlider();
}否则{
//在这种情况下,图表上不再绘制更多的系列
//清晰的图例
getChart().clearSubtitles();
}
}
/**
*刷新LegendTitle。
*仅显示beginIndex和toIndex之间的LegendItems,
*为图表保留空间。
*用作新{@link LegendTitle}开头的{@link LegendItemCollection}的@param beginIndex索引
*用作新{@link LegendTitle}结尾的{@link LegendItemCollection}的@param endIndex索引
*/
私有void refreshLegendItems(int-beginIndex,int-endIndex){
//最后10项
最终LegendItemCollection结果=新建LegendItemCollection();
//获取渲染器以检索图例项
XYPlot=getChart().getXYPlot();
XYItemRenderer=plot.getRenderer();
//图表上显示的系列数
//构建传奇
对于(int i=beginIndex;i在多次尝试失败后,我决定限制图表上显示的LegendItem
的数量
要更改图例项以显示在LegendTitle
中,我使用了一个滑块。最困难的部分是重新创建一个新的LegendTitle