【问题标题】:button triggers frame.repaint() even when I did not tell it to. What did I do wrong?即使我没有告诉它,按钮也会触发 frame.repaint()。我做错了什么?
【发布时间】:2020-04-18 12:30:39
【问题描述】:

我 4 天前刚开始学习 Java,正在阅读 Head First Java,第 12 章进展缓慢。 即使我没有告诉它,我的 JButton eastb 也会触发 frame.repaint()。我只告诉它在按下时触发 setText()。为什么会这样?我错过了什么?

还有什么是@Override?不是方法中的“覆盖”一词,而是“@Override”一词本身。

\\

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

    public class Exp {
     JFrame frame;
     JLabel label;
     JButton eastb;
     JButton southb;

     public static void main(String[] args) {
      Exp a = new Exp();
      a.start();
     }

     public void start() {
      frame = new JFrame();
      frame.setSize(700,700);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      label = new JLabel("I'm stored text only");
      frame.getContentPane().add(BorderLayout.WEST, label);

      eastb = new JButton("Don't click me");
      frame.getContentPane().add(BorderLayout.EAST, eastb);
      eastb.addActionListener(new EastButton());

      southb = new JButton("Change color");
      frame.getContentPane().add(BorderLayout.SOUTH, southb);
      southb.addActionListener(new SouthButton());

      frame.add(new DrawPanel());

      frame.setVisible(true);
     }

     class EastButton implements ActionListener {
      public void actionPerformed(ActionEvent event1) {  
       eastb.setText("Ouch!");
      }
     }

     class SouthButton implements ActionListener {
      public void actionPerformed(ActionEvent event2) {
       frame.repaint();
      }
     }

    }

    class DrawPanel extends JPanel {
     public void paintComponent(Graphics g) {

      int red = (int) (Math.random()*255);
      int green = (int) (Math.random()*255);
      int blue = (int) (Math.random()*255); 

      Color randomizer = new Color(red, green, blue);
      g.setColor(randomizer);

      int x = getWidth()/2;
      int y = getHeight()/2;
      int r = x/2;
      int d = 2*r;

      g.fillOval(x-r, y-r, d, d);
     }
    }

\\

【问题讨论】:

  • “即使我没有告诉它,按钮也会触发 frame.repaint()。” JVM 在计算/检测到需要时调用重绘。我们程序员无法控制,只能请求额外的重绘。 “我做错了什么?” 不了解 Java 绘制机制的工作原理。另见What is the XY problem?
  • “还有什么是@Override?” 将 SO 问题限制在一个明确、具体的问题上会更有用,根据需要提出其他问题。但是您是新手,所以我会迷路:@Override 是仅由编译器使用的符号。它用于标记应该覆盖父方法的方法。因此,如果添加到方法paintComponent(Graphics2D g) 中,编译器会发出警告,因为没有采用2D 图形对象的绘制方法。如果用于paintComponent(Graphics g) 方法,它不会显示编译器警告(& 不会被写入类文件 - 使用完成)。

标签: java swing jbutton actionlistener actionevent


【解决方案1】:

我只是告诉它在按下时触发 setText()。

当您更改组件的属性时,组件的大小可能会发生变化。如果大小发生变化,可能会影响所有组件的布局,因此调用布局管理器。一旦布局管理器被调用,所有的可能都会调整大小/位置,以便重新绘制面板上的所有组件。

此过程是自动的,这会导致您的代码出现问题。

绘画方法应该只用于绘画。您不应该在绘画方法中更改您的类的属性。

  int red = (int) (Math.random()*255);
  int green = (int) (Math.random()*255);
  int blue = (int) (Math.random()*255); 

  Color randomizer = new Color(red, green, blue);

上面的代码不应该出现在你的绘画方法中。同样,您无法控制调用 paintComponent() 方法的时间。所以每次 Swing 确定面板应该重新绘制时,都会生成随机颜色。

相反,您需要:

  1. 在您的类中添加“randomizer”作为实例变量。
  2. 添加一个类似generateRandomColor()的方法来设置这个变量的值,你可以在你的类的构造函数中调用,或者在你创建自定义面板之后调用。
  3. 更改您的绘制逻辑以引用此“随机化器”变量。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-09-15
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
相关资源
最近更新 更多