2

I am building a small chess board for tactics, it would be a fun way to reflect upon on interests (programming and chess).

One problem I have currently face, although solved, is maintaining the board aspect ratio of 1:1.

The Board extends JPanel. Due to a problem with constraints, I have opted towards maintaining the board's physical size rather than it's rendered size. This would lead to faster operations when actually being used.

What I want it to look like, and have achieved:

Horizontal buffer Vertical buffer

The way I achieved this though seemed very hackish and is poor code by Skeet standards (thank you based Skeet).

public Frame() {
    final JFrame frame = new JFrame("Chess");
    final JPanel content = new JPanel(new BorderLayout());
    final JPanel boardConfine = new JPanel(new BorderLayout());
    final Board board = new Board();

    boardConfine.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            int min = Math.min(boardConfine.getWidth(), boardConfine.getHeight());
            int xBuffer = (boardConfine.getWidth() - min) / 2;
            int yBuffer = (boardConfine.getHeight() - min) / 2;
            board.setBounds(xBuffer, yBuffer, min, min);

        }

    });
    boardConfine.add(board, BorderLayout.CENTER);
    content.setBackground(new Color(205, 205, 205));
    content.add(boardConfine, BorderLayout.CENTER);

    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setContentPane(content);
    frame.pack();
    frame.setVisible(true);
}

As seen above, I manually set the board's size and location. Even I have stated exhaustively that this shouldn't ever be done, but I couldn't find a solution to work. I need the board to fill the maximum possible area, yet maintain the aspect ratio.

If there are any suggestions (either code or concepts) you can provide, I really thank you for taking the time to help me with this elitist conundrum.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Obicere
  • 2,999
  • 3
  • 20
  • 31
  • If your board's corner is defined to be the min of either width|height, then I do not see any issue with your code. – TwoThe Oct 22 '13 at 21:43
  • @TwoThe `Although it is possible to do without a layout manager, you should use a layout manager if at all possible.` What I have done is not using a layout manager. Although I used border layout, the same results are accomplished with these methods by using a `null` layout. This is therefore bad code. – Obicere Oct 22 '13 at 21:46

1 Answers1

2

Although not a complete solution, the example below scales the board to fill the smallest dimension of the enclosing container. Resize the frame to see the effect.

Addendum: The ideal solution would be Creating a Custom Layout Manager, where you have access to the enclosing container's geometry, and setBounds() can maintain the desired 1:1 aspect ratio. A variation of GridLayout may be suitable. Grid coordinates can be calculated directly, as shown here.

test image

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * @see https://stackoverflow.com/a/19531648/230513
 */
public class Test {

    private static class MyPanel extends JPanel {

        private static final int N = 8;
        private static final int TILE = 48;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N * TILE, N * TILE);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.gray);
            int w = this.getWidth();
            int h = this.getHeight();
            int tile = Math.min(w, h) / N;
            for (int row = 0; row < N; row++) {
                for (int col = 0; col < N; col++) {
                    if ((row + col) % 2 == 0) {
                        g.fillRect(col * tile, row * tile, tile, tile);
                    }
                }
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new MyPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Thanks for the suggestion. As stated in the OP though, I would like to avoid this type of solution. It is less efficient when it comes to events and would be harder to maintain. Thanks though! P.S: dark square is bottom left. – Obicere Oct 23 '13 at 03:41
  • D'oh, thanks for the correction. I can see the problem with coordinates. For fixed size, see this [example](http://stackoverflow.com/a/2562685/230513) and [variation](http://stackoverflow.com/a/2563350/230513). The example cited [here](http://stackoverflow.com/a/7142109/230513) scales the world; the problem then becomes controlling the frame, which belong to the host OS. – trashgod Oct 23 '13 at 03:56