Java Swing popup window losing focus and not repainting - java

I have a simple Java Swing GUI Form with a browse button. The browse button creates a new JFileChooser when it's clicked.
However, if you click browse immediately after the window opens, the file chooser window seems to loose focus, showing the parent window behind it, but it refuses to repaint itself. I have to drag it off screen and back on again to get it to return to normal.
I've tried to reduce my code to the simplest version that still has the problem. (It just makes a very large browse button.
public class FormTest extends JFrame
{
private final int width = 490;
private final int height = 400;
private JPanel outerPanel;
private static FormTest myTest;
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch( Exception e )
{
e.printStackTrace();
}
myTest = new FormTest();
myTest.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
myTest.setResizable(false);
myTest.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
closeWindow();
}
});
myTest.setVisible(true);
}
public FormTest()
{
super("Convert Ratings");
this.setSize(width, height);
initComponents();
}
private void initComponents()
{
outerPanel = new JPanel();
outerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
outerPanel.add(Box.createRigidArea(new Dimension(0, 5)));
JButton myButton = new JButton("browse");
myButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
JFileChooser fileChooser = new JFileChooser();
fileChooser.showOpenDialog(myTest);
}
});
outerPanel.add(myButton);
this.add(outerPanel);
}
private static void closeWindow()
{
int result = JOptionPane.showConfirmDialog(myTest, "Are you sure you want to close the application?",
"Question", JOptionPane.YES_NO_OPTION);
if( result == JOptionPane.YES_OPTION )
{
System.exit(0);
}
}
}
In this example, the browse button must be clicked immediately after the window opens and the bug will show itself after about 10 seconds.
Any help or suggestions would be much appreciated.
Thanks,
B.J.

Since your question has changed I'll add another answer. It looks like you're looking to use a CardLayout.
The unresponsiveness of your application is probably caused by some incorrect logic with repainting/hiding/unhiding panels.
Here is Oracle's tutorial on using it
http://download.oracle.com/javase/tutorial/uiswing/layout/card.html

New Addition:
I'm currently on a mac and I can't see the issue, I'll try it again when I'm at a PC later today.
Original Post:
Sounds like a event dispatch thread issue. Make sure you are doing anything that manipulates the GUI in the event dispatch thread.
http://download.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
Any long running task should use another thread or swing worker to perform it's function, otherwise it will cause things to stop responding/lock up/etc.

Related

Java 8u161/8u162 makes Swing app use CPU

