I've got a simple java swing code where a text field changes when the button is hovered over and clicked, but when i use a variable to deactivate the mouseExited event, it does not work and continues to change the text field. I think its to do with the variable only being available to the mouseClicked event? How would i fix this. Thanks
my imports are java.awt and javax.swing
public static void main(String[] args) {
boolean check = true;
JFrame f =new JFrame("ActionListener Example");
JTextField tf = new JTextField("You should press button 1");
tf.setBounds(100,100, 150,20);
JButton b=new JButton("Click Here");
b.setBounds(50,100,60,30);
//2nd step
b.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
tf.setText("you did it");
boolean check = false;
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
tf.setText("DO IT!");
}
#Override
public void mouseExited(MouseEvent e) {
if (check) {
tf.setText("You should press the button");
}
}});
f.setLayout(new FlowLayout());
f.setSize(400,400);
f.add(b);
f.add(tf);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
I think its to do with the variable only being available to the mouseClicked event? How would i fix this.
Then don't define a second "check" variable in the mouseClicked method.
//boolean check = false;
check = false;
Edit:
Local variable check defined in an enclosing scope must be final or effectively final
Start be rewriting your entire class to give it a better structure.
Read the section from the Swing tutorial on How to Use Buttons.... Download the ButtonDemo code and modify it.
The demo code will show you how to structure your code so that
all the code is NOT contained in the main() method:
you use layout managers
you create the GUI on the Event Dispatch Thread (EDT)
your class can use "instance" variables, instead of a local variable. You "check" variable will be an instance variable.
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 have some labels that become visible when the letter a is pressed.
private void formKeyPressed(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
if(evt.getKeyCode()==KeyEvent.VK_A){
jLabel7.setVisible(true);
jLabel8.setVisible(true);
jLabel9.setVisible(true);
myBlink();
}
I have Label8 on a timer myBlink()
public void myBlink()
{
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("begin");
jLabel8.setVisible(false);
jLabel8.setVisible(true);
System.out.println("Timer");
}
}).start();
}
I have placed printlns to see if timer begins and ends and when I press key "a" my output shows begin Timer multiple times but my label does not appear and disappear. What tweak does this code need? What am I missing? Thanks for the extra set of eyes.
This is probably because you call successively setVisible(false) and setVisible(true) which is done too fast to be seen, you should use a variable and modify its value any time the action of the Timer is called as next:
public void myBlink()
{
new Timer(1000, new ActionListener() {
boolean visible = true;
public void actionPerformed(ActionEvent e) {
jLabel8.setVisible(visible = !visible);
}
}).start();
}
Somehow I cannot access & close a JFrame with.dispose(), and it gives me a nullPointerException. Neither do I want to do a System.exit(0). How do I access the JFrame directly, is there a workaround to close the JFrame?
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
frame = new ScannerUI();
frame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
... (further down, and I cannot access the JFrame already, gives me a nullpointerexception)
btnBack.setBounds(400, 270, 80, 40);
panel.add(btnBack);
btnBack.setText ("BACK");
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//ScannerUI.DISPOSE_ON_CLOSE();
//frame.dispose();
//this.dispose();
//frame.setVisible(false);
//System.out.println ("dsakjf;dsalkhfsa;lklf");
//System.exit(0);
//JFrame test = ScannerUI.frame;
//test.dispose();
// p = false;
System.out.println ("asdfasfas");
System.exit(frame.dispose());
}
});
You could use the SwingUtilities method, getWindowAncestor, to help you get the window that holds the button and then call dispose on it:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
AbstractButton button = (AbstractButton) e.getSource();
Window window = SwingUtilities.getWindowAncestor(button);
window.dispose();
}
});
Another option is to get the enclosing object of the current class (if it is the JFrame). You can get this from within your anonymous inner class by using the class name, a period, followed by this, or for you: ScannerUI.this:
btnBack.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
ScannerUI.this.dispose();
}
});
You can also check out Closing an Application and use the ExitAction. This is a more generic solution that will simulate a user clicking the "X" on the window. In this case any WindowsListeners you have added to the frame will be invoked first before the window is closed.
May not be applicable in this case, but just something to think about.
I added an AWTEventListener to process grab event. So this listener just use sun.awt.SunToolkit.GRAB_EVENT_MASK
mark.
But This listener can not capture UngrabEvent. The tricky thing is, when a JComboBox popuped its menulist, it can capture this event.
I use the following code for testing.
Start the program, click on the empty area of the frame, click on the frame title. Then there should be an UngrabEvent. But the listener does not capture it.
Start the program, click on the combobox and make its menulist popuped. click on the
frame title. Then there should be an UngrabEvent. And the listener captures it.
It is very strange...Is there any relationship between UngrabEvent and JComboBox?
public class ComboboxLearn {
public static void main(String[] args) {
// TODO Auto-generated method stub
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
System.out.println(event);
}
}, sun.awt.SunToolkit.GRAB_EVENT_MASK);
JComboBox box = new JComboBox(new Object[] { "AAA", "BBB", "CCC" });
box.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
System.out.println(e);
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
System.out.println(e);// Set a breakpoint here
}
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
System.out.println(e);
}
});
JFrame f = new JFrame();
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(box);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(new Dimension(100, 100));
f.setVisible(true);
}
}
I sense you're experimenting; but generally, you shouldn't rely on Sun/Oracle's undocumented APIs.
I want a popup that will hide when the
mouse is pressed outside the popup but
not hide when the mouse is pressed on the popup.
Why not bring up a JDialog when you see isPopupTrigger() and hide it when you see it deactivating, as another window activates? The notion is discussed here.
Although trashgod's reasoning is understandable, it doesn't answer the question: What you are actually trying to do won't work because for the grab even to fire, you need to have a window grabbed: ((SunToolkit)Toolkit.getDefaultToolkit()).grab(someWindow);.
You could change your code as follows
class ComboboxLearn {
public static void main(String[] args) {
// TODO Auto-generated method stub
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
System.out.println(event);
}
}, sun.awt.SunToolkit.GRAB_EVENT_MASK);
JComboBox box = new JComboBox(new Object[] { "AAA", "BBB", "CCC" });
JFrame f = new JFrame();
box.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
System.out.println(e);
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
System.out.println(e);// Set a breakpoint here
//UNGRABBING WINDOW
((SunToolkit) toolkit).ungrab(f);
}
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
System.out.println(e);
//GRABBING WINDOW
((SunToolkit) toolkit).grab(f);
}
});
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(box);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(new Dimension(100, 100));
f.setVisible(true);
}
}
Then you will get your grab events but at the level you are working on you don't need them.
Then when would I need them?
Assuming you run into this nasty bug which although closed, I could still reproduce it, you need to implement your own popup mechanism. You did everything fine you attached your AWT listeners to close the popup whenever there is a click outside it but something is missing. You click everywhere and the popup disappears except on the window captions and outside your application! Shoot you think! How does JPopupmenu do it. And after you spend some time reading jdk code and trying various stuff, you realize that it's this undocumented event that does the trick.
I don't know the internals of this grab() method and I don't have time to investigate so there might be side effects not very obvious. Call it on your own risk.