2

ウィンドウ内のチェス盤のようなものを表すGUIコンポーネントを作成しています。通常は8x8の正方形のグリッドになりますが、一部のバリエーションでは10x8のボードなどが必要です。最初のステップは、8x8のコンポーネントのグリッドを含むパネルを作成することです。

このクラスBoardは拡張さJPanelれ、を使用しGridLayoutて8x8コンポーネントのグリッドをモデル化します。何かを成し遂げるための努力において、これらは単にSquare拡張するクラスのものJButtonです。問題は、それらが正方形ではないということです!

Board、新たにインスタンス化JFrameされ、パックされ、画面にレンダリングされたものに追加されました。もちろん、現在、ボードはユーザーがサイズを変更するため、フレーム全体を占めています。グリッドはボードに合わせて拡大縮小され、これにより正方形が長方形に変形します。

これは完全に望ましくない動作ではありません。ボードをフレームに合わせて拡大縮小したいのですが。ただし、正方形は常に正方形のままにしておく必要があります。ボードは長方形(10x8)にすることができますが、一定の比率を維持する必要があります。

正方形を取得するにはどうすればよいですか?

4

2 に答える 2

7

LayoutManager代わりに、セルの優先サイズを尊重 するを使用することを選択できます。GridLayout各セルに同量の使用可能なスペースを提供しますが、これは希望どおりではないようです。

たとえば、GridBagLayout

ここに画像の説明を入力してください

public class TestChessBoard {

    public static void main(String[] args) {
        new TestChessBoard();
    }

    public TestChessBoard() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new ChessBoardPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ChessBoardPane extends JPanel {

        public ChessBoardPane() {
            int index = 0;
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            for (int row = 0; row < 8; row++) {
                for (int col = 0; col < 8; col++) {
                    Color color = index % 2 == 0 ? Color.BLACK : Color.WHITE;
                    gbc.gridx = col;
                    gbc.gridy = row;
                    add(new Cell(color), gbc);
                    index++;
                }
                index++;
            }
        }

    }

    public class Cell extends JButton {

        public Cell(Color background) {

            setContentAreaFilled(false);
            setBorderPainted(false);
            setBackground(background);
            setOpaque(true);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(25, 25);
        }

    }

}

比例例で更新

ここで、比例レイアウトを実行したい場合(使用可能なスペースに関係なく、グリッドの各セルが他のセルに比例したままになるように)、物事は...楽しくなり始めます...

ここに画像の説明を入力してください

public class TestChessBoard {

    public static void main(String[] args) {
        new TestChessBoard();
    }

    public TestChessBoard() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestChessBoard.ChessBoardPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ChessBoardPane extends JPanel {

        public ChessBoardPane() {
            int index = 0;
            setLayout(new ChessBoardLayoutManager());
            for (int row = 0; row < 8; row++) {
                for (int col = 0; col < 8; col++) {
                    Color color = index % 2 == 0 ? Color.BLACK : Color.WHITE;
                    add(new TestChessBoard.Cell(color), new Point(col, row));
                    index++;
                }
                index++;
            }
        }
    }

    public class Cell extends JButton {

        public Cell(Color background) {

            setContentAreaFilled(false);
            setBorderPainted(false);
            setBackground(background);
            setOpaque(true);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(25, 25);
        }
    }

    public class ChessBoardLayoutManager implements LayoutManager2 {

        private Map<Point, Component> mapComps;

        public ChessBoardLayoutManager() {
            mapComps = new HashMap<>(25);
        }

        @Override
        public void addLayoutComponent(Component comp, Object constraints) {
            if (constraints instanceof Point) {

                mapComps.put((Point) constraints, comp);

            } else {

                throw new IllegalArgumentException("ChessBoard constraints must be a Point");

            }
        }

        @Override
        public Dimension maximumLayoutSize(Container target) {
            return preferredLayoutSize(target);
        }

        @Override
        public float getLayoutAlignmentX(Container target) {
            return 0.5f;
        }

        @Override
        public float getLayoutAlignmentY(Container target) {
            return 0.5f;
        }

