JPanel重画问题

发布于 2024-12-01 23:01:09 字数 2482 浏览 2 评论 0 原文

我有一个 JFrame,其中包含 2 个 JPanel 子类和 BorderLayout 中的 2 个 JLabel。其中一个 JPanel 包含 JButton,另一个用于显示图形。 JLabels 位于北部和南部,按钮 JPanel 位于西部,显示 JPanel 位于中心。

显示 JPanel 需要不断刷新,因此我通过摆动计时器生成的动作事件调用其 repaint() 方法。我还重写了它的paintComponent()方法来完成我的绘图。

“JFrame 的内容”不是显示我绘制的内容,而是绘制到显示 JPanel 上。我知道我可以在绘图之前使用 g.fillRect() 或 super.paintComponent() 简单地“清除”显示 JPanel。

我只是好奇为什么会发生这种情况。

我使用的是jdk 1.6u27。下面是我的代码:

package test;

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

public class Main {

public static void main(String[] args) {
    Simulation sim = new Simulation();

    }
}

class Simulation extends JFrame {

    public JLabel state;
    private JLabel id;
    private ButtonPanel control;
    private Display display;

    public Simulation() {
        id = new JLabel("Test");
        state = new JLabel("Test");
        control = new ButtonPanel();
        display = new Display(this);

        this.setLayout(new BorderLayout());
        this.add(id, BorderLayout.NORTH);
        this.add(control, BorderLayout.WEST);
        this.add(display, BorderLayout.CENTER);
        this.add(state, BorderLayout.SOUTH);

        this.setSize(500, 600);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public ButtonPanel getControl() {
        return this.control;
    }
}

class ButtonPanel extends JPanel implements ActionListener {

    public JButton b[] = new JButton[8];
    public boolean bp[] = new boolean[8];

    public ButtonPanel() {
        this.setLayout(new GridLayout(8, 1));

        for (int i = 0; i < b.length; i++) {
            b[i] = new JButton(""+i);
            b[i].addActionListener(this);
            bp[i] = false;
            this.add(b[i]);
        }
    }

    public void actionPerformed(ActionEvent e) {
        //do something
    }
}

class Display extends JPanel implements ActionListener {

    private Timer tm;
    private int yco;
    private Simulation sim;

    public Display(Simulation sim) {
        tm = new Timer(100, this);
        tm.start();

        yco = 0;

        this.sim = sim;
    }

    @Override
    public void paintComponent(Graphics g) {
        //draw something
        g.drawLine(0, yco, 100, 100);
    }

    public void actionPerformed(ActionEvent e) {
        yco ++;
        this.repaint();
    }
}

screenshot

I have a JFrame which contains 2 JPanel subclass and 2 JLabel in BorderLayout. One of the JPanel contains JButtons and the other is used for displaying graphics. The JLabels are in north and south, the button JPanel in the west and the display JPanel in center.

The display JPanel requires constant refresh, so i invoke its repaint() method via the action event generated by swing timer. I also override its paintComponent() method to do my drawings.

Instead of displaying what i have drawn, the "content of the JFrame" is being drawn onto the display JPanel. I am aware that i can simply "clear" the display JPanel by using g.fillRect() or super.paintComponent() before doing my drawings.

I am just curious why this happens.

i'm using jdk 1.6u27. below is my code:

package test;

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

public class Main {

public static void main(String[] args) {
    Simulation sim = new Simulation();

    }
}

class Simulation extends JFrame {

    public JLabel state;
    private JLabel id;
    private ButtonPanel control;
    private Display display;

    public Simulation() {
        id = new JLabel("Test");
        state = new JLabel("Test");
        control = new ButtonPanel();
        display = new Display(this);

        this.setLayout(new BorderLayout());
        this.add(id, BorderLayout.NORTH);
        this.add(control, BorderLayout.WEST);
        this.add(display, BorderLayout.CENTER);
        this.add(state, BorderLayout.SOUTH);

        this.setSize(500, 600);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public ButtonPanel getControl() {
        return this.control;
    }
}

class ButtonPanel extends JPanel implements ActionListener {

    public JButton b[] = new JButton[8];
    public boolean bp[] = new boolean[8];

    public ButtonPanel() {
        this.setLayout(new GridLayout(8, 1));

        for (int i = 0; i < b.length; i++) {
            b[i] = new JButton(""+i);
            b[i].addActionListener(this);
            bp[i] = false;
            this.add(b[i]);
        }
    }

    public void actionPerformed(ActionEvent e) {
        //do something
    }
}

class Display extends JPanel implements ActionListener {

    private Timer tm;
    private int yco;
    private Simulation sim;

    public Display(Simulation sim) {
        tm = new Timer(100, this);
        tm.start();

        yco = 0;

        this.sim = sim;
    }

