JFrame-JDialog comunication - java

I have a JFrame main window wich has a Register button on in.Click the register button and the JDialog windows pops out.
public void mouseClicked(MouseEvent e) {
Reg new1=new Reg(users);
new1.setVisible(true);
}
The JDialog window has 2 buttons->Register,Cancel.Both of them must do something and close the Dialog window.
This is what I tried.
In the Reg(Dialog window)---> btnCancel:
public void mouseClicked(MouseEvent e) {
dialog.dispose();
System.out.println("Reg disposed by cancel button");
}
This closes the D window when run just the D window but I guess when executed from the main window(Button clicked) it still exists like an object in the main fraim"class" and doesn't close.What should I do ?How do I make it close ?

You need some way for the frame to determine how the dialog was closed
// Why are you using a `MouseListener` on buttons??
// User use keyboards to, use an ActionListener instead
public void mouseClicked(MouseEvent e) {
Reg new1=new Reg(users);
new1.setVisible(true);
switch (new1.getDisposeState()) {
case Reg.OK:
// Clicked Ok
break;
case Reg.CANCEL:
// Clicked cancel or was closed by press [x]
break;
}
}
Then in your Reg class, you need to maintain information about the state...
public class Reg extends JDialog {
public static final int OK = 0;
public static final int CANCEL = 1;
private int disposeState = CANCEL;
//...
public int getDisposeState() {
return disposeState
}
public void setDisposeState(int state) {
disposeState = state;
}
Then you change the state
// Why are you using a `MouseListener` on buttons??
// User use keyboards to, use an ActionListener instead
public void mouseClicked(MouseEvent e) {
setDisposeState(CANCEL);
dialog.dispose();
System.out.println("Reg disposed by cancel button");
}
This all assumes that your dialog is modal of course...
Now, having said all that, personally, I would make your Reg class a JPanel and add it to a JOptionPane instead or use a CardLayout
Take a look at:
How to Use Buttons, Check Boxes, and Radio Buttons
How to Write an Action Listeners
How to Make Dialogs
How to Use CardLayout
...for more details

Related

How do I guarantee that a Java Swing JDialog will maintain focus and register all key presses in game?

I am making a game. It uses a jDialog because one Stack Overflow question said I had to use a modal jDialog to always be in focus. My jDialog has an outgoing chat field and a game window. The game window is a jPanel, the field a jTextField. When I press the arrow keys, I want that to go to the jPanel. When I type on the keyboard, I want that to go to the jTextField. When I press enter, I want the jTextField to clear. I do not want to click on the jTextField to make it in focus to type stuff in it and then click on the game screen to to move again.
My code looks like this:
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
jDialog_GUI.singleton_ = new jDialog_GUI(new javax.swing.JFrame(), true);
singleton_.requestFocusInWindow();
singleton_.setVisible(true);
singleton_.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
});
}
});
Constructor:
public jDialog_GUI(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents(); // initializes all the components using Swing GUI builder code
this.setModalityType(jDialog_GUI.ModalityType.APPLICATION_MODAL);
if (this.getModalityType() != jDialog_GUI.ModalityType.APPLICATION_MODAL) {
RunGame.printStackTraceAndCrashTheProgramBecause("Not modal.");
}
}
One of the other StackOverflow questions told me that if I use a jDialog and make it modal, then it will maintain focus, but when I do:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if(! jDialog_GUI.get_GUI().isFocusOwner() ) {
RunGame.printStackTraceAndCrashTheProgramBecause("JDialog must always be in focus.");
}
}
});
It crashes and prints "JDialog must always be in focus."
Even when I don't crash the program, none of the key presses will register in my jDialog's key listener.
addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
formKeyPressed(evt);
}
public void keyTyped(java.awt.event.KeyEvent evt) {
formKeyTyped(evt);
}
});
...
private void formKeyPressed(java.awt.event.KeyEvent evt) {
int keyCode = evt.getKeyCode();
System.out.println(keyCode + " " + KeyEvent.getKeyText(keyCode));
}
private void formKeyTyped(java.awt.event.KeyEvent evt) {
char c = evt.getKeyChar();
System.out.println(c);
}
...
Mouse presses register, and button presses register, but the key presses won't register. I even have a I want the focus to be on the frame and the frame to modify its components based on what keys are pressed rather than having one of the components hog all the key input from the other components. How do I fix this?
There is also a formWindowFocused listener that goes off when I run the program, but my jDialog's formFocusGained listener does not.
KeyEvents are dispatched to the component that has focus, so using a KeyListener is not a good solution.
For more flexibility in handling KeyStrokes you need to use Key Bindings. You can map a KeyStroke to an Action even when a component doesn't have focus.
Read the section from the Swing tutorial on How to Use Key Bindings for more information and examples.

