Java Swing pack method not working as expected - java

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();
}
}

Related

I am writing a program using awt pakage in java but my components are not getting added

I am writing a program using the AWT package in which I also implemented ActionListner which shows the number of clicks I made on the button.
package awtlistenerdemo;
import java.awt.*;
import java.awt.event.*;
public class AwtListenerDemo implements ActionListener {
TextField t1 = new TextField(30);
Button b;
int count = 0;
Frame f;
AwtListenerDemo() {
f = new Frame("Action Listener Example");
b = new Button("Ok");
f.setLayout(null);
b.setBounds(100, 100, 60, 20);
t1.setBounds(100, 200, 80, 30);
f.add(b);
f.add(t1);
b.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b) {
count++;
t1.setText("Button Clicked" + count + "Times");
}
}
public static void main(String[] args) {
Frame f = new Frame("Action Listener Example");
f.setVisible(true);
f.setSize(300, 300);
}
}
The main method never constructs an AwtListenerDemo so all you see is the standard, blank frame created in that method. Once that problem is fixed, some of the statements in the main method need to be moved into the constructor and applied to the frame it creates.
This is the result:
import java.awt.*;
import java.awt.event.*;
public class AwtListenerDemo implements ActionListener {
TextField t1 = new TextField(30);
Button b;
int count = 0;
Frame f;
AwtListenerDemo() {
f = new Frame("Action Listener Example");
b = new Button("Ok");
f.setLayout(null);
b.setBounds(100, 100, 60, 20);
t1.setBounds(100, 200, 80, 30);
f.add(b);
f.add(t1);
b.addActionListener(this);
// ADD this!
f.setSize(300,300);
// then set it VISIBLE
f.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b) {
count++;
t1.setText("Button Clicked" + count + "Times");
}
}
public static void main(String[] args) {
// Change the main code to..
new AwtListenerDemo();
}
}
General Tips
See this answer for many good reasons to abandon AWT components in favor of Swing. Added to that is that few people in this day & age have ever used AWT (so can't help with problems) or if they did, have forgotten the finer details (so give faulty advice). As mentioned in the linked answer, Swing is built on AWT, but has differences that need to be unlearned when making the transition. Seriously, start with Swing or go directly to Java-FX (an entirely different GUI toolkit which is based on neither Swing nor AWT). Warning: This is the one & only time I will be helping to fix broken AWT code for you. (3)
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space. The (beginnings of these) problems can be seen even in that short example, in that: a) Either the button, the text field, or both are not center aligned. If the frame is resized even slightly, it would be both. b) The size guess for the text field is also wrong - it is not long enough to display the text!
Relevant to (1), there are still some problems with this code. I did the minimum needed to answer the question and will do no more.
TextField t1 = new TextField(30);
Button b;
int count = 0;
Frame f;
AwtListenerDemo() {
b = new Button("Ok");
f = new Frame("Action Listener Example");
f.setSize(300, 300);
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
f.dispose();
}
});
f.setLayout(null);
b.setBounds(100, 100, 60, 20);
t1.setBounds(100, 200, 80, 30);
f.add(b);
f.add(t1);
f.setVisible(true);
b.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b) {
count++;
t1.setText("Button Clicked" + count + "Times");
}
}
public static void main(String[] args) {
new AwtListenerDemo();
}

Added panel not showing up in frame (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));

How can I put textfield and graphics in the same jframe?

