簡體   English   中英

Swing Timer里面的繪畫不起作用

[英]Painting inside Swing Timer not working

我之前從未使用過Timer ,所以我的問題可能真的很愚蠢。 我的程序繪制一個紅色的圓圈,隨機秒后圓圈應將其顏色更改為綠色。 我剛剛制作了一個擺動計時器,你可以在下面的代碼中看到。 它進入actionPerformed()方法,但它不會改變顏色。 你能幫我改變一下顏色嗎?

我的代碼:

package igrica;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class ChangingCircle implements ActionListener{

JFrame frame;

Timer timer;
Random r;

public static void main(String[] args) {
    ChangingCircle gui = new ChangingCircle();
    gui.go();
}

public void go() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyPanel panel = new MyPanel();

    frame.getContentPane().add(BorderLayout.CENTER, panel);
    frame.setSize(300, 300);
    frame.setVisible(true);
}   

public void actionPerformed(ActionEvent event) {
    frame.repaint();
}

class MyPanel extends JPanel {
    public void paintComponent(Graphics g) {


        g.setColor(Color.red);
        g.fillOval(100, 100, 100, 100);

        Random r = new Random();

        Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
            public void actionPerformed(ActionEvent ev) {
                System.out.println("Timer out");
                g.setColor(Color.green);
                g.fillOval(100, 100, 100, 100);
            } 
        });
        timer.start();
    }
}
}

你的代碼中有很多混亂。 試試這個:

public class ChangingCircle {

    Color color = Color.RED;
    MyPanel panel = new MyPanel();

    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> {
            ChangingCircle gui = new ChangingCircle();
            gui.go();
        });
    }

    public void go() {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(panel, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);

        Random r = new Random();
        Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {

            public void actionPerformed(ActionEvent ev) {

                System.out.println("Timer");
                color = Color.GREEN;
                panel.repaint();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

    class MyPanel extends JPanel {

        private int size = 100, loc = 100;

        @Override
        public void paintComponent(Graphics g) {

            super.paintComponent(g);
            g.setColor(color);
            g.fillOval(loc, loc, size, size);
        }

        @Override
        public Dimension getPreferredSize() {

            return new Dimension(size + loc, size + loc);
        }
    }
}

這個想法是計時器只改變要繪制的形狀的屬性,然后調用repaint()來反映變化。 只要需要,就會調用paintComponent ,即使是快速連續也應該快速返回。

具體說明:

  • 從EDT開始揮桿
  • paintComponent外部創建並啟動計時器,因為它被多次調用並且將創建並啟動許多計時器。
  • 您應該將計時器設置為不重復。
  • 調用super.paintComponent(g); 作為paintComponent內部的第一件事。
  • 你似乎有一個什么都不做的ActionListener

一般提示:

  • 適用時,請使用@Override注釋。
  • 在框架上調用pack()而不是手動設置其大小,並@Override您繪制的組件的getPreferredSize方法。 根據您繪制的內容返回有意義的大小。
  • 使用add(component, location)而不是相反(不建議使用)。
  • 當局部變量可以使用時,不要使用字段(例如, Random r )。
  • 使用大寫常量名稱( Color.RED而不是Color.red )。

不要在paintComponent方法中啟動Timer。 此方法僅適用於繪畫和繪畫。 而是在構造函數中啟動Timer並在Timer的actionPerromed中調用repaint() ,更改類的字段的狀態,並使用paintComponent中的該信息使用該字段來繪制任何新信息。

例如

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ChangingCircle {
    JFrame frame;

    public static void main(String[] args) {
        ChangingCircle gui = new ChangingCircle();
        gui.go();
    }

    public void go() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MyPanel panel = new MyPanel();

        frame.getContentPane().add(BorderLayout.CENTER, panel);
        frame.setSize(300, 300);
        frame.setVisible(true);
    }   

    public void actionPerformed(ActionEvent event) {
        frame.repaint();
    }

    class MyPanel extends JPanel {
        private Random r = new Random();
        private boolean draw = false;

        public MyPanel() {
            Timer timer = new Timer(r.nextInt(5000) + 1000, new ActionListener() {
                public void actionPerformed(ActionEvent ev) {
                    draw = true;
                    repaint();
                } 
            });
            timer.setRepeats(false);
            timer.start();
        }
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (draw) {
                g.setColor(Color.red);
                g.fillOval(100, 100, 100, 100);
            }
        }
    }
}

另外,不要忘記在覆蓋中調用super的paintComponent方法。

如果你需要改變顏色,給JPanel一個Color字段,比如叫做color並從Timer中改變它的值,然后調用repaint() 同樣在paintComponent中,使用該字段的值來繪制橢圓。 同樣在這種情況下,Timer 應該重復,所以在那種情況下擺脫timer.setRepeats(false)

計時器異步工作, paintComponent在完成計時器工作之前完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM