amount of generated JLabels seems random on each start - java

I am trying generate a JLabel grid in Java, but on every start the generated JLabels vary, on one start of the program there can be 25 visual JLabels, and without changing the code and restarting there can be 27 visual JLabels, im so confused, I have no idea what might be causing this. In theory there should be 169 JLabels visual on the screen (13 x 13 grid).
public class GUI {
JFrame frame;
JPanel panel;
int matrixLength = 13;
JLabel label[] = new JLabel[matrixLength * matrixLength];
public GUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
frame.setResizable(false);
panel = (JPanel) frame.getContentPane();
panel.setLayout(null);
for (JLabel labels : label) {
labels = new JLabel();
labels.setVisible(true);
}
}
public void drawLabels() {
int xInc = 50;
int yInc = 50;
int xStart = 50;
int yStart = 0;
int y = yStart;
int x = 50;
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel(" ");
label[i].setOpaque(true);
label[i].setVisible(true);
label[i].setBackground(Color.black);
if (i % (matrixLength) == 0) {
y += yInc;
x = xStart;
} else {
x += xInc;
}
System.out.println("i: " + i + " | y: " + y + " | x: " + x);
label[i].setBounds(x, y, 40, 40);
panel.add(label[i]);
}
}
}

I created the following GUI from your code.
Here are the changes I made.
I added a main method so I could start the application. In the main method, I called the SwingUtilities invokeLater method to ensure that the Swing components are created and executed on the Event Dispatch Thread.
I used two Swing layout managers to create the GUI. The JFrame has a default BorderLayout. The JPanel I created to hold the JLabels uses a GridLayout.
I added a text value to each of the JLabels so you could see them in the grid.
Here's the complete runnable code I used to create the GUI.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class LabelGridGUI {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LabelGridGUI();
}
});
}
JFrame frame;
int matrixLength = 13;
JLabel label[] = new JLabel[matrixLength * matrixLength];
public LabelGridGUI() {
frame = new JFrame("Label Grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createLabelPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setResizable(false);
frame.setVisible(true);
}
public JPanel createLabelPanel() {
JPanel panel = new JPanel(new GridLayout(0, matrixLength));
for (int i = 0; i < label.length; i++) {
label[i] = new JLabel("X");
label[i].setBackground(Color.black);
label[i].setForeground(Color.yellow);
label[i].setOpaque(true);
panel.add(label[i]);
}
return panel;
}
}

Related

JButtons only appear when mouse hover over them