When running a Swing application on 8u161 or 8u162 and focus is in a JTextField and you switch to another application (like Chrome) and back to the application CPU usage grows to 15% on my 8 core Windows 10 PC (as if an entire core is busy processing events).
Just run the application and switch a couple of times.
If I click on the tab in the tabbed pane CPU usage drops to 0 as expected.
public class Test {
public static void main(String... args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame("Test");
JTabbedPane tp = new JTabbedPane();
tp.addTab("tab 1", new JTextField(20));
f.add(tp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
I have tried to look at the event queue to see what happens and it looks a lot like the last event gets processed again and again
If I add this to the above program I get a lot of java.awt.event.InvocationEvent[INVOCATION_DEFAULT,runnable=sun.awt.windows.WInputMethod ...
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue(){
#Override protected void dispatchEvent(AWTEvent event) {
System.out.println(event);
super.dispatchEvent(event);
}
});
Works OK on 8u151, 8u152 and 9.0.4
I have a lot of customers that are upgrading to 161 and get this problem so any suggestions for a workaround is much appreciated.
I have filed a bug with Oracle
JProfiler shows this:
Seems to work OK on 8u172 b02
According to openjdk this was introduced by 8184016 and fixed by 8183504
Are your customers using input methods? If you don't need input methods enabled, I suggest that you could disable it.
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Test");
JTabbedPane tp = new JTabbedPane();
JTextField tf = new JTextField();
tf.enableInputMethods(false); // disable IM
tp.addTab("tab 1", tf);
f.add(tp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
This is probably pretty ugly, but it's a workaround I created based on my observations on when the bug occurs. I'm sure it's possible to create a better workaround with better understanding of why exactly the bug occurs in the first place.
It basicially prevents any JTextComponent from being focused as the first thing after the window gets focused, transfers focus to another component (upFocusCycle(component) for me puts in on the frame/dialog) and then transfers it back the the JTextComponent. I don't know if this will work in every case or maybe even break something, but it seems to work for me. Use at your own risk obviously.
public class JTextFieldTest {
public static final void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// Install workaround, without this the bug occurs
installTextComponentFocusWorkaround();
JFrame window = new JFrame("Test");
window.setLocationByPlatform(true);
window.add(new JButton("Button"), BorderLayout.CENTER);
window.add(new JTextField(), BorderLayout.SOUTH);
window.pack();
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
window.setVisible(true);
});
}
public static void installTextComponentFocusWorkaround() {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addVetoableChangeListener(new VetoableChangeListener() {
private boolean rejectNext = false;
private JComponent target;
#Override
public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
if (evt.getNewValue() != null) {
if (evt.getPropertyName().equals("focusOwner")) {
if (evt.getNewValue() instanceof JTextComponent) {
if (rejectNext) {
JComponent component = (JComponent) evt.getNewValue();
KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle(component);
target = component;
System.out.println("Rejected JTextComponent focus");
throw new PropertyVetoException("Rejected JTextComponent focus", evt);
}
} else {
rejectNext = false;
if (target != null) {
System.out.println("Temp focus: " + evt.getNewValue());
target.requestFocus();
target = null;
}
}
} else if (evt.getPropertyName().equals("focusedWindow")) {
System.out.println("Window focused");
rejectNext = true;
}
}
}
});
}
}
I also tried things like clearing focus altogether or only throwing a PropertyVetoException, but only actually focusing someting else before the JTextComponent seemed to work.
I'm looking for JTextComponent because the bug occured for me with both JTextField and JTextArea, although I'm not sure if other classes are affected as well.

How to perform an action on class's field using dialog created by IntelliJ Idea designer

I'm curious how can I use a dialog designer that is built into IntelliJ IDEA since I find it an option with big potential but I don't really know how to use it.
Let's consider a desktop program with two classes created using designer: MainWindow and MainDialog. Let's assume that MainWindow class already has all fields, components etc. required for a simple form to be displayed. Then in the MainWindow class we have:
JLabel label = new JLabel("This is default text");
JButton showDialog = new JButton("Show dialog");
showDialog.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
MainDialog dialog = new MainDialog ();
dialog.pack();
dialog.setVisible(true);
}
});
which makes the dialog visible. The MainDialog class designed by default by designer looks like this:
public class MainDialog extends JDialog {
private JPanel contentPane;
private JButton buttonOK;
private JButton buttonCancel;
public MainDialog() {
setContentPane(contentPane);
setModal(true);
getRootPane().setDefaultButton(buttonOK);
buttonOK.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onOK();
}
});
buttonCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onCancel();
}
});
// call onCancel() when cross is clicked
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
onCancel();
}
});
// call onCancel() on ESCAPE
contentPane.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onCancel();
}
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
private void onOK() {
// add your code here
dispose();
}
private void onCancel() {
// add your code here if necessary
dispose();
}
}
Now let's also assume that in the dialog class I have a text field:
JTextField textField = new JTextField();
that I am getting a text to be displayed by label in the MainWindow class from.
Since I have an onOK() function created by default I'd like it to update a label in MainWindow class with text typed in text field in MainDialog class.
The problem is: how can I perform an action on another class's field using this pattern without writing in MainDialog a line MainWindow window = new MainWindow or making label static? Is it possible? I know that this can be done much simpler but this is also an easy example and I'd like to perform much more complex operations using this structure.
Yes, it's possible.
First option: since the dialog is modal, the code opening the modal in the main window will be blocked until the dialog is closed. So you could just do something like this in the modal:
public String getEnteredText() {
return textField.getText();
}
and in the main window:
dialog.setVisible(true);
myLabel.setText(dialog.getEnteredText());
Or (but I would use the first option), you can pass the main window, or any other callback, to the dialog. For example:
MainDialog dialog = new MainDialog(this);
And in the dialog:
private void onOK() {
mainWindow.setLabelText(textField.getText());
dispose();
}
My recommendation is to avoid UI designers. Especially if you're not able yet to write the code that they generate by yourself, and you don't have a deep understanding of how Swing works.