    @Override
    public void paintComponent(Graphics g) {
        //draw something
        g.drawLine(0, yco, 100, 100);
    }

    public void actionPerformed(ActionEvent e) {
        yco ++;
        this.repaint();
    }
}

screenshot

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

深海里的那抹蓝 2024-12-08 23:01:09

如果没有 super.paintComponent(g),结果取决于您平台的默认 opacity 属性。我的恰好是true,但您可以在您的平台上进行实验,如下所示。

附录:“如果您不遵守不透明属性,您可能会看到视觉伪影。”—paintComponent ()。您观察到的工件会因平台而异,但并非不典型。实际上,您违背了绘制每个像素的承诺,并且您看到了某个缓冲区中剩余的内容。

Main

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class Main {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Simulation sim = new Simulation();
            }
        });
    }
}

class Simulation extends JFrame {

    public JCheckBox state;
    private JLabel id;
    private ButtonPanel control;
    private Display display;

    public Simulation() {
        id = new JLabel("Test");
        state = new JCheckBox("Opaque");
        control = new ButtonPanel();
        display = new Display(this);

        this.setLayout(new BorderLayout());
        this.add(id, BorderLayout.NORTH);
        this.add(control, BorderLayout.WEST);
        this.add(display, BorderLayout.CENTER);
        this.add(state, BorderLayout.SOUTH);
        state.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                display.setOpaque(e.getStateChange() == ItemEvent.SELECTED);
            }
        });
        state.setSelected(true);

        this.pack();
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public ButtonPanel getControl() {
        return this.control;
    }
}

class ButtonPanel extends JPanel {

    private static final int N = 8;
    private List<JToggleButton> list = new ArrayList<JToggleButton>(N);

    public ButtonPanel() {
        this.setLayout(new GridLayout(0, 1));
        for (int i = 0; i < N; i++) {
            final JToggleButton b = new JToggleButton(String.valueOf(i));
            b.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    //System.out.println(b.isSelected());
                }
            });
            list.add(b);
            this.add(b);
        }
    }
}

class Display extends JPanel {

    private Simulation sim;
    private Timer tm;
    private int yco;

    public Display(Simulation sim) {
        this.setPreferredSize(new Dimension(320, 320));
        this.setOpaque(true);
        this.sim = sim;
        tm = new Timer(100, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                yco++;
                repaint();
            }
        });
        tm.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        //super.paintComponent(g);
        g.drawLine(0, yco, getWidth() / 2, getHeight() / 2);
    }
}

Without super.paintComponent(g), the result depends on your platform's default for the opacity property of the JPanel UI delegate, PanelUI. Mine happens to be true, but you can experiment on your platform, as suggested below.

Addendum: "If you do not honor the opaque property you will likely see visual artifacts."—paintComponent(). The artifact you observe will vary by platform, but it is not atypical. In effect, you are breaking the promise to draw every pixel, and you see whatever is left over in some buffer.

Main

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class Main {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Simulation sim = new Simulation();
            }
        });
    }
}

class Simulation extends JFrame {

    public JCheckBox state;
    private JLabel id;
    private ButtonPanel control;
    private Display display;

    public Simulation() {
        id = new JLabel("Test");
        state = new JCheckBox("Opaque");
        control = new ButtonPanel();
        display = new Display(this);

        this.setLayout(new BorderLayout());
        this.add(id, BorderLayout.NORTH);
        this.add(control, BorderLayout.WEST);
        this.add(display, BorderLayout.CENTER);
        this.add(state, BorderLayout.SOUTH);
        state.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                display.setOpaque(e.getStateChange() == ItemEvent.SELECTED);
            }
        });
        state.setSelected(true);

        this.pack();
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public ButtonPanel getControl() {
        return this.control;
    }
}

class ButtonPanel extends JPanel {

    private static final int N = 8;
    private List<JToggleButton> list = new ArrayList<JToggleButton>(N);

    public ButtonPanel() {
        this.setLayout(new GridLayout(0, 1));
        for (int i = 0; i < N; i++) {
            final JToggleButton b = new JToggleButton(String.valueOf(i));
            b.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    //System.out.println(b.isSelected());
                }
            });
            list.add(b);
            this.add(b);
        }
    }
}

class Display extends JPanel {

    private Simulation sim;
    private Timer tm;
    private int yco;

    public Display(Simulation sim) {
        this.setPreferredSize(new Dimension(320, 320));
        this.setOpaque(true);
        this.sim = sim;
        tm = new Timer(100, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                yco++;
                repaint();
            }
        });
        tm.start();
    }

    @Override
    public void paintComponent(Graphics g) {
        //super.paintComponent(g);
        g.drawLine(0, yco, getWidth() / 2, getHeight() / 2);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文