I have a problem (could be more than one..) with my project.
JButton components only show up when I hover the mouse over them.
My project, basically, is taking data from MySQL and setting it on buttons.
For example:
'Aaa', 1000, 'alphabet' on jbutton[0]
'Bbb', 50, 'alphabet2' on jbutton[1]
and so on...
Buttons are on JPanel which is in a JScrollPane. (I did this on purpose as data can not be fit in one panel without scroll and when I click the the button, a new window relating to the info on the clicked button have to pop up)
And I added an ActionListener on another button set which are 'category' buttons(chicken, pizza) to put data on the buttons I mentioned above. When the category button is clicked, data according to the category is extracted and set on buttons one by one.
I searched many times to solve the problem, but I couldn't find the answer. Just assuming, it happened because I used setLayout(null) all over, or because buttons are added after the main frame is set visible.
It's good to solve the problem but I, more importantly, want to know the reason why.
Please help me to find the cause of this problem so that I don't make the same error next time and avoid bad practices!
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class JbuttonNotShowUp extends JFrame implements ActionListener {
JButton chicken, pizza;
JButton[] jbtnArray;
JPanel jp, jpFullofButtons;
JScrollPane jsp;
public JbuttonNotShowUp() {
jp = new JPanel();
jp.setLayout(null);
jpFullofButtons = new JPanel();
jpFullofButtons.setLayout(null);
jsp = new JScrollPane(jpFullofButtons, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
chicken = new JButton("chicken");
pizza = new JButton("pizza");
jp.setBounds(0, 0, 440, 650);
chicken.setBounds(25, 80, 61, 35);
pizza.setBounds(90, 80, 61, 35);
jsp.setBounds(25, 140, 385, 450);
chicken.addActionListener(this);
pizza.addActionListener(this);
jp.add(jsp);
jp.add(chicken);
jp.add(pizza);
add(jp);
setBounds(0, 0, 450, 650);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
JbuttonNotShowUp f = new JbuttonNotShowUp();
}
#Override
public void actionPerformed(ActionEvent e) {
JButton jbutton = (JButton) e.getSource();
jpFullofButtons.removeAll();
DataDAO dao = new DataDAO();
ArrayList<DataVO> list = dao.dataExtract(jbutton.getText());
jbtnArray = new JButton[list.size()];
int y = 0;
for (int i = 0; i < list.size(); i++) {
jbtnArray[i] = new JButton(
list.get(i).getName() + "," + list.get(i).getPrice() + "," + list.get(i).getDescription());
jbtnArray[i].setSize(390, 50);
jbtnArray[i].setLocation(0, y);
jbtnArray[i].addActionListener(this);
jpFullofButtons.add(jbtnArray[i]);
y += 50;
}
}
}
Problems:
You're using a null layout-using JPanel to hold JButtons in a JScrollPane which will make the scroll pane fail in its ability to show scroll bars and scroll effectively
You add components into a container (the same JPanel above) without telling the GUI to repaint the container, and so the components, the added JButtons, don't display. This latter is fixed by calling jpFullofButtons.repaint(); after adding components to the JPanel -- but the JScrollPane still won't work right
Better to use a decent layout manager, here perhaps a GridLayout, and call revalidate() and repaint() on the container, the jpFullofButtons JPanel, after adding components to it.
Side note about your MRE attempt: it's almost there, but you still left in the DAO requirement as well as an undefined class, DataVO, preventing us from coping, pasting, and running your code.
My MRE example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.*;
#SuppressWarnings("serial")
public class JButtonsShowUp extends JPanel {
private JButton reAddButtonsBtn = new JButton("Re-Add Buttons");
private JPanel jpFullofButtons = new JPanel(new GridLayout(0, 1));
private JScrollPane jsp = new JScrollPane(jpFullofButtons);
public JButtonsShowUp() {
reAddButtonsBtn.addActionListener(e -> reAddButtons());
JPanel topPanel = new JPanel();
topPanel.add(reAddButtonsBtn);
jsp.setPreferredSize(new Dimension(385, 450));
int gap = 20;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(jsp, BorderLayout.CENTER);
}
private void reAddButtons() {
jpFullofButtons.removeAll();
int max = 100;
for (int i = 0; i < max; i++) {
String randomText = "";
for (int j = 0; j < 5; j++) {
char c = (char) ('a' + (int) (26 * Math.random()));
randomText += c;
}
double randomPrice = 10 + 20 * Math.random();
final DataVO2 data = new DataVO2(randomText, randomPrice);
String text = String.format("Text: %s%02d, Price: $%1.2f", randomText, i, randomPrice);
JButton button = new JButton(text);
button.addActionListener(e -> buttonAction(data));
jpFullofButtons.add(button);
}
jpFullofButtons.revalidate();
jpFullofButtons.repaint();
}
private void buttonAction(DataVO2 data) {
System.out.println("Button pressed: " + data);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JButtonsShowUp mainPanel = new JButtonsShowUp();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class DataVO2 {
private NumberFormat priceFormat = NumberFormat.getCurrencyInstance(Locale.US);
private String name;
private double price;
public DataVO2(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
#Override
public String toString() {
String priceText = priceFormat.format(price);
return "DataVO2 [name=" + name + ", price=" + priceText + "]";
}
}

Java, jframe resizing while dragging issue

I would like my jframe to change its size and contents depending on the x coordinate.
Initially the jframe appears in the 'primary zone' (x <= 1400) witn a panel sized 500x500 added to the jframe's content pane.
Desired: When it is dragged and leaves the 'primary zone' and enters the 'secondary zone' everything is removed from the content pane, the panel gets wrapped into a jscrollpane sized 200x200, and the jscrollpane is added the content pane. When the jframe leaves the 'secondary zone' the jscrollpane is removed from the content pane and the panel is added back.
Actual: Results are not stable. When the jframe leaves the primary zone I can see some flipping. Scrollbars appear but and the frame changes its size but then immediately resized back to the previous size. Stopping at breakpoints inside runnables in the changeSizeAndContent invokeLater codeblocks (not a good practice actually) brings the desired result and so does a conditional breakpoint.
There is some Swing multithreading taking place which I do not understand. I can see the EDT calling EventQueue's dispatchEvent and the COMPONENT_RESIZED (new, correct size) events triggered by runnables in the changeSizeAndContent are followed by COMPONENT_MOVED (old, now incorrect size) events which reference the component with its old size.
Tried with Java 8 and 11.
package Jna;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
/* 0------------------1200-1400--------->
* +---------------+
* | SECONDARY |
* +--------------------+---+ |
* | PRIMARY | B | x: 1200- |
* | x: 0-1400 | U | |
* | | F | |
* | | F | |
* | | E | |
* | | R | |
* | +---+-----------+
* | |
* +------------------------+
*/
public class FrameDemo3 {
static final JPanel panel;
static final JScrollPane jsp;
static {
panel = getInitializedPanel();
jsp = getInitilalizedJScrollPane();
}
static boolean isPrimaryZone = true;
static boolean isCurrentPrimaryZone = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("FrameDemo");
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
int x = frame.getX();
if (x > 1400) {
isCurrentPrimaryZone = false;
} else if (x < 1200) {
isCurrentPrimaryZone = true;
}
if (isPrimaryZone != isCurrentPrimaryZone) {
isPrimaryZone = isCurrentPrimaryZone;
changeSizeAndContent(frame);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
public static void changeSizeAndContent(JFrame frame) {
if (isPrimaryZone) {
SwingUtilities.invokeLater(() -> {
frame.getContentPane().removeAll();
frame.getContentPane().add(panel);
frame.pack();
});
} else {
SwingUtilities.invokeLater(() -> {
frame.getContentPane().removeAll();
frame.getContentPane().add(jsp);
frame.pack();
});
}
}
private static JPanel getInitializedPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.WHITE);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
panel.add(new JLabel(getLabelText(i, j)), getConstraints(i, j));
}
}
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private static JScrollPane getInitilalizedJScrollPane() {
JScrollPane jsp = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
jsp.setPreferredSize(new Dimension(200, 200));
return jsp;
}
static GridBagConstraints getConstraints(int gridX, int gridY) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = gridX;
gbc.gridx = gridY;
gbc.ipady = 40;
gbc.ipadx = 40;
return gbc;
}
static String getLabelText(int gridX, int gridY) {
StringBuilder sb = new StringBuilder("EXAMPLE ")
.append(gridX)
.append(',')
.append(gridY);
return sb.toString();
}
}
As mentioned in the comments, a component can only have a single parent, so an easier solution might be to add the component to the scroll pane and change the scrollbar policy as required. The code below demonstrates this.
There is some Swing multithreading taking place which I do not understand?
The issues appears to be the title bar of the frame.
(Note I changed the resizing behaviour to work at 1000/800 instead of 1400, 1200)
When the frame is moved to location 1001 your logic is invoked and the frame is resized as expected.
However, the issue is that additional events on the frame will always be generated.
For example if you move the frame to 1001 and hold the mouse down the frame will remain at the correct size. However as soon as you release the mouse it goes back to the previous size.
Or if you move the frame to location 1002 or greater it goes back to the previous size.
In both of the above cases code in your application is not executed to change the frame size.
I have no idea how to fix this as this logic is controlled by the OS frame widget. This may explain why it works for user153... I use Windows 10 and I see the problems you describe.
In the code below I added a Swing Timer to reset the frame size to the expected size after a delay of 2 seconds. It is not a practical solution, but it does demonstrate that your code is working as expected, you just can't control the external behaviour of the frame.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class FrameDemo4 {
static final JPanel panel;
static final JScrollPane jsp;
static Dimension preferredSize;
static {
panel = getInitializedPanel();
jsp = getInitilalizedJScrollPane();
}
static boolean isPrimaryZone = true;
static boolean isCurrentPrimaryZone = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("FrameDemo");
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
int x = frame.getX();
System.out.println(x);
if (x > 1000) {
isCurrentPrimaryZone = false;
} else if (x < 800) {
isCurrentPrimaryZone = true;
}
if (isPrimaryZone != isCurrentPrimaryZone) {
isPrimaryZone = isCurrentPrimaryZone;
changeSizeAndContent(frame);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.getContentPane().add(panel);
frame.getContentPane().add(jsp);
frame.pack();
frame.setLocation(1000, 0);
frame.setVisible(true);
}
public static void changeSizeAndContent(JFrame frame) {
System.out.println(isPrimaryZone);
if (isPrimaryZone) {
//frame.getContentPane().removeAll();
//frame.getContentPane().add(panel);
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
jsp.setPreferredSize( panel.getPreferredSize() );
frame.pack();
preferredSize = frame.getPreferredSize();
} else {
//frame.getContentPane().removeAll();
//frame.getContentPane().add(jsp);
jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
jsp.setPreferredSize( new Dimension(200, 200));
frame.pack();
preferredSize = frame.getPreferredSize();
}
Timer timer = new Timer(2000, (e) -> frame.setSize( preferredSize.width, preferredSize.height ) );
timer.start();
}
private static JPanel getInitializedPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.WHITE);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
panel.add(new JLabel(getLabelText(i, j)), getConstraints(i, j));
}
}
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private static JScrollPane getInitilalizedJScrollPane() {
// JScrollPane jsp = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
// jsp.setPreferredSize(new Dimension(200, 200));
JScrollPane jsp = new JScrollPane(panel);
jsp.setPreferredSize(panel.getPreferredSize());
return jsp;
}
static GridBagConstraints getConstraints(int gridX, int gridY) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = gridX;
gbc.gridx = gridY;
gbc.ipady = 40;
gbc.ipadx = 40;
return gbc;
}
static String getLabelText(int gridX, int gridY) {
StringBuilder sb = new StringBuilder("EXAMPLE ")
.append(gridX)
.append(',')
.append(gridY);
return sb.toString();
}
}
The only solution I can think of is to:
Maybe use the Metal LAF. It uses an undecorated frame with a custom title bar
Create your own title bar to use on an undecorated frame.

