I want to implement a method where the user needs to hold the left and right mouse buttons at the same time.
I'm using Swing and Java 1.7. I've tried this, but it doesn't detect the both-buttons case like I'd expect it to:
public void mousePressed(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e) && SwingUtilities.isRightMouseButton(e)){
///code here
}
}
i tried to separate methods and use bool values to decide if the mouse button is pressed and then i set a condition to find out if both of them are pressed at the same time , but that didint work out too ..
This is an SSCCE that does what you want... i.e. if I understood your question correctly.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class StackOverflow15957076 extends MouseAdapter
{
private JLabel status;
private boolean isLeftPressed;
private boolean isRightPressed;
public StackOverflow15957076 ()
{
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
JPanel panel = new JPanel (new FlowLayout (FlowLayout.CENTER));
status = new JLabel ("waiting for both mouse buttons...");
status.addMouseListener (this);
panel.add (status);
frame.add (panel);
frame.pack ();
frame.setVisible (true);
isLeftPressed = false;
isRightPressed = false;
}
#Override
public void mousePressed (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = true;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = true;
}
if (isLeftPressed && isRightPressed)
{
status.setText ("both buttons are pressed");
}
}
#Override
public void mouseReleased (MouseEvent e)
{
if (SwingUtilities.isLeftMouseButton (e))
{
isLeftPressed = false;
}
else if (SwingUtilities.isRightMouseButton (e))
{
isRightPressed = false;
}
status.setText ("waiting for both mouse buttons...");
}
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override
public void run ()
{
new StackOverflow15957076 ();
}
});
}
}
It seems that it's not possible do it directly, since mouse events are fired sequentially. See, for example, this SO question/answers.
So you will need to decide what "at the same time" actually means to you (i.e. how close in time thay should be). Then you can capture two separate events and compare their getWhen() values.
Related
I want to write a live search using Swing components. I am using a keyListener to keep track of the input. Basically i dont want the keyListener to take action every time a button is pressed but instead wait (for some period of time) for more incoming input. This period of time is refreshed every time a button is pressed and the input gets evaluated when it eventually times out (e.g. no button is being pressed within the period meaning that the input is complete). How do I implement that into my keyListener?
Code snippet of main method:
static JTextField nameTextField = new JTextField();
public static void main(String args[]) throws Exception {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(nameTextField, BorderLayout.NORTH);
nameTextField.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent keyEvent) {
//
}
#Override
public void keyPressed(KeyEvent e) {
//
}
#Override
public void keyReleased(KeyEvent e) {
if(waitForMoreInput(50)) {
doSomething(nameTextField.getText());
}
}
}
}
}
);
frame.setSize(250, 100);
frame.setVisible(true);
}
Thanks in advance
Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
The DocumentListener will register any time the text has changed, be it via a key press, via a copy and paste, via a deletion of text. The Timer will then wait however long you wish to do whatever action is required on the text. For example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
public class DocListenerFoo extends JPanel {
private JTextField nameTextField = new JTextField(20);
public DocListenerFoo() {
add(new JLabel("Add Text:"));
add(nameTextField);
int timerDelay = 1000; // one second
nameTextField.getDocument().addDocumentListener(new MyDocListener(timerDelay));
}
private class MyDocListener implements DocumentListener {
private Timer docTimer;
private int timerDelay;
public MyDocListener(int timerDelay) {
this.timerDelay = timerDelay;
}
#Override
public void changedUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
textChangedAction(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
textChangedAction(e);
}
private void textChangedAction(DocumentEvent e) {
Document doc = e.getDocument();
try {
String text = doc.getText(0, doc.getLength());
if (docTimer != null && docTimer.isRunning()) {
docTimer.stop();
}
docTimer = new Timer(timerDelay, new TimerListener(text));
docTimer.setRepeats(false);
docTimer.start();
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
}
private class TimerListener implements ActionListener {
private String text;
public TimerListener(String text) {
this.text = text;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO do check on text here
System.out.println("Checking text here: " + text);
}
}
private static void createAndShowGui() {
DocListenerFoo mainPanel = new DocListenerFoo();
JFrame frame = new JFrame("DocListenerFoo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Don't wait inside the key or document event, it just blocks the program from being processed further. Instead save the current time or (re)start a timer in the event and execute your action later somewhere else.
I'm guessing that you're trying to use a KeyListener with a Swing text component such as a JTextField (I have to guess since you don't tell or show us). If so, then the best solution is don't. Using a KeyListener with these components can mess up the functionality of the components. Much better is for you to use a DocumentListener or DocumentFilter, depending on if you want to listen before or after text has been fully registered with the text component.
For a better more complete answer, post a better more complete question, including your minimal code example and details about your problem.
I need to run a background thread in my Java GUI that only runs when I click a button and pauses when I click that button again. I am not exactly sure how to set this up, but I have placed a thread in my constructor and the while loop within is set to go through when I set a specific boolean to TRUE. One button switches from setting this boolean TRUE or FALSE.
Everything else I have in this GUI works fine. When I tried debugging the thread, it actually works as I step through the thread but nothing when I try running the GUI completely. The GUI is rather large so I'm gonna put up a portion of the constructor and the action listener of the button. The rest of the code is unnecessary since it works just fine. I need to know what I am doing wrong here:
public BasketballGUI() {
// certain labels and buttons
Thread runningSim = new Thread() {
public void run() {
while(simRun) {
// do stuff here
}
}
};
runningSim.start();
}
// other GUI stuff
// actionListener that should run the thread.
class SimButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
if(!simRun) {
simRun = true;
sim.setText("Pause Simulator");
}
else if(simRun) {
simRun = false;
sim.setText("Run Simulator");
}
// other stuff in this actionListener
}
}
Establish a Swing based Timer with an ActionListener that will be called repeatedly.
In the actionPerformed(ActionEvent) method call repaint().
Start the timer (Timer.start()) when the user clicks Start
Stop the timer (Timer.stop()) when the user clicks Stop
If you cannot get it working from that description, I suggest you post an SSCCE of your best attempt.
I thought I had one 'lying around'.. Try this working SSCCE which uses images created in this SSCCE.
I could see this background thread useful for a Java GUI when handling button events to affect something like a text area or progress bar.
For the sake of argument, I will build you a tiny GUI that affects a Text Area. I hope this helps you.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.*;
public class TestClass extends JPanel {
super("TestClass - Title");
private AtomicBoolean paused;
private JTextArea jta;
private JButton btn;
private Thread thread;
public TestClass() {
paused = new AtomicBoolean(false);
jta = new JTextArea(100, 100);
btn = new JButton();
initialize();
}
public void initialize() {
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
add(new JScrollPane(jta));
btn.setPreferredSize(new Dimension(100, 100));
btn.setText("Pause");
btn.addActionListener(new ButtonListener());
add(btn);
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
if(paused.get()) {
synchronized(thread) {
try {
thread.wait();
} catch(InterruptedException e) {
}
}
}
}
jta.append(Integer.toString(i) + ", ");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
};
thread = new Thread(runnable);
thread.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 30);
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
if(!paused.get()) {
btn.setText("Start");
paused.set(true);
} else {
btn.setText("Pause");
paused.set(false);
synchronized(thread) {
thread.notify();
}
}
}
}
}
Main class to call everything.
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainClass {
public static void main(final String[] arg) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestClass());
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
}
I did not test this code to see if it works exactly, Its main goal is to break you through your coders block and use my components to fix your issue. Hope this helped. Need anything else Email me at DesignatedSoftware#gmail.com
I'm trying to figure out how to make non-editable text (not a JTextField) whose background color changes when the mouse rolls over it. I tried using JButton implementing ActionListener and hiding elements to make the button appear to be just text, but it only allows me to change icons on rollover and detect when the button is clicked. Another thought was to use MouseListener and declare the specific coordinates of a rectangle around the text, where upon mouseMoved it could initiate the highlight. But w/ that there's a problem for varying string lengths and word wrap etc. What is the best object, and listener combo to achieve the effect of a highlighted text field on mouse rollover?
Hmm maybe use a foucs listener and when the field gains foucs select all the text?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TextField extends JTextField {
public TextField(String text) {
super(text);
addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent fe) {
selectAll();
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField tf = new JTextField("normal field");
f.add(tf, BorderLayout.CENTER);
TextField ftf =
new TextField("funny text field");
f.add(ftf, BorderLayout.SOUTH);
f.pack();
f.setVisible(true);
}
});
}
}
EDIT:
Hmmm actually found an even better way with the above method you'd have to click on the textfield to gain focus, now i've used a thread to check when the mouse is over the components co-ordinates and then to highlight the field, I used a boolean to control the highlighting as constant highlighting throws an error. Hope this is what you want:
import java.awt.*;
import javax.swing.*;
public class TextFieldHighlight extends JTextField {
static JTextField ftf;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ftf = new JTextField("Highlight");
ftf.setEditable(false);
f.add(ftf, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
Thread thread = new Thread(new Runnable() {
boolean focused = false;
#Override
public void run() {
while (true) {
if (mouseIsOverDisplayPanel()) {
if (ftf.hasFocus() && focused == false) {
ftf.selectAll();
focused = true;
} else if (!ftf.hasFocus()) {
focused = false;
}
}
}
}
});
thread.start();
}
});
}
private static boolean mouseIsOverDisplayPanel() {
if (MouseInfo.getPointerInfo().getLocation().x >= ftf.getLocationOnScreen().x
&& MouseInfo.getPointerInfo().getLocation().x <= ftf.getLocationOnScreen().x + ftf.getWidth()
&& MouseInfo.getPointerInfo().getLocation().y >= ftf.getLocationOnScreen().y
&& MouseInfo.getPointerInfo().getLocation().y <= ftf.getLocationOnScreen().y + ftf.getHeight()) {
return true;
} else {
return false;
}
}
}
On one of my programs, I want a Dialog to appear when the user attempts to exit the application. The user must then choose to save some state of the program, not to save or to cancel the exit operation.
I wrote this in an attempt to find a solution first and ony then implement it:
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.*;
class WL implements WindowListener
{
private boolean statussaved;
private JFrame tframe;
WL (JFrame frame)
{
statussaved = false;
tframe = frame;
}
#Override public void windowActivated (WindowEvent w) { }
#Override public void windowClosed (WindowEvent w) { }
#Override public void windowDeactivated (WindowEvent w) { }
#Override public void windowDeiconified (WindowEvent w) { }
#Override public void windowIconified (WindowEvent w) { }
#Override public void windowOpened (WindowEvent w) { }
#Override public void windowClosing (WindowEvent w)
{
if (statussaved)
{
return;
}
final JDialog diag = new JDialog (tframe, "Save Progress", true);
diag.setPreferredSize (new Dimension (500, 100));
diag.setResizable (false);
diag.setDefaultCloseOperation (JDialog.DISPOSE_ON_CLOSE);
JPanel notifypanel = new JPanel ();
notifypanel.add (new JLabel ("Do you want to save the current status ?"));
JButton yesbutton = new JButton ("Yes");
JButton nobutton = new JButton ("No");
JButton cancelbutton = new JButton ("Cancel");
yesbutton.addActionListener (new ActionListener ()
{
#Override public void actionPerformed (ActionEvent a)
{
//SAVE THE STATUS
System.out.println ("Saving status...");
statussaved = true;
diag.dispose ();
tframe.dispose ();
}
});
nobutton.addActionListener (new ActionListener ()
{
#Override public void actionPerformed (ActionEvent a)
{
//just exit/close the application
diag.dispose ();
tframe.dispose ();
}
});
cancelbutton.addActionListener (new ActionListener ()
{
#Override public void actionPerformed (ActionEvent a)
{
//DON'T EXIT !!!
diag.dispose ();
}
});
notifypanel.add (yesbutton);
notifypanel.add (nobutton);
notifypanel.add (cancelbutton);
diag.setContentPane (notifypanel);
diag.pack ();
diag.setVisible (true);
}
}
public class SaveTest
{
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
#Override public void run ()
{
JFrame frame = new JFrame ("Save Test");
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener (new WL (frame));
JLabel lab = new JLabel ("just some information");
frame.setPreferredSize (new Dimension (400, 300));
frame.setResizable (false);
frame.add (lab);
frame.pack ();
frame.setVisible (true);
}
});
}
}
It compiles and runs without any change, so you can test it.
The "Yes" and "No" choices work as expected, but I have absolutely no idea what to write in the ActionListener of the "Cancel" button. What I want is, when the user clicks the "Cancel" button, the dialog dissapears, but the main window remains visible (i.e. the program keeps running).
Now, since all this is implemented in the windowClosing method, it's kind of clear that some sort of dispose signal was sent in order to destroy the JFrame. This means that there is probably no way this can be done in the current design. I don't mind reorganizing/redesigning all this to make it work. It's just... I don't know how.
Any ideas ?
Replace
mainframe.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
with
mainframe.setDefaultCloseOperation (JFrame.DO_NOTHING_ON_CLOSE);
If user cancels closing - do nothing. If agrees - call dispose() manually.
Have a look at JOptionPane, which handles most of this stuff for you, e.g.
JOptionPane.showConfirmDialog(frame, "please choose one",
"information",
OptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.INFORMATION_MESSAGE);
Your DefaultCloseOperation needs to be DO_NOTHING_ON_CLOSE so that your dialog can handle things - otherwise the window will get disposed before the user can cancel it. Then you manually close the window or exit the application or whatever according to the user's choice.
I have made a multiple input dialog by building a JPanel with the fields I want and adding it to a JOption pane
JMainPanel mainPanel = new JMainPanel(mensaje, parametros, mgr);
int i = JOptionPane.showOptionDialog(null, mainPanel, "Sirena",
JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
new String[] {"Aceptar", "Cancelar"}, "Aceptar");
However I'm having trouble with the buttons, because some of the fields are required. How can I make the "Ok" button to be enabled once every required field is up, or making the click on the button to make the validations and do not close the pane until every required field is filled?
From the Java API, I found this:
options - an array of objects indicating the possible choices the user
can make; if the objects are components, they are rendered properly;
non-String objects are rendered using their toString methods; if this
parameter is null, the options are determined by the Look and Feel
So, can't I pass custom buttons as parameter?
Looks like I will have to make my own JDialog? for which case, I don't know how to make it return an int just like JOptionPane does, any recommended tutorial?
In the example options is {"Aceptar", "Cancelar"} which are the displayed buttons,
PS. I have full controll over the fields I added to the JPanel.
This is a screenshot of the JOptionPane:
I don't think that you can de-activate a JOptionPane's selections buttons, but one way to still use the JOptionPane is to simply re-display it if the required fields have not been set. You could display an error message JOptionPane first describing the error, and then display a new JOptionPane that holds the same JPanel as its second parameter -- so that the data already entered has not been lost. Otherwise, you may want to create your own JDialog which by the way isn't that hard to do.
Edit
I'm wrong. You can enable and disable the dialog buttons if you use a little recursion.
For example:
import java.awt.Component;
import java.awt.Container;
import java.awt.event.*;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
public class Foo extends JPanel {
private static final String[] DIALOG_BUTTON_TITLES = new String[] { "Aceptar", "Cancelar" };
private JCheckBox checkBox = new JCheckBox("Buttons Enabled", true);
private Set<AbstractButton> exemptButtons = new HashSet<AbstractButton>();
public Foo() {
JButton exemptBtn = new JButton("Exempt Button");
JButton nonExemptBtn = new JButton("Non-Exempt Button");
add(checkBox);
add(exemptBtn);
add(nonExemptBtn);
exemptButtons.add(checkBox);
exemptButtons.add(exemptBtn);
checkBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
allBtnsSetEnabled(checkBox.isSelected());
}
});
}
private void allBtnsSetEnabled(boolean enabled) {
JRootPane rootPane = SwingUtilities.getRootPane(checkBox);
if (rootPane != null) {
Container container = rootPane.getContentPane();
recursiveBtnEnable(enabled, container);
}
}
private void recursiveBtnEnable(boolean enabled, Container container) {
Component[] components = container.getComponents();
for (Component component : components) {
if (component instanceof AbstractButton && !exemptButtons.contains(component)) {
((AbstractButton) component).setEnabled(enabled);
} else if (component instanceof Container) {
recursiveBtnEnable(enabled, (Container) component);
}
}
}
public int showDialog() {
return JOptionPane.showOptionDialog(null, this, "Sirena",
JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
DIALOG_BUTTON_TITLES, "Aceptar");
}
private static void createAndShowGui() {
Foo foo = new Foo();
int result = foo.showDialog();
System.out.println(DIALOG_BUTTON_TITLES[result]);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This code uses listeners to check the state of a JCheckBox, but you can have listeners (DocumentListeners) listening to text field documents if you desire to know if they have data or not. The code then gets the JRootPane that holds the JCheckBox, then the root pane's contentPane, and all components of the dialog are held by this. It then recurses through all the components held by the dialog. If a component is a Container, it recurses through that container. If the component is an AbstractButton (such any JButton or checkbox), it enables or disables -- except for buttons held in the exempt buttons set.
A better example with document listeners
import java.awt.*;
import java.awt.event.*;
import java.util.HashSet;
import java.util.Set;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class Foo2 extends JPanel {
private static final String[] DIALOG_BUTTON_TITLES = new String[] {
"Aceptar", "Cancelar" };
private static final int FIELD_COUNT = 10;
private Set<AbstractButton> exemptButtons = new HashSet<AbstractButton>();
private JTextField[] fields = new JTextField[FIELD_COUNT];
public Foo2() {
setLayout(new GridLayout(0, 5, 5, 5));
DocumentListener myDocListener = new MyDocumentListener();
for (int i = 0; i < fields.length; i++) {
fields[i] = new JTextField(10);
add(fields[i]);
fields[i].getDocument().addDocumentListener(myDocListener);
}
// cheating here
int timerDelay = 200;
Timer timer = new Timer(timerDelay , new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
checkDocsForText();
}
});
timer.setRepeats(false);
timer.setInitialDelay(timerDelay);
timer.start();
}
private void checkDocsForText() {
for (JTextField field : fields) {
if (field.getText().trim().isEmpty()) {
allBtnsSetEnabled(false);
return;
}
}
allBtnsSetEnabled(true);
}
private void allBtnsSetEnabled(boolean enabled) {
JRootPane rootPane = SwingUtilities.getRootPane(this);
if (rootPane != null) {
Container container = rootPane.getContentPane();
recursiveBtnEnable(enabled, container);
}
}
private void recursiveBtnEnable(boolean enabled, Container container) {
Component[] components = container.getComponents();
for (Component component : components) {
if (component instanceof AbstractButton && !exemptButtons.contains(component)) {
((AbstractButton) component).setEnabled(enabled);
} else if (component instanceof Container) {
recursiveBtnEnable(enabled, (Container) component);
}
}
}
public int showDialog() {
return JOptionPane.showOptionDialog(null, this, "Sirena",
JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
DIALOG_BUTTON_TITLES, "Aceptar");
}
private class MyDocumentListener implements DocumentListener {
public void removeUpdate(DocumentEvent arg0) {
checkDocsForText();
}
public void insertUpdate(DocumentEvent arg0) {
checkDocsForText();
}
public void changedUpdate(DocumentEvent arg0) {
checkDocsForText();
}
}
private static void createAndShowGui() {
Foo2 foo = new Foo2();
int result = foo.showDialog();
if (result >= 0) {
System.out.println(DIALOG_BUTTON_TITLES[result]);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I suggest you to define some properties into your JPanel extended class, and use PropertyChangeListener to listen the occured changes and enable/disable relative buttons.
Here's an article.
Another issue maybe finding the ok/cancel buttons in the hierarchy of components, since the JDialog is created through JOptionPane and you haven't a reference to the buttons. Here's a useful thread .
You can add a property to a JComponent using putClientProperty method.
When changes occurs to a given property a PropertyChanged event is raised.
So in your example you can define a boolean property indicating that required that are inserted into the JDialog. Then add a PropertyChangeListener that when is notified enable/disable the ok button.