GridLayout doesn't respect the given number of rows and columns - java

I'm trying to display a grid of coloured JLabels inside a JPanel. I created a custom class PixelMatrix which extends JPanel and I populated it with a custom class Pixel which extends JLabel.
The problem is: when I put my Pixel objects inside my GridLayout in the PixelMatrix object, I don't get the number of rows and columns I desire.
This is my Pixel class:
public class Pixel extends JLabel{
private Color color = null;
private int dimension;
public Pixel(Color c, int dim) {
this.setPreferredSize(new Dimension(dim, dim));
this.dimension = dim;
this.color = c;
this.setBackground(color);
this.setOpaque(true);
}
public Pixel(int dim) {
this(new Color(0x000000), dim);
}
public Color getColor() {
return color;
}
public void setColor(Color c) {
color = c;
}
}
This is my PixelMatrix class:
public class PixelMatrix extends JPanel{
private int resolution;
private Pixel[][] pixels = null;
private GridLayout layout;
public PixelMatrix(int res) {
resolution = res;
layout = new GridLayout(0, res);
pixels = new Pixel[res][res];
for(int x = 0; x < res; x++) {
for(int y = 0; y < res; y++) {
pixels[x][y] = new Pixel(50);
this.add(pixels[x][y]);
}
}
}
}
And this is the class is use to display all the stuff:
public class EditorPanel extends JPanel{
private BorderLayout layout = new BorderLayout();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu("File");
private JMenu settingsMenu = new JMenu("Settings");
private JMenu sizeSubMenu = new JMenu("Size");
private JMenuItem newItem = new JMenuItem("New");
private JMenuItem openItem = new JMenuItem("Open...");
private JMenuItem saveItem = new JMenuItem("Save");
private JRadioButtonMenuItem size6x6Item = new JRadioButtonMenuItem("6 x 6", true);
private JRadioButtonMenuItem size8x8Item = new JRadioButtonMenuItem("8 x 8");
private ButtonGroup sizeButtonGroup = new ButtonGroup();
private PixelMatrix matrix = new PixelMatrix(6);
public EditorPanel() {
setup();
}
private void setup() {
fileMenu.add(newItem);
fileMenu.add(openItem);
fileMenu.add(saveItem);
sizeButtonGroup.add(size6x6Item);
sizeSubMenu.add(size6x6Item);
sizeButtonGroup.add(size8x8Item);
sizeSubMenu.add(size8x8Item);
settingsMenu.add(sizeSubMenu);
menuBar.add(fileMenu);
menuBar.add(settingsMenu);
this.setLayout(layout);
this.add(menuBar, BorderLayout.NORTH);
this.setPreferredSize(new Dimension(600, 600));
this.add(matrix, BorderLayout.CENTER);
}
}
And this is what I get. I don't understand what I am doing wrong.
Result

I created a custom class PixelMatrix which extends JPanel
layout = new GridLayout(0, res);
That doesn't do anything. That just creates a variable.
The default layout manager is the FlowLayout, and that hasn't been changed. The components flow one after another and wrap to the next line.
You need to set the layout of the panel if you want to use a GridLayout.
So you could do:
layout = new GridLayout(0, res);
setLayout( layout );
Or, even easier don't bother to use a variable:
setLayout( new GridLayout(0, res) );
Also, why would you call the variable "resolution". That term is normally used for the "resolution of your screen in terms of pixels". A layout has nothing to do with resolution. You area attempting to specify the "columns" in the grid, that would be a better variable name.

Related

Attempting to change grid size based on which RadioButton is selected - Java Swing GUI - SOS board game

