JPanel перекрасить вопрос

У меня есть JFrame, который содержит 2 подкласса JPanel и 2 JLabel в BorderLayout. Один из JPanel содержит JButton, а другой используется для отображения графики. JLabels находятся на севере и юге, кнопка JPanel на западе и дисплей JPanel в центре.

Дисплей JPanel требует постоянного обновления, поэтому я вызываю его метод repaint() через событие action, генерируемое таймером поворота. Я также переопределяю его метод paintComponent(), чтобы сделать мои рисунки.

Вместо отображения того, что я нарисовал, "содержимое JFrame" рисуется на дисплее JPanel. Я знаю, что я могу просто "очистить" дисплей JPanel с помощью g.fillRect() или super.paintComponent() перед выполнением моих рисунков.

Мне просто любопытно, почему это происходит.

Я использую 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();
    }
}

Скриншот

1 ответ

Без super.paintComponent(g) результат зависит от значения по умолчанию вашей платформы для свойства opacity JPanel Пользовательский интерфейс, PanelUI, Мой случается true, но вы можете экспериментировать на вашей платформе, как предложено ниже.

Приложение: "Если вы не соблюдаете непрозрачное свойство, вы, скорее всего, увидите визуальные артефакты". paintComponent(), Артефакт, который вы наблюдаете, будет варьироваться в зависимости от платформы, но он не является нетипичным. По сути, вы нарушаете обещание рисовать каждый пиксель и видите все, что осталось в каком-то буфере.

Главный

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);
    }
}
Другие вопросы по тегам