代码改变世界

在RCP应用上使用Jfreechart绘制图表(附源码)

2012-06-28 16:21  飘扬的红领巾  阅读(2455)  评论(0编辑  收藏  举报

        下午闲来无事,找出Jfreechart来复习一下,做了个在RCP上使用Jfreechart的小程序。

第一步、创建RCP程序。

    在Eclipse中,使用向导创建Eclipse插件程序:

image

后面就不说了,填写相应项,一路下去,创建好Eclipse插件程序,运行可以看到:

image

第二步、创建视图

    创建视图既可以使用向导创建,也可以手动添加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);
	}

}

代码就不详细讲解了,最后会把整个例子的源代码共享出来。

创建了视图,应用程序运行起来就会是这样子:

image

第三步、在视图中创建树

在创建好的视图类中,添加创建树的代码,代码有点多不贴了,可以到附件中下载。

image

上图创建了一个树,表示将要在右边视图显示的图表的类别(柱状图、坐标图、饼图)

第四步、创建图表

    先添加一个图表类,以饼图为例,如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类是自定义的一个图表工厂,用于创建指定的图表。做完这些事儿,之后。

image

第五步、实现视图间的通信

    简单的来说,就是点击左边的树节点,右边视图中的图表根据点击的节点做相应的更新。实现此功能有很多种方法,常用的方法是在左边视图中,取得右边视图的句柄,然后调用其相关的方法,实现更新。但此方法耦合性较高,不便于扩展,我们不推荐此方法。这里我们使用观察者模式来实现此功能,也就说创建一个被观察者(主题),让视图作为观察者,监听其变化,当监听到主题变化时,做更新图表的操作。而左边视图所做的事情就是在用户点击时,改变主题的内容,触发它的变化。

为此我们这样做:

添加主题: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();
	}

从而实现左右视图的消息传递。

image

(柱状图)

image

(坐标图)

下载

下载地址