调整窗口大小时 Java Swing 绘图消失
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10380317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Swing drawing disappears when resizing window
提问by user1365291
i need your help badly because i cannot solve this problem on my own. I am trying to create a GUI and want to draw something in it after pressing a button, but i seem to have some kind of refresh/revalidate or threading issue. The drawing is painted, but when I resize the window, the painting disappears. Also, when moving the window very quickly, parts of the drawing disappear. I have tried many things, but I can't get this problem to work, maybe you can help me. I was instructed not to write my own code to begin with, but use the NetBeans Design functions to generate Buttons and Panels etc. Maybe this impairs the drawing process/functions, but I don't know. I'll post you the relevant code and would be very thankful for suggestions (the outcommented stuff are just artefacts from what I've tried before, so don't mind it):
我非常需要你的帮助,因为我无法自己解决这个问题。我正在尝试创建一个 GUI 并想在按下按钮后在其中绘制一些东西,但我似乎有某种刷新/重新验证或线程问题。绘图已绘制,但是当我调整窗口大小时,绘图消失了。此外,当非常快速地移动窗口时,部分绘图会消失。我已经尝试了很多东西,但我无法解决这个问题,也许你可以帮助我。我被指示一开始不要编写自己的代码,而是使用 NetBeans 设计函数来生成按钮和面板等。也许这会影响绘图过程/功能,但我不知道。我会向您发布相关代码,并非常感谢您的建议(已注释的内容只是我之前尝试过的人工制品,所以不要介意):
public class NewJFrame extends JFrame {
public NewJFrame() { initComponents(); }
@SuppressWarnings("unchecked")
private void initComponents() {
jButton1 = new javax.swing.JButton();
jPanel1 = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(1200, 1000));
jButton1.setText("Draw");
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGap(0, 1000, Short.MAX_VALUE)
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jPanel1, GroupLayout.DEFAULT_SIZE, 1000, Short.MAX_VALUE)
.addGap(18, 18, 18)
.addComponent(jButton1)
.addGap(33, 33, 33))
);
layout.setVerticalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(0, 745, Short.MAX_VALUE)
.addComponent(jButton1)
.addGap(237, 237, 237))
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap())))
);
pack();
}// </editor-fold>
private void jButton1ActionPerformed(ActionEvent evt) {
Graphics g = jPanel1.getGraphics();
draw(jPanel1, g);
}
protected void paintComponent(Graphics g){
jPanel1.setSize(1000, 1000);
Dimension d = jPanel1.getSize();
g.setColor(Color.BLACK);
for (int i=0; i<=1000;i++){
if (i%100==0){
g.setColor(Color.RED);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
else if(i%50==0 && i%100!=0){
g.setColor(Color.BLUE);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
else {
g.setColor(Color.BLACK);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
}
g.setColor(Color.green);
g.drawLine(0, d.height / 2, d.width, d.height / 2);
}
public void draw(JPanel Jpanel1, Graphics g) {
System.out.println("wuffkowski");
Jpanel1.setSize(1000,1000);
Dimension d = Jpanel1.getSize();
g.setColor(Color.BLACK);
for (int i=0; i<=1000;i++){
if (i%100==0){
g.setColor(Color.RED);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
else if(i%50==0 && i%100!=0){
g.setColor(Color.BLUE);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
else {
g.setColor(Color.BLACK);
g.drawLine(i, d.height/2, i, (d.height/2)+100);
}
}
g.setColor(Color.green);
g.drawLine(0, d.height / 2, d.width, d.height / 2);
Jpanel1.paintComponents(g);
}
public static void lala () {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
NewJFrame JF =new NewJFrame();
JF.setVisible(true);
}
});
}
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
}
Again thanks a lot for your precious time.
再次感谢您的宝贵时间。
回答by Aaron Digulla
Java doesn't remember drawing commands for you; your graphic is rendered once when you click the button because that's the only time when draw()
is called.
Java 不记得为您绘制命令;当您单击按钮时,您的图形会呈现一次,因为这draw()
是调用的唯一时间。
If you want to refresh the rendering after a resize, override paint(Graphics)
and call draw()
in there.
如果您想在调整大小后刷新渲染,请覆盖paint(Graphics)
并调用draw()
那里。
If that is related to the button click, you must add fields to your class in which you remember everything that you need in draw()
including the fact whether it should draw anything:
如果这与按钮单击有关,则必须向类中添加字段,在其中记住您需要的所有内容,draw()
包括是否应该绘制任何内容:
private boolean drawAtAll = false;
private void jButton1ActionPerformed(ActionEvent evt) {
drawAtAll = true; // ok to draw now
draw();
}
@Override
public void paint(Graphics g) {
super.paint(g);
draw();
}
public void draw() {
if( !drawAtAll ) return;
Graphics g = jPanel1.getGraphics();
...
}
Further reading:
进一步阅读:
回答by nIcE cOw
Try your hands on this code, and ask any questions that may arise, do painting inside the paintComponent(...)method of the JPanel. Instead of providing size everytime for the said JComponent
you can simply override getPreferredSize(), of the said component. In order to call your paintComponent(...)
you can simply write repaint()
instead of explicitly making a call to paintComponent(...)
from within your program, Swing will do that automatically.
尝试使用此代码,并提出可能出现的任何问题,在JPanel 的paintComponent(...)方法内进行绘制。JComponent
您可以简单地覆盖所述组件的getPreferredSize(),而不是每次都提供大小。为了调用您的程序,paintComponent(...)
您可以简单地编写repaint()
而不是paintComponent(...)
从程序中显式调用,Swing 将自动执行此操作。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintingExample
{
private CustomPanel paintingPanel;
private Timer timer;
private int x = 1;
private int y = 1;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
x++;
y++;
paintingPanel.setPosition(x, y);
}
};
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Painting Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
paintingPanel = new CustomPanel();
final JButton startStopButton = new JButton("STOP");
startStopButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
if (timer.isRunning())
{
startStopButton.setText("START");
timer.stop();
}
else if (!timer.isRunning())
{
startStopButton.setText("STOP");
timer.start();
}
}
});
frame.add(paintingPanel, BorderLayout.CENTER);
frame.add(startStopButton, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(100, timerAction);
timer.start();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new PaintingExample().createAndDisplayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private int x = 0;
private int y = 0;
@Override
public Dimension getPreferredSize()
{
return (new Dimension(800, 600));
}
public void setPosition(int a, int b)
{
x = a;
y = b;
if (x <(getWidth() - 10) && y < (getHeight() - 10))
repaint();
else
System.out.println("Nothing is happening...");
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.clearRect(0, 0, getWidth(), getHeight());
g.setColor(Color.MAGENTA);
g.fillOval(x, y, 10, 10);
}
}
回答by Robin
I did not went through all of your code, but what is immediately visible is that you should not override the paintComponent
method without calling super.paintComponent
. And your commented out line calls super.paintComponents
(note the s), which is not the same.
我没有浏览您的所有代码,但可以立即看到的是,您不应在paintComponent
不调用super.paintComponent
. 和您注释掉的行调用super.paintComponents
(注意 s),这是不一样的。
I am also unsure what you mean 'when I resize the window', and how that is tied together with your Jpanel1.setSize( 1000, 1000 )
calls which appear all over your code. Your layout manager will take care of the size of the panel. You should not set that to a fixed size.
我也不确定你的意思是“当我调整窗口大小时”,以及它是如何与你Jpanel1.setSize( 1000, 1000 )
的代码中出现的调用联系在一起的。您的布局管理器会处理面板的大小。您不应将其设置为固定大小。
回答by Thomas Uhrig
When you resize your panel or change it position or minimize it and maximize it, a paint(...)
method is called that repaints the content. You have to overwrite this function and let it paint your line or what ever. To do this, you must probably save your drawing in a data-structure to be able to repaint it when every necessary.
当您调整面板大小或更改其位置或将其最小化和最大化时,将paint(...)
调用一种重新绘制内容的方法。您必须覆盖此功能并让它绘制您的线条或其他任何东西。为此,您可能必须将绘图保存在数据结构中,以便能够在必要时重新绘制它。
The paint method is described here.