Creating a JComboBox after setVisible makes JButton disappear - java

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();".

Related

Nothing is showing up on my pop up window for JLabel

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.

Overlaying a JButton onto a JFrame with a JTabbedPan in its content pane?

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

Call class/ JPanel from Main Project?

I've finished my store management program with many classes (many JForm panels actually. Thanks to people in this forum whom helped me so much).
I just need to call JPanel Login when I click Run Project.
Any idea how to call it? what code I have to insert to main project?
You cannot display JPanel independently.
So you have to create a JFrame and then add this JPanel object to this JFrame and then display the JFrame.
write these lines in your main method.
JFrame frame = new JFrame("Title");
frame.setSize(500,500);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // as per your requirement.
frame.add(new Login(), BorderLayout.CENTER);
frame.setVisible(true);
it will work properly.
JFrame myFrame = new JFrame("MyTitle");
myFrame.setSize(width, height);
myFrame.setLocation(x, y);
myFrame.setContentPane(new Login());
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// if you want add your jcomponent
myFrame.getContentPane().add(yourJComponent);
try it!
If you want add JComponent(JButton)
JButton myBtn = new JButton("btn name");
myBtn.setLocation(x, y);
myFrame.getContentPane().add(myBtn);
If you want add JComponent(JText)
JText myText = new JText("text");
myText.setLocation(x, y);
myFrame.getContentPane().add(myText);
JComponent [http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html]

Displaying GUI Issue

I am trying to display a gui but cannot get the frame to show here is the code so far:
The idea behind this is that the string path (which is the path to an image) is calculated in another class, it is then passed to this class where the image is to be displayed.
I cannot get the frame to be displayed, my usual method would be:
new displayWindow();
but this does not work.
What would be the best method of displaying the gui?
public class displayWindow {
public displayWindow(String path) {
JLabel label = new JLabel();
ImageIcon icon = new ImageIcon(speed);
label.setIcon(icon);
label.setText(path);
JPanel panel = new JPanel();
panel.add(label);
JFrame frame = new JFrame("Speed Limit");
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
System.out.println(path);
frame.setLayout(new BorderLayout());
frame.setLayout(new FlowLayout());
frame.setSize(430, 430);
frame.getContentPane().removeAll();
frame.getContentPane().add(panel);
frame.repaint();
}
public static void displayWindow() {
new displayWindow();
}
}
With the code you provide, your code even compile cause you don't have a default constructor with no args. Your constructor takes one parameter.
So your method should be:
public static void displayWindow(String param) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new displayWindow(param);
}
});
}
Using SwingUtilities.invokeLater(..) you ensure that will run in the EDT(Event Dispatch Thread.)
Is there a reason for this?
frame.setLayout(new BorderLayout());
frame.setLayout(new FlowLayout());
frame.setSize(430, 430);
In java by convention class names starts with upperCase so you class should be called DisplayWindow this is very important for readability.
And call setVisible(true) after you add components to your frame :)

Java Swing Application - buttons do not appear if resizable is set to false

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.

Categories