You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing:在装饰器模式中复用父JPanel的Graphics2D引用

解决Java Swing中装饰器模式传递Graphics对象的方案

1. 定义统一图表渲染接口(装饰器模式核心)

先创建一个接口,让基础图表和装饰器类都实现它,接口方法直接接收Graphics对象与绘制区域,这是传递Graphics的核心入口:

public interface Chart {
    // 传入Graphics对象与当前绘制区域的边界
    void draw(Graphics g, Rectangle drawArea);
}

2. 实现基础折线图组件(被装饰者)

这是最基础的简单折线图,实现Chart接口,在draw方法中使用传入的Graphics完成折线绘制:

import java.awt.*;
import java.awt.geom.*;

public class LineChart implements Chart {
    @Override
    public void draw(Graphics g, Rectangle drawArea) {
        // 创建Graphics副本,避免修改原始对象的全局状态
        Graphics2D g2d = (Graphics2D) g.create();
        
        // 设置折线样式
        g2d.setColor(Color.BLUE);
        g2d.setStroke(new BasicStroke(2));
        
        // 基于绘制区域计算折线坐标(示例数据)
        int[] xPoints = {drawArea.x + 50, drawArea.x + 150, drawArea.x + 250, drawArea.x + 350};
        int[] yPoints = {drawArea.y + 150, drawArea.y + 80, drawArea.y + 120, drawArea.y + 50};
        g2d.drawPolyline(xPoints, yPoints, 4);
        
        // 释放副本资源
        g2d.dispose();
    }
}

3. 实现柱状图装饰器(装饰者)

装饰器持有一个Chart类型的对象(可以是基础组件或其他装饰器),在draw方法中先调用被装饰对象的绘制逻辑,再用同一个Graphics对象添加柱状图:

import java.awt.*;

public class BarChartDecorator implements Chart {
    private Chart decoratedChart;

    public BarChartDecorator(Chart decoratedChart) {
        this.decoratedChart = decoratedChart;
    }

    @Override
    public void draw(Graphics g, Rectangle drawArea) {
        // 先绘制被装饰的基础图表(比如折线图)
        decoratedChart.draw(g, drawArea);
        
        // 复用同一个Graphics对象绘制柱状图
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(new Color(255, 165, 0, 120)); // 半透明橙色
        
        // 基于绘制区域计算柱子坐标(示例数据)
        int barWidth = 40;
        int[] barHeights = {100, 70, 90, 120};
        for (int i = 0; i < barHeights.length; i++) {
            int x = drawArea.x + 30 + i * 80;
            int y = drawArea.y + drawArea.height - barHeights[i] - 20;
            g2d.fillRect(x, y, barWidth, barHeights[i]);
        }
        
        g2d.dispose();
    }
}

4. 构建分割式JPanel,传递Graphics到装饰器

自定义JPanel,在paintComponent方法中将面板划分为上下均等区域,分别调用基础图表与装饰后图表的draw方法,传入对应区域的Graphics和边界:

import java.awt.*;
import javax.swing.*;

public class ChartPanel extends JPanel {
    private Chart topLineChart;
    private Chart bottomCombinedChart;

    public ChartPanel() {
        // 初始化顶部简单折线图
        topLineChart = new LineChart();
        // 用柱状图装饰器包装基础折线图,得到底部组合图表
        bottomCombinedChart = new BarChartDecorator(new LineChart());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        // 计算上下两个均等区域的边界
        int halfHeight = getHeight() / 2;
        Rectangle topArea = new Rectangle(0, 0, getWidth(), halfHeight);
        Rectangle bottomArea = new Rectangle(0, halfHeight, getWidth(), halfHeight);
        
        // 绘制顶部折线图
        topLineChart.draw(g, topArea);
        // 绘制底部组合图表(折线+柱状)
        bottomCombinedChart.draw(g, bottomArea);
        
        // 绘制分割线区分区域
        g.setColor(Color.GRAY);
        g.drawLine(0, halfHeight, getWidth(), halfHeight);
    }
}

5. 测试主程序

将自定义JPanel嵌入窗口运行:

import javax.swing.*;

public class ChartApplication {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("装饰器模式图表示例");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(500, 600);
            frame.add(new ChartPanel());
            frame.setVisible(true);
        });
    }
}

关键细节说明

  • Graphics传递逻辑:通过Chart接口的draw方法直接传递对象,装饰器复用同一个Graphics完成附加绘制,保证渲染上下文一致。
  • 状态隔离:每次绘制时创建Graphics副本,绘制完成后释放,避免修改原始对象的全局状态(如颜色、画笔样式)影响其他组件。
  • 区域划分:在paintComponent中动态计算上下区域边界,确保两个图表各占一半空间,可根据需求调整比例。

内容的提问来源于stack exchange,提问作者Vaishu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 21:25:22