2016-01-19 26 views
5

Tôi chưa bao giờ làm việc với Timer giây trước đó nên vấn đề của tôi có lẽ là một sự thật ngu ngốc. Chương trình của tôi vẽ một vòng tròn màu đỏ và sau giây ngẫu nhiên, vòng tròn sẽ đổi màu thành màu xanh lục. Tôi chỉ cần thực hiện một bộ đếm thời gian xoay như bạn có thể thấy bên dưới trong mã. Và nó đi vào phương pháp actionPerformed() nhưng nó không thay đổi màu sắc. Bạn có thể giúp tôi bằng cách nào đó sửa chữa vấn đề của tôi với thay đổi màu sắc?Vẽ bên trong Bộ định thời Đuổi không hoạt động

Mã của tôi:

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(); 
    } 
} 
} 
+0

Mẹo tiếng Anh: không bắt đầu mọi câu với "Vì vậy", bạn không kể một câu chuyện. – user1803551

+0

Tôi biết tôi không nên nhưng tôi không biết từ nào bắt đầu một câu. xD –

+0

Chỉ cần xóa "Vì vậy" và câu là tốt như nó được. – user1803551

Trả lời

8

Có khá nhiều mớ hỗn độn trong mã của bạn. Hãy thử điều này:

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); 
     } 
    } 
} 

Ý tưởng là bộ hẹn giờ chỉ thay đổi thuộc tính của hình được vẽ và sau đó gọi repaint() để phản ánh thay đổi. Các paintComponent được gọi là bất cứ khi nào nó là cần thiết, ngay cả trong kế nhanh chóng và nên trở lại một cách nhanh chóng.

Thuyết minh cụ thể:

  • Start Swing from the EDT.
  • Tạo và khởi động bộ hẹn giờ từ bên ngoài paintComponent vì được gọi nhiều lần và sẽ tạo và bắt đầu nhiều bộ tính giờ.
  • Có lẽ bạn nên đặt hẹn giờ không lặp lại.
  • Gọi super.paintComponent(g); là điều đầu tiên bên trong paintComponent.
  • Bạn dường như có một ActionListener không có gì.

lời khuyên chung:

  • Sử dụng @Override chú thích khi áp dụng.
  • Gọi pack() trên khung thay vì đặt kích thước theo cách thủ công và @Override phương pháp getPreferredSize của thành phần bạn vẽ.Trả về một kích thước có ý nghĩa dựa trên những gì bạn vẽ.
  • Sử dụng add(component, location) và không phải là cách khác xung quanh (không dùng nữa).
  • Không sử dụng các trường khi biến cục bộ sẽ thực hiện (ví dụ: Random r).
  • Sử dụng tên viết hoa thường (Color.RED thay vì Color.red).
+0

Cảm ơn bạn đã mô tả nó thật tuyệt vời! –

6

Đừng khởi một Timer từ bên trong một phương pháp paintComponent. Phương pháp này chỉ dành cho vẽ và sơn. Thay vào đó hãy khởi động Timer trong hàm khởi tạo của bạn và trong hành động của TimerPerromed và gọi repaint(), thay đổi trạng thái của một lớp và sử dụng thông tin đó trong paintComponent sử dụng trường đó để vẽ bất kỳ thông tin mới nào.

ví dụ:

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); 
      } 
     } 
    } 
} 

Ngoài ra, đừng quên gọi phương thức paintComponent của siêu từ trong ghi đè của bạn.

Nếu bạn cần đổi màu, hãy cho trường JPanel a Color, gọi là color và thay đổi giá trị của nó từ trong Timer, sau đó gọi repaint(). Một lần nữa trong paintComponent, sử dụng giá trị của trường đó để vẽ hình bầu dục. Cũng trong tình huống này, Timer nên lặp lại, vì vậy hãy loại bỏ timer.setRepeats(false) trong trường hợp đó.

+0

nhưng phải làm gì nếu cần thay đổi màu liên tục từ cũ. màu đỏ sang màu xanh lá cây và sau đó màu xanh lá cây sang màu đỏ, điều đó cũng có tác dụng không? –

+0

@DomagojSabolic: sau đó trong Timer thay đổi trạng thái của trường Màu và sử dụng nó trong phương thức paintComponent. –

+0

@DomagojSabolic: xem chỉnh sửa để trả lời. –

0

Bộ hẹn giờ hoạt động không đồng bộ và paintComponent hoàn tất trước khi hoàn thành công việc hẹn giờ.

+0

Nhưng System.out.println của tôi hoạt động và in ra mọi bộ đếm thời gian kết thúc –

+0

trong mẫu u này có JFrame và Jpanel, nếu u thêm nhiều thành phần, việc triển khai này sẽ ném ngoại lệ vì khi bộ hẹn giờ của bạn cố thực hiện thay đổi đối với g , trong cùng một thời gian, một thành phần khác sẽ sử dụng cùng một trường hợp g để vẽ lại –

+0

Tôi không thấy cách này trả lời câu hỏi. 'paintComponent' * nên/có thể * kết thúc trước khi bộ hẹn giờ bắt đầu hoặc thực hiện hành động của nó. Vấn đề không đồng bộ là không liên quan. – user1803551

Các vấn đề liên quan