Added panel not showing up in frame (Java) - java

I'm working on making a battleship game board using swing in java. I've added the panel (i.e. the grid or the game board) to the window but it still won't show up. I've pasted the code below. Any help is appreciated. Thanks.
public class board {
private static JFrame window;
private static JPanel[][] grid;
public static void main(String[] args) {
window = new JFrame();
window.setTitle("GAME BOARD");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
grid = new JPanel[10][10];
for (int i =0; i< 10; i++) {
for (int j =0; j< 10; j++) {
grid[i][j] = new JPanel();
grid[i][j].setBackground(Color.white);
grid[i][j].setBorder(BorderFactory.createLineBorder(Color.black));
grid[i][j].setPreferredSize(new Dimension(25,25));
window.add(grid[i][j]);
}
}
window.pack();
window.setVisible(true);
}
}

By default calling JFrame#add() will add to the JFrames contentPane which has a default layout of BorderLayout.
Have a read on A Visual Guide to Layout Managers. You probably want to either use a GridLayout or FlowLayout depending on your needs.
I'd also suggest overriding getPreferredSize and returning the dimensions as opposed to calling setPreferredSize.
You then would do something like this:
// this jpanel will hold the all grid jpanels could also use new FlowLayout()
JPanel container = new JPanel(new GridLayout(10,10));
grid = new JPanel[10][10];
for (int i =0; i< 10; i++) {
for (int j =0; j< 10; j++) {
grid[i][j] = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(25, 25);
}
};
...
container.add(grid[i][j]);
}
}
window.add(container);
window.pack();
window.setVisible(true);
Have a look at this question which is also about creating a layout for a battleship game. I'd suggest using something more lightweight and easier to customize like JLabel to represent each square.
You may also want to read up on The Event Dispatch Thread
Essentially all Swing components should be created on the EDT via SwingUtilities.invokeLater(...):
import javax.swing.SwingUtilities;
public class TestApp {
public TestApp() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(TestApp::new);
}
private void createAndShowGui() {
// create JFrame and other Swing components here
}
}

You need to set your frame size
window.setPreferredSize(new Dimension(800, 800));

Related

Java Swing pack method not working as expected

