JComboBox returning double value - java

I started making a small application where the user is required to select their province from a combobox, I added an action listener to the combobox. I wanted to test the ActionListener so I just made it print what was selected to the console. For some reason it seems as though I am getting the value of the combobox returned twice. For example, I select "Alberta" on the combobox, "Alberta Alberta" is printed to the console. Anyone have any idea why this might be?
JComboBox comboProv = new JComboBox(provinces);
comboProv.setBounds(40, 79, 137, 24);
contentPane.add(comboProv);
comboProv.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
String selectedProv = (String)comboProv.getSelectedItem();
System.out.print(selectedProv);
}
});

You didn't add an ActionListener, you add a ItemListener, a ItemListener will be notified twice when the value changes, once for the ItemEvent.DESELECTED event and once for the ItemEvent.SELECTED.
If you're not interested in the change of selection simply use a ActionListener
comboProv.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String selectedProv = (String)comboProv.getSelectedItem();
System.out.print(selectedProv);
}
});
Which will only be notified once
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

put this inside the listener.. It printed twice because it is called for selected and deselected.. so add this to filter
if (e.getStateChange() == ItemEvent.SELECTED) {
String selectedProv = (String)comboProv.getSelectedItem();
System.out.print(selectedProv);.
} else if(e.getStateChange() == ItemEvent.DESELECTED){
//Do any operations you need to do when an item is de-selected.
}

Related

Jcheckbox always returnig false in Swing Java [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I am using Java and Swing, all I want to de is to test if the Jcheckbox is selected and if so adding its text to a list of Strings, the problem is that the isSelected fuction is always returning False even if the checkbox is selected.
Here is the code I wrote:
List<JCheckBox> checkBoxes = new ArrayList<JCheckBox>();
List<String> infos = new ArrayList<String>();
String sql = "select NAME from drugs ";
pre=con.prepareStatement(sql);
res=pre.executeQuery();
while(res.next()){
checkBoxes.add(new JCheckBox(res.getString("NAME")));
panel.add(new JCheckBox(res.getString("NAME")));
};
for (JCheckBox checkBox : checkBoxes) {
if (checkBox.isSelected()) {
infos.add(checkBox.getText());
}
}
Code in Java runs once through unless you write code in a loop. You're checking if the checkbox is selected instantly after they are created in the panel. The code is checking if your newly added check boxes are selected (which of course no one has clicked them yet) and then finishes. They are never checked again.
The solution will be to move this selection check into an event handler. But before we get there, you have a second error in your code.
while(res.next()){
checkBoxes.add(new JCheckBox(res.getString("NAME")));
panel.add(new JCheckBox(res.getString("NAME")));
};
The checkbox you add to your checkBoxes data structure and the checkbox you add to the panel are two different check boxes. Each time you use the new keyword in Java, you create a new independent object. In your case what you really need is to create 1 new checkbox, and put it in the panel, and also store it in your data structure.
The solution:
while(res.next()){
JCheckBox checkBox = new JCheckBox(res.getString("NAME"));
checkBoxes.add(checkBox);
panel.add(checkBox);
};
Now we can continue to create an event handler. An event handler will react to someone clicking the check box and run the code that checks the state of the check box to apply any changes. An event handler example to suit your needs can be coded as follows:
checkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
infos.add(checkBox.getText());
}
if (e.getStateChange() == ItemEvent.DESELECTED) {
infos.remove(checkBox.getText());
}
}
});
Now when we join the code with all the fixes we get:
while(res.next()){
JCheckBox checkBox = new JCheckBox(res.getString("NAME"));
checkBoxes.add(checkBox);
panel.add(checkBox);
checkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
infos.add(checkBox.getText());
}
if (e.getStateChange() == ItemEvent.DESELECTED) {
infos.remove(checkBox.getText());
}
}
});
}

Editable JCombobox avoid multiple DocumentEvents when the selection change from the popup

