2012-11-12 30 views
6

Một JLabel chứa văn bản HTML tự động kết thúc tốt đẹp các dòng bằng cách sử dụng không gian có sẵn. Nếu người ta thêm JLabel đó vào một JSrollPane, anh ta phải thiết lập giá trị ưa thích cho một giá trị phong nha nếu không nó sẽ không bọc. Tất cả điều này sẽ làm việc tốt cùng với các thành phần bên trong một JPanel bằng cách sử dụng một LayoutManager.JLabel với gói HTML-văn bản như khách hàng JScrollPane

Vì tôi muốn cửa sổ ứng dụng có thể định lại, tôi mở rộng JScrollPane để theo dõi các sự kiện thay đổi kích thước và tự động thay đổi kích thước được đồng bộ hóa với chiều rộng của chế độ xem. Về cơ bản nó hoạt động nhưng đôi khi việc tính toán chiều cao ưa thích của trình quản lý bố cục là sai (giá trị quá lớn hoặc quá nhỏ). Ví dụ, khả năng hiển thị của đường viền màu đỏ cắt qua hàng đầu tiên cho biết rằng việc tính toán chiều cao là sai.

framegrabbing

tôi không thể tái tạo sự thất bại với một gói JLabel duy nhất.

import java.awt.Color; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 
import javax.swing.BorderFactory; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.SwingUtilities; 

public class WrappedLabel implements Runnable { 

    public static void main(String[] args){ 
     SwingUtilities.invokeLater(new WrappedLabel()); 
    } 

    @Override 
    public void run(){ 
     final JPanel panel = new JPanel(new GridBagLayout()); 
     final GridBagConstraints gc = new GridBagConstraints(); 
     gc.fill = GridBagConstraints.BOTH; 
     gc.weightx = 1.0; 
     gc.weighty = 1.0; 
     { 
      gc.gridx = 0; 
      gc.gridy = 0; 
      final JLabel label = new JLabel(
       "<html>" + "please add some more text here" 
      ); 
      label.setBorder(BorderFactory.createLineBorder(Color.RED)); 
      panel.add(label, gc); 
     } 
     { 
      gc.gridx = 0; 
      gc.gridy = 1; 
      final JLabel label = new JLabel(
       "<html>" + "please add some more text here" 
      ); 
      label.setBorder(BorderFactory.createLineBorder(Color.RED)); 
      panel.add(label, gc); 
     } 
     final JFrame frame = new JFrame(); 
     frame.add(new ScrollPane(panel)); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.setSize(256, 256); 
     frame.setVisible(true); 
    } 

    private class ScrollPane extends JScrollPane implements ComponentListener { 

     ScrollPane(Container view){ 
      super(view); 
      this.viewport.addComponentListener(this); 
     } 

     @Override 
     public void componentHidden(ComponentEvent ce){ 
     } 

     @Override 
     public void componentMoved(ComponentEvent ce){ 
     } 

     /** calculating required height is a 3 step process 
      * 1. sync width of client and viewport, set height of client to high value 
      * 2. let GridbagManager calculate required minimum size 
      * 3. set preferredSize and revalidate 
     **/ 
     @Override 
     public void componentResized(ComponentEvent ce){ 
      assert(this.viewport == ce.getSource()); 
      final Container view = (Container) this.viewport.getView(); 
      final int width = this.viewport.getExtentSize().width; 
      view.setPreferredSize(new Dimension(width, Integer.MAX_VALUE)); 
      final int height = view.getLayout().preferredLayoutSize(view).height; 
      view.setPreferredSize(new Dimension(width, height)); 
      view.revalidate(); 
     } 

     @Override 
     public void componentShown(ComponentEvent ce){ 
     } 

    } 

} 
+0

1 tốt câu hỏi – mKorbel

+5

'// thêm một số văn bản here' Uh , không, cảm ơn, tôi sẽ để điều đó cho * bạn * làm. Trong thực tế, để được trợ giúp tốt hơn sớm hơn, hãy đăng một [SSCCE] (http://sscce.org/). –

Trả lời

1

Dường như đó là lỗi trong GridBagLayout hoặc bạn đang sử dụng công cụ bố cục theo cách hoàn toàn bất ngờ của nhà phát triển. Một số nhãn nhiều dòng với HTML bên trong, thiết lập kích thước ưa thích và ngay lập tức yêu cầu kích thước ưa thích bằng cửa sau? Ugh!

Tôi nhận thấy rằng đôi khi bố cục hoạt động không chính xác khi giảm kích thước cửa sổ: bảng điều khiển bên trong scrollpane không giảm và thanh cuộn ngang xuất hiện. (Tôi đang sử dụng Windows bằng cách này).

when decreasing

Ngoài ra, đôi khi, nếu thanh cuộn dọc là có thể nhìn thấy và chiều cao bảng là lớn, và sau đó tôi tăng kích thước cửa sổ, chiều cao bảng vẫn còn bất hợp lý lớn và những khoảng trống xuất hiện xung quanh nhãn:

enter image description here

Đối với tôi, bố cục sai mỗi khi tôi giảm cửa sổ; tăng công trình tốt hơn nhưng nếu nó đi sai, nó cũng không chính xác mỗi lần khác. Tôi đã thử gỡ lỗi và in các giá trị để điều khiển; có vẻ như view.getLayout().preferredLayoutSize(view) không chỉ phụ thuộc vào view.setPreferredSize mà còn phụ thuộc vào kích thước hiện tại của bảng điều khiển và scrollpane. Mã GridBagLayout quá phức tạp để đi sâu vào.

DIRTY HACK

Vì mỗi thay đổi kích thước khác mang lại kết quả chính xác, tại sao không thay đổi kích thước gấp đôi? Việc sao chép trong trình xử lý ScrollPane.componentResized không thành công, có thể do kích thước của ScrollPane vẫn giữ nguyên. Bản thân ScrollPane cần được thay đổi kích thước hai lần, với các giá trị khác nhau. Để kiểm tra nó theo cách đơn giản nhất, tôi đã phân lớp JFrame: nó lắng nghe componentResized và thay đổi kích thước cửa sổ con của nó hai lần. Thay đổi kích thước thứ hai phải được hoãn lại qua SwingUtilities.invokeLater.

Thay thế các dòng

final JFrame frame = new JFrame(); 
frame.add(scroll); 

bởi

final MyFrame frame = new MyFrame(scroll); 

và thêm các lớp sau đây:

private class MyFrame extends JFrame implements ComponentListener { 

    private Component child; 

    public MyFrame(Component child){ 
     this.child=child; 
     setLayout(null); 
     getContentPane().add(child); 
     addComponentListener(this); 
    } 

    public void componentResized(ComponentEvent e) { 
     Dimension size=getContentPane().getSize(); 
     child.setSize(new Dimension(size.width-1,size.height)); 
     validate(); 
     SwingUtilities.invokeLater(new ResizeRunner(size)); 
    } 

    public void componentMoved(ComponentEvent e) {} 
    public void componentShown(ComponentEvent e) {} 
    public void componentHidden(ComponentEvent e) {} 

    private class ResizeRunner implements Runnable { 
     private Dimension size; 
     public ResizeRunner(Dimension size){ 
      this.size=size; 
     } 
     public void run() { 
      child.setSize(size); 
      validate(); 
     } 
    } 

} 

Cùng có thể đạt được bằng cách subclassing một người quản lý bố trí.

Rõ ràng, cách tiếp cận này được hay cho lắm và không hiệu quả, nhưng như một giải pháp cho sự lỗi JRE, và nếu không có gì khác giúp ... ;-)