I am trying to create a GUI using Java Swing, and am having a problem using the pack() method. As you can see, I create and add all of the elements to the frame in the createTitleText() method and the createBoxes() method. Only after those two methods are called do I call the pack() method, yet when I run the program, I get a small GUI with the close and minimize buttons. But if I expand it, it shows me the proper layout.
The only cause for such a problem that I have found online would be that I call pack() before adding all of my elements to the frame, but that is not the case. How can I fix this?
By the way, if it wasn't clear, I am trying to not use the setSize() method on the frame, and make it so that the frame's size fits the contents of the elements added to it.
import javax.swing.*;
import java.awt.*;
public class Frame extends JFrame {
private LetterBox[][] boxes;
public Frame() {
boxes = new LetterBox[6][5];
// frame styling
setTitle("My Frame");
getContentPane().setBackground(new Color(0x121213));
createTitleText();
createBoxes();
// boilerplate frame configuration
setLayout(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
public void createTitleText() {
JLabel label = new JLabel("Test");
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.TOP);
label.setBounds(0, 0, 400, 100);
label.setForeground(Color.WHITE);
label.setFont(new Font("Arial", Font.BOLD, 36));
add(label);
}
public void createBoxes() {
for (int r = 0; r < 6; r++) {
for (int c = 0; c < 5; c++) {
LetterBox box = new LetterBox();
boxes[r][c] = box;
box.setLetter(r + " " + c);
add(box.getBox()); // box.getBox() returns a JLabel
}
}
}
public static void main(String[] args) {
new Frame();
}
}

GridLayout is showing odd behavior

I am trying to create a grid comprised of 100 squares. My code below is extremely buggy and I am not sure why.
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class snake extends JFrame
{
public static void main(String[] args)
{
Border whiteLine = BorderFactory.createLineBorder(Color.white);
//-----------FRAME
JFrame frame = new JFrame();
frame.setSize(1000,1000);
frame.setTitle("Snake");
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.black);
frame.setVisible(true);
frame.setLayout(new GridLayout(10,10));
//-----------FRAME
//-----------PANELS
Dimension panelDimension = new Dimension(20,20);
int counter = 0;
JPanel[][] p = new JPanel[10][10];
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
p[i][j] = new JPanel();
//p[i][j].setPreferredSize(panelDimension);
p[i][j].setBackground(Color.red);
//p[i][j].setLocation(490,490);
p[i][j].setBorder(whiteLine);
p[i][j].setVisible(true);
frame.getContentPane().add(p[i][j]);
counter+=1;
}
}
System.out.println("counter: " + counter);
}
}
When I run the code like this it shows a grid comprised of 2 columns the first column has 7 rows and the second column has 6. Sometimes it even shows other incorrect numbers of columns and rows. I am not sure why it doesn't create a grid of 10 rows 10 columns.
You've got several problems including:
Calling setVisible(true) on the JFrame before adding components, before calling pack() on the top-level window. This can lead to wonky positioned components within our GUI's or even GUI's that remain empty
Not calling pack() on the JFrame after adding components and before setting it visible
Setting the size of the JFrame. Let the layout managers, containers and components do this for you (which is what calling pack() is for)
Setting it to a bad size, a "perfect square", one that ignores the menu bar that the OS adds,
...
For example:
package foo01;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class SnakePanel extends JPanel {
private static final int CELL_WIDTH = 80;
private static final Dimension CELL_DIMENSION = new Dimension(CELL_WIDTH, CELL_WIDTH);
private static final int COLUMNS = 10;
private static final int GAP = 2;
private static final Color BG_COLOR = Color.WHITE;
private static final Color CELL_COLOR = Color.RED;
public SnakePanel() {
setBackground(BG_COLOR);
// add a white line around the grid
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
// create a grid with gaps that show the background (white) color
setLayout(new GridLayout(COLUMNS, COLUMNS, GAP, GAP));
for (int row = 0; row < COLUMNS; row++) {
for (int col = 0; col < COLUMNS; col++) {
JPanel cell = new JPanel(); // create a new cell
cell.setPreferredSize(CELL_DIMENSION); // cheating here. Better to override getPreferredSize()
cell.setBackground(CELL_COLOR);
add(cell);
// give the cell JPanel some simple behavior:
cell.addMouseListener(new MyMouse(col, row));
}
}
}
private class MyMouse extends MouseAdapter {
private int col;
private int row;
public MyMouse(int col, int row) {
this.col = col;
this.row = row;
}
#Override
public void mousePressed(MouseEvent e) {
System.out.printf("Mouse pressed row and column: [%d, %d]%n", row, col);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// create the main JPanel
SnakePanel snakePanel = new SnakePanel();
// create the JFrame
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add the main JPanel to the JFrame
frame.add(snakePanel);
// pack the JFrame -- tells the layout managers to do their things
frame.pack();
// if we want to center the GUI:
frame.setLocationRelativeTo(null);
// only *now* do we display the GUI
frame.setVisible(true);
});
}
}
Some notes on the code:
Any code within the Runnable passed into the SwingUtilities.invokeLater(...) method is called on the Swing event thread, which is a wise thing to do when creating a Swing GUI
SwingUtilities.invokeLater(() -> {
// ....
});
First, create the main JPanel that is held by the JFrame:
SnakePanel snakePanel = new SnakePanel();
Then create the JFrame, add that JPanel and call pack(). The pack call tells the layout managers to do there thing, to lay out components within containers, to size things based on their preferred sizes and their layouts:
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(snakePanel);
frame.pack();
if we want to center the GUI:
frame.setLocationRelativeTo(null);
only now do we display the GUI
frame.setVisible(true);

How do I keep a JButton from changing size?

