0

I do not understand how repaint(); works.

I tried to look for a tutorial, but never found anything and the naswers on 'similar questions' also didn't really help.

Here is the most basic code that I could write that should work, but doesn't:

static String done = "0";

    public static void main(String[] args) {
        
        JFrame frame = new JFrame();
        frame.setResizable(false);
        JPanel panel = new JPanel();
        frame.setSize(800, 500);
        frame.setLocation(500, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        
        JButton end = new JButton(done);
        end.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                done += Integer.valueOf(1);
                panel.repaint();
            }
        });
        
        panel.add(ende);
        frame.add(panel);
        frame.setVisible(true);

    }

Obviously this is just a button that should be repainted once clicked with a number+1.

Followup question: How do I tell a panel to repaint itself while inside another panel? Here is the base code that should work:

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;

public class Repaint
{
    static String done = "0";
    
    public static void main(String[] args)
    {
        new Repaint();
        
    }
    
    public Repaint()
    {
        createframe();
        
    }
    
    public void createframe()
    {
        JFrame frame = new JFrame();
        frame.setResizable(false);
        JPanel panel = new JPanel();
        frame.setSize(800, 500);
        frame.setLocation(500, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        Border bo = new LineBorder(Color.black);
        JMenuBar bar = new JMenuBar();
        bar.setBorder(bo);
        JMenu menu = new JMenu("Edit");
        JMenuItem stats = new JMenuItem("Edit the button");
        
        stats.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ev)
            {
                
                createbox();
                
            }
        });
        menu.add(stats);
        
        JLabel end = new JLabel(done);
        
        bar.add(menu);
        frame.setJMenuBar(bar);
        panel.add(end);
        frame.add(panel);
        frame.setVisible(true);
        
    }
    
    public void createbox()
    {
        JFrame framebox = new JFrame();
        framebox.setResizable(false);
        JPanel panelbox = new JPanel();
        framebox.setSize(800, 500);
        framebox.setLocation(500, 400);
        
        JButton end = new JButton(done);
        
        end.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                done += String.valueOf(1);
                framebox.dispose();
            }
        });
        panelbox.add(end);
        framebox.add(panelbox);
        framebox.setVisible(true);
    }
    
}

Basicially pressing the button in frame 2 increases the number of the String "done" by one. But it does not repaint it in the original frame.

yur
  • 380
  • 2
  • 15
Razak
  • 43
  • 6
  • 1
    What are you trying to accomplish? Please clarify this point. – Miles Morales Jun 29 '20 at 07:21
  • "Obviously this is just a button that should be repainted once clicked with a number+1." Just click the button and the number on that button goes up by 1. But it doesnt because it doesn't get repainted properly. – Razak Jun 29 '20 at 07:27

2 Answers2

1

Ok so I've made an attempt at solving both your questions despite not being entirely sure what you what your program to do.

First off, the answer you accepted is actually wrong. I'm guessing the other commenter forgot that the variable done is actually of the type String, meaning that the operator += doesn't actually do any math, it merely appends the strings. In simpler words, the operator doesn't add 1 to done but it appends the literal string value 1 to done. So if done has value 0 and you click the button with that code, it will append 1 and done will now have the value 01. If you click it again it will build the String 011 and so on.

To fix that little mistake you simply need to parse the String to an Integer and then you can use math operators on it.

Regarding your second problem, I reread your question and your code again and now it seems like I misunderstood in my comment on the other answer. I tried to not change the underlying logic of your code and therefor went off of your code concerning what the JButton does. In your original code, the button increments done and the button is supposed to display that text. The button also is the closing operations of this frame though, since you're calling dispose() in the button's actionPerformed() call.

If that's what's supposed to happen (the button closing the frame on every press), then you don't even need a WindowListener or Override anything, you can simply execute whatever you want to in that actionPerformed() call.

Code:

public class Repaint
{
    String done = "0";
    
    JFrame frame;
    JPanel panel;
    Border bo;
    JMenuBar bar;
    JMenu menu;
    JMenuItem stats;
    JLabel endLabel;
    
    JFrame framebox;
    JPanel panelbox;
    JButton endButton;
    
    public static void main(String[] args)
    {
        new Repaint();
        
    }
    
    public Repaint()
    {
        createFrame();
    }
    
