My program reads in files from a given directory on program start (each one containing an object), and adds each object to a Vector. updateList() is then called which loops through each of these objects one by one, adding their names(String property) to a JList with a DefaultListModel.
The issue is that very rarely when the program starts, the list appears empty. I have performed many checks such as getting the number of entries in the list as reported by the list model and everything would appear to be correct.
Has anybody seen this before? Am I missing something important here?
Thanks, updateList() below:
private void updateList(){
for (int i=0; i < calculators.size(); i++){
listModel.addElement(calculators.get(i).getName());
}
}
Has anybody seen this before?
Random errors generally happen because you are not updating Swing components on the Event Dispatch Thread. Read the section from the Swing tutorial on Concurrency for more information.
In particular you would use the invokeLater() method when starting your GUI. The Swing tutorial has plenty of examples. The basic structure the tutorial uses is like:
import java.awt.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
add( new JLabel("Label") );
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new SSCCE() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Related
testing a game, i sometimes get exceptions thrown when a component is not displayable. i added a wait loop on isDisplayable().
seems like my game can take a few hundred ms. to become displayable.
is this a sane way to handle this problem?
i am testing game clients that talk over sockets to a server.
thanks
edit 1: thanks for the comments. i discovered that i am adding the mediator for the gui (an observer) to the model (an observable) before the gui completes its construction and initialization. it gets worse, as i am initializing a panel with calls to createImage which returns null and throws.
import java.awt.*;
import javax.swing.*;
public class WaitForFrameToBeVisible {
JFrame frame=new JFrame("FrameDemo");
private void createAndShowGUI() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel=new JLabel("");
emptyLabel.setPreferredSize(new Dimension(175,100));
frame.getContentPane().add(emptyLabel,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
void run() throws Exception {
System.out.println("waiting for frame to be displayable");
long t0=System.nanoTime();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
while (!frame.isDisplayable())
Thread.sleep(1);
long dt=System.nanoTime()-t0;
System.out.println("waited "+dt/1_000_000.+" ms. for frame to be displayable");
}
public static void main(String[] args) throws Exception {
new WaitForFrameToBeVisible().run();
}
}
You don't need to use isDisplayable(). You could use invokeAndWait(...) for what you are trying to do :
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createAndShowGUI();
}
});
// control will reach here when the GUI will be created
Notice that this way you are not actually checking if the frame is visible but you are checking if createAndShowGUI() has done its work
Another thing is you should not call isDisplayable() or any function like this in loop. It will consume unnecessary processing speed. Instead use wait-notify.
But as far as your case is concerned to use WindowListener is very good idea as suggested by MadProgrammer in comment.
public static void main(String args[]){
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMISED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I've used this code to maximise a JFrame, but instead of actually maximising the frame, it just sets the window size to that of the screen, without actually changing the state, so clicking the maximize button doesn't actually downscale it again.
Am I using the wrong command or something?
You have an error in frame.setExtendedState(JFrame.MAXIMISED_BOTH);
You should write frame.setExtendedState(JFrame.MAXIMIZED_BOTH); instead
Have you tried this?
f.setExtendedState(f.getExtendedState() | JFrame.MAXIMIZED_BOTH);
Based on your provided example and run on Windows 7...
"Maximised" state (this is cropped version of window as the original is quite large)
"Normal" state
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ExtendedFrame {
public static void main(String[] args) {
new ExtendedFrame();
}
public ExtendedFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
// frame.setExtendedState(JFrame.MAXIMISED_BOTH);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
You must want it maximized by default. Because the maximize button works out-of-the-box.
frame.setExtendedState(JFrame.MAXIMIZED_BOTH) works on Linux x64. Here's the program I tested with:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public static void main(String... args) {
new Test();
}
private JFrame frame;
public Test() {
frame = new JFrame();
frame.add(new JLabel("Hi!"), BorderLayout.CENTER);
JButton button = new JButton("maximize");
button.addActionListener(this);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
This worked for me:
We need to combine the setSize () and setExtendedState together
JFrame frame=new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // aligns itself with windows task bar
// set maximum screen
frame.setSize((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(), (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight());
You should use this when applying changes
frame.setResizable(true);
Seven years late is better than never, right?
The question does not provide an SSCCE presumably because this is not all of the code involved. The tiny fragment of code provided work as it is, so practically all previous answers are saying "works for me". So, the problem certainly lies with the rest of the code, which is not shown.
We cannot be sure what the rest of the code does, but I suspect that it tries to persist the state and bounds of the frame, and to restore that state and bounds later, and that is what fails. The OP did not receive an answer 7 years ago because they did not explain what the actual problem was, but this question will be viewed by many more, so here it goes:
In theory, persisting the state and bounds of a frame should be piece of cake, but in practice it is not.
This is a very common problem in GUI applications, and it is basically due to a common mistake on behalf of the programmer. However, it should be noted that various widely used GUI frameworks (and certainly both Swing and SWT in the Java world) operate in a specific perverse way which makes it a very easy mistake to make.
The problem begins with the fact that these frameworks do not support a 'maximized' event, (duh!) so the only way you can detect that your frame has been maximized is to listen to the 'resized' event. So, you are presumably persisting the state and dimensions of your frame from within your 'resized' event handler.
The problem is further compounded by the fact that once the 'resized' event has occurred as a result of maximizing the frame, the frame bounds are the maximized bounds of your frame, which are irrelevant, and you will be shooting yourself in the foot if you make the mistake of persisting them.
So, the solution is to manually keep track of the "normal state" bounds of your frame, and only persist those. This can be accomplished as follows:
addComponentListener( new ComponentAdapter()
{
#Override public void componentResized( ComponentEvent e )
{
if( (getExtendedState() & MAXIMIZED_HORIZ) == 0 )
normalStateBounds.width = getWidth();
if( (getExtendedState() & MAXIMIZED_VERT) == 0 )
normalStateBounds.height = getHeight();
stateAndOrSizeChanged();
}
#Override public void componentMoved( ComponentEvent e )
{
if( (getExtendedState() & MAXIMIZED_HORIZ) == 0 )
normalStateBounds.x = getX();
if( (getExtendedState() & MAXIMIZED_VERT) == 0 )
normalStateBounds.y = getY();
stateAndOrSizeChanged();
}
} );
...where:
normalStateBounds is defined as private final Rectangle normalStateBounds = new Rectangle(); and contains the bounds of your component when in the "normal" (i.e. not minimized, nor maximized) state
stateAndOrSizeChanged() is your function which handles persisting the state and bounds of your frame, being careful to only persist normalStateBounds instead of the values returned by getX(), getY(), getWidth(), and getHeight().
When loading the state and bounds from persistence, you can simply invoke setBounds() followed by setExtendedState(), and you should do that before invoking setVisible( true ) to avoid the possibility of your frame appearing restored for a blink of an eye before maximizing. The call to setBounds() will set the non-maximized bounds, and the call to setExtendedState() might maximize your frame, but if you then restore it, it will assume the non-maximized bounds that you have set.
It works for me running Java 7 on a WinXP machine.
For the record, this is what an SSCCE should look like:
import javax.swing.*;
public class JFrameExtendedDemo
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
// Then:
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
I've just started learning Swing/JFrame, basically making a GUI.
I've been doing Java for a month now, just using the console, making a sin/true or false games and it is pretty easy for me now.
I decided to take a further step, and I must say it's totally a pain, different logic.
That's what I've done so far:
Main.java:
import java.awt.*;
import javax.swing.*;
import java.io.*;
class Main {
public static void main(String[] args) {
final Gui gui = new Gui();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui.createMyGui();
}
});
}
}
gui.java
class Gui {
protected JFrame j = new JFrame("My First window");
protected JPanel p = new JPanel();
protected Container c;
public Gui() {
j.setSize(500, 400);
p.setSize(j.getSize());
this.c = j.getContentPane();
}
public void createMyGui() {
setButtons();
setGuiBackground();
j.setVisible(true);
p.setVisible(true);
this.c.add(p);
}
private void setGuiBackground() {
this.c.setBackground(Color.green);
}
private void setButtons() {
p.add(new JButton("Hey"));
}
}
Problem
I can't really get the button to show up, people are telling me to use setBounds but I am not really sure on how to start as I can't even place a button there. I've tried searching about my problem, but no luck actually.
Basically what happens is a 500x400 green GUI opens, and that's it.
Why won't the button show?
people are telling me to use setBounds
Dont! Layout managers are the correct way to go.
Your problem is you add your buttons to the "p" panel, but you never add it (p panel) to the contentPane
I am creating a basic screensaver for a small project for college and I am having trouble closing the JFrame after I open it. I have removed the outer panel so as to make it look a proper screensaver but I now have to open the Task Manager to close down the program, I want the window to close when I press a button on the keyboard how can I do that?
Thanks in advance.
-------EDIT--------
I have tried the first two methods given but I can't seem to get them to work properly. Here is my code for the frame so far:
import java.awt.Color;
import javax.swing.JFrame;
public class ScreensaverTest
{
public static void main( String[] args )
{
JFrame frame = new JFrame( "Screen Saver" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setUndecorated(true);
ScreenSaverJPanel screensaverTestJPanel = new ScreenSaverJPanel();
frame.add( screensaverTestJPanel );
frame.setBackground( Color.BLACK );
frame.setVisible( true );
frame.setLocation( 0, 0 );
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
--------EDIT---------
Also I am using the repaint method to move objects around the screen and I want some of them to move at different speed. I am using a random number generator for the positioning so adjusting the numbers isn't really an option, please help.
There are a lot of examples on how to do this.
You need to add an eventListener to the frame that listens for keyboard-inputs and then closes the frame.
Try looking at this: http://www.java2s.com/Code/Java/Swing-JFC/Reacttoframecloseaction.htm
You will have to replace the event with something keyboard-related, but that is the best way to go I would think..
Edit:
To respond to the edit in the post you could do something like this:
import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Test {
public Test() {
final JFrame frame = new JFrame("Screen Saver");
frame.validate();
frame.setVisible(true);
KeyAdapter listener = new KeyAdapter() {
#Override public void keyPressed(KeyEvent e) {
frame.dispose();
}
};
frame.addKeyListener(listener);
}
public static void main(String[] args) {
new Test();
}
}
And voila - that should work. It compiles for me on Java 7.
Here is the code if you have only a single JFrame. You should add it when you initialize your components.
addKeyListener(new KeyAdapter()
{
#Override
public void keyPressed(java.awt.event.KeyEvent evt)
{
processWindowEvent(new WindowEvent(getWindows()[0], WindowEvent.WINDOW_CLOSING));
}
});
Ok, I have a Java program, that displays some tiles that are SVGs in a FlowLayout. It does this by being a class ScrabbleRack, and extending JPanel, then adding JSVGCanvas tiles to this panel.
Afterwards I created a frame and added the panel, this. (packed it and displayed it). On appearing, the panel does not display properly. It just displays the first tile and then in the space where the rest of the tiles should be displayed, there is whitearea.
But if I resize the frame by any amount, the image will render correctly.
public class ScrabbleRackGUI extends JPanel{
ScrabbleRack rack=new ScrabbleRack();
JSVGCanvas rackContentsImages[]=new JSVGCanvas[8];
public ScrabbleRackGUI() {
setLayout(new FlowLayout());
createComponents();
}
public void createComponents() {
//INITIALISE SOURCE IMAGES
initImages();
for (int i=0;i<rackContentsImages.length;i++){
this.add(rackContentsImages[i]);
}
}
private void initImages(){
File tempImages[]=new File[8];
for(int i=0;i<8;i++){
tempImages[i]= new File("./src/res/rackBackground.svg");
rackContentsImages[i]=new JSVGCanvas();
try {
rackContentsImages[i].setURI(tempImages[i].toURL().toString());
} catch (MalformedURLException ex) {
Logger.getLogger(ScrabbleBoardGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public static void main(String args[])
{
JFrame frame = new JFrame("ScrabbleTest");
ScrabbleRackGUI rack= new ScrabbleRackGUI(1);
frame.add(rack);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(214,70);
frame.setVisible(true);
}
}
Any ideas on how I can get this panel to display properly, first time.
Or some hack that will resize it at the end of the program.
I used batik to render the SVGs in Java, for those who want to reproduce this problem.
You problem may be that the construction of your GUI is not being done on the EDT.
Your main should look something like:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyWindow window = new MyWindow();
MyWindow.setVisible(true);
}
});
}
and the rest of your code in your current main should be in the MyWindow constructor.
More detailed information can be found at http://leepoint.net/JavaBasics/gui/gui-commentary/guicom-main-thread.html (among other places)
This might be related to Batik issue 35922 reported here: https://issues.apache.org/bugzilla/show_bug.cgi?id=35922
If I understand that bug report correctly, you can workaround the problem by adding the JSVGCanvas instances (and the ScrabbleRackGUI instance) and calling pack() first, and then set the URIs on each JSVGCanvas.
First of all, you wrote:
ScrabbleRackGUI rack= new ScrabbleRackGUI(1);
and you don't have constructor that takes int.
Secondly, you're setting FlowLayout to JPanel component, and JPanel by default has FlowLayout as layout. better call super(); to get all the benefits of JPanel.
Try to run your application inside of Event Dispatching Thread (EDT), as others mentioned already.
SwingUtilities.invokeLater(new Runnable() {
// your code here
}
Also you should set your URI like this:
setURI(f.toURI().toURL().toString());
because f.toURL() is deprecated.
I hope it helps.