I have an editable JComboBox with a single listener on it.
It is a documentListener that execute some code when the user insert or remove some text inside the combobox textfield:
((JTextComponent)combobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(..)
My problem is that when the user select an element from the popup and the content of the combobox textfield changes there are two events executed into the documentListener, one is a removeUpdate() corresponding to the deletion of the previous content and the other is a insertUpdate() corresponding to the insertion of the new value.
I want that only one execution of my code is done and not two. How can I avoid that the code is executed two times when the user select an entry from the popup?
I tried various combination of different listener but for now without result.
What I want in the end is that my code is execute only one time when:
- The user change the text into the combobox textfield.
- The user select an element from the combobox popup
Thanks in advance.
[EDIT 1]
As requested I updated adding SSCCE
myCombobox = new javax.swing.JComboBox<String>();
myCombobox.setEditable(true);
((JTextComponent)myCombobox.getEditor().getEditorComponent()).getDocument().addDocumentListener(
new DocumentListener(){
#Override
public void insertUpdate(DocumentEvent e) {
System.out.println("insert performed");
}
#Override
public void removeUpdate(DocumentEvent e) {
System.out.println("remove performed");
}
#Override
public void changedUpdate(DocumentEvent e) {
System.out.println("change performed");
}
});
myCombobox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.SELECTED) {
System.out.println("Action performed");
}
}
});
Note that in this case I have an ItemEvent instead of an ActionEvent because I'm continuing to modify my code searching for a solution in any case the behavior should not be influenced by this.
You can check ((JTextComponent)combobox.getEditor().getEditorComponent()).hasFocus() to be sure user types in the editor.

Java Swing default focus on frame

I am learning java and Swing right now and trying to develop simple programms for education purposes.
So here is the question.
I have gridlayout and fields on my frame with default text
accNumberField = new JTextField("0", 10);
accNumberField.addFocusListener(new FocusListener() {
int focusCounter = 0;
#Override
public void focusGained(FocusEvent arg0) {
// TODO Auto-generated method stub
if (focusCounter > 0)
accNumberField.setText("");
focusCounter++;
}
What I want is that when user click on field for the first time the default text is disappered. So I add focus listener and used accNumberField.setText(""); in focusGained method.
But the problem is that for default first field in my frame getting focus right in time of frame creation. And default text is disappearing from the begining. I used counter as you can see. But that's not what I wanted.
I want that no field would get focus in time of creation and every field would be able to get focus from the time when user would click on one of them.
Sorry if I spelled something wrong. English is not my native language.
Found a thread having a code example of your desired functionality, Java JTextField with input hint. Precisely, you need to provide your own implementation of JTextField which will be holding the "default-text" in a field, specially created for that.
For your second question, you can set the focus to some button or frame itself.
Is there any reason that you use focusListener()? why not use mouseListener() as follow?
accNumberField.addMouseListener(new MouseAdapter()
{
#Override
public void mouseReleased(MouseEvent e)
{
accNumberField.setText("");
}
});
if you want to clear the text for the first click, you can simply use a boolean:
//outside constructor
private boolean isTextCleared = false;
//in constructor
accNumberField.addMouseListener(new MouseAdapter()
{
#Override
public void mouseReleased(MouseEvent e)
{
if (!isTextCleared)
{
accNumberField.setText("");
isTextCleared = true;
}
}
});

JTable won't listen to Doubleclicks

I´m trying to implement an undo (and redo) function for an editable JTable with the default components. The JTable has an extra class to specify its properties called SpecifiedJTable.
To do so I wanted to grab the moment when a cell is doubleclicked (i.e. the moment when a cell is chosen/marked to be edited) to push the information in the cell and its coordinates onto the stack.
This should be done by a MouseListener ...at least that was my idea.
I tried this (standing in the constructor of my SpecifiedJTable class)
class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
private int c; // the currently selected column
private int r; // the currently selected row
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
r = getSelectedRow();
c = getSelectedColumn();
// get the String at row r and column c
String s = (String) getValueAt(r, c);
if (jobDisplayed) jobSwitch(c, s);
else resSwitch(c, s);
}
});
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
}
});
}
}
but somehow the clickCounter doesn´t want to reach anything that´s higher than 1.
I am glad about any answer and help. Thanks.
The problem you are experiencing is related to use of mouseClicked() rather than using mousePressed(). In this case it appears to be very hard to increase the click counter, yet still it is possible. It took me lots of clicking and also mouse movement to increase the click counter over 1. You could try it by yourself, in your code. To get the counter over 1 you need to go crazy on the mouse by pressing & releasing fast while moving the mouse from cell to cell at the same time (or maybe I was just luckily clicking between the cells?).
As you can see in this fully working sample, made from your code, two mouse presses, using the mousePressed() method are being detected just fine.
public class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
}
});
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
System.out.println("e.getClickCount() = " + e.getClickCount());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanel panel = new JPanel();
panel.add(new JTableSpecified(new String[][]{{"oi", "oi2"}, {"oi3", "oi4"}}, new String[]{"Col1", "Col2"}));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setVisible(true);
}
});
}
}
Conclusion: Maybe you in fact want to use the mousePressed() method?
This answer extends Boro´s answer.
To catch every case that enables the user to edit the table I will also need to add a KeyListener for F2 (which has the same effect as double clicking onto a cell) and disable the automatic cell editing by pressing any key.
I just added it to the constructor right behind the mouseListener (see above)
// forbids the editing by striking a key
this.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
// keyListener to react on pressing F2 (key code 113)
this.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 113) System.out.println("test");
}
});
The BasicTableUI is responding to the double-click by going into an edit mode on the cell that was double-clicked. It does lots of complicated stuff, part of which involves creating a JTextField (or other component) to allow the data to be edited, and then preventing the mouse click event from propagating any further.
If your table, or that table cell, is not editable, you can easily capture mouse events with click count 2, 3, 4, .... But since you want your table to be editable, you need a different approach.
One idea would be to override JTable.editCellAt()
A better idea is to forget about messing with the JTable and instead listen for data changes on the table model itself.
the error in the code is that the mouseClicked method is called as soon as the first click takes place. when a double click takes place the mouseClicked method is called again. you can place a static variable (or a class variable) for the earlier click event storing the time (using the e.getWhen() method).
Check for the time difference and if it's small enough, execute your actions (I'd suggest calling a doubleClick method).
you may have to implement mouse listener in your class JTableSpecified since a static variable might not be placed in your existing code.