    public void createFrame()
    {
        frame = new JFrame();
        frame.setResizable(false);
        panel = new JPanel();
        frame.setSize(800, 500);
        frame.setLocation(500, 400);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        
        bo = new LineBorder(Color.black);
        bar = new JMenuBar();
        bar.setBorder(bo);
        menu = new JMenu("Edit");
        stats = new JMenuItem("Edit the button");
        
        stats.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent ev)
            {
                
                createBox();
                
            }
        });
        menu.add(stats);
        
        endLabel = new JLabel(done);
        
        bar.add(menu);
        frame.setJMenuBar(bar);
        panel.add(endLabel);
        frame.add(panel);
        frame.setVisible(true);
        
    }
    
    public void createBox()
    {
        framebox = new JFrame();
        framebox.setResizable(false);
        panelbox = new JPanel();
        framebox.setSize(800, 500);
        framebox.setLocation(500, 400);
        
        endButton = new JButton(done);
        
        endButton.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                done = Integer.toString(Integer.parseInt(done) + 1);
                endButton.setText(done);
                onDispose();
            }
        });
        panelbox.add(endButton);
        framebox.add(panelbox);
        framebox.setVisible(true);
    }
    
    private void onDispose() 
    {
        endLabel.setText(done);
        framebox.dispose();
    }
}

I ended up replacing all your local variables with class variables (perhaps you don't need all of them to be non-local, but whatever) so you can actually call the JFrame instance frame outside of the createFrame() method.

You can see the calls of toString() and parseInt() to actually get the math operator to work.

endButton.addActionListener(new ActionListener()
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        done = Integer.toString(Integer.parseInt(done) + 1);
        endButton.setText(done);
        onDispose();
    }
});

Next I simply replaced the direct call of JFrame.dispose() and added a little onDispose() method, in which I update (by calling setText()) the Label. In this method you can now basically add anything that's supposed to happen before the call of dispose().

private void onDispose() 
{
    endLabel.setText(done);
    framebox.dispose();
}

If this is not what you're looking for let me know.

yur
  • 380
  • 2
  • 15
  • Ah I see. So the problem was, that JLabel 'end' was a local variable, therefor it was impossible to reach it from another class. Did I understand that correctly? God dammit now I have to get all the important labels un-localed (in my real project :D). But it does work! Much thanks from me! This was what my problem was. I didn't realize that JLabel is just another variable. In my mind it was like a constructor that needed to be typed in one line and couldn't be split up. Beginners mistake i guess ^^ – Razak Jun 29 '20 at 10:11
  • Yes it seems the problem was a culmination of a few beginner mistakes (revalidate instead of calling `setText()`, math operators on `String` and trying to retrieve value of a local variable). If you care to learn a bit more about instance variables compared to local variables, [this](https://stackoverflow.com/questions/1794141/java-instance-variables-vs-local-variables) and [this](https://stackoverflow.com/questions/2088299/what-is-the-difference-between-local-and-instance-variables-in-java) thread both have some great information and discussion on the subject! – yur Jun 29 '20 at 10:16
  • 1
    thanks a bunch! To my credit, the string maths problem was just a hickup when writing up the examplecode. The real code is like 1500 lines long so I couldn't really import that here now could I :D And yes this helps immensely! Thanks a bunch again! Very helpful and easy to understand! – Razak Jun 29 '20 at 10:33
0

If you want to add 1 to the number on JButton and show it, then there is no need to use repaint() method.

It is irrelevant.

Instead you can just use setText() method.

Code:

JButton end = new JButton(done);
end.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        done = done + "1";
        end.setText(done);
    }
});

repaint() method is related to Graphics/Graphics2D in Java. It is called when we want to change the look of a component.

Miles Morales
  • 307
  • 1
  • 15
  • 1
    thank you very much. I guess .setText was what I was looking for. I might have another problem lateron (will modify my main code now)... but for now this was actually what I was looking for. Thanks! – Razak Jun 29 '20 at 07:46
  • quick followup question then: How can I tell panel 1 that it should update as soon as panel 2 closes? Because I have settings that need to be applied. So I have 1 panel. I open up panel 2. Once panel 2 closes, panel 1 should be updated. – Razak Jun 29 '20 at 07:53
  • 1
    @Razak I am sorry but I can't possibly help without code. Please try to provide a demo source code Or in other words https://stackoverflow.com/help/minimal-reproducible-example – Miles Morales Jun 29 '20 at 08:05
  • I added the code as a followup in the OP. Basicially, how can I tell another frame to do something? So how can frame 2 tell frame 1 to update itself? – Razak Jun 29 '20 at 08:29
  • Regarding your follow-up question: You could Override the dispose() method and call whatever you have to call in panel 1 there. You could alternatively add a Window Listener to your panels that listen for any operations on the window. [This thread](https://stackoverflow.com/questions/16295942/java-swing-adding-action-listener-for-exit-on-close) might help you out and explain these concepts a little better. – yur Jun 29 '20 at 08:50
  • thank you yur for the improved formatting. And I tried the window listener... but then I have the same problem as before, don't I? Could you edit the example code to include this change? Because I can not figure out how to use the windowlistener effectively. – Razak Jun 29 '20 at 08:59