我有以下程序在运行时有一些非常奇怪和不需要的行为。它应该有两个按钮,“开始”和“停止,但当我点击”开始“另一个按钮显示在”开始“的正下方。这是我正在谈论的打印屏幕:
我做错了什么,如何解决这个丑陋的问题?
以下是代码:
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
}
此外,我正在尝试使用“开始”按钮执行两项操作。一个当然是开始动画,但是当按下停止按钮并再次按下开始时,我希望它清理屏幕以便说话并再次启动动画。有关于此的任何提示吗?
答案 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 而是启动一旦创建了类并在实例上调用方法
这是固定代码(已实施上述修复):
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