Using a JTextPane, consumed mouse events still propagate to caret updates/selection updates

I seem to be having a problem with JTextPane. I have extended JTextPane to render a floating image because the JTextPane icon functionality does not suit my purpose. I want the user to be able to click on the image, and have certain events performed. However, when I click on the image, even when I use evt.consume(), the caret and selection are updated in the JTextPane. I would like clicks and mouse events in general that interact with the image to not affect the caret position or selection at all. Relevant code:
public class JTextPaneImg extends JTextPane {
public JTextPaneImg(){
super();
addMouseListener(new java.awt.event.MouseAdapter() {
public void mousePressed(java.awt.event.MouseEvent evt) {
formMousePressed(evt);
}
public void mouseReleased(java.awt.event.MouseEvent evt) {
formMouseReleased(evt);
}
});
}
private void formMousePressed(java.awt.event.MouseEvent evt) {
if (imgBound.contains(evt.getPoint())) {
evt.consume();
//Do some stuff in here to interact with the image
// but the event still undesirably interacts with selection/caret
}
}
private void formMouseReleased(java.awt.event.MouseEvent evt) {
if (imgBound.contains(evt.getPoint())) {
evt.consume();
//Do some stuff in here to interact with the image
// but the event still undesirably interacts with selection/caret
}
}
}
I have even called getMouseListeners and verified that my own mouse listener is the last in the array, I read that listeners are called from highest to lowest index, meaning if my listener calls consume, it should be the last to act on the event. Why is my mouse click event still updating the caret then? Is this a problem with the Look and Feel?
I read that listeners are called from highest to lowest index, meaning if my listener calls consume, it should be the last to act on the event
This order is not guaranteed. All that is guaranteed is that all listeners will be notified. I believe it is up to each listener to check if the event is consumed. At least that is my understanding
You might be able to use a Global Event Dispatcher to prevent the event from being dispatched to the component. Just remember that all events go through the dispatcher so the code should be efficient so you don't slow down the queue.
Or you can use the technique presented on Mouse Wheel Controller which removes all the listeners from the components and replaces it with your custom listener. You can then decide when to forward the events to the other listener.
Or maybe your image should be painted on the viewport, not the text pane.
Resolved by creating my own caret. The issue was the DefaultCaret implementation does NOT check e.isConsumed on mouse events, so you must override and add the isconsumed check. My textpane behaves as intended now that I have the following code in the constructor:
this.setCaret(new DefaultCaret() {
#Override
protected void positionCaret(MouseEvent e) {
if (!e.isConsumed()) super.positionCaret(e);
}
#Override
protected void moveCaret(MouseEvent e) {
if (!e.isConsumed()) super.moveCaret(e);
}
});
This was my fault for not fully understanding the role of the Caret in the event model. But, if you ask me this is somewhat silly. From the documentation I have read, the convention is to have all listeners only act tangibly if !e.isConsumed().

Categories