In a 2D array of JButtons, how to change lines?

I am trying to create a 2D array of buttons but the buttons I created are all in the same line. I can change lines in 2D arrays of int and float by using System.out.println(). What should I so for buttons? (line 67 to 75)
As well, I don't know how to create actionListeners for buttons in a loop. Should I create a method for acctionLisener? Do they share the same action listener?
import java.awt.*;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JInternalFrame;
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
frame.getContentPane().add(panelone, BorderLayout.CENTER);
panelone.setBackground(Color.WHITE);
GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};
panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}
Rather than modify your code, I have provided an example of GridLayout.
GridLayout divides the area of the JPanel into a grid, i.e. a table of rows and columns, where each "cell" in the grid can contain one component and each cell has the same size. Here is a complete, compilable and runnable example.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class Hanoi implements Runnable {
#Override // java.lang.Runnable
public void run() {
showGui();
}
private JPanel createGridPanel() {
// Number of rows will be calculated depending on total number
// of components added but each row will contain no more than
// three components.
GridLayout gridLayout = new GridLayout(0, 3);
JPanel gridPanel = new JPanel(gridLayout);
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
int number = (row + 3) + (col * 3);
String text = String.valueOf(number);
JButton button = new JButton(text);
gridPanel.add(button);
}
}
return gridPanel;
}
private void showGui() {
JFrame frame = new JFrame("Hanoi");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createGridPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Hanoi instance = new Hanoi();
EventQueue.invokeLater(instance);
}
}
And here is a screen capture of the running application.
(Note that I am using JDK 12 on Windows 10.)
You can use a grid layout, i change your original code (as you can see below). I recommend to use some designer for the gui, it more easy and clean. Net beans have a nice grafic interface builder.
public class Hanoi {
private JFrame frame;
JButton[][] buttons= new JButton[3][3];
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Hanoi window = new Hanoi();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Hanoi() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 901, 696);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panelone = new JPanel();
panelone.setLayout(new GridLayout(3,3));
frame.getContentPane().add(panelone);
panelone.setBackground(Color.WHITE);
/*GridBagLayout gbl_panelone = new GridBagLayout();
gbl_panelone.columnWidths = new int[]{0};
gbl_panelone.rowHeights = new int[]{0};
gbl_panelone.columnWeights = new double[]{Double.MIN_VALUE};
gbl_panelone.rowWeights = new double[]{Double.MIN_VALUE};*/
// panelone.setLayout(gbl_panelone);
JPanel paneltwo = new JPanel();
frame.getContentPane().add(paneltwo, BorderLayout.NORTH);
paneltwo.setBackground(Color.WHITE);
JLabel lblFunHanoiTower = new JLabel("Fun Hanoi Tower");
lblFunHanoiTower.setForeground(Color.BLACK);
lblFunHanoiTower.setBackground(SystemColor.activeCaption);
lblFunHanoiTower.setFont(new Font("Viner Hand ITC", Font.PLAIN, 36));
paneltwo.add(lblFunHanoiTower);
//JButton[][] buttons = new JButton[3][3];
for(int row = 0; row < buttons.length ; row++) {
for(int col= 0; col < buttons[0].length ;col++) {
buttons[row][col] = new JButton(String.valueOf((row+3)+(col*3)));
buttons[row][col].setFont(new Font("Tempus Sans ITC", Font.BOLD, 16));
buttons[row][col].setBackground(SystemColor.controlHighlight);
buttons[row][col].setSize(66, 66);
panelone.add(buttons[row][col]);
}
}
}
}

