2012-02-09 28 views
6

Tôi có một bảng điều khiển nơi tôi đặt một số bảng nhỏ, cạnh nhau, với các kích cỡ và màu sắc khác nhau và chúng sẽ chiếm toàn bộ bảng điều khiển chính (theo chiều ngang).JPanels không hoàn toàn kéo dài để chiếm không gian có sẵn

Đối với điều này tôi sử dụng BorderLayout (cho bảng điều khiển chính) và BoxLayout cho bảng phụ nơi tôi đặt tất cả các bảng nhỏ (xem mã bên dưới). Nó hoạt động và hoạt động đúng cách thay đổi kích thước và mọi thứ. Tuy nhiên, khi số lượng các bảng thu nhỏ trở nên lớn hơn, một hành vi lạ xảy ra: khoảng trống sẽ xuất hiện ở cuối bảng điều khiển chính.

enter image description here

Tôi nghĩ rằng tôi thấy rằng đây là một lỗi streching trong các nhà quản lý bố trí, bởi vì để strech các pa-nô, người quản lý bố trí cố gắng thêm một điểm ảnh duy nhất để mỗi mini-panel. Tuy nhiên, khi số lượng bảng nhỏ lớn, việc thêm một pixel vào mỗi pixel sẽ dẫn đến việc thêm nhiều pixel và vượt quá kích thước của bố cục. Do đó, trình quản lý bố cục sẽ không thêm bất kỳ pixel nào vào bất kỳ bảng điều khiển mini nào, dẫn đến khoảng trống.

Đây là SSCCE tôi: (thử chạy, và streching cửa sổ, để hiểu được vấn đề)

package com.myPackage; 

import java.awt.*; 
import java.util.Vector; 
import javax.swing.BorderFactory; 
import javax.swing.BoxLayout; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class ColoredPanels extends JPanel 
{ 
    /* Content information. */ 
    private Vector<Integer> partitions; 
    private Vector<Color> colors; 

    /* Panel where the content panels will go. */ 
    private JPanel contentHolder; 

    private final int defaultHeight = 20; 

    public ColoredPanels(Vector<Integer> partitions, Vector<Color> colors) 
    { 
     assert partitions != null; 
     assert !partitions.isEmpty(); 
     assert colors != null; 
     assert !colors.isEmpty(); 
     assert colors.size() == partitions.size(); 

     this.partitions = partitions; 
     this.colors = colors; 

     /* Set layout manager. */ 
     setLayout(new BorderLayout()); 

     /* Create the content holder. */ 
     contentHolder = new JPanel(); 
     contentHolder.setLayout(new BoxLayout(contentHolder, BoxLayout.X_AXIS)); 
     this.add(contentHolder, BorderLayout.NORTH); 

     /* Fill content holder with colored panels. */ 
     createPanels(); 
    } 

    private void createPanels() 
    { 
     assert partitions != null; 
     assert !partitions.isEmpty(); 
     assert colors != null; 
     assert !colors.isEmpty(); 
     assert colors.size() == partitions.size(); 

     for (int i = 0; i < partitions.size(); i++) 
     { 
      JPanel newPanel = new JPanel(); 
      newPanel.setBackground(colors.get(i)); 
      newPanel.setPreferredSize(new Dimension(partitions.get(i), defaultHeight)); 
      newPanel.setMinimumSize(new Dimension(1, defaultHeight)); 
      contentHolder.add(newPanel); 
     } 
    } 

    public static void main(String[] in) 
    { 
     Vector<Integer> sizes = new Vector<Integer>(); 
     Vector<Color> cols = new Vector<Color>(); 

     /* Make 100 random sizes, and use two colors. */ 
     for (int i = 0; i < 100; i++) 
     { 
      int size = (int)Math.round(1 + Math.random() * 10); 
      sizes.add(size); 
      cols.add((i%2 == 0)? Color.red : Color.green); 
     } 

     ColoredPanels panels = new ColoredPanels(sizes, cols); 
     panels.setBorder(BorderFactory.createLineBorder(Color.yellow, 1)); 

     JFrame newFrame = new JFrame(); 
     newFrame.getContentPane().add(panels); 
     newFrame.pack(); 
     newFrame.setVisible(true); 
    } 
} 

Làm thế nào để tránh hành vi này? Tôi muốn các tấm của tôi chiếm toàn bộ bình chứa.

CHỈNH SỬA: Các bảng nhỏ được thiết kế để có (một khi điều này được giải quyết) người nghe chuột. Do đó, các giải pháp sơn là không thể tránh khỏi.

+3

rất đẹp SSCCE +1 – mKorbel

+0

thú vị ... bạn sẽ làm gì? Cách dễ nhất (hầu hết không phải là cách tốt nhất :-) sẽ là để cung cấp cho tất cả không gian làm tròn cho ... – kleopatra

+0