Closing A JOptionPane Programmatically

I am working on a project in which I would like to close a generic JOptionPane programmatically (by not physically clicking on any buttons). When a timer expires, I would like to close any possible JOptionPane that may be open and kick the user back to the login screen of my program. I can kick the user back just fine, but the JOptionPane remains unless I physically click a button on it.
I have looked on many sites with no such luck. A doClick() method call on the "Red X" of the JOptionPane does not seem possible, and using JOptionpane.getRootFrame().dispose() does not work.
Technically, you can loop through all windows of the application, check is they are of type JDialog and have a child of type JOptionPane, and dispose the dialog if so:
Action showOptionPane = new AbstractAction("show me pane!") {
#Override
public void actionPerformed(ActionEvent e) {
createCloseTimer(3).start();
JOptionPane.showMessageDialog((Component) e.getSource(), "nothing to do!");
}
private Timer createCloseTimer(int seconds) {
ActionListener close = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane){
dialog.dispose();
}
}
}
}
};
Timer t = new Timer(seconds * 1000, close);
t.setRepeats(false);
return t;
}
};
This code gotten from
https://amp.reddit.com/r/javahelp/comments/36dv3t/how_to_close_this_joptionpane_using_code/ seems to be the best approach to me. It involves Instantiating the JOptionPane class rather that using the static helper methods to do it for you. The benefit is you have a JOptionPane object that you can dispose when you want to close the dialog.
JOptionPane jop = new JOptionPane();
jop.setMessageType(JOptionPane.PLAIN_MESSAGE);
jop.setMessage("Hello World");
JDialog dialog = jop.createDialog(null, "Message");
// Set a 2 second timer
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
dialog.dispose();
}
}).start();
dialog.setVisible(true);

How to "ignore/discard" Swing UI events when doing data validations on UI?