How to put 1 JPanel and 1 Custom JPanel in a JFrame

I want to have 2 JPanels in my app, side by side. One that will have some info about my custom board on the right and one about painting that custom board on the left. The first JPanel is a classic, but the second is a custom panel. It seems that im having problems with putting my custom panel into the frame.
I've created a class named BoardPanel within my gui class to draw my custom board. I don't know if this is the best approach. Should i create a separate class instead?
This is the code of the gui class:
public class BattleshipGUI extends JFrame {
private BoardPanel mainPanel;
///////////////////////////////////////////////////////////////////////////////////////////////
// Create my frame
///////////////////////////////////////////////////////////////////////////////////////////////
public BattleshipGUI() {
JPanel container = new JPanel(new BorderLayout()); //the container panel that contains the 2 other panels
mainPanel = new BoardPanel(); //main panel with my custom painting
JPanel detailsPanel = new JPanel(new BorderLayout()); //secondary panel with various details about the game
container.add(mainPanel, BorderLayout.CENTER); //add the 2 panels in the container
container.add(detailsPanel, BorderLayout.EAST);
this.add(container); //add container to my frame
//this.setContentPane(container);
this.setIconImage(Toolkit.getDefaultToolkit().getImage(BattleshipGUI.class.getResource("/resources/battleship_128.png")));
this.setTitle("My Battleship Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setBounds(100, 100, 850, 700);
//this.pack();
this.setSize(850, 600);
this.setVisible(true);
}
And this is the code of the inner class for the custom painting
class BoardPanel extends JPanel {
private static final int ROWS = 20;
private static final int COLUMNS = 20;
public void paintComponent(Graphics g) {
super.paintComponent(g);
int sqSize = this.getHeight()/ROWS;
for(int i=0; i<ROWS; i++) {
for(int j=0; j<COLUMNS; j++) {
int x = j * sqSize;
int y = i * sqSize;
g.drawRect(x, y, sqSize, sqSize);
}
}
}
}
Aside from all these, i have a question. If i want to have a custom painting, is it possible to work along side with the WindowsBuilderPro? I begun using that tool at first. But, i saw that i cant draw something custom with the tool and i had to write code to do that. Is it possible to write code for a custom paint AND use the tool at the same time for different purposes, like adding a simple text label, or even to edit that custon paint? The expected result that i want to see, appears when i run the program. My frame with the two panels. But when i open the WindowsBuilderPro, my custom panel does not appear and the result is a bit wrong. Thit is the reason why i have a question about my approach and if i can write code and use the tool at the same time. Thank you and sorry for the long text guys. I am too confused about this.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = gbc.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
JPanel filler = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 300);
}
};
filler.setBackground(Color.BLUE);
add(filler, gbc);
gbc.gridx++;
add(new BoardPanel(), gbc);
}
}
class BoardPanel extends JPanel {
private static final int ROWS = 20;
private static final int COLUMNS = 20;
private int sqSize = 20;
#Override
public Dimension getPreferredSize() {
return new Dimension(COLUMNS * sqSize, ROWS * sqSize);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLUMNS; j++) {
int x = j * sqSize;
int y = i * sqSize;
g.drawRect(x, y, sqSize, sqSize);
}
}
}
}
}
Take the time to read through Laying Out Components Within a Container to get a better understanding how the layout management API works