Tôi muốn các bảng mini hoàn toàn lấp đầy không gian có sẵn. Việc đưa phần còn lại cho người cuối cùng không phải là một lựa chọn, vì tỷ lệ kích thước phân vùng phải được tôn trọng. – Anoyz

Trả lời

3

Vấn đề về bố cục được giải quyết bằng ... LayoutManagers :-) Nếu không có thứ bạn muốn, hãy thực hiện hành vi bạn muốn.

Vì vậy, nếu lõi BoxLayout chỉ đơn giản là bỏ qua pixel do làm tròn lỗi, phân lớp và làm cho nó phân phối những pixel khi cần thiết. Ví dụ rất ngắn gọn:

public static class XBoxLayout extends BoxLayout { 

    enum Strategy { 
     NONE, 
     STRETCH_LAST, 
     DISTRUBUTE 
    } 

    private Strategy strategy; 

    public XBoxLayout(Container target, int axis, Strategy strategy) { 
     super(target, axis); 
     this.strategy = strategy; 
    } 


    @Override 
    public void layoutContainer(Container target) { 
     super.layoutContainer(target); 
     if (Strategy.NONE == strategy) return; 
     Insets targetInsets = target.getInsets(); 
     int targetSize = target.getWidth() - targetInsets.left - targetInsets.right; 
     int childSum = 0; 
     for (Component child : target.getComponents()) { 
      childSum += child.getWidth(); 
     } 
     if (targetSize > childSum) { 
      int excess = targetSize - childSum; 
      distribute(target, excess); 
     } 
    } 


    private void distribute(Container target, int excess) { 
     System.out.println("childCount/rounding excess " + target.getComponentCount() + "/" + excess); 
     if (Strategy.STRETCH_LAST == strategy) { 
      Component lastChild = target.getComponent(target 
        .getComponentCount() - 1); 
      lastChild.setSize(lastChild.getWidth() + excess, 
        lastChild.getHeight()); 
     } else { 
      int firstToDistribute = target.getComponentCount() - excess; 
      int summedOffset = 0; 
      for(int index = firstToDistribute; index < target.getComponentCount(); index++) { 
       Component child = target.getComponent(index); 
       Rectangle bounds = child.getBounds(); 
       bounds.x += summedOffset++; 
       bounds.width += 1; 
       child.setBounds(bounds); 
      } 
     } 
    } 

} 
+0

Cảm ơn sự giúp đỡ của bạn. Điều đó trông giống như một giải pháp khả thi và tôi đang tìm kiếm thứ gì đó liên quan đến người quản lý bố cục. Mã không giống như nó tôn trọng tỷ lệ kích thước thành phần (liên quan với nhau), ngay cả với chiến lược PHÂN PHỐI, nhưng tôi đã có điểm, và sẽ cố gắng thực hiện một cái gì đó trong những dòng đó. – Anoyz

+0

Tôi sẽ thứ hai này - khi bạn cần hành vi tùy chỉnh như vậy, làm quản lý bố cục của riêng bạn không phải là đau đớn và bạn có thể tối ưu hóa nó cho trường hợp sử dụng cụ thể của bạn. –

+0

@Anoyz phân phối các pixel đơn là .. một vấn đề chiến lược :-) Thực hiện bất cứ điều gì bạn cần, vào cuối ngày nó sẽ không được chính xác tỷ lệ thuận với thực tế/pref/kích thước bất cứ điều gì – kleopatra

2

Hai tùy chọn tôi có thể nghĩ:

  1. Có một thành phần tùy chỉnh mà có một phương pháp paintComponent(...) mà sơn tất cả các vùng, và khi cửa sổ được thay đổi kích cỡ nó sẽ sơn lại các khu vực trong khi mở rộng quy mô chúng theo thông tin chiều rộng mới.

  2. Vẽ các vùng màu một lần cho hình ảnh, sau đó vẽ vùng đó và khi cửa sổ được thay đổi kích thước, hãy rescale hình ảnh để vừa.

+0

Cảm ơn sự giúp đỡ của bạn. Tôi có ý định thêm người nghe chuột vào các bảng mini. Nếu tôi sử dụng chiến lược vẽ tranh, tôi có thể làm như thế nào? – Anoyz

+0

Sẽ cần phải thêm người nghe vào thành phần cơ bản (ví dụ:một bảng điều khiển), sau đó quy mô các tọa độ trở lại từ kích thước thu nhỏ của bảng điều khiển. –

+0

Không có giải pháp dễ dàng hơn với bố cục? – Anoyz

1

Tôi đã từng gặp sự cố này khi sử dụng GridLayout cho bàn cờ. Giải pháp của tôi là mở rộng GridLayout và tính toán bố cục với độ chính xác của dấu chấm động.

+0

Bạn có thể cung cấp thêm thông tin chi tiết về giải pháp đó không? – Anoyz

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