简体   繁体   中英

Inconsistent Behavior

The following code appears to produce inconsistent behavior when I run it. On some runs, the canvas ends up appearing grey, but on others it end up colored blue instead. Why is this, and how can I correct it?

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

public class psw extends JFrame {
    String symbols="~ ! @ # $ % ^ & * ( ) _ = + : ; < , > . ? / | \\ '";

    public static void main(String[] args){
    psw app=new psw();
    app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
    app.setSize(600, 450);
    app.setVisible(true);
    app.getContentPane().setBackground(new Color(30,144,255));

    @Override    
    public void paint(Graphics g) {
        g.setColor(new Color(255,255,255));
        g.drawRect(10, 10, 60, 50);
        g.drawLine(60, 50, 220, 20);
        g.drawString(symbols, 10, 150);
    }
}

Change your code to access the JFrame through the event dispatch thread , like this:

SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        createAndShowGUI();
    }
});

The Oracle tutorial says:

Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors. Some Swing component methods are labelled "thread safe" in the API specification; these can be safely invoked from any thread. All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.

which sounds like what you're seeing.

You need to remember to call super.paint(g); . That shows the painting.

public void paint(Graphics g) {
    super.paint(g);
    g.setColor(new Color(255,255,255));
    g.drawRect(10, 10, 60, 50);
    g.drawLine(60, 50, 220, 20);
    g.drawString(symbols, 10, 150);
}
  • Also, it's not a good idea to paint on top level containers like JFrame as they're not double buffered. Instead paint on a component, mostly JPanel and override its paintComponent method. Just like with paint , you need to call super.paintComponent . super.paintComponent(g) invokes the paintComponent method from the superclass of JPanel (the JComponent class) to erase whatever is currently drawn on the panel.

Here's how it would run using a JPanel instead of a JFrame

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class psw extends JPanel {
    String symbols = "~ ! @ # $ % ^ & * ( ) _ = + : ; < , > . ? / | \\ '";

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame app = new JFrame();
                app.add(new psw());
                app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                app.pack();
                app.setVisible(true);

            }
        });
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(new Color(30, 144, 255));
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(new Color(255, 255, 255));
        g.drawRect(10, 10, 60, 50);
        g.drawLine(60, 50, 220, 20);
        g.drawString(symbols, 10, 150);
    }

    public Dimension getPreferredSize() {
        return new Dimension(600, 450);
    }
}

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