There's a text field and when lost focus it will validate the inputs, if not passed, print out the error message (to be simple here just has an empty check). And there's a button next to the text field, it will print out the text once click on it.
As I tried, when input some text and then click the button it will trigger both the focus lost event of text field and the event of button. In a other word, it will do the validation first and then print out the input text.
Here comes my question, what is the good approach to prevent printing out the text if the validation not passed? Or is there a way to "ignore" the click event on button if validation not passed?
I tried to use a boolean flag which indicate the validation result and check the flag when perform the action for button, but I do not think it is a good approach. As I know there's an event dispatcher thread in Swing which deal with the events, is it possible I can cancel the events from here?
Below is a piece of code which explain the question:
public class SimpleDemo
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = new JPanel(new FlowLayout());
frame.setContentPane(content);
final JTextField textField = new JTextField(10);
textField.addFocusListener(new FocusAdapter()
{
#Override
public void focusLost(FocusEvent e)
{
String text = textField.getText();
// do some validation here, if not validated
// do not trigger the event on button.
if ("".equals(text))
{
System.out.print("please input a text!");
}
}
});
content.add(textField);
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// action performed for button
String text = textField.getText();
System.out.println(text);
}
});
content.add(button);
frame.setVisible(true);
frame.pack();
}
}
I faces similar issue while working on an application. I solved it like below
I created a abstract class ApplicationFrame which every frame in the application extends
public abstract class ApplicationFrame extends JFrame implements ActionListener {
#Override
final public void actionPerformed(ActionEvent event) {
if(validateInput()){
performAction(event);
}
}
/*
* Sub class should override this method to receive any action
*/
protected void performAction(ActionEvent event) {};
/*
* Sub class should override this method to perform validation
*/
abstract protected boolean validateInput();
}
All Frames will now extend this base frame, as below:
public class Frame1 extends ApplicationFrame{
#Override
protected void performAction(ActionEvent event) {
// perform action
}
#Override
protected boolean validateInput() {
// return true or false depending upon the validation results
}
// if you want to add Action Listener, you need to add like this:
btnSomeButton.addActionListener(this);
}
If you need to handle Focus events, you can make ApplicationFrame or the base frame implement FocusListener.
This is my custom implementation to solve the problem, hope this helps.
Make the button disabled on start-up
Upon lost focus, validate the text & enable button only when the input passes validation.
Upon start of text change, disable the button
It's always makes sense to make ui to communicate with user. So you can show "please input a text" as the default text of the textField when nothing is entered by user.
Here is the code for such custom textField:
public class TextFieldWithDefaultText extends JTextField implements FocusListener{
private final String hint;
public TextFieldWithDefaultText (String $text)
{
super($text);
this.hint = $text;
addFocusListener(this);
}
#Override
public void focusGained (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText("");
}
}
#Override
public void focusLost (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText(hint);
}
}
#Override
public String getText ()
{
String typed = super.getText();
return typed.equals(hint) ? "" : typed;
}
}
Write the acttionListerner for your button like this:
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(!textField.getText().isEmpty())
System.out.println(textField.getText());
}
});
And ur textField implementation should be :
final TextFieldWithDefaultText textField = new TextFieldWithDefaultText ("please input a text");
Hope this helps :)

Detecting Approval button in a Swing FileChooser event

I know that there is another way to do this, but I prefer to see if anyone has an answer for doing it this way. The original way is to get the integer return value after calling the ShowDialog() function; I want to grab it from within the Event (shown below) itself. I've thrown some code in there to check if a file is selected, but I need to check whether the approval button (the OK button) has been selected before it gets there. Does anyone know how to check which button is pressed in a FileChooser dialog, using a setup like below?
Here's my code:
private void FileChooser_OpenMouseClicked(java.awt.event.MouseEvent evt) {
if(!FileChooser_Open.getSelectedFile().equals(null))
{
}
}
Original method:
//In response to a button click:
int returnVal = fc.showOpenDialog(aComponent);
The difference is that the original method gets a return value when the dialog box is closed, while in this method, I do not know of a way to get that return value (I believe the box has already closed, but there is nothing there to catch the return value). I apologize if I do not appear to be making a lot of sense.
edit: More information
So this is how I am creating the dialogue (a menu item, "Open" raises an event, which calls the showOpenDialog() method. As you can see, it is not capturing the return value (bear with me). Is it possible then to get the return value or at design a method to figure out whether the OK button is then pressed in the MouseClicked event? I guess I am trying to focus on an event-based programming style, where the code reacts according to the event raised, and grabbing the checking for the OK / approval button click inside the Open Menu event seems a little...disorganized from my perspective. Perhaps I am too used to C# / WinForm's approach to this problem?
private void MenuItem_OpenActionPerformed(java.awt.event.ActionEvent evt) {
FileChooser_Open.showOpenDialog(this);
}
private void FileChooser_OpenMouseClicked(java.awt.event.MouseEvent evt) {
if(!FileChooser_Open.getSelectedFile().equals(null))
{
}
}
If I understand the question, you might be able to use a JFileChooser#approveSelection() method:
OTN Discussion Forums : How to react on events fired by a JFileChooser?
java - JFileChooser with confirmation dialog - Stack Overflow
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class ApproveSelectionDemo {
public JComponent makeUI() {
final JPanel p = new JPanel();
final JFileChooser fileChooser = new JFileChooser() {
#Override public void approveSelection() {
if(!getSelectedFile().exists()) {
int returnVal = JOptionPane.showConfirmDialog(
this, "message", "title", JOptionPane.YES_NO_OPTION);
if(returnVal!=JOptionPane.YES_OPTION) {
return;
}
}
super.approveSelection();
}
};
p.add(new JButton(new AbstractAction("Open") {
#Override public void actionPerformed(ActionEvent e) {
int retvalue = fileChooser.showOpenDialog(p);
if(retvalue==JFileChooser.APPROVE_OPTION) {
System.out.println(fileChooser.getSelectedFile());
}
}
}));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new ApproveSelectionDemo().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}