Change color of jpanels after their creation

I am trying to make a GUI maze game, where as the computer tries to solve the maze, it changes the colors of the point in the maze it is on. The maze is made up of a JFrame with a JPanel (GridLayout). In the grid is the JPanels that I need to change their colors. I'm not sure how to even access them after I create them.
My code:
public Maze(int length) {
JFrame frame = new JFrame();
JPanel panel = new JPanel(new GridLayout(length, length, 5,5));
panel.setPreferredSize(new Dimension(500, 500));
for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
JPanel p2 = new JPanel();
p2.setBackground(Color.red);
panel.add(p2);
}
}
frame.setDefaultCloseOperation(3);
frame.setTitle("Maze Game");
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
Is there a way to change the color of p2 in a different method? Or is there a better way to do it?
If your have the referee of JFrame then you can do it in this way.
int count = 0;
for (Component comp : frame.getContentPane().getComponents()) {
System.out.println(comp.getBackground());
if (count == 6) {
comp.setBackground(Color.GREEN);
}
count++;
}
Here 6 represent 2nd row and 3rd column as in the same order the JPanel are added in JFrame.
Complete Sample Code [EDITED]
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
public class Maze {
private JFrame frame = null;
public Maze(int length) {
frame = new JFrame();
JPanel panel = new JPanel(new GridLayout(length, length, 5, 5)) {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
};
for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
JPanel p2 = new JPanel();
p2.setBackground(Color.red);
panel.add(p2);
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Maze Game");
frame.setContentPane(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void setPanelColor(int index) {
frame.getContentPane().getComponents()[index].setBackground(Color.GREEN);
}
public static void main(String[] a) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
Maze maze = new Maze(4);
maze.setPanelColor(6);
}
});
}
}
Edits:
EventQueue.invokeLater()
All GUI related things in java should always go through a single thread. The thread is our legendary AWT-EventQueue . Hence all GUI related actions should necessarily go through the AWT Event thread. If not so you may end up in a deadlock.
Read more Should we use EventQueue.invokeLater for any GUI update in a Java desktop application?
UIManager.setLookAndFeel()
UIManager manages the current look and feel, the set of available look and feels.
Read more How to Set the Look and Feel
JComponent#getPreferredSize()
Read more Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

Categories