I have a JPanel with multiple components in it - like a few JLabels, JTextBoxes, JComboBoxes, JCheckBoxes etc.
I want to display a pop up help window if the user hovers over these components for say 3 secs.
So far I added a MouseListener to one of my Components and it does display the required pop up and help. However I can't achieve it after 3 sec delay. As soon as the user moves the mouse to through that area of the component the pop up displays. This is very annoying as the components are almost unusable. I have tried using MouseMotionListener and having the below code in mouseMoved(MouseEvent e) method. Gives the same effect.
Any suggestion on how can I achieve the mouse hover effect - to display the pop up only after 3 sec delay?
Sample Code:(Mouse Entered method)
private JTextField _textHost = new JTextField();
this._textHost().addMouseListener(this);
#Override
public void mouseEntered(MouseEvent e) {
if(e.getSource() == this._textHost())
{
int reply = JOptionPane.showConfirmDialog(this, "Do you want to see the related help document?", "Show Help?", JOptionPane.YES_NO_OPTION);
if(reply == JOptionPane.YES_OPTION)
{
//Opens a browser with appropriate link.
this.get_configPanel().get_GUIApp().openBrowser("http://google.com");
}
}
}
Use a Timer in mouseEntered(). Here's a working example:
public class Test {
private JFrame frame;
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test test = new Test();
test.createUI();
}
});
}
private void createUI() {
frame = new JFrame();
JLabel label = new JLabel("Test");
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
startTimer();
}
});
frame.getContentPane().add(label);
frame.pack();
frame.setVisible(true);
}
private void startTimer() {
TimerTask task = new TimerTask() {
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JOptionPane.showMessageDialog(frame, "Test");
}
});
}
};
Timer timer = new Timer(true);
timer.schedule(task, 3000);
}
}
Related
I'm making a minesweeper game, and I want the user to be able to pick from beginner, intermediate, and advanced before playing the game. So far what I have is a JFrame that opens when I open the program with buttons for each difficulty.
Here are my main functions and the function to choose the difficulty. I'm wondering how I could still call all the functions in my main function after I call chooseGameDifficulty, because right now they're not being called.
public static void main(String[] args) {
chooseGameDifficulty();
game.initGame();
initBoard();
getClick();
while (gameOver == false) {
showUserTile();
checkGameWon();
}
}
public static void chooseGameDifficulty() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame chooseDifficulty = new JFrame("Minesweeper");
chooseDifficulty.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
chooseDifficulty.setPreferredSize(new Dimension(500,500));
chooseDifficulty.setLayout(new GridLayout(1, 3));
JButton B = new JButton("Beginner");
JButton I = new JButton("Intermediate");
JButton E = new JButton("Expert");
chooseDifficulty.add(B);
chooseDifficulty.add(I);
chooseDifficulty.add(E);
B.addMouseListener(
new MouseListener() {
public void mouseClicked(MouseEvent event) {
game.setGameDifficulty("Beginner");
chooseDifficulty.setVisible(false);
}
public void mouseExited(MouseEvent event) {
}
public void mouseEntered(MouseEvent event) {
}
public void mouseReleased(MouseEvent event) {
}
public void mousePressed(MouseEvent event) {
}
}
);
// same thing for the other buttons
chooseDifficulty.pack();
chooseDifficulty.setLocationRelativeTo(null);
chooseDifficulty.setVisible(true);
}
Do not exit on close as default operation on the choose difficulty frame.
I will advise you to use JDialog for choose difficulty popoup
I'm confused about how the Swing timer work. In the code below, I want to display from 0~9 every 400ms in the first text field when press START (once). After that the second text field will display "Finished".
public class Main extends JPanel{
private static final long serialVersionUID = 1L;
private JButton bStart;
private JTextField tTest;
private JTextField tNumber;
Main(){
bStart = new JButton("Start");
bStart.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
displayNumbers();
}
});
tTest = new JTextField(null, 30);
tNumber = new JTextField(" ", 30);
tNumber.setEditable(false);
this.setSize(300, 100);
this.add(bStart);
this.add(tNumber);
this.add(tTest);
}
public void displayNumbers(){
new Timer(400, new ActionListener() {
int i = 0;
public void actionPerformed(ActionEvent evt) {
if(i<10){
tNumber.setText(Integer.toString(i));
i++;
}
else
((Timer)evt.getSource()).stop();
}
}).start();
tTest.setText("Finished");
}
public static void createAndShowGUI(){
JFrame frame = new JFrame("test");
frame.add(new Main());
frame.setSize(400, 150);
frame.setVisible(true);
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
// TODO Auto-generated method stub
createAndShowGUI();
}
});
}
}
However, it first displays "Finished" before finishing displaying 0 ~ 9. I think the Swing timer works also in EDT, so "tTest.setText("Finished");" will be executed after timer thread. Why does not it work? How do I wait finishing displaying 0 ~ 9 then print "Finished"? Thanks!
Thanks for your answers. In fact what I want to ask is in general:
new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
doSomething();
}
}).start();
doOthers();
How to let doOthers() execute after all the doSomething()? (In some cases, we cannot put doOthers() inside actionPerformed function, as some answers mentioned).
The timer works concurrently. So the timer is started, then the text is set to finished, and then the timer fires and the first number appears.
To make the timer display finished after it is finished, put the tTest.setText("Finished"); in the else clause of if(i<10).
JFrames not displaying properly in loop.
Code:-
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class SwingDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run()
{
final JFrame jfrm= new JFrame("A Simple Swing Application");
final JFrame jfrm2= new JFrame("A Simple Swing Application 2");
jfrm.setSize(275,100);
jfrm.setLocation(100,100);
jfrm2.setLocation(50,50);
jfrm2.setSize(275,100);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfrm2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel jlab = new JLabel("Swing means powerful GUIs.");
jfrm.add(jlab);
JButton button0= new JButton("loop");
jfrm.add(button0);
jfrm.setLayout(new FlowLayout());
JLabel jlab2 = new JLabel("Swing means powerful GUIs again");
jfrm2.add(jlab2);
//jfrm2.setVisible(true);
jfrm.setVisible(true);
button0.addActionListener(new ActionListener() {
private boolean confirmAction;
#Override
public void actionPerformed(ActionEvent e) {
confirmAction = true;
if (confirmAction) {
try {
while(true)
{
jfrm.setVisible(false);
jfrm2.setVisible(true);
try{
Thread.sleep(15000);
}
catch(InterruptedException ie)
{
System.out.println("nothing");
}
jfrm2.setVisible(false);
jfrm.setVisible(true);
}
} catch (Throwable t) {
t.printStackTrace(System.out);
}
}
}
});
}
});
}
}
If the problem is that they are not updating correctly (this is my only thought since you didn't explain the issue), you should try to include these methods in the loop:
validate();
repaint();
If your issue is different, please inform us.
The method
#Override
public void actionPerformed(ActionEvent e) {
...
}
is executed in the EDT. Once you have implemented an infinite loop inside EDT it will stop processing any farther events and your GUI will stop responding.
A possible solution may be to start a timer and on every timer tick post relevant events to EDT, using SwingUtilities.invokeLater() or invokeAndWait():
Replace the contents of actionPerformed(ActionEvent e) with the following:
Timer timer = new Timer(15000, new ActionListener() {
boolean flip = false;
#Override
public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jfrm.setVisible(flip);
jfrm2.setVisible(!flip);
flip =! flip;
}
});
}
});
timer.start();
If a JFrame window is minimized, is there any way to bring it back to focus?
I am trying to get it to click a certain point, then restore it.
while (isRunning) {
start = System.currentTimeMillis();
frame.setState(Frame.ICONIFIED);
robot.mouseMove(clickX, clickY);
robot.mousePress(InputEvent.BUTTON1_MASK);
frame.setState(Frame.NORMAL);
Thread.sleep(clickMs - (System.currentTimeMillis() - start));
}
If you want to bring it back from being iconified, you can just set its state to normal:
JFrame frame = new JFrame(...);
// Show the frame
frame.setVisible(true);
// Sleep for 5 seconds, then minimize
Thread.sleep(5000);
frame.setState(java.awt.Frame.ICONIFIED);
// Sleep for 5 seconds, then restore
Thread.sleep(5000);
frame.setState(java.awt.Frame.NORMAL);
Example from here.
There are also WindowEvents that are triggered whenever the state is changed and a WindowListener interface that handles these triggers.In this case, you might use:
public class YourClass implements WindowListener {
...
public void windowDeiconified(WindowEvent e) {
// Do something when the window is restored
}
}
If you are wanting to check another program's state change, there isn't a "pure Java" solution, but just requires getting the window's ID.
You can set the state to normal:
frame.setState(NORMAL);
Full example:
public class FrameTest extends JFrame {
public FrameTest() {
final JFrame miniFrame = new JFrame();
final JButton miniButton = new JButton(
new AbstractAction("Minimize me") {
public void actionPerformed(ActionEvent e) {
miniFrame.setState(ICONIFIED);
}
});
miniFrame.add(miniButton);
miniFrame.pack();
miniFrame.setVisible(true);
add(new JButton(new AbstractAction("Open") {
public void actionPerformed(ActionEvent e) {
miniFrame.setState(NORMAL);
miniFrame.toFront();
miniButton.requestFocusInWindow();
}
}));
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new FrameTest();
}
}
I'm in the process of creating a GUI in Netbeans 6.1 for my senior design project but i've run into an annoying snag. Temporary Windows like my login PopUp and others wont disappear when i tell it. I've been researching how to solve this for about 2 months on an off. I've even mad a separate thread for my Pop Up but it still wont work....the only way it will disappear if i literally dont mess with any of the other GUI components....my sample code should help describe my anger...dont mind the shadow code, it was for testing purposes, which obviously didnt help.
//This method is called once a user presses the "first" login button on the main GUI
public synchronized void loginPopUpThread() {
doHelloWorld = new Thread(){
#Override
public synchronized void run()
{
try
{
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
System.out.println("waitin");
doHelloWorld.wait();
System.out.println("Not Sleepin..");
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(false);
}
catch (InterruptedException e)
{
}
}
};
doHelloWorld.start();
//This is called when the "second" loginB is pressed and the password is correct...
public synchronized void notifyPopUp() {
synchronized(doHelloWorld) {
doHelloWorld.notifyAll();
System.out.println("Notified");
}
}
I've also tried Swing Utilities but maybe i implemented it wrong as it's my first time using them. It essentially does the same thing as the code above except the window freezes when it gets to wait, which the above code doesnt do:
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public synchronized void run() {
try
{
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
System.out.println("waitin");
wait();
System.out.println("Not Sleepin.");
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(false);
}
catch (InterruptedException e)
{
}
}
});
PLEASE HELP ME!!!
Rules of thumb:
Don't manipulate GUI components in arbitrary threads; always arrange to manipulate them in the event thread
Never wait or sleep inside the event thread (so, never inside code sent to invokeLater())
So the answer to how you solve this problem is "some other way"...
Standing back from the problem a bit, what is it you're actually trying to do? If you just want a login dialog to wait for the user to enter user name and password, is there a reason not to just use a modal JDialog (after all, that's what it's there for...).
If you really do want some arbitrary thread to wait for a signal to close the window/manipulate the GUI, then you need to do the waiting in the other thread, and then make that thread call SwingUtilities.invokeLater() with the actual GUI manipulation code.
P.S. There are actually some GUI manipulation methods that it is safe to call from other threads, e.g. calls that are "just setting a label" are often safe. But which calls are safe isn't terribly well-defined, so it's best just to avoid the issue in practice.
The Swing components should only be manipulated by the swing event dispatch thread.
class SwingUtilites has methods to submit tasks to the dispatch thread.
It is difficult to diagnose your problem. I'm not sure what you're trying to do with the wait methods, but I recommend leaving wait/notify alone.
This code has two frames - when you create a second frame, the first is hidden until you close it.
public class SwapFrames {
private JFrame frame;
private JFrame createMainFrame() {
JButton openOtherFrameButton = new JButton(
"Show other frame");
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(openOtherFrameButton);
frame.pack();
openOtherFrameButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
onClickOpenOtherFrame();
}
});
return frame;
}
private void onClickOpenOtherFrame() {
frame.setVisible(false);
JFrame otherFrame = new JFrame();
otherFrame
.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
otherFrame.setContentPane(new JLabel(
"Close this to make other frame reappear."));
otherFrame.pack();
otherFrame.setVisible(true);
otherFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
frame.setVisible(true);
}
});
}
public static void main(String[] args) {
JFrame frame = new SwapFrames().createMainFrame();
frame.setVisible(true);
}
}
Because I don't see any evidence of them in your code, I'm going to suggest you read up on using event listeners rather than trying to "wait" for code to finish.
It isn't entirely clear what you're trying to achieve, but you might be better off with a modal dialog:
public class DialogDemo {
public JFrame createApplicationFrame() {
JButton openDialogButton = new JButton("Open Dialog");
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = frame.getContentPane();
container.setLayout(new FlowLayout());
container.add(openDialogButton);
frame.pack();
openDialogButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
onOpenDialog(frame);
}
});
return frame;
}
private void onOpenDialog(JFrame frame) {
JDialog dialog = createDialog(frame);
dialog.setVisible(true);
}
private JDialog createDialog(JFrame parent) {
JButton closeDialogButton = new JButton("Close");
boolean modal = true;
final JDialog dialog = new JDialog(parent, modal);
dialog
.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
Container container = dialog.getContentPane();
container.add(closeDialogButton);
dialog.pack();
dialog.setLocationRelativeTo(parent);
closeDialogButton
.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
}
});
return dialog;
}
public static void main(String[] args) {
new DialogDemo().createApplicationFrame().setVisible(
true);
}
}
How about doing simply:
//This method is called once a user presses the "first" login button on the main GUI
public void loginPopUpThread() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loginPopUpFrame.pack();
loginPopUpFrame.setVisible(true);
}
};
}
//This is called when the "second" loginB is pressed and the password is correct...
public void notifyPopUp() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loginPopUpFrame.setVisible(false);
}
};
}
What you really want to be using is a modal JDialog.
Note, bits of this are left out. It's your homework/project.
public void actionPerformed(ActionEvent e)
{
// User clicked the login button
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
LoginDialog ld = new LoginDialog();
// Will block
ld.setVisible(true);
}
});
}
public class LoginDialog extends JDialog
{
public LoginDialog()
{
super((Frame)null, "Login Dialog", true);
// create buttons/labels/components, add listeners, etc
}
public void actionPerformed(ActionEvent e)
{
// user probably clicked login
// valid their info
if(validUser)
{
// This will release the modality of the JDialog and free up the rest of the app
setVisible(false);
dispose();
}
else
{
// bad user ! scold them angrily, a frowny face will do
}
}
}