问题描述
这是我直接从“ Head First Java”获得的资源,但是无论如何我似乎都无法使其工作,而且我也不知道我可能会缺少什么
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
JFrame frame;
public static void main(String[] args) {
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color randomColor = new Color(red, green, blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
我试图找到另一种方法,该方法不涉及重新绘制,而是在事件发生时创建MyDrawPanel的新实例,但是由于我没有找到正确清除面板的方法,因此它仍然不起作用。到目前为止,我发现的唯一hack就是这样做,但这不是我想要实现的目标...
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
JFrame frame;
public static void main(String[] args) {
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
go();
}
}
class MyDrawPanel extends JPanel {
int red;
int green;
int blue;
public MyDrawPanel() {
this.red = (int) (Math.random() * 255);
this.green = (int) (Math.random() * 255);
this.blue = (int) (Math.random() * 255);
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
Color randomColor = new Color(this.red, this.green, this.blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
1楼
这将满足您的要求。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SimpleGui3C implements ActionListener {
static JFrame frame = null; // changed here...
public static void main(String[] args) {
frame = new JFrame(); // changed here....
SimpleGui3C gui = new SimpleGui3C();
gui.go();
}
public void go() {
MyDrawPanel drawPanel = new MyDrawPanel();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Change colors");
button.addActionListener(this);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
}
}
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 300, 300);
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
Color randomColor = new Color(red, green, blue);
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}
在go()
方法中...每次通过JFrame frame = new JFrame();
创建新对象JFrame frame = new JFrame();
因此,每次单击都会在屏幕上显示一个新框架...
通过在main()
方法中创建对象,我们每次仅在同一jframe
对象上调用repaint()
方法,而不创建新对象。...
希望能有所帮助...
2楼
在处理Swing
,应牢记一些麻烦。
当我查看您使用的代码时,我想将其指出给您,使其走在正确的轨道上。
-
基于
Swing
的应用程序从其各自的线程(称为EventDispatcherThread ( EDT )
而不是直接从main线程启动。 有关该主题的更多信息,请参见 -
尽量不要在
paintComponent ( ... )
方法内执行任何计算,而是在其他位置执行这些计算,而只需调用repaint ()
-
paintComponent ( ... )
的访问说明符是protected
而不是public
,因此,在重写超类的方法时,请尽量不要更改方法的访问权限,直到没有必要为止。 -
在
JPanel
上绘制时,只需在JPanel
实例上调用repaint ()
,而不是顶层容器的 -
当扩展任何
JComponenet/JPanel
,请始终尝试覆盖该JComponent/JPanel
的getPreferredSize ()
,因为许多布局将返回0
,如果未指定任何布局,则不会进行绘制。 -
请记住要调用
super.paintComponent ( g )
,作为paintComponent ( ... )
的第一行。 添加了注释以使内容更加清晰。 -
代替在
JFrame
上设置大小,而是尝试调用pack ()
,如中所述,以获得附带的好处。 打包方法调整框架的大小,以便其所有内容均等于或大于其首选大小。 打包的另一种方法是通过调用setSize或setBounds(也设置帧位置)显式建立帧大小。 通常,使用pack优于调用setSize,因为pack由框架布局管理器负责框架大小,并且布局管理器擅长调整平台依赖性和其他影响组件大小的因素。
根据以上几点,这是经过修改的代码(刚刚在DrawPanel
添加了一个名为setValues ()
的方法,在DrawPanel
方法中完成了计算,并称为repaint ()
):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SimpleGui implements ActionListener {
private MyDrawPanel drawPanel;
public static void main(String[] args) {
Runnable r = new Runnable () {
@Override
public void run () {
new SimpleGui ().go ();
}
};
EventQueue.invokeLater ( r );
}
public void go() {
drawPanel = new MyDrawPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
JButton button = new JButton( "Change colors" );
button.addActionListener( this );
frame.add( drawPanel, BorderLayout.CENTER );
frame.add( button, BorderLayout.PAGE_END );
frame.pack ();
frame.setLocationByPlatform ( true );
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
drawPanel.setValues ();
}
}
class MyDrawPanel extends JPanel {
private int width = 300;
private int height = 300;
private int red;
private int green;
private int blue;
private Color randomColor;
/*
* Make this one customary habbit,
* of overriding this method, when
* you extends a JPanel/JComponent,
* to define it's Preferred Size.
* Now in this case we want it to be
* as big as the Image itself.
*/
@Override
public Dimension getPreferredSize () {
return new Dimension ( width, height );
}
public void setValues () {
red = ( int ) ( Math.random() * 255 );
green = ( int) ( Math.random() * 255 );
blue = ( int ) ( Math.random() * 255 );
randomColor = new Color( red, green, blue );
repaint ();
}
/*
* This is where the actual Painting
* Code for the JPanel/JComponent goes.
* Here the first line super.paintComponent(...),
* means we want the JPanel to be drawn the usual
* Java way first (this usually depends on the opaque
* property of the said JComponent, if it's true, then
* it becomes the responsibility on the part of the
* programmer to fill the content area with a fully
* opaque color. If it is false, then the programmer
* is free to leave it untouched. So in order to
* overcome the hassle assoicated with this contract,
* super.paintComponent(g) is used, since it adheres
* to the rules, and performs the same task, depending
* upon whether the opaque property is true or false),
* then later on we will add our image to it, by
* writing the other line, g.drawImage(...).
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent ( g );
g.setColor(randomColor);
g.fillOval(70, 70, 100, 100);
}
}