在RCP应用上使用Jfreechart绘制图表(附源码)
2012-06-28 16:21 飘扬的红领巾 阅读(2455) 评论(0) 编辑 收藏 举报下午闲来无事,找出Jfreechart来复习一下,做了个在RCP上使用Jfreechart的小程序。
第一步、创建RCP程序。
在Eclipse中,使用向导创建Eclipse插件程序:
后面就不说了,填写相应项,一路下去,创建好Eclipse插件程序,运行可以看到:
第二步、创建视图
创建视图既可以使用向导创建,也可以手动添加Java类,如添加类似这样的类:
public class ChartCategoryViewPart extends ViewPart
然后在Perspective .java中将创建的视图添加到透视图中:
public class Perspective implements IPerspectiveFactory { @Override public void createInitialLayout(IPageLayout layout) { String editorArea = layout.getEditorArea(); layout.addStandaloneView( com.cnblogs.leefreeman.views.ChartCategoryViewPart.ID, true, IPageLayout.LEFT, 0.23f, editorArea); layout.addStandaloneView(ChartInfoViewPart.ID, true, IPageLayout.RIGHT, 0.77f, editorArea); layout.setEditorAreaVisible(false); layout.setFixed(true); } }
代码就不详细讲解了,最后会把整个例子的源代码共享出来。
创建了视图,应用程序运行起来就会是这样子:
第三步、在视图中创建树
在创建好的视图类中,添加创建树的代码,代码有点多不贴了,可以到附件中下载。
上图创建了一个树,表示将要在右边视图显示的图表的类别(柱状图、坐标图、饼图)
第四步、创建图表
先添加一个图表类,以饼图为例,如PieChart.java。
public class PieChart { /** * 创建提供给图表显示的数据 * * @return */ private static PieDataset createDataset() { DefaultPieDataset defaultpiedataset = new DefaultPieDataset(); defaultpiedataset.setValue("C", 17.00D); defaultpiedataset.setValue("Java", 17.00D); defaultpiedataset.setValue("C++", 9.00D); defaultpiedataset.setValue("Objective-C", 8.00D); defaultpiedataset.setValue("C#", 7.00D); defaultpiedataset.setValue("Other", 42.00D); return defaultpiedataset; } /** * 创建图表 * @return */ @SuppressWarnings("deprecation") public static JFreeChart createChart() { PieDataset dataset = createDataset(); JFreeChart chart = ChartFactory.createPieChart3D("", dataset, true, true, true); // 设置图片的背景色 chart.setBackgroundPaint(java.awt.Color.white); // 设置图片标题的字体和大小 TextTitle title = new TextTitle("编程语言排名"); chart.setTitle(title); PiePlot3D pie = (PiePlot3D) chart.getPlot(); pie.setInsets(new RectangleInsets(5, 5, 5, 5)); // 指定 section 轮廓线的颜色 pie.setOutlinePaint(java.awt.Color.BLACK); // 指定 section 轮廓线的厚度 pie.setOutlineStroke(new BasicStroke(1)); // 设置第一个 section 的开始位置,默认是12点钟方向,90度,逆时针 pie.setStartAngle(90); // 指定 section 的色彩 pie.setSectionPaint(1, new Color(0x99, 0x99, 0xFF)); pie.setLabelFont(new Font("黑体", Font.BOLD, 12)); // 指定显示的饼图上圆形还椭圆形。true为圆形,false为椭圆形。默认为false pie.setCircular(true); // 指定图片的透明度 pie.setForegroundAlpha(0.5f); pie.setLabelGap(0.01);// 间距 pie.setNoDataMessage("No data available"); return chart; } }
完成图表类之后,想要在视图中显示它,必须完成下面的工作:
@Override public void createPartControl(Composite parent) { JFreeChart chart = ChartFactory.createChart(categoryEnum); if (chart != null) { final ChartComposite frame = new ChartComposite(parent, SWT.NONE, chart, true); if (parent.getChildren().length > 1) { parent.getChildren()[0].dispose(); } frame.pack(); parent.layout(); } }
ChartFactory类是自定义的一个图表工厂,用于创建指定的图表。做完这些事儿,之后。
第五步、实现视图间的通信
简单的来说,就是点击左边的树节点,右边视图中的图表根据点击的节点做相应的更新。实现此功能有很多种方法,常用的方法是在左边视图中,取得右边视图的句柄,然后调用其相关的方法,实现更新。但此方法耦合性较高,不便于扩展,我们不推荐此方法。这里我们使用观察者模式来实现此功能,也就说创建一个被观察者(主题),让视图作为观察者,监听其变化,当监听到主题变化时,做更新图表的操作。而左边视图所做的事情就是在用户点击时,改变主题的内容,触发它的变化。
为此我们这样做:
添加主题:StateModel.java
public class StateModel extends Observable implements IAdaptable { private ChartCategoryEnum categoryEnum; /** * @return the categoryEnum */ public ChartCategoryEnum getCategoryEnum() { return categoryEnum; } /** * @param categoryEnum the categoryEnum to set */ public void setCategoryEnum(ChartCategoryEnum categoryEnum) { this.categoryEnum = categoryEnum; } @Override public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { return null; } public void fireModelChanged() { this.setChanged(); notifyObservers(); } }
在应用程序启动时,放置到系统内存中:
@Override public void postWindowOpen() { StateModel stateModel = new StateModel(); try { IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); configurer.getWindow().openPage(PERSPECTIVE_ID, stateModel); } catch (WorkbenchException e) { e.printStackTrace(); } super.postWindowOpen(); }
在左边视图类中先从系统内存中取得StateModel(主题):
@Override public void init(IViewSite site) throws PartInitException { stateModel = (StateModel) site.getPage().getInput(); super.init(site); }
然后点击事件中:
Object obj = ((IStructuredSelection) selection) .getFirstElement(); if (obj.toString().equals("Bar Chart")) { stateModel.setCategoryEnum(ChartCategoryEnum.BAR); } if (obj.toString().equals("Pie Chart")) { stateModel.setCategoryEnum(ChartCategoryEnum.PIE); } if (obj.toString().equals("MultipleAxis Chart")) { stateModel.setCategoryEnum(ChartCategoryEnum.MULTIPLEAXIS); } stateModel.fireModelChanged();
stateModel就会触发变更。
而在右边视图中,同样先从内存中取得stateModel,然后将自己加入到观察者队列中(视图必须实现Observer接口):
@Override public void init(IViewSite site) throws PartInitException { stateModel = (StateModel) site.getPage().getInput(); stateModel.addObserver(this); super.init(site); }
响应到主题变更后会自动调用update方法:
@Override public void update(Observable o, Object arg) { categoryEnum = stateModel.getCategoryEnum(); draw(); }
从而实现左右视图的消息传递。
(柱状图)
(坐标图)
下载