簡體   English   中英

JPanels並沒有完全伸展以占據可用空間

[英]JPanels don't completely stretch to occupy the available space

我有一個面板,我可以並排放置幾個不同尺寸和顏色的迷你面板,它們應該占據整個父面板(​​水平)。

為此我使用BorderLayout(用於父面板),BoxLayout用於子面板,我放置所有迷你面板(參見下面的代碼)。 它可以正常工作,並且可以正常調整大小和一切。 但是,隨着迷你面板數量的增加,會出現奇怪的行為:父面板末端出現空白區域。

在此輸入圖像描述

我想我發現這是布局管理器中的拉伸錯誤,因為為了拉伸面板,布局管理器嘗試向每個迷你面板添加一個像素。 但是,當迷你面板的數量很大時,向每個面板添加一個像素將導致添加許多像素並超出父級的大小。 因此,布局管理器最終不會向任何迷你面板添加任何像素,從而導致空白空間。

這是我的SSCCE :(嘗試運行,拉伸窗口,以了解問題)

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

我該如何避免這種行為? 我希望我的面板占據整個容器。

編輯:迷你面板旨在(一旦解決)鼠標聽眾。 因此,塗料解決方案是不幸的。

布局問題通過以下方式解決:LayoutManagers :-)如果不是您想要它做的,請實現您想要的行為。

因此,如果核心BoxLayout由於舍入錯誤而忽略像素,則子類並使其根據需要分配這些像素。 一個非常原始的快速示例:

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

}

我能想到的兩個選擇:

  1. 擁有一個自定義組件,該組件具有繪制所有區域的paintComponent(...)方法,並且在調整窗口大小時,它將重新繪制區域,同時根據新的寬度信息縮放它們。

  2. 將彩色區域繪制一次到圖像,然后繪制它,並在調整窗口大小時重新縮放圖像以適合。

我曾經在使用GridLayout作為棋盤時遇到過這個問題。 我的解決方案是擴展GridLayout並使用浮點精度計算布局。

暫無
暫無

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

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