I have two classes, GUI and Test.
In GUI, it has a JTextArea and a button. When the button is click, the method running() in Text is called. listener of the button is as follows:
public void actionPerformed(ActionEvent event){
if (event.getSource() == start) //start is the button
{
textArea.setText(" Testing starts!");
pane.updateUI();
new Text().running(this);
}
}
And the running() in class Text as follows:
public void running(GUI gui) {
gui.textArea.setText("clientIP IS:"+clientIP);
gui.pane.updateUI();
.......
}
When I click the start button in GUI, the running method in class Test is performed. However, the text in the textArea is updated after method running() is finished.
How can I update the text before the method is called?
Thanks very much!
You need to execute your update method in defendant thread. so try to wrap your logic with:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//update
}
});
Read more about Swing Concurrency
Related
I have added an action listener to the text field. When the btnReadString (Button Read String) is pressed the program should read what is on the text field and show on the JPanel. but nothing shows on the panel.
stringTextField.addActionListener(new ActionListener() {
public void stringTextField (java.awt.event.ActionEvent e) {
if(e.getSource()==btnReadString) //when the button is pressed
{
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
});
The functionality for the ActionListener should go in the actionPerformed method, as nothings calling the stringTextField method...
stringTextField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btnReadString) //when the button is pressed
{
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
}
});
But, based on the code, the ActionListener should be attached to the btnReadString and not the field, as the above logic will never result in anything been executed (as the source of the event will never be btnReadString)
btnReadString.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String stringParameter = stringTextField.getText(); //gets the text and puts it on this string called "stringParameter"
textPane.setText(stringParameter);//the JPanel is set to what is on the string.
}
});
I would suggest having a closer look at How to Write an Action Listener and How to Use Buttons, Check Boxes, and Radio Buttons for more details
You have added the ActionListener to the text field. So the event source is never going to be the button and hence, the code is never going to execute. What you want is to add the ActionListener to the JButton.
Also, the actionPerformed() is there for a reason. All your 'action' code goes inside this method.
So your code should look like this:
btnReadString.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String stringParameter = stringTextField.getText();
textPane.setText(stringParameter);
}
});
I want to create a JDialog where the text in the textfields is selected but only if the focus is gained from keyboard (TAB, CTRL+TAB). I have found several topics on this matter but had problems with implementing it.
Here is one which I was trying.
And my code:
public class Dialogg extends JDialog implements FocusListener, MouseListener {
private boolean focusFromMouse = false;
public Dialogg() {
JTextField tf1 = new JTextField("text1");
JTextField tf2 = new JTextField("text2");
tf1.addMouseListener(this);
tf2.addMouseListener(this);
tf1.addFocusListener(this);
tf2.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if (!focusFromMouse) {
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse = true;
}
}
#Override
public void focusLost(FocusEvent e) {
focusFromMouse = false;
}
#Override
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
}
It does not work as intended, it does not matter what is focus source the text always highlights. When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked code so the flag is not reset when it should. Any hints?
EDIT:
As suggested by M. Prokhorov I have deleted less relevant (for the question) lines from the code.Thank you.
EDIT 2:
I am trying to wrap focus listener as suggested by camickr. It looks like this now:
tf1.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (!focusFromMouse){
tf1.selectAll();
focusFromMouse=true;
}
}
});
}
public void focusLost(FocusEvent evt){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
focusFromMouse=false;
}
});
}
});
public void mouseClicked(MouseEvent e) {
focusFromMouse=true;
I am printing line after each event to see the action order and still mouseClicked happens last. What am I doing wrong?
EDIT 3:
OK, I have found a solution which fulfils requirements of my simple Dialog.
I could not find a way of doing this with use of invokeLater or EventQueue. Vladislav's method works but as I understand it restricts the user to only use the keyboard.
I have used the initial approach but I have added an auxiliary variable and few conditions which allow to pass the flag "unharmed" trough Events that should not change the flag at given moment. It may not be subtle or universal but works for my app. Here is the code:
public void focusGained(FocusEvent e) {
if(!focusFromMouse){
if (higlight){
JTextField tf = (JTextField) e.getComponent();
tf.selectAll();
focusFromMouse=false;
}
}
}
public void focusLost(FocusEvent e) {
if (focusFromMouse){
higlight=false;
focusFromMouse=false;
}else{
higlight=true;
}
}
public void mousePressed(MouseEvent e) {
focusFromMouse=true;
}
At the first, by default, focus on JTextField is requested by mouse-press event, not by mouse-click.
So, this method:
public void mouseClicked(MouseEvent e) {
focusFromMouse = true;
}
is useless because the mouse-click event is triggered after the mouse-press event.
One way to solve your problem is to remove all native MouseListeners from JTextField:
...
for( MouseListener ml : tf1.getMouseListeners() ){
tf1.removeMouseListener(ml);
}
for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
tf1.removeMouseMotionListener(mml);
}
...
Another way is to handle all mouse events and consume those of them, which are triggered by JTextField:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if( event.getSource() == tf1 ){
((MouseEvent)event).consume();
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
When I run the code and follow it step by step it turns out that focusGained code happens before mouseClicked
Wrap the code in the FocusListener in a SwingUtilities.invokeLater(). The will place the code on the end of the Event Dispatch Thread (EDT), so the code will run after the variable in the MouseListener has been set.
See Concurrency in Swing for more information about the EDT.
Edit:
Just noticed the other answer. You might be able to do something simpler. Istead of listener for mouseClicked, listen for mousePressed. A mouseClicked event is only generated AFTER the mouseReleased event, so by that time the FocusListener logic has already been executed, even when added to the end of the EDT.
Edit 2:
If the above doesn't work then you might be able to use the EventQueue.peek() method to see if a MouseEvent is on the queue. This might even be easier than worrying about using the invokeLater.
I'm creating a java program that involves a button that gives a bunch of problems. I'm wondering how can I create a delay between the times a user can click a button (to prevent button spamming). Here is what I tried.
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
Thread DelayTHREAD = new Delay();
if(DelayTHREAD.isAlive()) {
/*do nothing*/
}
else {
/*some other code*/
DelayTHREAD.start();
}
}
public static class Delay extends Thread /*Prevents user from spamming buttons*/ {
#Override
public void run() {
try {
Thread.sleep(5000); /*sleeps for the desired delay time*/
}catch(InterruptedException e){
}
}
}
OK so here is the problem, it doesn't matter whether or not the delay thread is started or not, the program still goes on and continues to perform the action performed as if the delay thread never even existed.
Someone please tell me how can I create a delay, so that a user cannot spam button in a program? Thanks :)
You might just create a little method that disables the button for a period of time after the user clicks on it, and then enables it afterward, like so:
static void disable(final AbstractButton b, final long ms) {
b.setEnabled(false);
new SwingWorker() {
#Override protected Object doInBackground() throws Exception {
Thread.sleep(ms);
return null;
}
#Override protected void done() {
b.setEnabled(true);
}
}.execute();
}
Then call it from your actionPerformed method like this:
disable(button, 5000);
Just make sure you call it from the EDT.
Use a SwingTimer to inject a delay between the button click and the activation of the associated action....
import javax.swing.Timer;
/*...*/
private Timer attackTimer;
/*...*/
attackTimer = new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Do attack...
}
});
attackTimer.setRepeats(false);
/*...*/
public void ButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Restart the timer each time the button is clicked...
// In fact, I would disable the button here and re-enable it
// in the timer actionPerformed method...
attackTimer.restart();
}
in the program that I am writing at the moment, I have 2 JFrames (each in a different class, each has a different purpose, however you could consider the widget frame to be a slave of some sort), one is a main window, and the other is a 'widget' that pops up upon hitting a button in the main window.
I only want one copy of the widget open at one time. I am currently doing this through boolean variables under an actionPerformed action listener. Below is the action listener for the main window.
public void actionPerformed(ActionEvent e) {
if(getOpenWidget() == false){
System.out.println(getOpenWidget()); //test line
widget.initialize(); // please note that the instance "widget" is declared just after "public class MainWindow{" :)
widget.frame.setVisible(true);
setOpenWidget(true);
System.out.println(getOpenWidget() ); // test line
}else{
System.out.println(getOpenWidget());
JOptionPane.showMessageDialog(frame, "There is already an instance of the Booking Widget open.");
}
}
Now the booking widget is open, on the booking widget there is a cancel button. Below here is the action listener for the widget's 'cancel' button.
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
MainWindow ui = new MainWindow();
frame.dispose();
ui.setOpenWidget(false);
}
}
Now, upon hitting my button in the main window again, in theory, the openWidget bool should be false, and allow me to open another window, however in the cancel button action listener, my variable isnt changed. So, am I going about my problem in the right way without making openWidget a static variable?(I should be using getters and setters right?)
What am I doing wrong and what don't I understand about instantiating a new instance of the main window every time I click that button?
Also, my getters and setters are stock standard as follows.
void setOpenWidget(boolean val){
this.openWidget = val;
}
boolean getOpenWidget(){
return this.openWidget;
}
Just pass the reference of MainWindow to the Widget class so that it can update its flag on cancel button.
You are calling setOpenWidget(false) on some other new instance you have created using this line MainWindow ui = new MainWindow();
You should call setOpenWidget(false) using same instance from which you have initialised widget. Pass the reference of MainWindow to widget while creating widget and invoke setOpenWidget(false) using that reference
When you are creating the object of widget within MainWindow you can call it like this:
widget = new Widget(this);
And change the Widget Window Constructor as follows:
MainWindow ui;
public Widget(MainWindow mw)
{
this.ui = mw;
//...initialize btnCancel...
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
frame.dispose();
ui.setOpenWidget(false);
}
});
//..do all other stuffs here...
}
I'm making an App. in java , in which there is a Button to which I have added an actionlistener. The ActionEvent it(the button) generates executes some code. Now I want this piece of code to run whenever the app. starts and without pressing the button. I mean, I want to generate the Actionevent (without pressing the button) so that the piece of code the ActionPerformed contains gets executed as the app. start. After that, it may run whenever I press the button.
You can create ActionEvents like any other Java Object by just using the constructor. And then you can send them directly to the component with Component.processEvent(..)
However, in this case I think you are better making your code into a separate function which is called both:
By the ActionListener when the button is pressed
Directly by your application startup code (possibility using SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() if you need it to happen on the event-handling thread)
This way you don't mix up presentation logic with the business logic of whatever the code does....
Yes it can be done, but it doesn't really make sense, since your goal isn't to press a button or to call an ActionListener's code, but rather to have a common behavior on button press and on program start up. To me the best way to achieve this is to have a method that is called by both the actionPerformed method of the ActionListener and by the class at start up.
Here's a simple example. In the code below, a method disables a button, turns the JPanel green, and starts a Timer that in 2 seconds enables the button and resets the JPanel's background color to its default. The method that causes this behavior is called both in the main class's constructor and in the JButton's ActionListener's actionPerformed method:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionOnStartUp extends JPanel {
private static final int PANEL_W = 400;
private static final int PANEL_H = 300;
private static final int TIMER_DELAY = 2000;
private JButton turnGreenBtn = new JButton("Turn Panel Green for 2 seconds");;
public ActionOnStartUp() {
turnPanelGreen();
turnGreenBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
turnPanelGreen();
}
});
add(turnGreenBtn);
}
public void turnPanelGreen() {
setBackground(Color.green);
turnGreenBtn.setEnabled(false);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
setBackground(null);
turnGreenBtn.setEnabled(true);
((Timer) ae.getSource()).stop(); // stop the Timer
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_W, PANEL_H);
}
public static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ActionOnStartUp());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Usually, the button action event responds to an external event, to notify the application that the user (or rather something or someone) interacted with the application. If your button executes some code that you want to also execute at application start, why not just place everything at it's proper place?
Example:
public class SomeSharedObject {
public void executeSomeCode() { /*....*/ }
}
Set the button with something like
public void setButtonAction(final SOmeSharedObject obj) {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
obj.executeSomeCode();
}
});
}
And run at application start with something like
public void initApplication(SomeSharedObject obj) {
obj.executeSomeCode();
}
And, if the code you need to execute takes a while to complete, you might want to use a separate thread inside your actionPerformed button event so your application UI does not freeze up.
Just Call JButton.doClick() it should fire the ActionEvent associated with the JButton.