【问题标题】:Calling repaint() and/or revalidate() through an EventListener - Swing通过 EventListener 调用 repaint() 和/或 revalidate() - Swing
【发布时间】:2018-09-25 00:14:56
【问题描述】:

我最近在挥杆方面遇到了一些问题。我正在创建一个需要在 JFrame 和 JPanel 中频繁编辑内容(在本例中是显示在 JButton 上的字符串)的项目,并且想要掌握如何执行此操作。

我搜索了很长时间,我发现的主要答案是我需要调用 .repaint(),可能在我调用 .revalidate() 之后。但是,我一直无法让我的代码正常运行。

现在,框架最初会按应有的方式绘制,但按下按钮后,其中的文本不会改变 - 事实上,它会产生一个很大的错误日志,可在此处查看:https://pastebin.com/7P85cB8h

下面是我的代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Actions extends JFrame implements ActionListener
{
    JButton Beans;
    String String1;
    JPanel things;

    public static void main (String[] args)
    {
        new Actions();
    }

    public Actions()
    {
        JPanel things = new JPanel();
        String1 = "Beans";

        this.setSize(400,400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("Hello there");

        Box theBox = Box.createHorizontalBox();

        Beans = new JButton("" + String1);
        Beans.addActionListener(this);

        theBox.add(Box.createHorizontalStrut(50));
        theBox.add(Beans);

        this.add(theBox);

        setVisible(true);
    }

    public void actionPerformed(ActionEvent e)
    {
        String1 = "Surprise!";
        things.revalidate();
        things.repaint();
    }
}

所以,澄清一下,我有一个 JButton,在 JPanel 内,在 JFrame 内。该按钮在其自身中显示一个字符串,该字符串最初显示为“Beans”。当我按下按钮时,我希望字符串现在变为“惊喜!”。

感谢您的宝贵时间。

【问题讨论】:

  • "I searched for a long while, and the main answer I have found is that I need to call .repaint(), potentially after I call .revalidate()." -- 不,这在更改 JButton 或 JLabel 的文本时不是必需的。问题出在其他地方。

标签: java swing jframe jbutton repaint


【解决方案1】:

您的问题是将对象与引用变量混淆,认为更改 String1 的文本会神奇地导致 JButton 显示的文本发生更改,但这不是 Java 的 OOP 模型的工作方式。了解 JButton 正在显示一个 String 对象,即 String1 最初引用的同一对象,但是当您更改 String1 引用的 String 时,这 对原始 String 对象没有影响。为了更改显示的字符串,您必须通过调用 JButton 的setText(...) 方法来更改 JButton 显示的字符串对象并将新字符串传递给它。这是唯一可行的方法。

public void actionPerformed(ActionEvent e) {
    Beans.setText("Surprise!");
}

见 cmets:

// here are several reference variables
// all without assigned objects, and thus
// all holding "null" values:
JButton Beans;
String String1;
JPanel things;


public Actions()  {
    //..... 

    // here you assign the String object, "Beans" to the String1 variable
    String1 = "Beans";

    // .....

    // here you create a JButton and pass in String1's current object, "Beans"
    // into the constructor (note the "" + is NOT needed for Strings, only for numberrs)
    Beans = new JButton("" + String1);

    //.....
}

public void actionPerformed(ActionEvent e)  {
    // here you change the object that String1 refers to
    String1 = "Surprise!";

    // but this has no effect on the original String object, "Beans" displayed in the
    // JButton, but rather all it does is change the state of String1. 
    // To change the state of the JButton, you must explicitly do this 
    // by calling setText on it

    //....

顺便说一句,你会想学习和使用Java naming conventions。变量名应全部以小写字母开头,而类名应以大写字母开头。学习这一点并遵循这一点将使我们能够更好地理解您的代码,并让您更好地理解其他人的代码。

请注意#2:如果您确实绘制字符串,那么您的原始代码将可以工作。请注意,在下面的代码中,我有一个字符串变量currentString,它最初引用字符串数组中的第一项,TEXTS,即字符串"One"。在JButton 的ActionListener 中,我更新了数组索引变量index,并将currentString 变量设置为数组中的下一个字符串项,然后调用repaint()。这段代码起作用的原因是因为我在JPanel的绘画方法paintComponent(...)中绘制currentString持有的文本:

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.*;

public class DrawStringPanel extends JPanel {
    private static final String[] TEXTS = {
            "One", "Two", "Three", "Four", "Five", 
            "Six", "Seven", "Eight", "Nine", "Ten"
            };
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private static final Font TEXT_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 40);
    private static final int TEXT_X = 150;
    private static final int TEXT_Y = 200;
    private int index = 0;

    // Note that this String variable holds the first item in the TEXTS array
    private String currentString = TEXTS[index];

    public DrawStringPanel() {
        setPreferredSize(new Dimension(PREF_W, PREF_H));
        JButton nextBtn = new JButton("Next");
        add(nextBtn);
        nextBtn.addActionListener(e -> {
            // update the array index
            index++;  // get next index
            index %= TEXTS.length;  // but don't let get bigger then array length

            // and in the ActionListener here I'm changing the variable and calling repaint
            // this works because this variable is actually painted within this JPanel's 
            // paintComponent method....
            currentString = TEXTS[index];
            repaint();
        });
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2.setFont(TEXT_FONT);

        // ****** HERE ****** I draw the contents of the currentString variable
        g2.drawString(currentString, TEXT_X, TEXT_Y);
    }

    private static void createAndShowGui() {
        DrawStringPanel mainPanel = new DrawStringPanel();

        JFrame frame = new JFrame("DrawStringPanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

【讨论】:

  • 这很完美!并提供一些关于挥杆的见解,不少于。我承认我开始使用 Applets,并且似乎一些坏习惯和误解已经被延续了下来。不过,谢谢!
  • @MatthewMakaryn:这与 Swing 无关,都与“神奇思维”有关,认为更改变量所指的内容会影响之前使用该变量对象的其他对象。这再次得到了对象是什么和引用变量是什么之间的关键区别。我会在一分钟内尝试更好地解释这一点,但这是一个您需要完全理解才能继续前进的关键概念。
  • 好的,谢谢。我还有很长的路要走,我很高兴能继续前进!我记得在 Applet 中做过这个,并且错误地假设它在摇摆中会同样工作。啊,好吧,向上和向上
  • @MatthewMakaryn I remember having done this in an Applet, - 它也不能在 Applet 中工作。
  • 是的,所以我有点傻而且记错了,原来我的旧项目是使用paint方法来绘制字符串,而不是替换按钮中的文本 - 我试图这样做在一个小程序中,它确实没有用。感谢您的所有帮助,感谢您处理我的愚蠢错误。
猜你喜欢
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2017-12-05
  • 2011-09-08
  • 1970-01-01
  • 2016-12-15
  • 1970-01-01
相关资源
最近更新 更多