按钮事件触发时自定义JPanel Canvas无法绘制线条问题求助
问题原因
- 错误缓存了
Graphics对象引用:Swing中paintComponent传入的Graphics对象是临时的,仅在重绘周期内有效,你将其存为Canvas的成员变量g2d,在drawL中调用时该对象已经失效,绘制操作不会生效。 - 绘制逻辑被覆盖:
drawL中直接绘制的内容,会被后续触发的repaint调用的paintComponent方法完全覆盖,paintComponent中只绘制了初始线条和圆点,不会保留你动态绘制的内容。 - Canvas组件未添加到窗口:你创建了
canva实例,但没有将其添加到JFrame的内容面板中,组件本身都不可见,自然看不到绘制结果。 - 构造方法命名错误:
Window类的构造方法被命名为Ventana,和类名不一致,导致类初始化逻辑不会执行,属于基础语法错误。
解决方案
- 移除缓存的
Graphics成员变量,所有绘制操作统一在paintComponent中执行 - 新增集合存储需要动态绘制的线条参数,每次点击按钮仅向集合中添加数据,触发重绘即可
- 将Canvas组件添加到窗口的内容面板
- 修正构造方法命名错误
修改后的Canvas类核心代码
public class Canvas extends JPanel { static final int SCREEN_WIDTH = 300; static final int SCREEN_HEIGHT = 300; // 存储动态添加的线条,每个元素保存起点、终点、颜色 private final List<LineData> dynamicLines = new ArrayList<>(); // 内部类存储线条参数 private static class LineData { char posi; int posf; Color color; LineData(char posi, int posf, Color color) { this.posi = posi; this.posf = posf; this.color = color; } } public Canvas() { this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT)); this.setBackground(new Color(66, 64, 64)); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; // 绘制初始线条 trazarLinea(g2d, 'a', 1, new Color(75, 201, 201)); trazarLinea(g2d, 'b', 3, new Color(240, 20, 255)); trazarLinea(g2d, 'c', 1, new Color(235, 64, 52)); trazarLinea(g2d, 'd', 2, new Color(128, 64, 123)); // 绘制动态添加的线条 for (LineData line : dynamicLines) { trazarLinea(g2d, line.posi, line.posf, line.color); } dibujarCirculos(g2d); } public void dibujarCirculos(Graphics2D g2d) { g2d.setColor(new Color(230, 160, 30)); g2d.fillOval(20, 20, 20, 20); g2d.fillOval(20, 97, 20, 20); g2d.fillOval(20, 182, 20, 20); g2d.fillOval(20, 255, 20, 20); g2d.fillOval(270, 20, 20, 20); g2d.fillOval(270, 97, 20, 20); g2d.fillOval(270, 182, 20, 20); g2d.fillOval(270, 255, 20, 20); } // 方法新增Graphics2D参数,使用传入的对象绘制 public void trazarLinea(Graphics2D g2d, char posi, int posf, Color c) { final int X1 = 27; final int Y2 = 275; int y1 = 0, y2 = 0; g2d.setStroke(new BasicStroke(6)); g2d.setColor(c); switch (posi) { case 'a': y1 = 30; break; case 'b': y1 = 109; break; case 'c': y1 = 194; break; case 'd': y1 = 264; break; default: y1 = 30; } switch (posf) { case 1: y2 = 30; break; case 2: y2 = 109; break; case 3: y2 = 194; break; case 4: y2 = 264; break; default: y2 = 30; } g2d.drawLine(X1, y1, Y2, y2); } public void drawL() { // 仅添加线条数据到集合,触发重绘即可 dynamicLines.add(new LineData('a', 4, new Color(240, 20, 255))); repaint(); } }
修改后的Window类核心代码
public class Window extends JFrame { private JTextField txt_ubicacion; private JTextField txt_color; private JPanel panel_1; private Canvas canva; // 修正构造方法名称和类名一致 public Window() { this.setPreferredSize(new Dimension(575, 330)); this.setTitle("Relación de puntos - canvas"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setResizable(true); panel_1 = new JPanel(); getContentPane().add(panel_1, BorderLayout.NORTH); iniciarComponentes(); this.pack(); this.setLocationRelativeTo(null); this.setVisible(true); // 组件初始化完成后再显示窗口 } public void iniciarComponentes() { canva = new Canvas(); // 将canvas添加到窗口中央区域 getContentPane().add(canva, BorderLayout.CENTER); JButton boton_dibujar = new JButton("Dibujar"); boton_dibujar.addActionListener(e -> canva.drawL()); boton_dibujar.setFocusPainted(false); boton_dibujar.setBackground(new Color(0, 139, 139)); boton_dibujar.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 11)); // 此处省略面板布局相关代码,确保按钮被添加到可见容器中即可 panel_1.add(boton_dibujar); } public static void main(String[] args) { // Swing组件初始化要放在EDT线程中执行 SwingUtilities.invokeLater(() -> new Window()); } }
内容的提问来源于stack exchange,提问作者Jugo de mora
相关产品推荐
相关产品推荐

