Unchecking checkbox does not undo command? - java

Its my first time programming checkboxes; I figured out how to make a checkbox appear, and do a command when checked. However, when the box is unchecked, instead of undoing the command, it instead does the command a second time. How can I undo the command when unchecking the box?
Code: (instantiation of checkboxes)
negA = new JCheckBox("Neg");
negA.addActionListener(this);
negA.setActionCommand("A-5");
tossupA = new JCheckBox("Tossup");
tossupA.addActionListener(this);
tossupA.setActionCommand("A10");
powerA = new JCheckBox("Power");
powerA.addActionListener(this);
powerA.setActionCommand("A05");
Command:
public void actionPerformed(ActionEvent e)
{
//get the String value from the button pressed
String result = e.getActionCommand();
char team = result.charAt(0);
//set text on screen to reflect new score
String screenText = "Team "+(team)+"'s total score for this tossup: ";
//add score to subtotal and show on screentext
if(team=='A'){
teamATempScore += Integer.parseInt(result.substring(1));
screenText += teamATempScore;
}
//and now for B
else if(team=='B'){
teamBTempScore += Integer.parseInt(result.substring(1));
screenText += teamBTempScore;
}
When the box is unchecked, I want the score to decrement by the amount that it was incremented, but instead the score just increments again :(
Thanks!
(yes, if you were wondering, this is a scorekeeping program for a game of Quizbowl) :D

The listener just checks to see if the checkBox was clicked -- It doesn't check if it went from unchecked to checked, or vice versa.
Use the .isSelected() method to determine whether the checkbox is checked or not after it becomes clicked.
For example:
if (negA.isSelected())
{
//the checkbox was checked after they clicked it, do something
}
else
{
//the checkbox was unchecked after they clicked it, do something else
}

You have to check the state of the control and then either increment or decrement. The compiler cannot auto generate the reverse of your code.
To check the state of the checkbox, you call the isSelected() method on it like in the example below.
import javax.swing.JOptionPane;
public class CheckboxExample extends javax.swing.JFrame {
private javax.swing.JCheckBox jCheckBox1;
public CheckboxExample() {
jCheckBox1 = new javax.swing.JCheckBox();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout());
jCheckBox1.setText("CheckMe");
jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
jCheckBox1ActionPerformed(evt);
}
});
getContentPane().add(jCheckBox1);
pack();
}
// this will get called when the state of the checkbox changes
private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {
if(jCheckBox1.isSelected()) {
JOptionPane.showMessageDialog(this, "Checked", "Message",
JOptionPane.INFORMATION_MESSAGE);
}
else {
JOptionPane.showMessageDialog(this, "Unchecked", "Message",
JOptionPane.INFORMATION_MESSAGE);
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new CheckboxExample().setVisible(true);
}
});
}
}

Related

How to add an action listener to JDialog Textfield in Java Swing?

