奇怪的JFrame行为

时间:2012-12-11 14:39:23

标签: java swing jframe actionlistener

我有以下程序在运行时有一些非常奇怪和不需要的行为。它应该有两个按钮,“开始”和“停止,但当我点击”开始“另一个按钮显示在”开始“的正下方。这是我正在谈论的打印屏幕:

enter image description here

我做错了什么,如何解决这个丑陋的问题?

以下是代码:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class TwoButtonsTest {

    JFrame frame;
    Timer timer;
    boolean isClicked;

    public static void main(String[] args) {
    TwoButtonsTest test = new TwoButtonsTest();
    test.go();
    }

    public void go() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);

    JButton startButton = new JButton("Start");
    startButton.addActionListener(new StartListener());
    JButton stopButton = new JButton("Stop");
        stopButton.addActionListener(new StopListener());

    final DrawPanel myDraw = new DrawPanel();

    frame.getContentPane().add(BorderLayout.CENTER, myDraw);
    frame.getContentPane().add(BorderLayout.NORTH, startButton);
    frame.getContentPane().add(BorderLayout.SOUTH, stopButton);


    frame.setVisible(true);

    timer = new Timer(50, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            myDraw.repaint();
        }
        });
    }

    class StartListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        //needs to be implemented
        if(!isClicked) {
        }
        isClicked = true;
        timer.start();
    }
    }

    class StopListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        //needs to be implemented
        timer.stop();
        isClicked = false;
    }
    }

    class DrawPanel extends JPanel {
    public void paintComponent(Graphics g) {

        int red = (int)(Math.random()*256);
        int blue = (int)(Math.random()*256);
        int green = (int)(Math.random()*256);

        g.setColor(new Color(red, blue, green));

        Random rand = new Random();
        // following 4 lines make sure the rect stays within the frame
        int ht = rand.nextInt(getHeight());
        int wd = rand.nextInt(getWidth());

        int x = rand.nextInt(getWidth()-wd);
        int y = rand.nextInt(getHeight()-ht);

        g.fillRect(x,y,wd,ht);
    }
    } // close inner class
}

此外,我正在尝试使用“开始”按钮执行两项操作。一个当然是开始动画,但是当按下停止按钮并再次按下开始时,我希望它清理屏幕以便说话并再次启动动画。有关于此的任何提示吗?

3 个答案:

答案 0 :(得分:4)

您不应在覆盖super.paintComponent(Graphics g)方法中调用paintComponent(..),以便尊重绘画链,从而绘制其他组件。

此调用也应该是方法中的第一个调用:

@Override
public void paintComponent(Graphics g) {
     super.paintComponent(g);

    //do painting here
}  

可能会出现图纸不持久的问题。您必须每次都有办法存储图纸和重绘。最常见的是ArrayList,它将保存要绘制的对象(因此您可以添加到列表中删除等),您可以迭代列表并重新绘制paintComponent中的每个对象。请参阅我的回答here以获取示例。

  • 另请注意在Event Dispatch Thread上创建和操作Swing组件:

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
             //create UI and components here
        }
    });
    
  • 请勿在{{1​​}}上致电setSize(..),而是覆盖JFrame的{​​{1}}并返回适合所有组件的适当高度,而不是之前致电getPreferredSize()设置JPanel可见(但在添加所有组件后)。

  • 从Java 6 + JFrame#pack()开始,JFrame默认不需要 contentPane

  • 每次调用getContentPane().add(..)时都不要重新声明add(..)Random,因为这会使值的分布减去 random 而是启动一旦创建了类并在实例上调用方法

这是固定代码(已实施上述修复):

enter image description here

Random r=new Random()

答案 1 :(得分:3)

我希望我能提供解决方案,但到目前为止我还没有找到解决方案。我可以告诉你,问题的根源在于你绘制BorderLayout的Center部分的方式。您将覆盖此程序的整个paintComponent()函数,并将其创建的内容放入BoarderLayout的Center中。在这种情况下,每次单击按钮时,程序都会调用重绘以绘制单击按钮的图像,但由于您还将任何绘制的对象添加到“中心”面板,因此也会在此处绘制。由于此特定重绘不指定位置,因此它位于左上角。

答案 2 :(得分:2)

我通过调用SwingUtilities修复了我的Windows XP计算机上的按钮问题。

我格式化了您的Java代码。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

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

public class TwoButtonsTest implements Runnable {

    JFrame frame;
    Timer timer;
    boolean isClicked;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TwoButtonsTest());
    }

    @Override
    public void run() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 500);

        JButton startButton = new JButton("Start");
        startButton.addActionListener(new StartListener());
        JButton stopButton = new JButton("Stop");
        stopButton.addActionListener(new StopListener());

        final DrawPanel myDraw = new DrawPanel();

        frame.getContentPane().add(BorderLayout.CENTER, myDraw);
        frame.getContentPane().add(BorderLayout.NORTH, startButton);
        frame.getContentPane().add(BorderLayout.SOUTH, stopButton);

        frame.setVisible(true);

        timer = new Timer(50, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                myDraw.repaint();
            }
        });
    }

    class StartListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            // needs to be implemented
            if (!isClicked) {
            }
            isClicked = true;
            timer.start();
        }
    }

    class StopListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            // needs to be implemented
            timer.stop();
            isClicked = false;
        }
    }

    class DrawPanel extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            int red = (int) (Math.random() * 256);
            int blue = (int) (Math.random() * 256);
            int green = (int) (Math.random() * 256);

            g.setColor(new Color(red, blue, green));

            Random rand = new Random();
            // following 4 lines make sure the rect stays within the frame
            int ht = rand.nextInt(getHeight());
            int wd = rand.nextInt(getWidth());

            int x = rand.nextInt(getWidth() - wd);
            int y = rand.nextInt(getHeight() - ht);

            g.fillRect(x, y, wd, ht);
        }
    } // close inner class
}

要在按下“开始”按钮时清理屏幕,您将不得不向DrawPanel类添加一些方法。

这是一种方法。

class DrawPanel extends JPanel {
        protected boolean eraseCanvas;

        public void setEraseCanvas(boolean eraseCanvas) {
            this.eraseCanvas = eraseCanvas;
        }

        @Override
        public void paintComponent(Graphics g) {
            if (eraseCanvas) {
                g.setColor(Color.WHITE);
                g.fillRect(0,  0, getWidth(), getHeight());
            } else {
                int red = (int) (Math.random() * 256);
                int blue = (int) (Math.random() * 256);
                int green = (int) (Math.random() * 256);

                g.setColor(new Color(red, blue, green));

                Random rand = new Random();
                // following 4 lines make sure the rect stays within the frame
                int ht = rand.nextInt(getHeight());
                int wd = rand.nextInt(getWidth());

                int x = rand.nextInt(getWidth() - wd);
                int y = rand.nextInt(getHeight() - ht);

                g.fillRect(x, y, wd, ht);
            }
        }
    } // close inner class