I'm trying to create a simple script that will allow a pop up of images and text. The window is poping up but its blank with nothing on it. Anyone know what I am doing wrong?
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.*;
public class Thermomter {
public static void main(String[] args) {
ImageIcon cold = new ImageIcon("cold_thermomtor.png");
JLabel label = new JLabel();
label.setIcon(cold);
label.setText("omg this is painfull");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
frame.add(label);
}
}
Try to put
frame.add(label);
first, after:
JFrame frame = new JFrame();
Like this:
JFrame frame = new JFrame();
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setVisible(true);
A call to frame.pack(); before calling setVisible(true) will ensure all the elements inside get sized correctly before displaying them.
The pack method sizes the frame so that all its contents are at or above their preferred sizes
[...]
[...] pack leaves the frame layout manager in charge of the frame size, and layout managers are good at adjusting to platform dependencies and other factors that affect component size.
Related
The below code creates a frame with a JTabbedPane in the frame's contentPane and a "Help" button added directly to the frame's layered pane - at a higher index than the default, so it should always be painted in front of the tabbed pane. But as you can see if you run it, as soon as you click on one of the tabs (or, on Mac, as soon as you hover over a tab), the "Help" button gets painted over - i.e. disappears. You have to resize the frame to make the "Help" button re-appear.
Is this a Java bug or am I doing something wrong? If the latter, what needs to be done to fix the problem? I've consulted both https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html and https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html .
Please pardon the poor positioning of the "Help" button. I was just trying to write a quick test to include here. The idea is the to overlay a "Help" icon button in the unused space of the JTabbedPane.
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class TabTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
JTabbedPane tp = new JTabbedPane();
tp.addTab("hello", new JPanel());
tp.addTab("there", new JPanel());
frame.getContentPane().add(tp, BorderLayout.CENTER);
JLayeredPane layeredPane = frame.getRootPane().getLayeredPane();
JButton helpButton = new JButton("Help");
helpButton.setBounds(800, 5, 50, 20);
layeredPane.add(helpButton, 400);
frame.setSize(new Dimension(900, 800));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
This is a common misunderstanding with JLayeredPane.
If you have a look at the JavaDocs for Container, you will note that there are (at least) two add methods
Container#add(Component, int)
Container#add(Component, Object)
The question you need to answer is, which one are you actually calling?
Both the JavaDocs for JLayeredPane and How to use JLayeredPane demonstrate that you should be calling the second one.
While the first can affect the z-ordering of the components, it's no guarantee that the component positions won't be changed.
Instead of:
layeredPane.add(helpButton, 400);
you should be using:
layeredPane.add(helpButton, new Integer(400));
which will pass the value as a constraint to the container, instead of the desired position within the container hierarchy - yeah, suitable I know
An alternative solution might be to use the glassPane instead, for example...
JFrame frame = new JFrame();
JTabbedPane tp = new JTabbedPane();
tp.addTab("hello", new JPanel());
tp.addTab("there", new JPanel());
frame.getContentPane().add(tp, BorderLayout.CENTER);
// Null layout used here for demonstration purposes only
JPanel glassPane = new JPanel(null);
glassPane.setOpaque(false);
frame.getRootPane().setGlassPane(glassPane);
// This is important, as setGlassPane makes it invisible
glassPane.setVisible(true);
JButton helpButton = new JButton("Help");
helpButton.setBounds(800, 5, 50, 20);
glassPane.add(helpButton);
frame.setSize(new Dimension(900, 800));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
I have tried looking at many documentations and tutorials but none of them seem to work together. I am just trying to make a simple "main menu" for a "game" my friend and I are attempting to make. I am able to move the buttons around when there is no background image present, and I am only able to get the background image but I can't move the buttons around.
So my question is how can I position JButtons?
Here is my code & a screenshot:
What my frame looks like
package game;
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MainMenu extends JFrame{
private JButton singPlay = new JButton("Single Player");
private JButton twoPlay = new JButton("Two Player");
public MainMenu()
{
JFrame frame = new JFrame("TestTEST");
JPanel panel = new JPanel();
frame.setSize(400,500);
frame.setLocation(700,300);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Austin\\Pictures\\Landscape.jpg")));
frame.setLayout(new FlowLayout());
frame.add(singPlay);
frame.add(twoPlay);
frame.setSize(399,499);
frame.setSize(400, 500);
}
public static void main(String[] args)
{
new MainMenu();
}
}
So my question is how can I position JButtons?
Use an appropriate layout manager.
You set the layout manager to a FlowLayout so the buttons are displayed at the top of the frame.
Maybe you want to center the buttons on the frame. If so then you can use a GridbagLayout.
Also, don't use setSize(). Use the pack() method. Finally the frame should be made visible AFTER you add the components to the frame.
So your code might look something like:
public MainMenu()
{
JPanel panel = new JPanel();
panel.setOpaque(false);
panel.add(singPlay);
panel.add(twoPlay);
JFrame frame = new JFrame("TestTEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setContentPane(new JLabel(new ImageIcon("yourfilename.jpg")));
frame.setLayout(new GridBagLayout());
frame.add(panel, new GridBagConstraints());
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
Or maybe you want the buttons centered vertically. Then you can use a vertical BoxLayout.
Read the Swing tutorial on Layout Managers and decide for yourself what is appropriate.
Right now you're using a JLabel as a content pane, which doesn't make a ton of sense.
Instead of putting your background in a JLabel, you should extend JPanel and override paintComponent() to draw the background yourself. Here is a great tutorial on performing custom painting.
Once you have your background JPanel, put your JButtons inside that and use it as your content pane.
After that, if you're looking to manually position your JButtons, then you might be looking for a null layout.
JFrame.setContentFrame() is not how you set a background image. See the selected answer at How to set background image in Java?
Also, you should be doing all these operations in the Swing event thread.
public static void main(String [] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
new MainMenu();
}
});
}
A simple solution is to use GridBagLayout, the following will centre the buttons, on on top of each, vertically and horizontally in the container
public MainMenu() {
JFrame frame = new JFrame("TestTEST");
JPanel panel = new JPanel();
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Austin\\Pictures\\Landscape.jpg")));
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 4);
gbc.fill = GridBagConstraints.HORIZONTAL; frame.add(singPlay, gbc);
frame.add(twoPlay, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
As a side note, while JLabel work in this case, you need to be ware that it will calculate it's preferred size from the icon (and text) properties of the label itself, not it's children, JLabel really wasn't designed to hold other components
I try to just use a add.method to add a button to a frame. But only the frame pops up.
I don't see any buttons.
import javax.swing.*;
public class okd {
public static void main() {
JFrame frame = new JFrame();
JButton b1 = new JButton();
frame.setSize(500,500);
frame.add(b1);
b1.setSize(400,400);
b1.setVisible(true);
frame.setVisible(true);
}
}
There is a button there. Add some text to it and it will magically appear.
public static void main(String[] args){
JFrame frame = new JFrame();
JButton b1 = new JButton();
frame.setSize(500,500);
b1.setSize(400,400);
b1.setVisible(true);
b1.setText("HelloWorld");
frame.add(b1);
frame.setVisible(true);
}//SSCCE1
Your button has been added to the frame. You'll notice a difference if you remove your frame.add() line. The 'problem' lies with the following.
You haven't specified a layout resulting in your frame using the
default BorderLayout manager.
You haven't specified a constraint in frame.add(). Because of this the
component has been added to whatever the default position is for the
layout which is BorderLayout.CENTER. Components added to the center
take up the much space as possible hence why your button is filling the entire frame.
Here's some tutorials on layout managers. You might want to have a read through these at some point.
To remove the Large appearance of the button, You need to add a layout Manager to the Code
Like this:
import javax.swing.*;
import java.awt.*;
public static void main(String[] args)
{
JFrame frame = new JFrame();
JButton b1 = new JButton();
frame.setSize(500,500);
b1.setVisible(true);
b1.setText("HelloWorld");
frame.setLayout(new FlowLayout());
frame.add(b1);
frame.setVisible(true);
}
While creating a JFrame and adding some components I noticed that if I create a instance of a JComboBox between setting the JFrame visible and adding a button, the button disappears.
I start of by creating a JFrame:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
Then I add set the frame visible and add a JButton:
frame.setVisible(true);
frame.add(new JButton("text"));
It works as expected and displays one big button:
BUT, if I create one instance of a JComboBox in between those lines:
frame.setVisible(true);
new JComboBox();
frame.add(new JButton("text"));
And now the buttons is gone..
I expect no change at all, since I'm only creating a instance and not assigning it to anything. Why does the button disappears?
Also, if move new JComboBox(); above frame.setVisible(true);, the button goes visible again.
Once you display the UI, it should not be modified from any thread except of the EDT. In the first case you had some "luck", and it worked. In the second case probably the time of creation of the JComboBox was long enough to prevent you from modifying the UI from a thread that is not the EDT.
What you should do, is invoking that code on the EDT:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.add(new JButton("text"));
frame.setVisible(true);
}
})
I found that problem is in setSize(); and setVisible(true); methods you are calling before adding components on your JFrame. So answer is simple, call setSize(); and setVisible(true) in the end of code(or even better, call pack(); instead of setSize()) and everything should work fine:
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class Fnatte {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
new JComboBox();
frame.add(new JButton("Text"));
//frame.setSize(200,200);
frame.pack();
frame.setVisible(true);
}
}
From the JavaDoc for the add() method:
If the container has already been
displayed, the hierarchy must be
validated thereafter in order to
display the added component.
Change:
frame.setVisible(true);
new JComboBox();
frame.add(new JButton("text"));
To:
frame.setVisible(true);
new JComboBox();
frame.add(new JButton("text"));
frame.validate();
I think the oddity you encountered is not so much the adition of "new JComboBox();"
but the fact that calling "frame.add(new JButton("text"));" after calling
"frame.setVisible(true);" worked without calling "frame.validate();".
I have the following code. Class KochSnowflakesMenu is a grid JPanel with three buttons. Class KochSnowflakesDraw currently draws a circle using drawOval:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakes
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.repaint();
}
}
This works if I comment out frame.setResizable(false). When I don't the buttons don't appear. Why is that? As you can see, I have tried using repaint(). I had previously the problem that the buttons would not show up until I manually resized the window...
Also, as a bonus question, if anyone can tell me how to get the dimensions of a JPanel that would be great. The reason why I can't use a resizable layout manager such as BorderLayout, which really is what I want to use, is that I can't figure out the dimension of the JPanel that occupies the center (and hence have no idea how to large to draw the things I'm drawing).
EDIT:
As requested, here is the KockSnowflakesMenu class:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesMenu extends JPanel
{
public KochSnowflakesMenu()
{
setLayout(new GridLayout(3,1));
setBounds(0,0,200,400);
JButton button_red = new JButton("Red");
JButton button_yellow = new JButton("Yellow");
JButton button_blue = new JButton("Blue");
add(button_red);
add(button_yellow);
add(button_blue);
}
}
And, just to be sure I didn't mess something up with KochSnowflakesDraw, here's that class as well:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesDraw extends JPanel
{
public KochSnowflakesDraw()
{
setLayout(null);
setBounds(200, 0, 400, 400);
}
public void paintComponent(Graphics g)
{
g.setColor(Color.RED);
g.drawOval(0,0,400, 400);
}
}
A general point, when using JFrame, you should be using the contentPane, rather than the JFrame itself, so to add items, try
frame.getContentPane().add(.....);
For your first question, try using pack on your JFrame.
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Window.html#pack()
For your bonus question, JComponent has a getWidth and getHeight method. This will tell you the current size of the JPanel.
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JComponent.html#getWidth()
Adding more info to the previous answers...
The size is random until the component is drawn so make sure you have a setVisible(true) on your frame. Here's your code w/some modifications that let you use the BorderLayout and get the size of your drawing panel. I substituted some fake buttons for your interfaces but you'll get the drift.
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout());
buttons.add(new JButton("MENU"));
buttons.add(new JButton("DRAW"));
frame.add(buttons, BorderLayout.SOUTH);
JPanel drawArea = new JPanel();
drawArea.setBackground(Color.BLUE);
frame.add(drawArea, BorderLayout.CENTER);
frame.setVisible(true);
Dimension drawAreaDim = drawArea.getSize();
System.out.println(drawAreaDim);
When you add components to a visible frame the code should be something like:
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes required
Make sure you create your Swing objects on the Event Dispatch Thread (EDT). In your example you aren't, and that is often the candidate when you get weird, inconsistent behavior. Swing isn't thread-safe, and relies on creation and modification of Swing objects on the EDT.
To remedy, just wrap the contents of your main method in a SwingUtilities.invokeLater call like so:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.setVisible(true);
}
});
}
That will create your JFrame and other components on the EDT thread. Does that fix the inconsistent "it doesn't work most of the time" behavior?
Also, I prefer to call setVisible last...though it probably doesn't matter.