I'm trying to make a simple game where you can set out tiles that make up a celtic design and I can't seem to make the buttons stay the same size. Here's the code:
public class CTGContent {
public static JPanel content = new JPanel();
private static JButton board[][] = new JButton[20][20];
static private Random random = new Random();
public static int CTGcolumn = random.nextInt(14)+1;
public static int CTGRow = 15;
private static GridLayout boardLayout;
public final int getBoardWidth(){
return CTGcolumn*40;
}
public final int getBoardHeight(){
return CTGRow*40;
}
public static void initializeBoard(){
int row = 0;
int column = 0;
int defaultCOL = 0;
int defaultROW = 0;
boardLayout = new GridLayout(CTGRow, CTGcolumn);
content.setLayout(boardLayout);
Random determine = new Random();
while (row < CTGRow){
column = 0;
while (column < CTGcolumn){
board[row][column] = new JButton(new ImageIcon("images\\template.gif"));
board[row][column].setPreferredSize(new Dimension(40, 40));
board[row][column].setMaximumSize(new Dimension(40, 40));
board[row][column].setMinimumSize(new Dimension(40, 40));
content.add(board[row][column]);
column++;
}
row++;
}
}
private static void build(){
initializeBoard();
JFrame window = new JFrame("testing the menubar");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setContentPane(content);
content.add(new JLabel("My Label"));
window.pack();
window.setVisible(true);
}
public CTGContent() {
}
public CTGContent(JFrame window){
initializeBoard();
window.add(content);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
build();
}
});
}
}
It starts off the right size usually but then for some reason if I resize the window or something they change size with it. I need them to stay the same size no matter what. How can I do that?
Change:
window.setContentPane(content);
To:
JPanel contentCenter = new JPanel(new GridBagLayout());
contentCenter.add(content);
window.setContentPane(contentCenter);
There are other ways to do it, like make the layout a FlowLayout, but the GBL will keep it nicely centered - both vertically and horizontally.
Tips
Please learn common Java naming conventions (specifically the case used for the names) for class, method & attribute names & use them consistently.
For better help sooner, post an MCVE. That code only needed import in order to make it an MCVE.
See also this answer to Centering a JLabel on a JPanel
You use GridLayout because of your buttons resize horisontally/vertically always to fill whole grid cell. To prevent that you can use another LayoutManager, for example GridBagLayout.
Always read about setting size to components.

JTabbedPane within JScrollPane only showing one item at a time

