Визуальные артефакты, появляющиеся на JPanel


Я пытаюсь создать программу с 2 JPanel, используя BorderLayout. Центральная панель предназначена для случайного рисования прямоугольника, а южная - для кнопок.

Я получаю странное изображение кнопки в верхнем левом углу JFrame всякий раз, когда я навожу курсор мыши на Северную или Южную кнопку. Я провел небольшое исследование и выяснил, что это может быть причиной наличия прозрачного фона. Я попытался использовать super.paintComponent(g) для панели, но остальные прямоугольники, нарисованные ранее исчезнуть. Мне нужно, чтобы прямоугольники оставались в JPanel, но не странное изображение в левом верхнем углу.

Я не знаю, что я делаю не так, надеюсь, кто-то может помочь или дать какой-то ключ к решению этой проблемы.
    public class TwoBRandomRec extends JFrame{

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        TwoBRandomRec rec = new TwoBRandomRec();

        rec.setSize(500,500);
        rec.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        rec.setVisible(true);
    }

    public TwoBRandomRec() {
        //Create the buttons
        JButton north = new JButton("North");
        JButton south = new JButton("South");
        DrawPanel drawPanel = new DrawPanel(500,500);

        JPanel southP = new JPanel();
        southP.add(south);
        southP.add(north);

        this.add(drawPanel, BorderLayout.CENTER);
        this.add(southP, BorderLayout.SOUTH);

        this.setTitle("TwoButtonRandomRec");
        this.pack();        
    }

    public class DrawPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        private Random rand = new Random();
        private int x,y,xSize,ySize;
        private int height,width;

        public DrawPanel(int w,int h) {
            width = w;
            height = h;
        }
        public void RandomX(){
             x=rand.nextInt(width-1);
             xSize=rand.nextInt(width-x);
         }

         public void RandomY(){
             y=rand.nextInt(height-1);
             ySize=rand.nextInt(height-y);
         }

         public Color RandomColour(){
             rand.nextInt(height);
             return new Color(rand.nextInt(255),rand.nextInt(255),rand.nextInt(255));
         }

        @Override
        protected void paintComponent(Graphics g) {
            RandomX();
            RandomY();

            g.setColor(RandomColour());
            g.fillRect(x, y, xSize, ySize);
            try {
                Thread.sleep(50);

            } catch (InterruptedException e) {  
            }

            repaint();
        }
    }
}
1 2

1 ответ:

Ты не звонишь super.paintComponent

protected void paintComponent(Graphics g) {
    super.paintComponent(g); // <-- Insert me here and watch problem go away
    RandomX();
    RandomY();

    g.setColor(RandomColour());
    g.fillRect(x, y, xSize, ySize);
    try {
        Thread.sleep(50); // <-- This is an INCREDIBLY bad idea, NEVER, EVER do this

    } catch (InterruptedException e) {  
    }

    repaint(); // <-- This is a bad idea, watch CPU max out...
}

Вы обязаны вызвать super.paintComponent, чтобы убедиться, что цепочка рисования поддерживается правильно и происходят такие вещи, как непрозрачность и очистка графического контекста.

Объект Graphics разделяется между компонентами через один проход перекраски, несоблюдение правильной цепочки покраски приведет к, ну, таким проблемам, как ваша

Никогда не обновляйте пользовательский интерфейс в любом случае из любого метода paint (это включает вызов repaint), это просто вызывает ваш метод paint будет вспоминаться снова и снова...пока ваш процессор не достигнет 100% и программа не зависнет.

Никогда, никогда не делайте никаких трудоемких или блокирующих операций в рамках методов paint (или пользовательского интерфейса в целом), это сделает его похожим на программу, как зависший и расстроит пользователей (вы думаете, орды зомби плохие :P). Блокировка таким образом предотвращает EDT от ответа на запросы paint...

Я бы рекомендовал прочитать до конца: