Java - Wait for component to be shown - java

UPDATE #3: After madProgrammer's suggestions, maybe the timed solution is the best. But no answer has been given to this strange behaviour.
I understand the fact that components are not shown immediately and need to be set.
The problem here is the onShow method, which executes correctly if called from onCreate, but doesn't work if called from the callback method "componentShown".
UPDATE #2: Added a componentListener on fragmentContentPane, to see when actually this component is shown and VALID
fragmentContentPane.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
if (e.getComponent().isValid()) System.out.println("SHOWN AND VALID!");
}
});
UPDATE:
The show method now gets called in EDT.
public void show() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
System.out.println("Showing..");
frame.setVisible(true);
}
});
}
By now, the problem still exists.
Original Post:
I have this code:
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TEST {
private JFrame frame;
private JScrollPane contentPane;
private JPanel contentViewport;
private JScrollPane fragmentContentPane;
private JPanel fragmentContentViewport;
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
}
});
}
public void onCreate(){
System.out.println("On create!");
frame=new JFrame();
contentPane=new JScrollPane();
contentViewport=new JPanel();
contentPane.setViewportView(contentViewport);
frame.setContentPane(contentPane);
frame.addComponentListener(new ComponentAdapter(){
public void componentShown(ComponentEvent e){
onShow();
}
});
}
public void onShow(){
System.out.println("On show!");
fragmentContentViewport=new JPanel();
fragmentContentPane=new JScrollPane(fragmentContentViewport);
fragmentContentPane.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if (e.getChangeFlags()==HierarchyEvent.SHOWING_CHANGED && fragmentContentPane.isShowing()) {
System.out.println("Component is completely shown");
}
}
});
contentViewport.add(fragmentContentPane);
}
public void show(){
frame.setVisible(true);
}
public static final void main(String[] args) throws InvocationTargetException, InterruptedException{
TEST t=new TEST();
t.show();
}
}
The task is simple. I want to get known when the fragmentContentPane has been correctly added and is completely shown.
With this code this never happens, why?
Everything works if the onShow method is called in the ThreadEvent together with onCreate, for example:
public TEST() throws InvocationTargetException, InterruptedException{
SwingUtilities.invokeAndWait(new Runnable(){
public void run(){
onCreate();
onShow();
}
});
}
any help is appreciated

Related

See if a window loses focus

I have an undecorated JFrame with my own 'header' at the top. It works fine except for telling if the window is out of focus.
I've tried things like
if(!frame.hasFocus()
//Do stuff here
But this obviously won't work when I have other components in the window, such as a JTextField. I haven't found a way to do this so any help is appreciated.
Here is a sample code by which you can implement it:
import java.awt.event.FocusListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class SwingTest {
public static void main(String args[])
{
swing();
}
public static void swing()
{
JFrame g= new JFrame("First");
g.setVisible(true);
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
g.setSize(300, 300);
g.setLayout(null);
JLabel l=new JLabel("Times Windows Lost Focus : 0");
l.setBounds(20,10, 200, 60);
g.add(l);
g.addWindowFocusListener( new WindowFocusListener() {
int c=0;
#Override
public void windowLostFocus(WindowEvent e) {
c++;
}
#Override
public void windowGainedFocus(WindowEvent e) {
l.setText("Times Windows Lost Focus :"+c);
//System.out.println(c);
// TODO Auto-generated method stub
}
});;
}
}

Launch GUI: facade vs main

It is better to launch the user interface from a method in the same class of the main, or from a different class called by the main? Here an example:
From the main
Main.java
package main_version;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
launchGUI();
}
});
}
private static void launchGUI() {
JFrame frame = new JFrame("Main version");
//other code
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(333, 333);
frame.setVisible(true);
}
}
From another class
Main.java
package facade_version;
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
UserInterface.lauch();
}
});
}
}
UserInterface.java
package facade_version;
import javax.swing.JFrame;
public class UserInterface {
public static void lauch() {
JFrame frame = new JFrame("Facade version");
//other code
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(333, 333);
frame.setVisible(true);
}
}
I recommend having each GUI component in a different class, for reusability.
However it makes no big difference for small projects, if one only wants to test something, he can just skip creating multiple classes. It makes no difference for the compiler.

Why does this swing app hang?