I am trying to have a textfield and graphics in the same jframe but it is not working properly. I want to have the textfield in the bottom and the rest of the jframe for the graphics instead when I run it the textfield acts weirdly and covers up the entire area. Does anybody know how I can get it to work how I want it?
package pack;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class gui extends JPanel implements Runnable{
Thread t = new Thread(this);
protected JTextField textField;
private final static String newline = "\n";
public int x;
public int y;
public static void main(String args[])
{
new gui();
new input();
}
public void input()
{
textField = new JTextField(20);
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridwidth = 500;
c.gridheight = 100;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
}
public void actionPerformed(ActionEvent evt) {
String text = textField.getText();
textField.selectAll();
}
public gui()
{
textField = new JTextField(20);
JFrame f = new JFrame("lol");
System.out.println("::");
f.setTitle("Basic window");
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.add(this);
f.setVisible(true);
f.setFocusable(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(textField);
run();
}
public void run()
{
while(true)
{
try
{
t.sleep(10);
}
catch(Exception e){}
System.out.println(":D");
x++;
y++;
repaint();
}
}
public void paint (Graphics g)
{
g.setColor(Color.red);
}
}
Delete this class and start fresh with a new class. The structure of the code is wrong , the class names are wrong, the custom painting is wrong, the use of Threads is wrong, the new input() doesn't do anything, you should not be using Thread.sleep(), you should not override paint(), you should not add a component to the frame after the frame is visible.
Start by reading the section from the Swing tutorial on Custom Painting. There you will find a working example that will show you how to better structure you class when doing custom painting. Use this demo code as the starting point for your program and make changes (one at a time) to this working code.
Then you can change that code and add a JTextField to the frame. You will also need to read the Swing tutorial on Using Layout Managers, to understand how a BorderLayout works. So start with something simple that works and then add extra components. Don't try to do it all at one time.
Things that you are doing in wrong way.
JFrame by default has uses BorderLayout and you are adding two components in the center hence only last components are visible.
You are adding JTextField inside JFrame as well as JPanel. Don't know why?
Use BorderLayout.SOUTH to add the JTextField in the south and don't add it into JPanel as shown below:
public gui() {
...
textField = new JTextField(20);
JFrame f = new JFrame("lol");
f.add(this);
f.add(textField, BorderLayout.SOUTH);
...
}
Please read below post once again.
How to Use GridLayout
How to Use GridBagLayout

Open a new window by button Press

I am trying to open a New Window by pressing the JButton. Now my actionPerformed method for the Jbutton is just closing the window after pressing it. I want it to open a new window as the old window closes. I know, this question is already had been asked, but I tried lot of things, no one seems to work perfectly.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.Random;
public class secondTab extends JFrame
{
static JTabbedPane Pane = new JTabbedPane();
static JPanel Second = new JPanel();
static JPanel second = new JPanel(); // This Panel is inside the Second Panel
static JButton guess1 = new JButton();
static String words[] = new String[9];
static Random getRandomWord = new Random();
static int rr;
static JButton Labels[] = new JButton[10];
public static void main(String args[])
{
//construct frame
new secondTab().show();
}
public secondTab()
{
// code to build the form
setTitle("Shopping Cart");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridBagLayout());
// position tabbed pane
GridBagConstraints gridConstraints = new GridBagConstraints();
gridConstraints.gridx = 1;
gridConstraints.gridy = 1;
Pane.setForeground(Color.YELLOW);
Pane.setBackground(Color.MAGENTA);
getContentPane().add(Pane, gridConstraints);
getContentPane().setLayout(new GridBagLayout());
// Tabs Starts From Here
Second.setLayout(new GridBagLayout());
words[1] = "JAVA";
words[2] = "FLOAT";
words[3] = "VOID";
words[4] = "MAIN";
words[5] = "STATIC";
words[6] = "FINAL";
words[7] = "PRIVATE";
words[8] = "CHAR";
words[9] = "IF";
rr = getRandomWord.nextInt(10);
for(int i = 1; i <=words[rr].length(); i++)
{
Labels[i] = new JButton();
gridConstraints.gridx = 0;
gridConstraints.gridy = 0;
second.add(Labels[i]);
}
gridConstraints.gridx= 0;
gridConstraints.gridx= 0;
Second.add(second, gridConstraints);
guess1.setText("New Word");
gridConstraints.gridx = 0;
gridConstraints.gridy = 2;
Second.add(guess1, gridConstraints);
Here is my button's Action Performed method
// Action Performed method for the JButton guess1
guess1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
Pane.addTab("Game ", Second);
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((int) (0.5 * (screenSize.width - getWidth())), (int) (0.5 *
(screenSize.height - getHeight())), getWidth(), getHeight());
}
}
Just add your new panel statement after the dispose(). for example : add
guess1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
new JFrame("New Window").show();
}
});
and one more point - you have created array of 9 element and you are trying to insert at 10 index that throws ArrayIndexOutOfBound exception.
You have to remove static keyword for your button and other controls, then you can do this
JTabbedPane Pane = new JTabbedPane();
JPanel Second = new JPanel();
JPanel second = new JPanel(); // This Panel is inside the Second Panel
JButton guess1 = new JButton();
String words[] = new String[10];
Random getRandomWord = new Random();
int rr;
JButton Labels[] = new JButton[10];
You have to create new instance of same class and show it
guess1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose();
new secondTab().show();
}
});
So, rather then closing the current window and creating a new instance of the window, which is just annoying (and a little lazy).
You should provide a means by which you can reset the state of your UI.
You should do this via some method call that resets the internal state and updates the UI.
You could accomplish the same thing by removing the "game" panel, creating a new instance of it and adding it back to the frame.
Blinking frames is a bad idea - IMHO
Hi,
Please try like this.. It may help..
guess1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
new AnotherJFrame();
}
}
---------------------------------------------
import javax.swing.JFrame;
import javax.swing.JLabel;
public class AnotherJFrame extends JFrame
{
public AnotherJFrame()
{
super("Another GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new JLabel("Empty JFrame"));
pack();
setVisible(true);
}
}
I see your question has been answered, so this does not address your problem. I just thought I'd share some things you might want to condider fixing:
Don't use show()/hide(), because they are deprecated. [More info]
Use setVisible(true/false) respectively. [More info]
You don't have to add a new 'GridBagLayout()' before adding each component into the same container. I.e., you can remove the second getContentPane().setLayout(new GridBagLayout()); [More info]
Just make sure you understand that array-indices in Java (and all programming languages I know od - which isn't that much...but still) are zero-based ! [More info]
In order to find the center of the "usable" screen size Toolkit.getDefaultToolkit().getScreenSize(); isn't enough, since it includes screen-insets (e.g. non-visible margins, taskbars etc). You need to also use Toolkit.getDefaultToolkit().getScreenInsets(GraphicsConfiguration); and substract left and right insets from screen-width as well as top and bottom insets from screen-height.
If all you need is center a JFrame on the screen, you can simply use setLocationRelativeTo(null). [More info]
see the below link... It may help for you..
Java swing application, close one window and open another when button is clicked

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