        @Override
        public void invalidateLayout(Container target) {
        }

        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        @Override
        public void removeLayoutComponent(Component comp) {
            Point[] keys = mapComps.keySet().toArray(new Point[mapComps.size()]);
            for (Point p : keys) {
                if (mapComps.get(p).equals(comp)) {
                    mapComps.remove(p);
                    break;
                }
            }
        }

        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return new CellGrid(mapComps).getPreferredSize();
        }

        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return preferredLayoutSize(parent);
        }

        @Override
        public void layoutContainer(Container parent) {
            int width = parent.getWidth();
            int height = parent.getHeight();

            int gridSize = Math.min(width, height);

            CellGrid grid = new CellGrid(mapComps);
            int rowCount = grid.getRowCount();
            int columnCount = grid.getColumnCount();

            int cellSize = gridSize / Math.max(rowCount, columnCount);

            int xOffset = (width - (cellSize * columnCount)) / 2;
            int yOffset = (height - (cellSize * rowCount)) / 2;

            Map<Integer, List<CellGrid.Cell>> cellRows = grid.getCellRows();
            for (Integer row : cellRows.keySet()) {
                List<CellGrid.Cell> rows = cellRows.get(row);
                for (CellGrid.Cell cell : rows) {
                    Point p = cell.getPoint();
                    Component comp = cell.getComponent();

                    int x = xOffset + (p.x * cellSize);
                    int y = yOffset + (p.y * cellSize);

                    comp.setLocation(x, y);
                    comp.setSize(cellSize, cellSize);

                }
            }

        }

        public class CellGrid {

            private Dimension prefSize;
            private int cellWidth;
            private int cellHeight;

            private Map<Integer, List<Cell>> mapRows;
            private Map<Integer, List<Cell>> mapCols;

            public CellGrid(Map<Point, Component> mapComps) {
                mapRows = new HashMap<>(25);
                mapCols = new HashMap<>(25);
                for (Point p : mapComps.keySet()) {
                    int row = p.y;
                    int col = p.x;
                    List<Cell> rows = mapRows.get(row);
                    List<Cell> cols = mapCols.get(col);
                    if (rows == null) {
                        rows = new ArrayList<>(25);
                        mapRows.put(row, rows);
                    }
                    if (cols == null) {
                        cols = new ArrayList<>(25);
                        mapCols.put(col, cols);
                    }
                    Cell cell = new Cell(p, mapComps.get(p));
                    rows.add(cell);
                    cols.add(cell);
                }

                int rowCount = mapRows.size();
                int colCount = mapCols.size();

                cellWidth = 0;
                cellHeight = 0;

                for (List<Cell> comps : mapRows.values()) {
                    for (Cell cell : comps) {
                        Component comp = cell.getComponent();
                        cellWidth = Math.max(cellWidth, comp.getPreferredSize().width);
                        cellHeight = Math.max(cellHeight, comp.getPreferredSize().height);
                    }
                }

                int cellSize = Math.max(cellHeight, cellWidth);

                prefSize = new Dimension(cellSize * colCount, cellSize * rowCount);
                System.out.println(prefSize);
            }

            public int getRowCount() {
                return getCellRows().size();
            }

            public int getColumnCount() {
                return getCellColumns().size();
            }

            public Map<Integer, List<Cell>> getCellColumns() {
                return mapCols;
            }

            public Map<Integer, List<Cell>> getCellRows() {
                return mapRows;
            }

            public Dimension getPreferredSize() {
                return prefSize;
            }

            public int getCellHeight() {
                return cellHeight;
            }

            public int getCellWidth() {
                return cellWidth;
            }

            public class Cell {

                private Point point;
                private Component component;

                public Cell(Point p, Component comp) {
                    this.point = p;
                    this.component = comp;
                }

                public Point getPoint() {
                    return point;
                }

                public Component getComponent() {
                    return component;
                }

            }

        }
    }
}
于 2013-01-31T23:08:21.703 に答える
3

これは少し長くなったので、ここに簡単な答えがあります:ボードの寸法(8x8、10x8)を指定すると、正方形のボードを維持して、ユーザーがサイズを変更できる場合は画面全体に表示することはできません。フレームに空白がある場合でも、アスペクト比が維持されるようにボードのサイズを制限する必要があります。OK、長い説明を読んでください...

これを機能させるには2つの方法があります。の可能なサイズを制限するかJFrame、サイズを制限して、Board常にフレームを埋めるとは限らないようにすることができます。ボードのサイズを制限するのがより一般的な方法なので、それから始めましょう。

オプション1:ボードを制限する

ボードの寸法の固定セット(8x8、10x8、および他のいくつかの可能性があります)で作業していて、各正方形に最小サイズがあると仮定すると(チェスボード上の1ピクセルの正方形はあまり実用的ではないように聞こえます)、ボードが完全に埋めることができるほど多くのフレーム寸法。フレームが80ピクセル×80ピクセルの場合、8x8ボードは完全にフィットします。しかし、ユーザーが85x80のようなサイズに変更するとすぐに、指定したボードの寸法で正方形を維持しながらそれを完全に埋めることができないため、行き詰まります。

この場合、5ピクセルを空のままにしておきます。これは、上下5ピクセル、上下2.5ピクセルなど、関係ありません。これはおなじみのように聞こえるはずです。これはアスペクト比の問題であり、基本的に、テレビと映画のサイズによっては、テレビの端に黒いバーが表示される理由です。

オプション2:フレームを制限する

ボードを常にフレーム全体に表示したい場合は、おそらく希望どおりではない場合は、ユーザーがフレームのサイズを変更した後で、フレームのサイズを調整する必要があります。10x8ボードを使用していて、ユーザーがフレームを107x75に設定するとします。それはそれほど悪くはありません。少し計算すれば、100x80が最も近いアスペクト比であることがわかり、ウィンドウを修正できます。ただし、ウィンドウがジャンプし続ける場合、特に50x200のようにウィンドウをずらそうとした場合は、ユーザーにとっては少しイライラするでしょう。

最後の考え/例

ボードを制限することが正しい解決策である可能性が最も高いです。ゲームからデスクトップアプリまで、すべてがその原則に従います。たとえば、MSOffice製品のリボンを取り上げます。ウィンドウを大きくすると、リボンは最大サイズに達するまで拡大し(比率を維持し)、ドキュメント用のスペースが増えます。ウィンドウを小さくすると、リボンは最小サイズに達するまで小さくなり(再びその比率を維持します)、その後、リボンの一部が失われ始めます(ボード上に1x1の正方形が必要ないことを忘れないでください)。

一方、ユーザーがウィンドウのサイズを変更できないようにすることもできます。これがMineSweeperの動作方法であると確信しており(このコンピューターに再確認する必要はありません)、必要なものに対してより優れた/より簡単なソリューションになる可能性があります。

于 2013-01-31T22:34:25.517 に答える