当调整窗口大小时,Java Swing绘图消失

4
我非常需要您的帮助,因为我不能独自解决这个问题。我正在尝试创建一个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;
}

再次感谢您宝贵的时间。

请学习并遵守Java命名规范 :-) - nIcE cOw
4个回答

6

Java不会为您记住绘图命令;当您单击按钮时,您的图形只会呈现一次,因为那是唯一调用draw()的时间。

如果您想在调整大小后刷新渲染,请覆盖paint(Graphics)并在其中调用draw()

如果这与按钮单击有关,则必须向您的类添加字段,其中包括您在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();
  ...
}

进一步阅读:


谢谢你的建议,我正在尝试。你提到的很有道理。但是目前的结果是:当调整窗口大小时,绘画仍然会消失,但不总是;)有时调整大小后,图形仍然存在。我将尝试更改一些东西并告诉你结果。谢谢。 - user1365291
绘图并不像看起来的那么简单。请阅读我提到的这两篇文章,它们会帮助你理解正在发生的事情。之后,你应该更容易地找到并修复你的问题。 - Aaron Digulla
再次感谢大家的帮助,我将这个答案选为“最佳答案”,因为基本上重写paint方法是我现在使用的方法,但其他答案也很有帮助。然而,我仍然在作弊以避免消失的问题:由于我使用NetBeans的设计部分来使用Swing,我取消了我的JPanel的水平可调整大小和垂直可调整大小按钮,这与重写paint方法和固定我的JFrame的最小大小(正如我告诉你的那样,我仍然不能完全信任我的布局管理器)相结合,它可以完成工作。再次感谢。 - user1365291

5

试着用这段代码,如果有任何问题,请在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);
    }
}

2
我没有检查你的所有代码,但是立即可见的是,你不应该在不调用super.paintComponent的情况下重写paintComponent方法。而且你注释掉的那行调用了super.paintComponents(注意有s),这是不同的。
我也不确定你所说的“当我调整窗口大小”是什么意思,以及它如何与你在代码中到处出现的Jpanel1.setSize(1000, 1000)相关联。你的布局管理器将负责面板的大小。你不应该将其设置为固定大小。

非常感谢,我会尝试并回答你是否有效。注释掉的东西只是表明我不知道在哪里放什么以及该使用什么:p。所以我只是随意地尝试了一些我在其他地方读到可能有帮助的不同代码,并查看了发生了什么变化。但是没有任何帮助:p编辑:当我删除所有set.Size方法时,就不再绘制任何内容了;)。这个GUI我以前从未使用过,真的让我抓狂^^。 - user1365291
啊哈,太真实了,但仔细看整个内容,我意识到他并没有覆盖paintComponent(...)方法,这只是他自己的私有方法取的一个邪恶的名字,因为他继承了JFrame,而且我猜它没有这样的方法。 - nIcE cOw
是的,你说得对,我不能调用这个方法,看起来我真的没有调用paintComponent方法^^。根据你的回答和下面的回答,当我不为JFrame设置大小时,重写paint方法似乎“有效”,但第一次绘制会立即在框架顶部绘制,而且按钮的布局也很奇怪。但我会继续尝试并让你知道是否成功。 - user1365291

0
当您调整面板大小、更改其位置或将其最小化和最大化时,会调用paint(...)方法来重新绘制内容。您必须覆盖此函数并让它绘制您的线条或其他内容。为此,您可能需要将绘图保存在数据结构中,以便在每个必要时重新绘制它。
绘画方法在这里描述。

非常感谢,我会仔细研究这些内容,并尝试更好地管理事物。 - user1365291

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接