代码改变世界

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

  飘扬的红领巾  阅读(2462)  评论(0编辑  收藏  举报

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

第一步、创建RCP程序。

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

image

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

image

第二步、创建视图

    创建视图既可以使用向导创建,也可以手动添加Java类,如添加类似这样的类:

1
public class ChartCategoryViewPart extends ViewPart

然后在Perspective .java中将创建的视图添加到透视图中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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;
    }
}

完成图表类之后,想要在视图中显示它,必须完成下面的工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
@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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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();
    }
}

在应用程序启动时,放置到系统内存中:

1
2
3
4
5
6
7
8
9
10
11
@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(主题):

1
2
3
4
5
@Override
    public void init(IViewSite site) throws PartInitException {
        stateModel = (StateModel) site.getPage().getInput();
        super.init(site);
    }

然后点击事件中:

1
2
3
4
5
6
7
8
9
10
11
12
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接口):

1
2
3
4
5
6
@Override
    public void init(IViewSite site) throws PartInitException {
        stateModel = (StateModel) site.getPage().getInput();
        stateModel.addObserver(this);
        super.init(site);
    }

响应到主题变更后会自动调用update方法:

1
2
3
4
5
@Override
    public void update(Observable o, Object arg) {
        categoryEnum = stateModel.getCategoryEnum();
        draw();
    }

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

image

(柱状图)

image

(坐标图)

下载

下载地址

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示