This project revolves around a game that is a variation of TicTacToe called SOS. One of the requirements is that the game grid needs to have two size options. The smaller grid is 5x5 and the larger is 8x8.
My goal is to have the grid size change based off which radio button is selected. In my code below I have a commented out method to change the GRID_SIZE variable based off which radio button is selected. But it does not work where it is currently and I am struggling to come up with the solution. The other problem related to the grid size changing that I think I'll have is, I do not believe the way I create the grid now will allow for it to change live as the radio buttons are pushed.
I will need to be keeping track of what gets played in each cell of the grid (whether a player is placing an S or an O) So my thought is maybe there is a better way to create the grid for both the GUI and as a storage method for the moves played.
This project is my first java project and first GUI project of this depth. It is also the major project for one of my last classes to graduate so I'm taking this seriously and could really use the help. I know my code is probably not great, I'm here to improve so any help is welcomed.
package practice;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings({ "serial", "unused"})
public class SOS_GUI extends JFrame {
public int GRID_SIZE = 8;
public Grid grid;
public SOS_GUI() {
GameBoard();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setTitle("SOS Practice");
this.setLocationRelativeTo(null);
setVisible(true);
}
public void GameBoard(){
// CONTENT PANE FOR HOLDING ALL GUI COMPONENTS
Container ContentPane = getContentPane();
// PANEL FOR GAME GRID
JPanel gameBoardCanvas = new JPanel();
gameBoardCanvas.setLayout(new GridLayout(GRID_SIZE, GRID_SIZE));
for (int x = 0; x < GRID_SIZE; x++) {
for (int y = 0; y < GRID_SIZE; y++) {
final Grid cell = new Grid(x, y);
gameBoardCanvas.add(cell);
}
}
// FOUR PANELS SURROUNDING GAME GRID
JPanel TopPanel = new JPanel();
JPanel BottomPanel = new JPanel();
JPanel LeftPanel = new JPanel();
JPanel RightPanel = new JPanel();
JLabel SpacerLabel = new JLabel(" || ");
// GAME MODE OOPTIONS - SIMPLE OR GENERAL
JLabel GameModeLabel = new JLabel("Game Mode :");
JRadioButton SimpleGameButton = new JRadioButton("Simple", true);
JRadioButton GeneralGameButton = new JRadioButton("General");
ButtonGroup GameModeButtons = new ButtonGroup();
GameModeButtons.add(SimpleGameButton);
GameModeButtons.add(GeneralGameButton);
// BOARD SIZE BUTTONS - SMALL(5X5) OR LARGE(8X8)
JLabel SizeOptionLabel = new JLabel("Board Size :");
JRadioButton SmallGridButton = new JRadioButton("Small", true);
JRadioButton LargeGridButton = new JRadioButton("Large");
ButtonGroup GridSizeButtons = new ButtonGroup();
GridSizeButtons.add(SmallGridButton);
GridSizeButtons.add(LargeGridButton);
// PLAY LETTER SETTINGS
JRadioButton PlayS_Button = new JRadioButton("S", true);
JRadioButton PlayO_Button = new JRadioButton("O");
ButtonGroup PlayLetterButtons = new ButtonGroup();
PlayLetterButtons.add(PlayS_Button);
PlayLetterButtons.add(PlayO_Button);
// BLUE PLAYER SETTINGS
JLabel BluePlayerLabel = new JLabel("Blue Player");
JRadioButton BlueHumanButton = new JRadioButton("Human", true);
JRadioButton BlueComputerButton = new JRadioButton("Computer");
ButtonGroup BluePlayerButtons = new ButtonGroup();
BluePlayerButtons.add(BlueHumanButton);
BluePlayerButtons.add(BlueComputerButton);
// RED PLAYER SETTINGS
JLabel RedPlayerLabel = new JLabel("Red Player");
JRadioButton RedHumanButton = new JRadioButton("Human");
JRadioButton RedComputerButton = new JRadioButton("Computer", true);
ButtonGroup RedPlayerButtons = new ButtonGroup();
RedPlayerButtons.add(RedHumanButton);
RedPlayerButtons.add(RedComputerButton);
// ADDING COMPONENTS TO TOP PANEL
TopPanel.add(GameModeLabel);
TopPanel.add(SimpleGameButton);
TopPanel.add(GeneralGameButton);
TopPanel.add(SpacerLabel);
TopPanel.add(SizeOptionLabel);
TopPanel.add(SmallGridButton);
TopPanel.add(LargeGridButton);
// ADDING COMPONENTS TO BOTTOM PANEL
BottomPanel.add(PlayS_Button);
BottomPanel.add(PlayO_Button);
// ADDING COMPONENTS TO LEFT PANEL
LeftPanel.add(BluePlayerLabel);
LeftPanel.add(BlueHumanButton);
LeftPanel.add(BlueComputerButton);
// ADDING COMPONENTS TO RIGHT PANEL
RightPanel.add(RedPlayerLabel);
RightPanel.add(RedHumanButton);
RightPanel.add(RedComputerButton);
// ADDING PANELS TO CONTENT PANE
ContentPane.setLayout(new BorderLayout());
ContentPane.add(TopPanel, BorderLayout.NORTH);
ContentPane.add(BottomPanel, BorderLayout.SOUTH);
ContentPane.add(LeftPanel, BorderLayout.WEST);
ContentPane.add(RightPanel, BorderLayout.EAST);
ContentPane.add(gameBoardCanvas, BorderLayout.CENTER);
TopPanel.setPreferredSize(new Dimension(50, 50));
BottomPanel.setPreferredSize(new Dimension(50, 50));
LeftPanel.setPreferredSize(new Dimension(100, 100));
RightPanel.setPreferredSize(new Dimension(100, 100));
ContentPane.setPreferredSize(new Dimension(550, 500));
}
// CLASS SETTING UP HOW THE GRID WILL BE CREATED
class Grid extends JPanel {
public static final int CELL_SIZE = 1;
private int xPos;
private int yPos;
public JLabel gridLabel;
public Grid (int x, int y) {
xPos = x;
yPos = y;
gridLabel = new JLabel("");
gridLabel.setFont(new Font("Serif", Font.BOLD, 40));
add(gridLabel);
setOpaque(true);
setLayout(new FlowLayout());
setBorder(BorderFactory.createBevelBorder(CELL_SIZE));
setBackground(new Color(200, 200, 200));
setPreferredSize(new Dimension(CELL_SIZE, CELL_SIZE));
}
}
/* POSSIBLE FUNCTION TO SET GRID_SIZE BASED OFF RADIO BUTTON INPUT? DOESNT WORK HERE
public getGridSize() {
if (GameBoard().SmallGridButton.isSelected() == true) {
GRID_SIZE = 5;
}
else if (GameBoard().LargeGridButton.isSelected() == true) {
GRID_SIZE = 8;
}
return GRID_SIZE;
}
*/
public static void main(String[] args) {
new SOS_GUI();
}
}
screenshot of the smaller 5x5 grid
screenshot of larger 8x8 grid
Again, I suggest that if you want to use components as your grid cell, that you either swap views (JPanels) using a CardLayout, or you swap out the grid cells when a JRadioButton is pressed.
I suggest:
Adding an ActionListener to the JRadioButton to be notified when it is pressed.
If you will swap components, then create a JPanel to hold the grid cells, say called gridHolder, and remove all components when the button is pressed.
Then add a new GridLayout layout manager to this JPanel, with constraints set depending on whih JRadioButton has been pressed.
Then re-adding grid cell components to this holder JPanel
Then relaying out all components in the GUI and resizing it by calling pack() on the top-level window, here a JFrame.
In the example below, I use JLabels to hold the grid cells since it is trivial to add text to these.
I store the row and column of each grid cell using the .putClientProperty(...) method and likewise can retrieve values using the .getClientProperty(...) method.
I call createGrid(...) in the constructor to create the grid with the default, small, size.
I call the same method whenever a JRadioButton has been pressed.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.border.BevelBorder;
#SuppressWarnings("serial")
public class SosGrid2 extends JPanel {
private static final int SMALL_SIZE = 5;
private static final int LARGE_SIZE = 8;
private static final String[] SIZES = { "Small", "Large" };
private static final Dimension CELL_SIZE = new Dimension(60, 60);
private static final Color GRID_BG = new Color(200, 200, 200);
private static final String ROW = "row";
private static final String COL = "col";
private JPanel gridHolder = new JPanel();
private ButtonGroup gridSizeGroup = new ButtonGroup();
public SosGrid2() {
JPanel radioButtonPanel = new JPanel();
for (String size : SIZES) {
JRadioButton radioButton = new JRadioButton(size);
radioButton.setSelected(size.equals(SIZES[0]));
radioButton.setActionCommand(size);
gridSizeGroup.add(radioButton);
radioButtonPanel.add(radioButton);
radioButton.addActionListener(e -> radioListener());
}
createGrid(SMALL_SIZE);
setLayout(new BorderLayout());
add(gridHolder);
add(radioButtonPanel, BorderLayout.PAGE_END);
}
private void createGrid(int gridSize) {
gridHolder.removeAll();
gridHolder.setLayout(new GridLayout(gridSize, gridSize));
for (int row = 0; row < gridSize; row++) {
for (int col = 0; col < gridSize; col++) {
JLabel gridCell = createGridCell(row, col);
gridHolder.add(gridCell);
}
}
}
// factory method to create grid cell JLabels.
private JLabel createGridCell(int row, int col) {
JLabel label = new JLabel("", SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(Font.BOLD, 32f));
label.setOpaque(true);
label.setBackground(GRID_BG);
label.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
label.setPreferredSize(CELL_SIZE);
label.putClientProperty(ROW, row);
label.putClientProperty(COL, col);
label.addMouseListener(new MyMouseListener());
return label;
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
JLabel gridCell = (JLabel) e.getSource();
int row = (int) gridCell.getClientProperty(ROW);
int col = (int) gridCell.getClientProperty(COL);
String message = String.format("Row: %d, Col: %d", row, col);
String title = "Cell Pressed";
int type = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(SosGrid2.this, message, title, type);
String text = gridCell.getText();
if (text.isEmpty()) {
gridCell.setText("X");
} else {
gridCell.setText("");
}
}
}
private void radioListener() {
ButtonModel btnModel = gridSizeGroup.getSelection();
if (btnModel != null) {
int gridSize = btnModel.getActionCommand().equals(SIZES[0]) ? SMALL_SIZE : LARGE_SIZE;
createGrid(gridSize);
Window jframe = SwingUtilities.getWindowAncestor(this);
jframe.pack();
jframe.setLocationRelativeTo(null);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SosGrid2 mainPanel = new SosGrid2();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

Java Repaint gridlayout

I am trying to repaint a snake game I am creating on the new game action.It is working but it isn't clearing the old snake body or blocks from the screen.
public class View extends JFrame implements ActionListener {
private static final long serialVersionUID = -2542001418764869760L;
public static int viewWidth = 20;
public static int viewHeight = 20;
private SidePanel side;
private JMenuBar menuBar;
private JMenuItem newGameButton;
private JMenu menu, mode;
private SnakeController sController;
private GamePanel gamePanel;
/*
* Initialize the game's panels and add them to the window.
*/
public View() {
menuBar = new JMenuBar();
menu = new JMenu("Menu");
menuBar.add(menu);
newGameButton = new JMenuItem("New Game");
menu.add(newGameButton);
newGameButton.addActionListener(this);
mode = new JMenu("Mode");
menuBar.add(mode);
this.setJMenuBar(menuBar);
this.gamePanel = new GamePanel(this);
this.side = new SidePanel(this);
this.add(gamePanel, BorderLayout.CENTER);
this.add(side, BorderLayout.EAST);
Tuple position = new Tuple(10, 10);
sController = new SnakeController(position, side, gamePanel);
this.addKeyListener((KeyListener) new Listener());
// this.requestFocus();
pack();
}
public static void main(String args[]) {
View window = new View();
window.setTitle("og-snake");
window.setSize(700, 400);
window.setVisible(true);
window.setResizable(false);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == newGameButton) {
System.out.println("clicked");
gamePanel.removeAll();
gamePanel.revalidate();
gamePanel.repaint();
Tuple position = new Tuple(10, 10);
sController = new SnakeController(position, side, gamePanel);
sController.start();
}
}
This is my main class that basically makes a view adds a side panel and board panel.The action performed is done on the new game action on the game panel.
public class GamePanel extends JPanel {
public static ArrayList<ArrayList<ColorCell>> snakeGrid;
public static int viewWidth = 20;
public static int viewHeight = 20;
ArrayList<ColorCell> data;
SnakeController sc ;
private View game;
public GamePanel(View game) {
this.game = game;
this.snakeGrid = new ArrayList<ArrayList<ColorCell>>();
this.data = new ArrayList<ColorCell>();
for (int i = 0; i < viewWidth; i++) {
data = new ArrayList<ColorCell>();
for (int j = 0; j < viewHeight; j++) {
ColorCell c = new ColorCell(2);
data.add(c);
}
snakeGrid.add(data);
}
setLayout(new GridLayout(viewWidth, viewHeight, 0, 0));
setPreferredSize(new Dimension(400,400));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < viewWidth; i++) {
for (int j = 0; j < viewHeight; j++) {
add(snakeGrid.get(i).get(j).viewCell);
}
}
}
}
gamePanel.removeAll();
gamePanel.fillGrid();
gamePanel.revalidate();
gamePanel.repaint();
Tuple position = new Tuple(10, 10);
this.gamePanel = new GamePanel(this);
this.add(gamePanel,BorderLayout.CENTER);
That code doesn't really do anything. When you add a component to the CENTER of the BorderLayout it does not replace the original component.
The way Swing painting works is that the last component added is painted first. So this means the newly added panel is painted and then the original panel is painted over top of the newly added panel.
So, since you have logic to remove all the components from the original gamePanel, there is no need to create a new gamePanel. Just reset the state of the game panel.

Edit and update a running instance variable in a separate class

I am making a Simon Says style game, there are four colored squares and the computer does a sequence, then you copy that, etc. and am at a point where I want to add some more advanced features. The current feature I am looking at is looking to change the color panels actual colors at the users will and being able to change them individually from one another.
How can I get the 'color panel(s)' to change to a new color via JColorChooser while keeping everything else set up?
At the moment I have it split up into a few different classes and am having issues getting them all to communicate and just work properly.
Main class(Only a snippet):
public class Simonish implements ActionListener, MouseListener {
private ColorPanel colorPanel[] = new ColorPanel[4];
private ScorePanel scorePanel = new ScorePanel();
private Menu menuBar = new Menu();
private JPanel gameBoard = new JPanel();
private Random rand = new Random();
private ArrayList<ColorPanel> compSeq = new ArrayList<ColorPanel>();
private Iterator<ColorPanel> iter;
private JFrame frame = new JFrame();
private boolean playerTurn = false;
private int speed = 500;
public Simonish(Color[] colors){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel pane = (JPanel)frame.getContentPane();
pane.setLayout(new BorderLayout());
gameBoard.setLayout(new GridLayout(2,2));
gameBoard.setPreferredSize(new Dimension(400,400));
for (int i=0;i<colorPanel.length;i++){
colorPanel[i] = new ColorPanel(colors[i]);
colorPanel[i].addMouseListener(this);
gameBoard.add(colorPanel[i]);
}
scorePanel.addStartListener(this);
frame.setJMenuBar(menuBar);
pane.add(scorePanel, BorderLayout.NORTH);
pane.add(gameBoard, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
My Menu code (builds the menubar and implements the actions):
public class Menu extends JMenuBar {
private JMenuBar menuBar = new JMenuBar();
private JMenu settings = new JMenu("Settings");
private JMenu stats = new JMenu("Stats");
private JMenu help = new JMenu("Help");
private JMenuItem chooseColor = new JMenuItem(new ChooseColorAction("Choose Color"));
private JMenuItem colorMode = new JMenuItem(new ColorModeAction("Color Mode"));
private JMenuItem hScore = new JMenuItem("High Scores");
private JMenuItem history = new JMenuItem("History");
private JMenuItem about = new JMenuItem("About");
private JMenuItem rules = new JMenuItem("Rules");
public Menu(){
this.add(settings);
this.add(stats);
this.add(help);
settings.add(chooseColor);
settings.add(colorMode);
stats.add(hScore);
stats.add(history);
help.add(about);
help.add(rules);
}
}
Action class to house the color changing code:
public class ColorModeAction extends AbstractAction {
public ColorModeAction(String name){
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
Color[] colors = {Color.CYAN, Color.BLACK, Color.WHITE, Color.GREEN};
//new Simonish(colors);
//JOptionPane.showMessageDialog(null, "Color Mode");
}
}
Use interfaces to communicate your classes. For example; ColorModeAction needs to change colors so it should take an interface as parameter which able to change colors:
public interface ColorChanger {
public void changeColor(int index, Color newColor);
}
Make Simonish implement that interface:
public class Simonish implements ActionListener, MouseListener, ColorChanger {
public void changeColor(int index, Color new Color) {
//Change the given panel's color
}
}
Pass Simonish as parameter to the menu, and move new ColorModeAction("Color Mode") to the constructor. Then pass ColorChanger to the ColorModeAction as a parameter.
public class Menu extends JMenuBar {
...
private JMenuItem colorMode;
...
public class Menu(ColorChanger colorChanger) {
colorMode = new JMenuItem(new ColorModeAction(colorChanger, "Color Mode"));
}
}
And the new ColorModeAction:
public class ColorModeAction extends AbstractAction {
private ColorChanger colorChanger;
public ColorModeAction(ColorChanger colorChanger, String name) {
super(name);
this.colorChanger = colorChanger;
}
#Override
public void actionPerformed(ActionEvent e) {
Color[] colors = { Color.CYAN, Color.BLACK, Color.WHITE, Color.GREEN };
colorChanger.changeColor(index, Color)
}
}
It is not fully working code but I think you got the idea.

JPanel appears as a small white box

I am in the early stages of trying to create a Java 2d graphics paint program. I'm using a flow layout, and I'm using three panels. The first two are rows of buttons, combo boxes, etc. and the third is meant to be a large, blank, white panel that will be used to paint on. The first two panels show up beautifully, but the paint panel appears as a small white box next to the second button panel. Any help would be appreciated.
public class DrawingApp extends JFrame
{
private final topButtonPanel topPanel = new topButtonPanel();
private final bottomButtonPanel bottomPanel = new bottomButtonPanel();
private final PaintPanel paintPanel = new PaintPanel();
public DrawingApp()
{
super("Java 2D Drawings");
setLayout(new FlowLayout());
add(topPanel);
add(bottomPanel);
add(paintPanel);
}
public static void main(String[] args)
{
DrawingApp frame = new DrawingApp();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(750,500);
frame.setVisible(true);
}
}
public class topButtonPanel extends JPanel
{
private final String[] names = {"Line", "Oval", "Rectangle"};
private final JButton undo = new JButton("Undo");
private final JButton clear = new JButton("Clear");
private final JLabel shape = new JLabel("Shape:");
private final JComboBox<String> shapesComboBox = new JComboBox(names);
private final JCheckBox filled = new JCheckBox("Filled");
public topButtonPanel()
{
super();
setLayout(new FlowLayout());
add(undo);
add(clear);
add(shape);
shapesComboBox.setMaximumRowCount(3);
add(shapesComboBox);
add(filled);
}
}
public class bottomButtonPanel extends JPanel
{
private final JCheckBox useGradient = new JCheckBox("Use Gradient");
private final JButton firstColor = new JButton("1st Color");
private final JButton secondColor = new JButton("2nd Color");
private final JLabel lineWidthLabel = new JLabel("Line Width:");
private final JLabel dashLengthLabel = new JLabel("Dash Length:");
private final JTextField lineWidthField = new JTextField(2);
private final JTextField dashLengthField = new JTextField(2);
private final JCheckBox filled = new JCheckBox("Dashed");
public bottomButtonPanel()
{
super();
setLayout(new FlowLayout());
add(useGradient);
add(firstColor);
add(secondColor);
add(lineWidthLabel);
add(lineWidthField);
add(dashLengthLabel);
add(dashLengthField);
add(filled);
}
}
public class PaintPanel extends JPanel
{
public PaintPanel()
{
super();
setBackground(Color.WHITE);
setSize(700,400);
}
}
Basically, it's a misunderstanding of how the Swing API works.
Swing relies (heavily) on the layout management API which is used to make decisions about how large components should be (and where they should be placed)
Using setSize is pointless, as the layout manager will make it's own decisions about what it thinks the size of your component should be and will adjust it accordingly.
You can make suggestions to the layout manager about how large you'd like the component to be using getPreferred/Minimum/MaximumSize, for example
public class PaintPanel extends JPanel
{
public PaintPanel()
{
super();
setBackground(Color.WHITE);
}
public Dimension getPreferredSize() {
return new Dimension(700, 400);
}
}
Just remember, layout managers are well within their right to ignore these values, so you need to have a better understanding of how these managers work
See Laying Out Components Within a Container for more details

Java - Dynamic GridLayout

I am trying to create a dynamic GridLayout using the following code:
package resizablegui;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
class GUIHandler extends JFrame {
JSpinner widthSpinner;
JSpinner heightSpinner;
JPanel board;
private JPanel resizer() {
final JPanel resizer = new JPanel(new GridLayout(2,2));
final JPanel resizer_wrapper = new JPanel();
JLabel widthLabel;
JLabel heightLabel;
SpinnerModel widthModel;
SpinnerModel heightModel;
resizer_wrapper.setLayout(new BoxLayout(resizer_wrapper, BoxLayout.X_AXIS));
widthModel = new SpinnerNumberModel(8, 4, 32, 1);
heightModel = new SpinnerNumberModel(8, 4, 32, 1);
ResizeWindow onResize = new ResizeWindow();
widthLabel = new JLabel("Width: ");
resizer.add(widthLabel);
widthSpinner = new JSpinner(widthModel);
resizer.add(widthSpinner);
widthSpinner.addChangeListener(onResize);
heightLabel = new JLabel("Height: ");
resizer.add(heightLabel);
heightSpinner = new JSpinner(heightModel);
resizer.add(heightSpinner);
heightSpinner.addChangeListener(onResize);
resizer.setMaximumSize(new Dimension(100,100));
resizer_wrapper.add(resizer);
return resizer_wrapper;
}
private JPanel board(int width, int height) {
final JPanel board = new JPanel(new GridLayout(width, height));
for(int x = 0; x < width; x++) {
for(int y = 0; y < width; y++) {
JButton button = new JButton(x+", "+y);
board.add(button);
}
}
return board;
}
public GUIHandler() {
super("Board");
setLayout(new BorderLayout());
board = board(8,8);
add(resizer(), BorderLayout.NORTH);
add(board, BorderLayout.CENTER);
}
private class ResizeWindow implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
int width = (Integer)widthSpinner.getValue() * 45;
int height = (Integer)heightSpinner.getValue() * 45;
setSize(width,height);
}
}
}
public class ResizableGUI {
public static void main(String[] args) {
GUIHandler gui = new GUIHandler();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(350,350);
gui.setVisible(true);
}
}
The goal, as you can probably tell, is to have an 8x8 grid of buttons, that can be made larger (ex 9x10, 10x10...) or smaller (ex 6x8, 4x4) based on the values of the spinners. The code compiles well, but upon trying to resize the dialog, the program freezes and crashes.
Not sure why your code freezes and crashes, it didn't do that for me.
Anyway, I still see problems with your code.
Since you want a dynamic grid you need the ability to remove/add buttons to the grid as the spinner is used. So, I would create and empty "board" panel and add it to the GUI. Then I would rename your "boar(...)" method to "resetBoard(...)" as this method should be used to just remove/add buttons, not create a new panel.
The next problem is your looping code in this new "resetBoard(...)" method. The outer loop should be for the height and the inner loop for the width, since you will be adding rows of buttons to the grid, one at a time.
So the restructuring of this method might look like:
private void resetBoard(int width, int height) {
board.removeAll();
board.setLayout( new GridLayout(0, width) );
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
JButton button = new JButton(x+", "+y);
board.add(button);
}
}
}
So now you need to create the board and add buttons to it:
//board = board(8,8);
board = new JPanel();
resetBoard(8, 8);
Finally, in the ChangeListener you need to reset the button on the board, not change the size of the frame:
int width = (Integer)widthSpinner.getValue();
int height = (Integer)heightSpinner.getValue();
resetBoard(width,height);
board.revalidate();
//pack(); pack the frame is you wish
Also, when you first create the frame, don't set the size manually let the pack() method do the work for you:
//gui.setSize(350,350);
gui.pack();

Categories