How do I make non-modal dialog whose setVisible blocks?

In a Swing (J)Dialog, setModal sets the modality - that is, whether the dialog should block input to other windows or not. Then, setVisible docs say for modal dialogs:
If the dialog is not already visible, this call will not return until the dialog is hidden by calling setVisible(false) or dispose.
Indeed, setVisible does return right away if the dialog is not modal. Sample code:
JDialog jd = new JDialog();
jd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
/**
* If set to false, setVisible returns right away.
* If set to true, setVisible blocks until dialog is disposed.
*/
jd.setModal(false);
System.out.println("setting visible");
jd.setVisible(true);
System.out.println("set visible returned");
I want to make a dialog that doesn't block input to other windows, but still does block the caller. What is a good way to do this, now that setVisible doesn't block when the dialog is not modal?
Is there some rationale why setVisible's behavior depends on the modality?
I need to make a dialog that doesn't block input to other windows, but does block the caller so that I know when the dialog has been closed.
I usually solve this not by blocking the caller, but by using a callback of some sort - a simple interface that the dialog invokes when it's done. Let's say your dialog has an "OK" and a "Cancel" button and you need to distinguish which one is pressed. Then you could do something like this:
public interface DialogCallback {
void ok();
void cancel();
}
public class MyModelessDialog extends JDialog {
private final DialogCallback cbk;
private JButton okButton, cancelButton;
public MyModelessDialog(DialogCallback callback) {
cbk = callback;
setModalityType(ModalityType.MODELESS);
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onOK();
}
};
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onCancel();
}
};
// Treat closing the dialog the same as pressing "Cancel":
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
onCancel();
}
};
}
private void onOK() {
cbk.ok();
}
private void onCancel() {
cbk.cancel();
}
}
Then you just pass in an instance of DialogCallback to the constructor:
MyModelessDialog dlg = new MyModelessDialog(new DialogCallback() {
public void onOK() {
// react to OK
}
public void onCancel() {
// react to Cancel
}
});
EDIT
Is there some rationale why setVisible's behavior depends on the modality?
Well, that's just how how modal windows are supposed to work, no? A modal window should block the current workflow when displayed, and a non-modal/modeless should not. See e.g. the Wikipedia pages on modal windows or dialog boxes.
Just put this.setModal(true) but not set the parent dialog on the constructor:
MyDialog dlg = new JDialog();
this.setModal(true);
When you call setVisible(true), it wont stop
The direct approach is by:
JDialog dialog = new JDialog(owner, ModalityType.DOCUMENT_MODAL);
I have found another way to do this. In the constructor of my progress bar, which extends javax.swing.JDialog, I added:
setModalityType(ModalityType.APPLICATION_MODAL);
I then overrode the setVisible method:
#Override
public void setVisible(boolean b) {
if (b) {
new Thread(new Runnable() {
#Override
public void run() {
showProgress();
}
}).start();
} else {
super.setVisible(false);
}
}
In the run(), you can see a call to showProgress(). This simply is:
public void showProgress() {
super.setVisible(true);
}
What happens here, is the setVisible() method of JDialog blocks. So I overrode it, and called setVisible() of the JDialog, in a thread. Resulting in it not blocking.

Categories