When I launch my application, it launches the JFrame and loads up the JTabbedPane which contains the JScrollPane, yet it only shows one component inside it at a time. I have tried everything, and still I cannot solve the problem...
Here is my code:
package test;
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame{
public Main()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,500);
JPanel pane=new JPanel();
pane.setLayout(new BorderLayout());
UIManager.put("TabbedPane.contentOpaque", false);
JTabbedPane tabbedPane=new JTabbedPane();
JScrollPane scrollPane=new JScrollPane(pane);
tabbedPane.setPreferredSize(new Dimension(getWidth(),getHeight()));
for(int i = 0; i < 10; i++) pane.add(new JLabel("label22222222222222222222222222222222222222222222222222222222"+i));
//pane.add(scrollPane,BorderLayout.CENTER);
tabbedPane.add("Test",scrollPane);
add(tabbedPane);
}
public static void main(String[] args) {
Main main=new Main();
main.setVisible(true);
}
}
Please help me, I have no idea what I am doing wrong.
Your pane JPanel uses BorderLayout and you're adding components in a default fashion, or BorderLayout.CENTER. This is the expected behavior to show only the last component added.
You should consider using another layout such as GridLayout. Also, Google and read the "laying out components in a container" tutorial and understand the layouts that you're using.
Also, consider using a JList to display your data rather than a grid of JLabels.
As an aside, you should format your code for readability, not compactness. Don't put for loops on one line only. In fact all loops and blocks should go into curly braces to prevent your later editing your code, adding another line and thinking that it's in the loop when it's not.
Edit
For example, using a JList:
import javax.swing.*;
public class Main2 {
private static final int MAX_CELLS = 30;
private static void createAndShowGUI() {
final DefaultListModel<String> listModel = new DefaultListModel<>();
final JList<String> myList = new JList<>(listModel);
myList.setVisibleRowCount(8);
for (int i = 0; i < MAX_CELLS; i++) {
listModel.addElement("label22222222222222222222222222222222222222222222222222222222" + i);
}
JTabbedPane jTabbedPane = new JTabbedPane();
jTabbedPane.add("Test", new JScrollPane(myList));
JFrame frame = new JFrame("Main2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(jTabbedPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

draw control inside another using its graphics

I'm basically trying to draw a JComponent inside another by calling the second component's paint passing it the first component's Graphics.
I'm trying to create a GUI editor, (reinventing the wheel, I know, it's just a proof of concept)
So I have a class that extends JPanel where I want to draw components from a VectorControls.
So far I got this method in my extended JPanel:
#SuppressWarnings("serial")
public class Sketch extends JPanel {
private Vector<JComponent> controls = new Vector<JComponent>();
public Sketch() {
super();
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
}
public void addControl(JComponent c) {
Dimension d = new Dimension(100,50);
c.setPreferredSize(d);
c.setMinimumSize(d);
c.setMaximumSize(d);
controls.add(c);
this.repaint();
this.revalidate();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int i=controls.size()-1; i>=0; i--) {
JComponent c = controls.get(i);
c.paint(g);
}
}
}
I'm building/attaching the Sketch panel like this:
public GUIEditor() {
mainFrame = new JFrame("GUI EDITOR");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Sketch mainPanel = new Sketch();
mainPanel.setPreferredSize(new Dimension(640,480));
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
mainFrame.setLayout(gbl);
JPanel toolsPanel = new JPanel();
toolsPanel.setPreferredSize(new Dimension(160,480));
toolsPanel.setLayout(new GridLayout(0,1));
for(Control c : toolBoxItems ) {
AbstractAction action = new ToolBoxButtonAction(mainPanel, c.type);
JButton b = new JButton(action);
b.setText(c.title);
toolsPanel.add(b);
}
gbc.gridx = 0;
gbc.gridy = 0;
gbl.setConstraints(mainPanel, gbc);
mainFrame.add(mainPanel);
gbc.gridx = 1;
gbc.gridy = 0;
gbl.setConstraints(toolsPanel, gbc);
mainFrame.add(toolsPanel);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
Inside ToolBoxButtonAction, basically I'm doing this:
public void actionPerformed(ActionEvent e) {
try {
sketch.addControl(control.newInstance());
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
}
but I'm writing this because it doesn't work.
Any ideas on how to achieve this?
I'm basically trying to draw a JComponent inside another by calling the second component's paint passing it the first component's Graphics.
Components can only be painted when the component has non-zero size. Normally the size of a component is determined by the layout manager.
Your basic code looks reasonable, but unless you have code to size and locate the components you won't see anything. If you just set the size then all components will paint on top of one another.
Or the problem may be that your parent panel doesn't have a size so it is not even painted. The default FlowLayout uses the preferred size of the child components to determine the panels size. Since you don't add components directly to the panel there are no child components so the preferred size will be 0. When you reinvent the wheel you need to reinvent everything.
Without a SSCCE the context of how you use this code is unknown to all we can do is guess.
Edit:
Create a SSCCE when you have a problem and get it working with hard coded values before trying to get it to work dynamically. Something like:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class Sketch extends JComponent
{
private Vector<JComponent> controls = new Vector<JComponent>();
public void addControl(JComponent c)
{
c.setSize(100, 50);
int location = controls.size() * 50;
c.setLocation(location, location);
controls.add(c);
repaint();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=controls.size()-1; i>=0; i--)
{
JComponent c = controls.get(i);
Point location = c.getLocation();
g.translate(location.x, location.y);
c.paint(g);
g.translate(-location.x, -location.y);
}
}
private static void createAndShowUI()
{
Sketch sketch = new Sketch();
sketch.addControl( new JButton("button") );
sketch.addControl( new JTextField(10) );
sketch.addControl( new JCheckBox("Checkbox") );
JFrame frame = new JFrame("Sketch");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( sketch );
frame.setSize(400, 400);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Some time ago, I've written a framework for such tasks. Maybe you find it useful (the library is Open Source):
Tutorial:
http://softsmithy.sourceforge.net/lib/current/docs/tutorial/swing/customizer/index.html
Javadoc:
http://softsmithy.sourceforge.net/lib/current/docs/api/softsmithy-lib-swing-customizer/index.html
Info about the latest release:
http://puces-blog.blogspot.ch/2012/11/news-from-software-smithy-version-03.html

Categories

Resources