6

サイズと色が異なるいくつかのミニパネルを並べて配置するパネルがあり、それらは親パネル全体 (水平方向) を占める必要があります。

このために、BorderLayout (親パネル用) と、すべてのミニパネルを配置するサブパネル用の BoxLayout を使用します (以下のコードを参照)。サイズ変更などすべての際に機能し、正しく動作します。ただし、ミニパネルの数が増えると、奇妙な動作が発生します。親パネルの最後に空白が表示されます。

ここに画像の説明を入力

パネルをストレッチするために、レイアウト マネージャーは各ミニパネルに 1 つのピクセルを追加しようとするため、これはレイアウト マネージャーのストレッチング バグであることがわかりました。ただし、ミニパネルの数が多い場合、すべてに 1 つのピクセルを追加すると、多くのピクセルが追加され、親のサイズを超えてしまいます。したがって、レイアウト マネージャーは最終的にどのミニパネルにもピクセルを追加せず、空のスペースが生じます。

これが私の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);
    }
}

この動作を回避するにはどうすればよいですか? パネルをコンテナ全体に配置したい。

EDIT: ミニパネルは(これが解決されたら)マウスリスナーを持つことを意図しています。したがって、塗装ソリューションは残念ながら避けられます。

4

3 に答える 3

4

レイアウトの問題は次の方法で解決できます... 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);
            }
        }
    }

}
于 2012-02-13T15:47:39.437 に答える
2

私が考えることができる2つのオプション:

  1. すべての領域を描画するメソッドを持つカスタム コンポーネントがありpaintComponent(...)、ウィンドウのサイズが変更されると、新しい幅情報に従って領域をスケーリングしながら領域を再描画します。

  2. 色付きの領域を一度画像にペイントしてから、それをペイントします。ウィンドウのサイズが変更されたら、画像が収まるように再スケーリングします。

于 2012-02-09T15:00:33.193 に答える
1

チェス盤に GridLayout を使用しているときに、この問題に遭遇したことがあります。私の解決策は、GridLayout を拡張し、浮動小数点精度でレイアウトを計算することでした。

于 2012-02-09T15:41:43.857 に答える