I have a JDialog form in a Java Swing app. If the user enters valid inputs and clicks the Ok button, the data will save to the DB, but if not valid, a message box should display with the appropriate message, and then the dialog form should remain visible until the user clicks the Cancel button or entered valid input and clicks the OK button. I'm very new to Java Swing. Any sample code is highly appreciated.
Here is what I want to do:
private void saveOnOKCklicked() {
String string1ToValidate = textField1.getText();
String string2ToValidate = textField2.getText();
// here I want to do the validation for the Dialog box and the fields but not knowing how to start.
// Though I have read some documents online but do not fully understand how to do it.
}
This is what I have done so far: I want to call this method when the ok button is clicked.
private void onOk() {
name = nameTextField.getText();
inputToValidate = inputField.getText();
okClick = true;
dispose();
}
private ActionListener oKButtonClicked() {
return new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String checkInput = inputField.getText();
if (checkInput is valid){
continue with the process
}
else show a message box and dialog form remains visible
}
};
}
But this one only shows the message box if the input is not valid. but the dialog form closes when the message box's ok button is clicked. I want the dialog form to remain open until the input is valid before it closes when the ok button is clicked. please, help.
Complete runnable solution.
You're welcome.
public class MyDialog extends JDialog
{
public MyDialog()
{
txtField = new javax.swing.JTextField();
btn = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout());
txtField.setText("XXXXXXXXXXXX");
getContentPane().add(txtField);
btn.setText("OK");
btn.addActionListener(new java.awt.event.ActionListener()
{
public void actionPerformed(java.awt.event.ActionEvent evt)
{
btnActionPerformed(evt);
}
});
getContentPane().add(btn);
pack();
}
private void btnActionPerformed(java.awt.event.ActionEvent evt)
{
if (txtField.getText().equals("XXX"))
{
JOptionPane.showMessageDialog((Component)evt.getSource(),"Good input, closing.");
dispose();
}
else
{
JOptionPane.showMessageDialog((Component)evt.getSource(),"Bad input, correct please.");
}
}
public static void main(String args[])
{
MyDialog dialog = new MyDialog();
dialog.setVisible(true);
}
private javax.swing.JButton btn;
private javax.swing.JTextField txtField;
}

How can I prevent every click on the edit button from opening a JFrame to edit the selected row?

