2012-06-17 44 views
14

Tôi phân lớp JPanel để ghi đè lên paintComponent (Đồ họa), tôi muốn vẽ một hình ảnh lên jpanel trong một khung hình.JPanel không cập nhật cho đến khi thay đổi kích thước Jframe

Nhưng hình ảnh của tôi không hiển thị cho đến khi tôi thay đổi kích thước của jframe. Đây là mã của tôi:

public class ImagePanel extends JPanel{ 

    public void setImage(BufferedImage bi) 
    { 
     image = bi; 
     revalidate(); 
    } 

    @Override 
    public void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 
     if(image != null) 
     { 
      g.drawImage(image, 0, 0, this); 
     } 
    } 
} 

Trả lời

7

Nếu bạn muốn "làm mới" JPanel thì bạn nên gọi repaint(), mà sẽ gọi paintComponent của bạn(). Điều này sẽ khắc phục sự cố của bạn:

public void setImage(BufferedImage bi) 
{ 
    image = bi; 
    EventQueue.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
      repaint(); 
     } 
    }); 
} 

Thực hành tốt để cập nhật và thay đổi GUI bằng cách sử dụng EDT. Thông tin Heres thêm về các EDT nếu bạn quan tâm:

How does the event dispatch thread work?

repaint không cần phải được gọi từ EDT. Nếu bạn đang thay đổi GUI, chẳng hạn như thiết lập văn bản thành một JLabel, nó sẽ nằm bên trong EDT. Heres thêm thông tin về những gì có thể được gọi là bên ngoài của EDT (biếu không của bò thoải mái):

Safe to use Component.repaint() outside EDT?

+0

Cảm ơn John, nó hoạt động hoàn hảo! – nautilusvn

+1

+1 cho đầu vào có giá trị. Chỉ là một gợi ý, không cần phải đặt 'repaint()' gọi bên trong EDT, vì nó an toàn để gọi 'repaint()' từ bất kỳ luồng nào, như được mô tả [ở đây] (http://stackoverflow.com/questions/9786497/safe -to-use-component-repaint-outer-edt/9786598 # 9786598) –

+1

"các lớp con của các thành phần Swing có giao diện người dùng giao diện người dùng ... nên gọi' super.paintComponent() '" - [* Phương thức vẽ *] (http: //java.sun.com/products/jfc/tsc/articles/painting/index.html#callback). – trashgod

18

Xác minh rằng bạn gọi setVisible()sau thành phần bổ sung và gọi pack(), như đã thảo luận trong liên quan example này. Bạn cũng có thể cần phải áp dụng một số thích hợp layout. Gọi repaint(), như đề xuất here, có thể khắc phục các triệu chứng nhưng không phải nguyên nhân cơ bản.

2

Tôi đã gặp sự cố tương tự và đã khắc phục sự cố bằng cách gọi setVisible (true); JFrame tôi đang sử dụng.

Ví dụ: nếu JFrame của bạn không cập nhật sau khi sử dụng:

jframe.setContentPane(new MyContentPane()); 

sửa chữa nó với:

jframe.setContentPane(new MyContentPane()); 
jframe.setVisible(true); 

Tôi biết rằng nó có vẻ ngớ ngẩn để làm điều này mặc dù JFrame của bạn là đã có thể nhìn thấy, nhưng đó là cách duy nhất tôi đã tìm thấy cho đến nay để khắc phục vấn đề này (giải pháp được đề xuất ở trên không hiệu quả đối với tôi).

Dưới đây là ví dụ hoàn chỉnh. Chạy nó và sau đó bỏ ghi chú "f.setVisible (true);" hướng dẫn trong các lớp Panel1 và Panel2 và bạn sẽ thấy sự khác biệt. Đừng quên nhập (Ctrl + Shift + O để nhập tự động).

lớp chính:

public class Main { 
    private static JFrame f; 
    public static void main(String[] args) { 
     f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setContentPane(new Panel1(f)); 
     f.pack();  
     f.setVisible(true); 
    } 
} 

Panel1 lớp:

public class Panel1 extends JPanel{ 
    private JFrame f; 
    public Panel1(JFrame frame) { 
     f = frame; 
     this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 
     JButton b = new JButton("Panel 1"); 
     b.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       f.setContentPane(new Panel2(f)); 
       // Uncomment the instruction below to fix GUI "update-on-resize-only" problem 
       //f.setVisible(true); 
      } 
     }); 
     add(b); 
    } 
} 

Panel2 lớp:

public class Panel2 extends JPanel{ 
    private JFrame f; 
    public Panel2(JFrame frame) { 
     f = frame; 
     this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS)); 
     JButton b = new JButton("Panel 2"); 
     b.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       f.setContentPane(new Panel1(f)); 
       // Uncomment the instruction below to fix GUI "update-on-resize-only" problem 
       //f.setVisible(true); 
      } 
     }); 
     add(b); 
    } 
} 

Hy vọng rằng sẽ giúp.

Trân trọng.

+0

Hoàn hảo! Không chắc tại sao nó lại hoạt động, nhưng đó là điều duy nhất giải quyết được vấn đề của tôi. Trước đó, tôi đã làm điều này: Dimension size = frame.getSize(); \t Boolean maximized = frame.getExtendedState() == JFrame.MAXIMIZED_BOTH; \t frame.setSize (kích thước mới ((int) size.getWidth() - 1, (int) size.getHeight() - 1)); \t nếu (tối đa) frame.setExtendedState (JFrame.MAXIMIZED_BOTH); \t else frame.setSize (kích thước); Câu trả lời của bạn là nhiều, sạch hơn và ít hacky hơn. Cảm ơn! – dberm22

+1

@ dberm22 thực sự, không cần hack (ít nhất không có trong ví dụ này, không kiểm tra bản gốc với hình ảnh có thể có kích thước khác nhau, cũng như trạng thái kích thước mở rộng có thể khó): thiết lập contentPane là-a sửa đổi hệ thống phân cấp container của khung và như vậy yêu cầu xác nhận lại trên khung. – kleopatra

5

Hãy xem the docs cho JPanel.add(), mà nó được thừa hưởng từ java.awt.Container:

Gắn các thành phần quy định đến hết thùng này. Đây là một phương thức tiện lợi cho addImpl (java.awt.Component, java.lang.Object, int). Phương pháp này thay đổi thông tin liên quan đến bố cục và do đó, vô hiệu hóa cấu trúc phân cấp thành phần. Nếu vùng chứa đã được hiển thị, cấu trúc phân cấp phải được xác nhận sau đó để hiển thị thành phần được thêm vào.

Nhấn mạnh thêm.

Do đó, nếu bạn thay đổi một container sau nó đã được hiển thị, bạn phải gọi validate() để cho nó để hiển thị. Chỉ cần gọi repaint() là không đủ. Bạn có thể nhận thấy rằng việc gọi setVisible(true) cũng hoạt động; điều này là bởi vì it calls validate() internally.

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