opening JFrame from applet

So I programmed am applet that makes a ball roll in circles for ever, and I wanted to make the user decide what speed the circle should roll in, but something failed when I added the JFrame:
applet(the stop,destroy and update do not appear because they aren't important, and in start there is nothing):
public class Main extends Applet implements Runnable{
private Image I;
private Graphics GfU;
int ballX, ballY=249;
static int radius=20;
double Memory;
int changeY ,changeX=1;
Speed S = new Speed();
#Override
public void init() {
setSize(750,750);
S.setVisible(true);
}
#Override
public void run() {
while(true){
if(ballY>=250 || ballY<=-250){
changeY=0-changeY;
changeX=0-changeX;
}
ballY+=changeY;
Memory=(double)ballY/250;
Memory=Math.asin(Memory);
Memory=Math.cos(Memory);
ballX=(int)(Memory*250);
if(changeX==-1)
ballX=0-ballX;
repaint();
try {
Thread.sleep(17);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillOval(ballX-radius+250, ballY-radius+250, radius*2, radius*2);
}
public void setChangeY(int changeY) {
this.changeY = changeY;
}
public void Done(){
S.setVisible(false);
Thread BallRun = new Thread(this);
BallRun.start();
}
}
JFrame:
public class Speed extends JFrame implements ActionListener{
private static final long serialVersionUID = 1L;
public Speed(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel P = new JPanel();
JLabel L = new JLabel("please enter velosity(pixels per second)");
final JTextField TF = new JTextField("00");
final Main M = new Main();
JButton B = new JButton("OK");
B.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
M.setChangeY(Integer.parseInt(TF.getText()));
M.Done();
}
});
P.add(L,BorderLayout.NORTH);
P.add(TF,BorderLayout.WEST);
}
#Override
public void actionPerformed(ActionEvent arg0) {
}
}
thanks (and sorry if it's bothering you the lack of information)
Here are some things to consider:
Don't use a JFrame. Use a JDialog as a popup window. Also, you should probably not create the dialog in the constructor. Instead you should have a JMenuItem so that the user can click on the menu when they want the popup to display.
Don't use "Applet", that is an AWT component. You should be using "JApplet" in a Swing application.
You should not be overriding the paint() method of the applet. Instead you should be adding a JPanel to the applet and then override the paintComponent(...) with your custom painting.
Don't use a loop to control the animation. Instead you should be using a Swing Timer.
Start by reading the Swing tutorial. There are sections on:
How to Make Applets
How to Use Swing Timers
Performing Custom Painting
setDefaultCloseOperation(EXIT_ON_CLOSE);
This is not allowed even in a fully trusted applet. Closing the frame would close the JVM that runs the applet that launched it. That JVM might also be running other applets.
Look at it like this. The web page that hosts an applet is like a guest, while the web page is a guest house. For an applet to end the JVM is like the guest burning down the guest house while smashing out all the windows.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
Might 'work' (to not produce an AccessControlException), but really, no applet should be launching frames. Use a JDialog instead.
As a general tip: Ensure the Java Console is configured to show for applets & JWS apps. If there is no output at the default level, raise it and try again. Without the information contained in it, I doubt it would be possible to successfully develop an applet.
Your Speed class extends JFrame, but the only things that you set is setDefaultCloseOperation(EXIT_ON_CLOSE), you should set at least se size of your JFrame with setSize(width, height) and set it visible with: setVisible(true).
Another thing... i can't see where you added your JFrame to the Main class...
You should add it creating a new Speed object: Speed objectname = new Speed()
If i've understood correctly that was your problem.
I think you could read here to learn how to use the JFrame: http://www.dreamincode.net/forums/topic/206344-basic-gui-in-java-using-jframes/

Making custom close and minimize button

I have a decorated JFrame. I need to make close button and minimize button. What should I do?
Here is my code snippet:
public Startup()
{
setTitle("STARTUP");
setSize(800,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUndecorated(true);
setLocationRelativeTo(null);
setVisible(true);
}
Your approach is very unique and will look quite good. There are many ways to solve your problem. Now, as per your request, you want a CLOSE and a MINIMIZE button. Let us make the following Actions.
private final Action exitAction = new AbstractAction("Exit")
{
#Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
};
private final Action minimizeAction = new AbstractAction("Minimize")
{
#Override
public void actionPerformed(ActionEvent e)
{
setState(JFrame.ICONIFIED);
}
};
Now, let us apply the above actions to JButtons:
JButton closeButton = new JButton(exitAction);
JButton miniButton = new JButton(minimizeAction);
There you have it. Now, all you need to do is add your buttons to your JFrame.
Note For Eclipse Users
this code will come in your minimize button when You click On minimize button in Eclipse.
YourFrameName is the Frame name you had set or it is set by default, use that frame name here:
YourFrameName.setState(YourFrameName.ICONIFIED);

Passing values between JFrames

I have two Jframes where frame1 has some text fields and when a button on frame1 is clicked, I open another JFrame which contains a search box and a JTable containing search results.
When I click on a result row on JTable, I want that particular values to be reflected in the frame1 text fields.
I tried passing the JFrame1's object as a parameter but I have no clear idea on how to achieve this.
Any help would be highly appreciated.
Thanks
First of all, your program design seems a bit off, as if you are using a JFrame for one of your windows where you should in fact be using a JDialog since it sounds as if one window should be dependent upon the other.
But regardless, you pass references of GUI objects the same as you would standard non-GUI Java code. If one window opens the other (the second often being the dialog), then the first window usually already holds a reference to the second window and can call methods off of it. The key often is when to have the first window call the second's methods to get its state. If the second is a modal dialog, then the when is easy -- immediately after the dialog returns which will be in the code immediately after you set the second dialog visible. If it is not a modal dialog, then you probably want to use a listener of some sort to know when to extract the information.
Having said this, the details will all depend on your program structure, and you'll need to tell us more about this if you want more specific help.
For a simple example that has one window open another, allows the user to enter text into the dialog windows JTextField, and then places the text in the first window's JTextField, please have a look at this:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class WindowCommunication {
private static void createAndShowUI() {
JFrame frame = new JFrame("WindowCommunication");
frame.getContentPane().add(new MyFramePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// let's be sure to start Swing on the Swing event thread
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MyFramePanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton openDialogeBtn = new JButton("Open Dialog");
// here my main gui has a reference to the JDialog and to the
// MyDialogPanel which is displayed in the JDialog
private MyDialogPanel dialogPanel = new MyDialogPanel();
private JDialog dialog;
public MyFramePanel() {
openDialogeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openTableAction();
}
});
field.setEditable(false);
field.setFocusable(false);
add(field);
add(openDialogeBtn);
}
private void openTableAction() {
// lazy creation of the JDialog
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
dialog = new JDialog(win, "My Dialog",
ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
}
dialog.setVisible(true); // here the modal dialog takes over
// this line starts *after* the modal dialog has been disposed
// **** here's the key where I get the String from JTextField in the GUI held
// by the JDialog and put it into this GUI's JTextField.
field.setText(dialogPanel.getFieldText());
}
}
class MyDialogPanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton okButton = new JButton("OK");
public MyDialogPanel() {
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
okButtonAction();
}
});
add(field);
add(okButton);
}
// to allow outside classes to get the text held by the JTextField
public String getFieldText() {
return field.getText();
}
// This button's action is simply to dispose of the JDialog.
private void okButtonAction() {
// win is here the JDialog that holds this JPanel, but it could be a JFrame or
// any other top-level container that is holding this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose();
}
}
}
You'd do a very similar technique to get information out of a JTable.
And again, if this information doesn't help you, then please tell us more about your program including showing us some of your code. The best code to show is a small compilable example, an SSCCE similar to what I've posted above.

Categories

Resources