0

I have a pretty simple JFrame (it consists only of one text field and a lot of stuff I paint), though whenever repaint() is called the text field changes. I'm pretty sure it's repaint(), as it happens even when I drag the frame from one monitor to the next as well as whenever I call it in the code.

It starts off fine when I run the program:

However, whenever repaint() is called, this happens:

If I start typing in the field, the rest immediately pops back up and works fine. Ultimately, my end goal is to reset a large portion of my frame to what is painted in paintComponent() while still having the text field visible.

I'm relatively new to Graphics and painting, any help is greatly appreciated!

EDIT

In creating the SSCCE, I discovered the problem with the text field was being caused by the Graphics2D method rotate that was in my paintComponent method. I don't know why it's happening, but I can work around it and consider that problem solved.

Now, I'm having a new problem: my paintComponent method is being called one too many times. Below is a SSCCE of this problem, the order I want things to happen is:

  1. Call to paintComponent()
  2. (when button is pressed) Call to repaint()
  3. (when button is pressed, but after repaint) Call to paintStuff()

That all happens, however afterwards paintComponent is somehow being called, erasing everything painted by paintStuff().

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class tester extends JFrame {

    private JPanel contentPane;
    private JButton button;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    tester frame = new tester();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public tester() {
        setBounds(100, 100, 450, 300);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        contentPane = new JPanel(){
            public void paintComponent(Graphics g1) {
                System.out.println("draw rectangle - should be first");
                super.paintComponent(g1);

                g1.drawRect(50,50,50,50);
            }
        };
        contentPane.setLayout(null);
        setContentPane(contentPane);

        button = new JButton("Click me!");
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println("repaint - should be second");
                repaint();

                paintStuff(contentPane.getGraphics());
            }
        });
        button.setBounds(10, 11, 95, 20);
        contentPane.add(button);
    }

    public void paintStuff(Graphics g){
        System.out.println("draw circle - should be last");
        g.drawOval(100,100,10,10);
    }

}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • Make sure you invoke `super.paintComponent(...)` at the start of your paintComponent() method. If that doesn't help then post a proper [SSCCE](http://sscce.org/) that demonstrates the problem. – camickr Jan 23 '16 at 01:47
  • 1) *"I have a pretty simple JFrame (it consists only of one text field.."* Where? That code shows a `JButton`, but no `JTextField`. 2) The best way to set a size to a text field is to set the number of columns (characters) it needs to display. Another way to adjust its size is to change the size of `Font` it is using. But more generally.. 3) .. – Andrew Thompson Jan 23 '16 at 10:05
  • .. 3) Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). – Andrew Thompson Jan 23 '16 at 10:06
  • Thanks for the tips, I'll keep them in mind. I changed it to a button in the SSCCE to make things simpler to understand for my second problem. – Kalashnikov Jan 23 '16 at 16:26

1 Answers1

2
paintStuff(contentPane.getGraphics());

No, don't use the getGraphics() method to do painting. To repaint the component you simply use:

contentPane.repaint();

and then you move the drawOval(...) statement to the paintComponent() method.

If you want to draw the oval conditionally then you need to create a Boolean property for your custom painting. Then the code would look something like:

super.paintComponent(g1);

g1.drawRect(50,50,50,50);

if (drawOval)
    g1.drawOval(100,100,10,10);    

Then in your class you would create a method like:

public void setDrawOval(Boolean drawOval)
{
    this.drawOval = drawOval;
    repaint();
}

So in the ActionListener you simply use:

contentPane.setDrawOval(true);
camickr
  • 321,443
  • 19
  • 166
  • 288