The program hangs after trying to construct another instance of itself when I wait for the reference returned by the constructor to be set.
If I click on the button, the program will hang.
edit: removed silly second wait loop.
edit 2: change true to false when calling constructor. program seems to work now.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
public class Problem extends JPanel {
public Problem(boolean wait) {
frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
if(wait) try {
System.out.println("calling invoke and wait");
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
Problem.this.run();
}
});
} catch(InvocationTargetException|InterruptedException e) {
throw new RuntimeException(e);
}
else {
System.out.println("calling invoke later");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Problem.this.run();
}
});
}
}
public String title() {
return "title";
}
public void addContent() {
JButton button=new JButton("click");
add(button,BorderLayout.CENTER);
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent arg0) {
Runnable runnable=new Runnable() {
#Override public void run() {
System.out.println("before new "+Thread.currentThread());
problem=new Problem(false);
System.out.println("after new "+Thread.currentThread());
}
};
new Thread(runnable).start();
System.out.println("before first wait "+Thread.currentThread());
while (problem==null)
;
}
});
}
void run() {
frame.setTitle(title());
frame.getContentPane().add(this,BorderLayout.CENTER);
addContent();
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new Problem(false);
}
Problem problem;
public final JFrame frame;
private static final long serialVersionUID=1;
}
p1 = problem instance from main function
State 1: Creation - p1 is initialized. p1.problem is null
State 2: User clicks button. Eventually, in another thread, p1.problem is created. However, p1.problem.problem had never been initialized and won't be until the user clicks a button, which will never happen. I'm not sure what you're trying to do but it seems like your program is hanging on while (problem.problem==null);

How to close Threads before opening new Threads in Java?

I have problems with Java's Multi-Threading feature, so hopefully somebody can help me....
Here is my problem:
In the JPanel ExamplePanel which is located in the JFrame ExampleFrame I've added a ComponentListener which invokes the startPaint()-Method. This method should work in a new Thread. My Problem is that by resizing the window "former" Threads aren't closed, meanwhile new Threads are added....
So is there a way to resize the JPanel and to close at the same time the "old" threads, so that the number of threads is not growing, when I resize the JPanel?
I have tried something with a boolean exiter-variable, but it do not seemed to work...
here is the code:
package example;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Example2 {
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new ExampleFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class ExampleFrame extends JFrame {
private static final long serialVersionUID = 1L;
ExamplePanel examplePanel = new ExamplePanel();
private Thread t=null;
private class ExamplePanel extends JPanel implements ComponentListener {
private static final long serialVersionUID = 1L;
#Override
public void componentHidden(ComponentEvent e) {
}
#Override
public void componentMoved(ComponentEvent e) {
}
#Override
public void componentResized(ComponentEvent e) {
startPaint();
}
#Override
public void componentShown(ComponentEvent e) {
}
private void startPaint() {
t=new Thread(new Runnable() {
#Override
public void run() {
//System.out.println(Thread.currentThread().getName());
while (true) {
//System.out.println(Thread.activeCount());
}
}
});
t.start();
}
}
public ExampleFrame() {
examplePanel.addComponentListener((ComponentListener) examplePanel);
getContentPane().add(examplePanel);
}
}
if the calculations don't take long don't use an extra Thread.
if you need this extra Thread make sure that it doesn't run forever (no while (true) without returning at some point)
you can always interrupt your running Thread bfore creating the new one
if (t != null && t.isAlive()) {
t.interrupt();
}
and check in the while(true) loop if the Thread is interrupted
if (t.isInterrupted()) {
System.out.println("Thread ended");
return;
}
hope this helps

Java dialog does not dispose

Java noob here. My Swing class that extends JDialog does not dispose when the user presses the Windows Close button - java.exe stays in memory. I've stripped the code right down to this shell, I still get this behaviour.
I took a look at other samples, such as at Basic Java Swing, how to exit and dispose of your application/JFrame
When I commented out the two System.exit(0) lines in that sample code, the class in that sample still disposed correctly. What am I missing to make my class dispose?
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog{
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
//System.exit(0);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
You're creating a JFrame and never disposing it here:
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL); // *********
pack();
}
So since the JFrame is alive and a GUI has been rendered, the Swing event thread keeps on running.
If you instead make the JFrame behave so that the program exits on JFrame close, and then explicitly dispose of the JFrame, your program now exits:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
JFrame win = (JFrame) frame.getOwner();
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
win.dispose();
// System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super(new JFrame(title), ModalityType.APPLICATION_MODAL);
pack();
}
}
But this is very kludgy code, to say the least -- what if the owning window isn't a JFrame? What if it's null?
Another solution is to use no JFrame at all, so that when the JDialog is disposed, there's no persisting window left over to make the event thread persist:
import java.awt.Window;
import javax.swing.JFrame;
import javax.swing.JDialog;
public class WhyNoDispose extends JDialog {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
WhyNoDispose frame = new WhyNoDispose("my title");
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public WhyNoDispose(String title) {
super((JFrame)null, title);
pack();
}
}

Categories