I am creating a popup JFrame that will have a message and yes/no buttons. I am using this method in 2 ways. In 1, the main program calls this method and in the other, this method is called directly after a previous JFrame is closed. This method works when being called form the main program, but when another JFrame calls it, the JFrame created in this method shows up completely blank and the GUI freezes. I cannot exit out of the JFrame, but I can move it. The freezing is a result of the Thread.yield because response is always null, but in what instances will the JFrame fail to be created properly?
Note: response is a static variable. Also when this JFrame is created by another JFrame, the original JFrame does not exit correctly. That JFrame has a JComboBox, and the selected option is frozen on the dropdown. When it does not call this method, it closes properly.
public static String confirmPropertyPurchase(String message)
{
response = null;
final JFrame confirmFrame = new JFrame("Confirm");
confirmFrame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent ev){
response = "No";
}
public void windowDeactivated(WindowEvent e) {
confirmFrame.requestFocus();
}
});
final JPanel confirmPanel = new JPanel();
final JButton yes = new JButton();
final JButton no = new JButton();
yes.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
response = "Yes";
confirmFrame.setVisible(false);
}
});
no.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0){
response = "No";
confirmFrame.setVisible(false);
}
});
final JLabel confirmLabel = new JLabel(" " + message);
yes.setText("Yes");
yes.setPreferredSize(new Dimension(100, 100));
no.setText("No");
no.setPreferredSize(new Dimension(100,100));
confirmFrame.add(confirmLabel, BorderLayout.CENTER);
confirmPanel.add(yes);
confirmPanel.add(no);
confirmFrame.add(confirmPanel, BorderLayout.AFTER_LAST_LINE);
confirmFrame.setPreferredSize(new Dimension(520, 175
));
confirmFrame.pack();
confirmFrame.setVisible(true);
while(response == null)
{
Thread.yield();
}
return response;
}
Again, you shouldn't be using a JFrame as a dialog. In fact your whole bit of code can be replaced with a simple JOptionPane. e.g.,
Component parent = null; // non-null if being called by a GUI
queryString = "Do you want fries with that?";
int intResponse = JOptionPane.showConfirmDialog(parent, queryString,
"Confirm", JOptionPane.YES_NO_OPTION);
myResponse = (intResponse == JOptionPane.YES_OPTION) ? "Yes" : "No";
System.out.println(myResponse);
And this:
while(response == null)
{
Thread.yield();
}
should never be called on the main Swing thread, the EDT or event dispatch thread. The reason the code works when it does is because you're calling this little bit above off of the EDT, but when you call it on the EDT it freezes the EDT and thus the entire GUI. Simply don't do it.
You can't do this, plain and simple. There's only one event thread, and while you're sitting in a loop waiting for somebody to click in your JFrame, you're tying up that thread such that no events can be handled.
Don't try to create your own dialog out of a JFrame -- use JOptionPane or a JDialog, which are designed to handle this situation for you internally.
Related
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.
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.
I'm trying to programmatically click a JButton, which is fine, the doClick() method works prefectly. The problem is that I want to be able to programmatically click whatever button is currently in focus.
I can programmatically give a button focus just fine with .grabFocus() (at least it would seem so) but for some reason .isFocusOwner() always returns false.
If the code is run you can visually confirm that the button 'b2' is indeed in focus, however both if(frame.getFocusOwner() instanceof JButton) and if(b2.isFocusOwner) return false.
The code below illustrates the problem I'm having.
I imagine I've missed something obvious, but any advice would be fantastic.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton b1 = new JButton("b1");
JButton b2 = new JButton("b2");
JTextField j1 = new JTextField(10);
b1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Push the button...");
}
});
b2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("...and let it go...");
}
});
panel.add(b1);
panel.add(b2);
panel.add(j1);
frame.add(panel);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
//// The two problems are below
// It looks like this does give 'b2' the focus, at least as far as the generated GUI is concerned
b2.grabFocus();
// First - Always returns false
if(frame.getFocusOwner() instanceof JButton) {
JButton focusedButton = (JButton) frame.getFocusOwner();
focusedButton.doClick();
System.out.println("In focus?");
}
else {
System.out.println("Apparently not");
}
// Second - Also always returns false
if(b2.isFocusOwner()) {
System.out.println("In focus...");
}
else {
System.out.println("Not in focus");
}
}
Not all code executes synchronously. Some code get added to the end of the Event Dispatch Thread (EDT). It appears that this is the case for focus requests. So when the if statements are executed, focus has not yet been placed on the component.
The solution is to wrap your code with a SwingUtilties.invokeLater() so the code gets added to the end of the EDT, so it can execute after the component has received focus:
//b2.grabFocus();
b2.requestFocusInWindow();
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// First - Always returns false
if(frame.getFocusOwner() instanceof JButton) {
JButton focusedButton = (JButton) frame.getFocusOwner();
focusedButton.doClick();
System.out.println("In focus?");
}
else {
System.out.println("Apparently not");
}
// Second - Also always returns false
if(b2.isFocusOwner()) {
System.out.println("In focus...");
}
else {
System.out.println("Not in focus");
}
}
});
Also, don't use grabFocus(), you should use requestFocusInWindow(). Read the API for more information.
I was reading about Swing Timers and the example really looks nothing like I was trying to do so I found it logically confusing to apply it to my program. I'm starting to think I don't even need a timer for this.
Here is what I am trying to do:
I am making a JFrame program that has the user enter a credit card number into a JTextField. Before they do this there is a JLabel that says "Please enter your number into the text field", then once they enter this into the field and hit enter, depending on whether my code determines that the card number is valid or not valid, the JLabel will change to "Invalid" or "Thank you, processing."
However, I have unsuccessfully found a way to make it change text based, it just seems to stay with whatever text I initially give it.
So could someone please look at my code and change it to do what I am asking? That would be excellent. You guys have been helpful in the past.
public class CreditGraphics {
public String cardNum;
public JFrame frame;
public JPanel panel;
public JLabel label;
public JTextField text;
public Timer timer;
public CreditGraphics() {
frame = new JFrame("HI");
panel = new JPanel();
label = new JLabel();
text = new JTextField(16);
panel.add(label);
panel.add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(500, 500));
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
label.setText("Hi");
label.setText("Hello");
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardNum = text.getText();
timer = new Timer(2000,this);
timer.setInitialDelay(1000);
timer.start();
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CreditGraphics();
}
});
}
public void checkCard(){
}
}
You have some major problems with your Timer's ActionListener as it is adding the anonymous inner ActionListener object, the this in the Timer's constructor, to itself. So it will call the very same actionPerformed inside the Timer that is called by the JButton that starts the Timer -- quite confusing. If your program were to need a Timer, you would do well to make sure to give it its own ActionListener, and not the same ActionListener that you add to your JButton as you're doing now.
Most importantly, do you even need a Swing Timer? I don't think so since you don't appear to be wanting an action repeatedly happening every xxx milliseconds, or an action that occurs once after xxx milliseconds, and since all you want to do is change the text. I suggest that instead you simply change your JLabel's text in the anonymous inner ActionListener class, and just leave it at that. If your requirements are different, then you will want to clarify and expand on your question.
So in semi-pseudocode, something like:
public void actionPerformed(ActionEvent e) {
String userText = text.getText();
if (testIfTextValid(userText)) { // some method to test if input OK
label.setText(INPUT_VALID); // String constant for JLabel to display
// here pass the userText to other parts of your code that needs to use it
} else {
label.setText(INPUT_INVALID);
}
}
I just get stuck with app. The thing is in second actionListener, I want to get object or more specifically access to methods in my JDialog class.
I got few dialogs created, but not visible. In first actionListener I get to them by getDialog function which is returning JDialog. So I can each one of them visible.
2nd actionListener which I need help with, is showing JOptionPane and if user pick the YES_OPTION I want to run my method from specific dialog.
I it's not clear I'd try to fix my explanations so you can understand it.
modifyButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton thisButton = (JButton) e.getSource();
JPanel parentPanel = (JPanel) thisButton.getParent();
Container topLevel = parentPanel.getTopLevelAncestor();
MainFrame mainFrame = (MainFrame) topLevel;
mainFrame.getDialog(TABLECOUNTER).setVisible(true);
}
});
abortButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object[] options = {"Tak", "Nie"};
int userReply = JOptionPane.showOptionDialog(null, "Czy na pewno chcesz anulować rachunek?", "Probujesz anulować rachunek!", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
if (userReply == JOptionPane.YES_OPTION) {
JButton thisButton = (JButton) e.getSource();
JPanel parentPanel = (JPanel) thisButton.getParent();
Container topLevel = parentPanel.getTopLevelAncestor();
MainFrame mainFrame = (MainFrame) topLevel;
mainFrame.getDialog(TABLECOUNTER).myMethod(); //here
}
}
});
"I want to get object or more specifically access to methods in my JDialog class"
If the method getDialog returns a standard JDialog,
public JDialog getDialog(...) {}
Then you're stuck with the methods of JDialog, without proper casting, or changing the return type. That would explain why you are able to setVisible in the first method, because JDialog does have a method setVisible. So to access the method myMethod you'll want to do some casting.
((MyDialog)mainFrame.getDialog(TABLECOUNTER)).myMethod();