I am using 2 different classes: one holding a main JFrame with an edit JButton and one holding an edit JFrame that is called when the button is pressed.
First i select a row from a jtable for edit. After i press Edit button and a Jframe opens. If i press repeatedly the button, the same jframe are openning. So i want, after the first press of the button -> Jframe are openning and if i press again button I do not want to open the same frame again.
Here is a link with app image: https://ibb.co/gYfR9a
Here is my code for the Edit button:
JButton btnEdit = new JButton("Edit");
btnEdit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < table.getRowCount(); i++) {
Boolean chkDel = Boolean.valueOf(table.getValueAt(i, 0).toString());
if (chkDel) {
String id = table.getValueAt(i, 1).toString();
String num = table.getValueAt(i, 2).toString();
String pre = table.getValueAt(i, 3).toString();
String name = table.getValueAt(i, 4).toString();
String email = table.getValueAt(i, 5).toString();
EditFrame f = new EditFrame(Integer.valueOf(id), num, pre, name, email);
f.initFrame(Integer.valueOf(id), num, pre, name, email);
}
}
}
});
btnEdit.setBounds(150, 250, 90, 23);
getContentPane().add(btnEdit);`
And here is the code for the Edit Frame:
public class EditFrame extends JFrame {
private JPanel contentPane;
private JTextField idField;
private JTextField numField;
private JTextField preField;
private JTextField nameField;
private JTextField emailField;
private final JButton btnEdit = new JButton("Edit");
/**
* Launch the application.
*/
public void initFrame(int id, String num, String pre, String name, String email) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
EditFrame eframe = new EditFrame(id, num, pre, name, email);
eframe.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
In your actionPerformed method of your button you should memorize if it was already clicked by using a boolean. You can then do something like if(!wasClickedAlready) { ... }. However the boolean needs to be kept in the correct scope (one above the method). For example as member variable of your ActionListener or in the wrapping class, or something like this. Else the state of the boolean can not be memorized between method-calls.
For example see this snippet:
btnEdit.addActionListener(new ActionListener() {
private boolean wasClicked = false;
#Override
public void actionPerformed(ActionEvent e) {
if (wasClicked) {
// Do nothing if clicked already
return;
} else {
// The button was clicked for the first time
wasClicked = true;
}
for (int i = 0; i < table.getRowCount(); i++) {
// Your stuff
...
}
}
});
If your question refers to not opening a frame for the same table row again, then you need to memorize the rows you have already clicked, for example by using a table of boolean like boolean[] or a Map mapping the row-index to a boolean like HashMap<Integer, Boolean>. However the scheme remains the same. If that is the case, just tell me in the comments and I will show you another snippet.
Edit: You commented that you maximally one frame should be shown for each row, not for the whole table. As stated above you can apply the same scheme than before:
btnEdit.addActionListener(new ActionListener() {
private boolean[] wasClickedTable = new boolean[table.getRowCount()];
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < table.getRowCount(); i++) {
Boolean chkDel = Boolean.valueOf(table.getValueAt(i, 0).toString());
// A row should be processed
if (chkDel) {
// Lookup if row was already clicked before
if(wasClickedTable[i]) {
// It was, skip the row and do not process it
continue;
}
// The row was not clicked before
// However it is now, set it
wasClickedTable[i] = true;
// Further process the row
// Your stuff
...
}
}
}
});
I'm not sure if I understood correctly. So you have a button that opens a JFrame, but you don't want the JFrame to be opened every time the button is clicked? What is the expected behavior?

Input hint disappearing on mouseclick when component disabled

Thanks to the very helpful post by Bart Kiers in someone else's post, I have managed to get my input hints working. Hurray! Unfortunately I can't seem to get a small glitch to stop occurring.
During the normal course of operation, the HintTextFields are disabled and enabled to allow or disallow edits. The input hint should only show when the field is empty and not selected, but when I left click the boxes, even when disabled and containing text, the text disappears in favor of the hint. Then, when I click on something else, I lose the contents entirely.
I have added an extra bit to the if then statements regarding gaining and losing focus to prevent it from running that code if the component is disabled, but the problem still occurs. It must be some small interaction with the JTextField class (or maybe FocusListener?). I have also tried getParent() in favor of this in that clause, in case I was misunderstanding the 'this' keyword, but that didn't help. The class below:
class HintTextField extends JTextField implements FocusListener {
private final String hint;
private boolean showingHint;
public HintTextField(final String hint) {
super(hint);
this.hint = hint;
this.showingHint = true;
super.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
if(this.getText().isEmpty() && this.isEnabled()) {
super.setText("");
showingHint = false;
}
}
#Override
public void focusLost(FocusEvent e) {
if(this.getText().isEmpty() && this.isEnabled()) {
super.setText(hint);
showingHint = true;
}
}
#Override
public String getText() {
return showingHint ? "" : super.getText();
}
}
Original post if anyone wants to go upvote the wonderful Bart Kiers.
Java JTextField with input hint
Also, here is the initialization. This started as a JDeveloper gui.
startDateField.setHorizontalAlignment(javax.swing.JTextField.CENTER);
startDateField.setToolTipText(notes);
startDateField.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
startDateField.setMaximumSize(new java.awt.Dimension(2, 16));
startDateField.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
startDateFieldMouseClicked(evt);
}
});
private void startDateFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_startDateFieldMouseClicked
if (SwingUtilities.isRightMouseButton(evt)) {
editNote();
}
}
public void editNote() {
int selected = -1;
for (int a = 0; a < spinner.bitem.bldg.stallArray[1].length; a ++) {
if (spinner.bitem.bldg.stallArray[1][a].equals(stallName)) {
selected = a;
}
}
String oldNote = notes;
JTextField xField = new JTextField(oldNote);
xField.setPreferredSize(new Dimension(200,30));
JPanel myPanel = new JPanel();
myPanel.add(new JLabel("Note:"));
myPanel.add(xField);
int result =
JOptionPane.showConfirmDialog(this, myPanel, "Please enter note.",
JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
String note = xField.getText();
if (!note.equals(oldNote)) {
notes = note;
spinner.bitem.bldg.stallArray[9][selected] = notes;
spinner.bitem.master.sendNoteDataToSQL(spinner.bitem.bldg.buildingName, spinner.bitem.bldg.stallArray[1][selected], notes);
spinner.updateScreen();
}
}
}

ActionListener on JOptionPane

I am following the Oracle tutorial on how to create a custom dialog box: http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
I have two buttons: Save Object and Delete Object which when clicked should execute a certain piece of code. Unfortunately I can't seem to add any ActionListener to the JOptionPane buttons so when they're clicked nothing happens.
Can anyone help tell me how I can go about doing this? Here is the class I have for the dialog box so far:
class InputDialogBox extends JDialog implements ActionListener, PropertyChangeListener {
private String typedText = null;
private JTextField textField;
private JOptionPane optionPane;
private String btnString1 = "Save Object";
private String btnString2 = "Delete Object";
/**
* Returns null if the typed string was invalid;
* otherwise, returns the string as the user entered it.
*/
public String getValidatedText() {
return typedText;
}
/** Creates the reusable dialog. */
public InputDialogBox(Frame aFrame, int x, int y) {
super(aFrame, true);
setTitle("New Object");
textField = new JTextField(10);
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
//Create the JOptionPane.
optionPane = new JOptionPane(array,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.YES_NO_OPTION,
null,
options,
options[0]);
setSize(new Dimension(300,250));
setLocation(x, y);
//Make this dialog display it.
setContentPane(optionPane);
setVisible(true);
//Handle window closing correctly.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
/*
* Instead of directly closing the window,
* we're going to change the JOptionPane's
* value property.
*/
optionPane.setValue(new Integer(
JOptionPane.CLOSED_OPTION));
}
});
//Ensure the text field always gets the first focus.
addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent ce) {
textField.requestFocusInWindow();
}
});
//Register an event handler that puts the text into the option pane.
textField.addActionListener(this);
//Register an event handler that reacts to option pane state changes.
optionPane.addPropertyChangeListener(this);
}
/** This method handles events for the text field. */
public void actionPerformed(ActionEvent e) {
optionPane.setValue(btnString1);
System.out.println(e.getActionCommand());
}
/** This method reacts to state changes in the option pane. */
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (isVisible()
&& (e.getSource() == optionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
Object value = optionPane.getValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
//ignore reset
return;
}
//Reset the JOptionPane's value.
//If you don't do this, then if the user
//presses the same button next time, no
//property change event will be fired.
optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
if (btnString1.equals(value)) {
typedText = textField.getText();
String ucText = typedText.toUpperCase();
if (ucText != null ) {
//we're done; clear and dismiss the dialog
clearAndHide();
} else {
//text was invalid
textField.selectAll();
JOptionPane.showMessageDialog(
InputDialogBox.this,
"Please enter a label",
"Try again",
JOptionPane.ERROR_MESSAGE);
typedText = null;
textField.requestFocusInWindow();
}
} else { //user closed dialog or clicked delete
// Delete the object ...
typedText = null;
clearAndHide();
}
}
}
/** This method clears the dialog and hides it. */
public void clearAndHide() {
textField.setText(null);
setVisible(false);
}
I think you're missing the point of the JOptionPane. It comes with the ability to show it's own dialog...
public class TestOptionPane02 {
public static void main(String[] args) {
new TestOptionPane02();
}
public TestOptionPane02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JTextField textField = new JTextField(10);
String btnString1 = "Save Object";
String btnString2 = "Delete Object";
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
int result = JOptionPane.showOptionDialog(null, array, "", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, "New Object", options, options[0]);
switch (result) {
case 0:
System.out.println("Save me");
break;
case 1:
System.out.println("Delete me");
break;
}
}
});
}
}
To do it manually, you're going to have to do a little more work.
Firstly, you're going to have to listen to the panel's property change events, looking for changes to the JOptionPane.VALUE_PROPERTY and ignoring any value of JOptionPane.UNINITIALIZED_VALUE...
Once you detect the change, you will need to dispose of your dialog.
The you will need extract the value that was selected via the JOptionPane#getValue method, which returns an Object. You will have to interrupt the meaning to that value yourself...
Needless to say, JOptionPane.showXxxDialog methods do all this for you...
Now if you worried about having to go through all the setup of the dialog, I'd write a utility method that either did it completely or took the required parameters...but that's just me
UPDATED
Don't know why I didn't think it sooner...
Instead of passing an array of String as the options parameter, pass an array of JButton. This way you can attach your own listeners.
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
For the flexibility you seem to want you should have your class extend JFrame instead of JDialog. Then declare your buttons as JButtons:
JButton saveButton = new JButton("Save"); and add an actionListnener to this button:
saveButton.addActionListener();
either you can put a class name inside the parenthesis of the saveButton, or you can simply pass it the keyword 'this' and declare a method called actionPerformed to encapsulate the code that should execute when the the button is pressed.
See this link for a JButton tutorial with more details:
http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

Java Swing: Focus issue

I'm making a level editor for my game. I have a property panel where I can modify the selected object its properties. I also have a Save button to write the level xml.
A field-edit is submitted(*) when the editor component lost the focus or Enter is pressed. This is working great, but the only problem is that when I have this sequence of actions:
Edit a field
Press the save button
Because, what happens is this:
I edit the field
I press the save button
The level is saved
The field lost the focus
The edit is submitted
As you can see, this is the wrong order. Of course I want the field to lose its focus, which causes the submit and then save the level.
Is there a trick, hack or workaround to make the field first lose the focus and then perform the action listener of the save button?
Thanks in advance.
(* submit = the edit to the field is also made in the object property)
EDIT: For the field I'm using a FocusAdapter with focusLost:
FocusAdapter focusAdapter = new FocusAdapter()
{
#Override
public void focusLost(FocusEvent e)
{
compProperties.setProperty(i, getColor());
record(); // For undo-redo mechanism
}
};
And for the button a simple ActionListener with actionPerformed`.
btnSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
// Save the level
}
});
Hmm ... can't reproduce: in the snippet below the lost is always notified before the actionPerfomed, independent on whether I click the button or use the mnemonic:
final JTextField field = new JTextField("some text to change");
FocusAdapter focus = new FocusAdapter() {
#Override
public void focusLost(FocusEvent e) {
LOG.info("lost: " + field.getText());
}
};
field.addFocusListener(focus);
Action save = new AbstractAction("save") {
#Override
public void actionPerformed(ActionEvent e) {
LOG.info("save: " + field.getText());
}
};
save.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
JButton button = new JButton(save);
JComponent box = Box.createHorizontalBox();
box.add(field);
box.add(button);
On the other hand, focus is a tricky property to rely on, the ordering might be system-dependent (mine is win vista). Check how the snippet behave on yours.
If you see the same sequence as I do, the problem is somewhere else
if you get the save before the lost, try to wrap the the save action into invokeLater (which puts it at the end of the EventQueue, so it's executed after all pending events)
Action save = new AbstractAction("save") {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
LOG.info("save: " + field.getText());
}
});
}
};
Normally, wrapping your save code into an SwingUtilities.invokeLater() should do the trick. As you already mentioned, this doesn't work? Try this:
private boolean editFocus = false;
FocusAdapter focusAdapter = new FocusAdapter()
{
#Override
public void focusGained(FocusEvent e){
editFocus = true;
}
#Override
public void focusLost(FocusEvent e){
compProperties.setProperty(i, getColor());
record(); // For undo-redo mechanism
editFocus = false;
if (saveRequested){
save();
}
}
};
and for your button:
private boolean saveRequested = false;
btnSave.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if (editFocus){
saveRequested = true;
return;
} else {
save();
}
}
});
and then your save method:
private void save(){
// do your saving work
saveRequested = false;
}
This only works when your focusLost gets called after your button's action. If suddenly the order is correct, this code will get save() called twice.
But again, wrapping your save() code in your original approach should work, because the save code will execute after processing all events. That is after processing your button click and your focusLost events. Because your focusLost code executes immediately (it's not wrapped in an invokeLater()), the focusLost code should be executed always before your save code. This does not mean that the event order will be correct! But the code associated to the events will executed in the right order.

Categories

Resources