简体   繁体   中英

Calling repaint() and/or revalidate() through an EventListener - Swing

I've been having some problems with swing as of late. I'm creating a project that requires editing things (in this case, a string displayed on a JButton) within a JFrame and a JPanel quite frequently, and wanted to get to grips with how to do this.

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(). However, I have been unable to get my code to run properly.

Right now, the frame will draw initially as it should, but upon pressing the button, the text within it does not change - in fact, it produces a large error log, viewable here: https://pastebin.com/7P85cB8h

below is my code:

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();
    }
}

So, to clarify, I have a JButton, inside a JPanel, inside a JFrame. The button displays a string within itself, which initially reads "Beans". When I press the button, I want the string to now read "Surprise!".

Thanks for your time.

Your problem is one of confusing object with reference variable, thinking that changing String1's text will magically cause a change in the text that is displayed by the JButton, but that is not how Java's OOP model works. Understand that the JButton is displaying a String object, the same object that String1 is initially referring to, but then when you change the String that String1 refers to, this has no effect on the original String object . In order to change the displayed String, you have to change the String object displayed by the JButton by calling the JButton's setText(...) method and pass the new String into it. That's the only way this will work.

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

See comments:

// 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

    //....

在此处输入图片说明

As an aside, you will want to learn and use Java naming conventions . Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.

Note as an aside #2: If you actually draw the String, then your original code would work. Note in the code below I have a String variable, currentString that originally refers to the first item in a String array, TEXTS , the String "One" . In a JButton's ActionListener, I update the array index variable aptly named index , and set the currentString variable to the next String item in the array, and then call repaint() . The reason this code works is because I am drawing the text held by currentString in the JPanel's painting method, paintComponent(...) :

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());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM