I have a JSpinner with SpinnerDateModel. I want when users click on any part of the editor (the date, month, or year), it will automatically select them. So I wrote this:
JSpinner dateSpn = new JSpinner();
dateSpn.setModel(new SpinnerDateModel());
JSpinner.DateEditor editor = new JSpinner.DateEditor(dateSpn, "dd-MM-yyyy");
dateSpn.setEditor(editor);
JFormattedTextField field = editor.getTextField();
field.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
int i = field.getCaretPosition();
if (i <= 2) {
field.select(0, 2);
} else if (i >= 3 && i <= 5) {
field.select(3, 5);
} else if (i >= 6){
field.select(6, 10);
}
}
});
But when the first time it clicked, nothing happened. Although when I click it again, it works perfectly. Where's wrong with my code?
From the documentation of MouseAdapter#mousePressed():
Invoked when a mouse button has been pressed on a component.
Which means this is executed when the mouse has only been pressed (not yet released mind you). So this is the first of the clicked / pressed / released methods to be invoked.
The issue you are having then is, that at this point in time, when mousePressed is invoked, your JFormattedTextFields caret position might not have been correctly updated yet. Hence the issue you are encountering.
The solution is to switch to mouseClicked() (or mouseReleased() as an alternative), because at that point, you can be sure that your JFormattedTextField has been updated correctly and the invoked method gets the correct value.
Related
I have a JInternalFrame, where I wanted to display a JOptionPane when my JTable was double clicked. I looked around in the internet and found that the only way of doing it was to override mousePressed() method and this is how I did it:
tblJobs.addMouseListener (new MouseAdapter() {
#Override
public void mousePressed (MouseEvent e) {
JTable tbl = (JTable)e.getSource();
int row = tbl.rowAtPoint(e.getPoint());
if (e.getButton() == MouseEvent.BUTTON1 && row != -1) {
if (e.getClickCount() == 2) {
JOptionPane.showMessageDialog(null, "Double click detected");
}
}
}
});
The thing is, I also have a button to hide the frame, and when the frame was hidden and re-shown, I found that upon double clicking my JTable, the JOptionPane got displayed twice. The number of times the JOptionPane got displayed seemed to increase along with the number of times I hid and show the frame. My guess is, the mouseListener got called again and again when I hide and re-show my frame. Is there a way of removing the mouseListener that was added in this way? Or is there another way to stop the JOptionPane from displaying more than once? And also, if what my code was stupid in any way, feel free to tell me! :) Thanks in advance!
How about setting a Boolean calss variable hidden = true when you hide, hidden = false when you unhide ?
Set the first line in mousePressed() to if(hidden) return;
Ok, I'm new to listeners (still learning the language), and this is my first full-scale attempt to implement them (ie more than just a practice problem in a textbook).
So far, everything is working fine except one big bug: the checkboxes don't stay checked. The ItemListener I assign them runs perfectly (I have a JOptionPane set up to trigger to let me know if it's working or not), but the box itself doesn't stay checked.
I went even further and added conditional logic for if it's state is checked versus unchecked, and found that when I click the box BOTH states get triggered. So I get both JOptionPane popups, the one with the message for if the box is checked and the one for if the box isn't checked.
I'm including my code here. What am I doing wrong?
PS. You'll notice that the code has conditional logic to either add a radio button or a checkbox. When the program finally runs, this component is generated in multiple locations in both formats. The radio button works fine, it's the checkbox ones that I'm having the above issue with.
CODE THAT CREATES THE CHECKBOXES AND ASSIGNS THE LISTENERS:
public OtherField(int voteFor){
this.voteFor = voteFor;
otherPanel = new JPanel();
otherPanel.setLayout(new GridLayout(1, 3));
otherField = new JTextField(10);
otherField.setHorizontalAlignment(SwingConstants.CENTER);
JLabel otherLabel;
otherLabel = new JLabel("Other", SwingConstants.CENTER);
otherRadio = new JRadioButton("", false);
otherRadio.setHorizontalAlignment(SwingConstants.CENTER);
otherRadio.addActionListener(new OtherFieldRadioListener());
otherCheckBox = new JCheckBox("");
otherCheckBox.setHorizontalAlignment(SwingConstants.CENTER);
otherCheckBox.addItemListener(new OtherFieldCheckBoxListener());
otherPanel.add(otherLabel);
otherPanel.add(otherField);
if(voteFor == 1){
otherPanel.add(otherRadio);
}else{
otherPanel.add(otherCheckBox);
}
}
LISTENER CODE (it's a private class in the same class as the code above):
private class OtherFieldCheckBoxListener implements ItemListener{
public void itemStateChanged(ItemEvent e){
String name = otherField.getText();
if(e.getStateChange() == ItemEvent.SELECTED){
JOptionPane.showMessageDialog(null, name);
}else{
JOptionPane.showMessageDialog(null, "Not Selected");
}
}
}
First thing I would try is to set the checkbox either to true or false when you initialize it, i.e
otherCheckBox.setSelected(false)
If this does not work I would check whether OtherField gets called from somewhere else everytime the checkbox is selected and thus the components are redrawn/ the selection is reset (use the debugger and set a breakpoint at the beginning of OtherFields)
I'm really struggling to find the functionality (if it even exists),
to move a JTextFields cursor by clicking a Button, instead of using the mouse.
For instance, I have my text field with a string added.
By clicking a back button, the cursor will move back through the string, 1 position at a time or forward depending on which button is pressed.
I can do it with the mouse, just click and type, but I actually need to have it button based so that the user can choose to use the keypad to enter a name or just click into the JTextArea and type away.
Is it possible? What methods should I look for if so.
Thank you.
These are sample buttons that are doing what you're asking for:
btnMoveLeft = new JButton("-");
btnMoveLeft.setFocusable(false);
btnMoveLeft.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
txtAbc.setCaretPosition(txtAbc.getCaretPosition() - 1); // move the carot one position to the left
}
});
// omitted jpanel stuff
btnmoveRight = new JButton("+");
btnmoveRight.setFocusable(false);
btnmoveRight.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
txtAbc.setCaretPosition(txtAbc.getCaretPosition() + 1); // move the carot one position to the right
}
});
// omitted jpanel stuff
They are moving the carot in the textfield txtAbc with 1 position per click. Notice, that you need to disable the focusable flag for both buttons, or the focus of your textfield will be gone if you click one of these buttons and you can't see the carot anymore.
To avoid exceptions if you're trying to move the carot out of the textfield boundaries (-1 or larger than the text length), you should check the new values (for example in dedicated methods):
private void moveLeft(int amount) {
int newPosition = txtAbc.getCaretPosition() - amount;
txtAbc.setCaretPosition(newPosition < 0 ? 0 : newPosition);
}
private void moveRight(int amount) {
int newPosition = txtAbc.getCaretPosition() + amount;
txtAbc.setCaretPosition(newPosition > txtAbc.getText().length() ? txtAbc.getText().length() : newPosition);
}
I am implementing minesweeper and I have a little problem with handling mouse events. I want actions to take place on mouseRelease (not mousePressed), so the user can change his mind after pressing a mouse button. There are three possible actions:
LMB released - reveal current field
RMB released - put a flag in current field
both LMB and RMB released - highlight or reveal adjacent fields
Actions are not really important, what I have problem with is how to trigger them.
In cases 1 and 2 no others buttons are down - this is easy to check.
The problem is that releasing both buttons results in two calls of mouseRelease method. If there is too large delay between both buttons releases I would prefer not to trigger an action. In other words, it should trigger only if both buttons were released at about the same time.
I can easily check that e.g. button 3 is down when button 1 is released, however it is not really helpful.
At the moment I have no other idea then storing a time when first button was released and then comparing it against the time when another button is released - and if the difference is small enough, trigger an action.
I do not really like an idea of playing with System.currentTimeMillis() or System.nanoTime() and I wonder whether there is a better way of doing it?
SOLUTION:
What has extremely simplified the problem was not allowing the user to drag a mouse pointer to another field (and hence changing the "selected" field). Delay between releasing both buttons does not matter. If the mouse pointer goes to another field, everything is cleared. Here is the code snippet:
private static final int B1DM = MouseEvent.BUTTON1_DOWN_MASK;
private static final int B3DM = MouseEvent.BUTTON3_DOWN_MASK;
private boolean bothWereDown = false;
#Override
public void mousePressed(MouseEvent e) {
// action if single button pressed
// in my case this is a sub-action of pressing both buttons
int both = B1DM | B3DM;
bothWereDown = (e.getModifiersEx() & both) == both;
if (bothWereDown) {
// action if both buttons pressed
}
}
#Override
public void mouseDragged(MouseEvent e) {
// some other code
if ( /* if pointer leaves field where mouse was pressed */) {
// some other code
bothWereDown = false;
// some other code
}
}
#Override
public void mouseReleased(MouseEvent e) {
// some other code
if (e.getButton() == MouseEvent.BUTTON1) {
if (bothWereDown) {
if ((e.getModifiersEx() & B3DM) != B3DM) {
// action if both released
}
} else {
// action if left button released
}
} else if (e.getButton() == MouseEvent.BUTTON3) {
if (bothWereDown) {
if ((e.getModifiersEx() & B1DM) != B1DM) {
// action if both released
}
} else {
// action if right button released
}
}
}
Obvious solution is to also track mouse presses. No need to play around with timeouts in this case, I think.
So pressing both buttons, then releasing one, will not count as release of single button. In fact, in your case, it would probably do nothing. Only when also other mouse button gets released, that will then count as releasing both buttons.
Edit: Actually, you do not even need to track mouse presses, though you probably want to give visual indication that button is pressed, and releasing it will have an effect. But when button is released, and you detect other is still pressed, just set a flag that half of two button release has happened, and single release of one button will then complete it. If flag is not set on single button release, then it's not part of two button action, and you do the single button release action instead.
By default MouseClicked event starts with one click. I have one in a JTextPane but I want to start with double click. Is it possible?
I believe you can extract the click count from the MouseEvent (assuming its called e)
Try this
if (e.getClickCount() == 2 && !e.isConsumed()) {
e.consume();
//handle double click event.
}
I don't think there will be a solution to this, since Java can run on non-pc devices.
Most portable devices don't support double-click.
You may keep track of the moment of each mouse click and fire your own "double-click" event. But I don't think this is a good idea.
private void jEditorPane3MouseClicked(java.awt.event.MouseEvent evt) {
if (evt.getClickCount() == 2 && !evt.isConsumed()) {
evt.consume();
System.out.println("Double Click");
}
}
You can override the mousePressed() or mouseReleased() methods and asking if e.getClickCount() == 2 , I recommend using the mousePressed() or mouseReleased() instead of mouseClicked() method since using those will give the user more time to perform the clicks.
You can compute the time lapsed between consecutive clicks. Compare it with a threshold value and decide yourself whether it is a double click or not.