JTable add row after sorting bug - java

I have a JTable and it setAutoCreateRowSorter(true) so that I can sort the row. When I add a row to the table without using sorting, it works fine. But When I sort the table first, (just clicking the column title and rows will be sorted), then add a row to the table bugged.
I used tableModel.addRow(new Object[]{row,row}); to add a row, TableModelListener to listen the insert event. The bug is in the TableModelListener, which means I couldn't find the row I just added,
java.lang.ArrayIndexOutOfBoundsException: 3
Here's my SSCCE, it's a dialog with a table, clicking the button 'add' to Add a row to the table.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.GridLayout;
import javax.swing.JTable;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
public class MainTable extends JDialog {
private static final long serialVersionUID = 156332386872772726L;
private final JPanel contentPanel = new JPanel();
private DefaultTableModel tableModel;
private JTable table;
public static void main(String[] args) {
try {
MainTable dialog = new MainTable();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public MainTable() {
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new GridLayout(1, 0, 0, 0));
{
JScrollPane scrollPane = new JScrollPane();
contentPanel.add(scrollPane);
{
table = new JTable();
table.setAutoCreateRowSorter(true);
tableModel = new DefaultTableModel(new String[]{"first","second"},0);
table.setModel(tableModel);
tableModel.addTableModelListener(new TableModelListener(){
#Override
public void tableChanged(TableModelEvent arg0) {
if(arg0.getType() == TableModelEvent.INSERT){
int row = arg0.getFirstRow();
System.out.println(table.getValueAt(row, 0));//bug!! I couldn't find the row I added.
}
}
});
scrollPane.setViewportView(table);
}
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("Add");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int row = tableModel.getRowCount();
tableModel.addRow(new Object[]{row,row});//click button to add a row
}
});
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
}
}
}
What I tried
convert row index to model index doesn't work.
use tableModel.insert() instead tableModel.add(),doesn't work.

convert row index to model index doesn't work.
A TableModelListener is a listener for changes to the TableModel. So indexes in the TableModelEvent are relative to the TableModel.
System.out.println(table.getValueAt(row, 0));
Should be:
System.out.println(table.getModel().getValueAt(row, 0));
to get the data from the TableModel.
Or if you want to get the data from the JTable, then you need to use the convertRowIndexToView(...) method.

Related

How to disable JScrollBar when the JList inside JScrollPane does not fill entire area?

When the jlist only has a couple rows in it, I don't want the scroll bar to be able to scroll down because there is no need. Also, I am able to click on the empty rows, which highlights the row, even though it is empty. How can I disable the ability to highlight the row?
public ProductApplication()
{
//WEST PANEL
JPanel west = new JPanel(new BorderLayout());
west.setBorder(BorderFactory.createMatteBorder(
5, 5, 5, 5, Color.blue));
west.add(new JTextField("Products"),
BorderLayout.NORTH);
pList = new JList(product);
pList.setFixedCellHeight(20);
pList.setFixedCellWidth(100);
west.add(pList, BorderLayout.CENTER);
scrollpane = new JScrollPane(pList);
west.add(scrollpane, BorderLayout.WEST);
add(west, BorderLayout.WEST);
1) If you needn't to show JScrollBar just create JScrollPane like next :
JScrollPane jScrollPane = new JScrollPane(list);
jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
2) You can manage highlight ability with help of ListCellRenderer.
Try next example:
import java.awt.Component;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
public class TestFrame extends JFrame {
public TestFrame(){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
init();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
});
}
private void init() {
DefaultListModel<String> model;
JList<String> l = new JList<>(model = new DefaultListModel<>());
l.setFixedCellHeight(20);
l.setFixedCellWidth(100);
model.addElement("");
for(int i=0;i<5;i++){
model.addElement(i+"");
}
model.addElement("");
model.addElement("5");
l.setCellRenderer(getRenderer());
JScrollPane jScrollPane = new JScrollPane(l);
jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
add(jScrollPane);
}
private ListCellRenderer<? super String> getRenderer() {
return new DefaultListCellRenderer(){
#Override
public Component getListCellRendererComponent(JList<?> list,Object value, int index, boolean isSelected,boolean cellHasFocus) {
Component listCellRendererComponent = super.getListCellRendererComponent(list, value, index, isSelected,cellHasFocus);
if((value == null || value.toString().isEmpty()) && isSelected){
listCellRendererComponent.setBackground(list.getBackground());
((JComponent)listCellRendererComponent).setBorder(null);
}
return listCellRendererComponent;
}
};
}
public static void main(String... s){
new TestFrame();
}
}

JTable autoscroll methods are one row too high

Here is an example table of what I have been using:
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane);
table = new JTable();
DefaultTableModel tableModel = new DefaultTableModel(new Object[]{"Row 1","Row 2"},0);
table.setModel(tableModel);
scrollPane.setViewportView(table);
I've attempted to use the following autoscrolling methods both with the same result.
// Method 1
JScrollBar vertical = scrollPane.getVerticalScrollBar();
vertical.setValue(vertical.getMaximum());
// Method 2
table.scrollRectToVisible(table.getCellRect(table.getRowCount(), 0, true));
Both examples go to the near-bottom of the table, up until the last (bottom) row that the user has to scroll down to see, only to happen again when another row is added.
EDIT: Example code to replicate the problem
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
import javax.swing.table.DefaultTableModel;
public class ScrollTableEx extends JFrame {
private static final long serialVersionUID = 1L;
public int i = 100;
public JScrollPane scrollPane;
public JPanel contentPane;
public JTable table;
public JButton add;
public DefaultTableModel model = new DefaultTableModel(new Object[] { "Int (+)", "Int (-)" }, 0);
public static void main(String[] args) {
ScrollTableEx frame = new ScrollTableEx();
frame.setVisible(true);
}
public ScrollTableEx() {
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(500,400);
scrollPane = new JScrollPane();
table = new JTable();
table.setCellSelectionEnabled(true);
table.setModel(model);
scrollPane.setViewportView(table);
for (int i = 0; i < 100; i++) {
model.addRow(new Object[] { i, i * -1 });
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
table.scrollRectToVisible(goodRect);
}
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
table.scrollRectToVisible(goodRect);
model.addRow(new Object[] { i, i * -1 });
i++;
}
});
add(add, BorderLayout.NORTH);
add(scrollPane, BorderLayout.CENTER);
}
}
The problem is, JTable and TableModel are both 0 indexed. That is, the last value is actually rowCount - 1.
So when you use table.getCellRect(table.getRowCount(), 0, true), it's actually returning a Rectangle of the right position, just with a 0 height, because the row doesn't actually exist.
Instead you want to use table.getCellRect(table.getRowCount() - 1, 0, true)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class ScrollTable {
public static void main(String[] args) {
new ScrollTable();
}
public ScrollTable() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final DefaultTableModel model = new DefaultTableModel(new Object[]{"Test"}, 0);
for (int index = 0; index < 100; index++) {
model.addRow(new Object[]{index});
}
final JTable table = new JTable(model);
JButton add = new JButton("Add");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
model.addRow(new Object[]{model.getRowCount()});
Rectangle badRect = table.getCellRect(model.getRowCount(), 0, true);
Rectangle goodRect = table.getCellRect(model.getRowCount() - 1, 0, true);
System.out.println("bad = " + badRect);
System.out.println("goodRect = " + goodRect);
table.scrollRectToVisible(goodRect);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(table));
frame.add(add, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I would avoid using .setBounds where possible. It does not take into consideration the variety of differences that exist between different computers and OS's and while it might look perfectly fine when you are developing, when you move it another system, it could produce undeseriable results - IMHO

JTable autoscroll to the bottom in Java

I would like the JTable to autoscroll to the bottom whenever I add a new column and show the last 10 rows. However, I have the option of scrolling to anywhere I want (mouse listener?). Do you know how to do that? Here's the code I have so far. It builds a JTable and adds a new row for every mouse click on the JButton.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public class sampleGUI extends JFrame implements ActionListener {
private JButton incrementButton;
private JTable table;
private DefaultTableModel model;
private int count;
private JScrollPane scroll;
public sampleGUI() {
JFrame frame = new JFrame("sample frame");
frame.setLayout(new BorderLayout());
incrementButton = new JButton("Increase the count!");
model = new DefaultTableModel();
model.addColumn("column 1");
table = new JTable(model);
frame.add(incrementButton, BorderLayout.NORTH);
scroll = new JScrollPane(table)
frame.add(scroll, BorderLayout.CENTER);
count = 0;
incrementButton.addActionListener(this);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public synchronized void actionPerformed(ActionEvent e) {
if (e.getSource() == incrementButton) {
count++;
model.addRow(new Object[] { count });
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
sampleGUI gui = new sampleGUI();
}
});
}
}
Thanks!
Required to change selection in JTable, add code line
table.changeSelection(table.getRowCount() - 1, 0, false, false);
to
public (synchronized) void actionPerformed(ActionEvent e) {
I would like the JTable to autoscroll to the bottom whenever I add a new column
I assume you mean scroll to the bottom when you add a new row?
model.addRow(new Object[] { count });
table.scrollRectToVisible(...);
You forget add JScrollPane to the table :
//...
frame.add(new JScrollPane(table), BorderLayout.CENTER);
//...
and don't forget
import javax.swing.JScrollPane;

Java Box (BoxLayout) does not work as expected

I have a weird problem using the Java Box class. I am using JDK 1.6.21.
I have an own class, DropDownPanel, that inherits from JPanel. The purpose of the DropDownPanel is to be able to hide and show another Component on it. If you click on the title of the DropDownPanel, the hosted Component (now it is a JTable) is set to visible or invisible. It works fine alone.
I am putting these DropDownPanels into a vertical Box class, then the Box into a JScrollPane. All X and Y alignments of the DropDownPanels are set to 0, so there should be no mis-alignment in the Box.
So I have the following logical tree: a JTable in a DropDownPanel in a Box in a JScrollPane.
The problem is that if the Box contains only the DropDownPanels, then I observe the following behaviour, when I add and remove rows from/to the table:
the JScrollPane is correctly shown after a lot of rows added, meaning that the sizes and the layouts are properly calculated. The scrollbar disappears after I remove enough rows, so the table fits the JFrame.
the JTable rows are refreshed properly, i.e. I see the correct number of rows.
But, JTable never seem to resize itself. Added rows are invisible, removed rows disappear, but the table background (with white color) is still visible. I would expect the JTable to be as compact as possible. It does not.
Now comes the weird thing. If I add an empty JPanel as the last component to the Box, everything works as I would expect. The JTable is always as compact as it can. When removing rows, the table size gets smaller and it is repainted correctly. Without the last JPanel however, the JTable resizes itself correclty (I know it from the appearance of the scrollbar), but never will be compact. Resizing the JFrame does not help. The only thing that forces the proper behaviour is to hide and show the JTable via the DropDownPanel. Then it is shown properly.
Since the DropDownPanel is an extended JPanel and the added JPanel is just the default JPanel, I have no clue, why it does not work without the extra JPanel at the end of the Box.
Finally here is the code. Note the commented line. If it is uncommented, the table behaves properly (better start with his setup), if not, then it is not. You need to click on the DropDownPanel title to show the table at all. Then you can add a lot of rows to see that the scrollpane appears after the number of rows do not fit into the JFrame and it disappears properly when they do. Still, the JTable is not as compact as it should be:
package tabletest;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class TableTest {
public class DropDownPanel extends JPanel implements ActionListener, MouseListener {
private static final long serialVersionUID = 1L;
protected JPanel header = new JPanel();
protected JLabel titleLabel;
protected Component content;
protected boolean isExpanded = true;
public DropDownPanel(String title, Component c) {
content = c;
setLayout(new BorderLayout());
titleLabel = new JLabel(title);
header.setLayout(new BorderLayout());
header.add(titleLabel, BorderLayout.WEST);
add(header, BorderLayout.NORTH);
add(content, BorderLayout.CENTER);
header.addMouseListener(this);
titleLabel.addMouseListener(this);
apply();
}
public void toggleExpanded() {
isExpanded = !isExpanded;
apply();
}
protected void apply() {
titleLabel.setText("Drop state: " + (isExpanded ? "Expanded" : "Collapsed"));
content.setVisible(isExpanded);
setMaximumSize(new Dimension(1024, getPreferredSize().height));
invalidate();
}
#Override
public void actionPerformed(ActionEvent e) {
toggleExpanded();
}
#Override
public void mouseClicked(MouseEvent e) {
toggleExpanded();
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
public void run() {
JFrame f = new JFrame();
JPanel p = new JPanel();
Box box = Box.createVerticalBox();
p.setLayout(new BorderLayout());
final JTable table = new JTable();
table.setFocusable(false);
table.setFillsViewportHeight(true);
table.setBackground(Color.white);
DefaultTableModel m = (DefaultTableModel) table.getModel();
m.addColumn("Color");
JButton b = new JButton("Remove row");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
((DefaultTableModel) table.getModel()).removeRow(0);
table.invalidate();
}
});
JButton b2 = new JButton("Add row");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
table.invalidate();
}
});
DropDownPanel ddp = new DropDownPanel("Title", table);
ddp.setAlignmentX(0);
ddp.setAlignmentY(0);
box.add(ddp);
// ---------------------------------------------------------------
// Without this line, it does not work; with this line, it is fine
//box.add(new JPanel());
// ---------------------------------------------------------------
JLabel lll = new JLabel("End of Story");
lll.setAlignmentX(0);
lll.setAlignmentY(0);
box.add(lll);
p.add(new JScrollPane(box), BorderLayout.CENTER);
p.add(b, BorderLayout.SOUTH);
p.add(b2, BorderLayout.NORTH);
f.add(p);
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
f.pack();
f.setVisible(true);
f.setSize(new Dimension(600, 400));
}
public static void main(String[] args) {
new TableTest().run();
}
}
I am sweating blood now, so any help is appreciated :)
Within DropDownPanel you have added component i.e. JTable to center, So it takes all space available.
Following is quoted from API doc:
The components are laid out according
to their preferred sizes and the
constraints of the container's size.
The NORTH and SOUTH components may be
stretched horizontally; the EAST and
WEST components may be stretched
vertically; the CENTER component may
stretch both horizontally and
vertically to fill any space left
over.
Also have look at this guide : A Visual Guide to Layout Managers
I have changed your code. Hope this is what you are looking for :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class TableTest {
public class DropDownPanel extends JPanel implements ActionListener,
MouseListener {
private static final long serialVersionUID = 1L;
//protected JPanel header = new JPanel();
protected JLabel titleLabel;
protected Component content;
protected boolean isExpanded = true;
public DropDownPanel(String title, Component c) {
content = c;
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
titleLabel = new JLabel(title);
//header.setLayout(new BorderLayout());
//header.add(titleLabel, BorderLayout.NORTH);
add(titleLabel);
add(content);
//header.addMouseListener(this);
titleLabel.addMouseListener(this);
apply();
}
public void toggleExpanded() {
isExpanded = !isExpanded;
apply();
}
protected void apply() {
titleLabel.setText("Drop state: "
+ (isExpanded ? "Expanded" : "Collapsed"));
content.setVisible(isExpanded);
//setMaximumSize(new Dimension(1024, getPreferredSize().height));
invalidate();
}
#Override
public void actionPerformed(ActionEvent e) {
toggleExpanded();
}
#Override
public void mouseClicked(MouseEvent e) {
toggleExpanded();
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
public void run() {
JFrame f = new JFrame();
JPanel p = new JPanel();
Box box = Box.createVerticalBox();
p.setLayout(new BorderLayout());
final JTable table = new JTable();
table.setFocusable(false);
table.setFillsViewportHeight(true);
table.setBackground(Color.white);
DefaultTableModel m = (DefaultTableModel) table.getModel();
m.addColumn("Color");
JButton b = new JButton("Remove row");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
((DefaultTableModel) table.getModel()).removeRow(0);
table.invalidate();
}
});
JButton b2 = new JButton("Add row");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
((DefaultTableModel) table.getModel())
.addRow(new Object[] { "Red" });
table.invalidate();
}
});
DropDownPanel ddp = new DropDownPanel("Title", table);
ddp.setAlignmentX(0);
ddp.setAlignmentY(0);
box.add(ddp);
// ---------------------------------------------------------------
// Without this line, it does not work; with this line, it is fine
// box.add(new JPanel());
// ---------------------------------------------------------------
JLabel lll = new JLabel("End of Story");
lll.setAlignmentX(0);
lll.setAlignmentY(0);
box.add(lll);
p.add(new JScrollPane(box), BorderLayout.CENTER);
p.add(b, BorderLayout.SOUTH);
p.add(b2, BorderLayout.NORTH);
f.add(p);
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
f.pack();
f.setVisible(true);
f.setSize(new Dimension(600, 400));
}
public static void main(String[] args) {
new TableTest().run();
}
}
Normally a JTable's direct parent should be a JScrollPane, you should add the table this way:
DropDownPanel ddp = new DropDownPanel("Title", new JScrollPane(table));

How to configure JComboBox not to select FIRST element when created?

Problem:
Update:
From the Java SE 6 API:
public JComboBox() Creates a JComboBox
with a default data model. The default
data model is an empty list of
objects. Use addItem to add items. By
default the first item in the data
model becomes selected.
So I changed to JComboBox(model) as the API says:
public JComboBox(ComboBoxModel aModel)
Creates a JComboBox that takes its
items from an existing ComboBoxModel.
Since the ComboBoxModel is provided, a
combo box created using this
constructor does not create a default
combo box model and may impact how the
insert, remove and add methods behave.
I tried the following:
DefaultComboBoxModel model = new DefaultComboBoxModel();
model.setSelectedItem(null);
suggestionComboBox = new JComboBox(model);
suggestionComboBox.setModel(model);
But could not get it to work, the first item is still being selected.
Anyone that can come up with a working example would be very much appreciated.
Old part of the post:
I am using JComboBox, and tried using setSelectionIndex(-1) in my code (this code is placed in caretInvoke())
suggestionComboBox.removeAllItems();
for (int i = 0; i < suggestions.length; i++) {
suggestionComboBox.addItem(suggestions[i]);
}
suggestionComboBox.setSelectedIndex(-1);
suggestionComboBox.setEnabled(true);
This is the initial setting when it was added to a pane:
suggestionComboBox = new JComboBox();
suggestionComboBox.setEditable(false);
suggestionComboBox.setPreferredSize(new Dimension(25, 25));
suggestionComboBox.addActionListener(new SuggestionComboBoxListener());
When the caretInvoke triggers the ComboBox initialisation, even before the user selects an element, the actionPerformed is already triggered (I tried a JOptionPane here):
http://i126.photobucket.com/albums/p109/eXPeri3nc3/StackOverflow/combo1.png
http://i126.photobucket.com/albums/p109/eXPeri3nc3/StackOverflow/combo2.png
http://i126.photobucket.com/albums/p109/eXPeri3nc3/StackOverflow/combo3.png
The problem is: My program autoinserts the selected text when the user selects an element from the ComboBox. So without the user selecting anything, it is automatically inserted already.
How can I overcome the problem in this situation? Thanks.
Here is my SSCCE: (finally)
package components;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
public class Temp extends JFrame {
JTextPane textPane;
AbstractDocument doc;
JTextArea changeLog;
String newline = "\n";
private JComboBox suggestionComboBox;
private JPanel suggestionPanel;
private JLabel suggestionLabel;
private JButton openButton, saveButton, aboutButton;
public Temp() {
super("Snort Ruleset IDE");
//Create the text pane and configure it.
textPane = new JTextPane();
textPane.setCaretPosition(0);
textPane.setMargin(new Insets(5, 5, 5, 5));
StyledDocument styledDoc = textPane.getStyledDocument();
if (styledDoc instanceof AbstractDocument) {
doc = (AbstractDocument) styledDoc;
//doc.setDocumentFilter(new DocumentSizeFilter(MAX_CHARACTERS));
} else {
System.err.println("Text pane's document isn't an AbstractDocument!");
System.exit(-1);
}
JScrollPane scrollPane = new JScrollPane(textPane);
scrollPane.setPreferredSize(new Dimension(700, 350));
//Create the text area for the status log and configure it.
//changeLog = new JTextArea(10, 30);
//changeLog.setEditable(false);
//JScrollPane scrollPaneForLog = new JScrollPane(changeLog);
//Create a JPanel for the suggestion area
suggestionPanel = new JPanel(new BorderLayout());
suggestionPanel.setVisible(true);
suggestionLabel = new JLabel("Suggestion is not active at the moment.");
suggestionLabel.setPreferredSize(new Dimension(100, 50));
suggestionLabel.setMaximumSize(new Dimension(100, 50));
suggestionComboBox = new JComboBox();
suggestionComboBox.setEditable(false);
suggestionComboBox.setPreferredSize(new Dimension(25, 25));
//suggestionComboBox.addActionListener(new SuggestionComboBoxListener());
suggestionComboBox.addItemListener(new SuggestionComboBoxListener());
//suggestionComboBox.setSelectedIndex(-1);
//add the suggestionLabel and suggestionComboBox to pane
suggestionPanel.add(suggestionLabel, BorderLayout.CENTER);
suggestionPanel.add(suggestionComboBox, BorderLayout.PAGE_END);
JScrollPane sp = new JScrollPane(suggestionPanel);
JScrollPane scrollPaneForSuggestion = new JScrollPane(suggestionPanel);
//Create a split pane for the change log and the text area.
JSplitPane splitPane = new JSplitPane(
JSplitPane.VERTICAL_SPLIT,
scrollPane, scrollPaneForSuggestion);
splitPane.setOneTouchExpandable(true);
splitPane.setResizeWeight(1.0);
//Disables the moving of divider
splitPane.setEnabled(false);
//splitPane.setDividerLocation(splitPane.getHeight());
//splitPane.setPreferredSize(new Dimension(640,400));
//Create the status area.
JPanel statusPane = new JPanel(new GridLayout(1, 1));
CaretListenerLabel caretListenerLabel =
new CaretListenerLabel("Status: Ready");
statusPane.add(caretListenerLabel);
//Create the toolbar
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.setRollover(true);
openButton = new JButton("Open Snort Ruleset");
toolBar.add(openButton);
saveButton = new JButton("Save Ruleset");
toolBar.add(saveButton);
toolBar.addSeparator();
aboutButton = new JButton("About");
toolBar.add(aboutButton);
//Add the components.
getContentPane().add(toolBar, BorderLayout.PAGE_START);
getContentPane().add(splitPane, BorderLayout.CENTER);
getContentPane().add(statusPane, BorderLayout.PAGE_END);
JMenu editMenu = createEditMenu();
JMenu styleMenu = createStyleMenu();
JMenuBar mb = new JMenuBar();
mb.add(editMenu);
mb.add(styleMenu);
setJMenuBar(mb);
//Put the initial text into the text pane.
//initDocument();
textPane.setCaretPosition(0);
//Start watching for undoable edits and caret changes.
textPane.addCaretListener(caretListenerLabel);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textPane.requestFocusInWindow();
}
});
}
//This listens for and reports caret movements.
protected class CaretListenerLabel extends JLabel
implements CaretListener {
public CaretListenerLabel(String label) {
super(label);
}
//Might not be invoked from the event dispatch thread.
public void caretUpdate(CaretEvent e) {
caretInvoke(e.getDot(), e.getMark());
}
protected void caretInvoke(final int dot, final int mark) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Rectangle caretCoords = textPane.modelToView(dot);
//Find suggestion
suggestionComboBox.removeAllItems();
for (int i = 0; i < 5; i++) {
suggestionComboBox.addItem(Integer.toString(i));
}
//suggestionComboBox.setSelectedItem(null);
suggestionComboBox.setEnabled(true);
suggestionLabel.setText("The following keywords are normally used as well. Click to use keyword(s). ");
//changeLog.setText("The following keywords are suggested to be used together: " + str);
} catch (BadLocationException ble) {
setText("caret: text position: " + dot + newline);
System.out.println("Bad Location Exception");
}
}
});
}
}
public class SuggestionComboBoxListener implements ItemListener {
//public void actionPerformed(ActionEvent e) {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
JComboBox cb = (JComboBox)e.getSource();
String selection = (String) cb.getSelectedItem();
JOptionPane.showMessageDialog(null, "Item is selected", "Information", JOptionPane.INFORMATION_MESSAGE);
}
}
}
/*
* Menu Creation
*/
//Create the edit menu.
protected JMenu createEditMenu() {
JMenu menu = new JMenu("Edit");
return menu;
}
protected JMenu createStyleMenu() {
JMenu menu = new JMenu("Style");
return menu;
}
private static void createAndShowGUI() {
//Create and set up the window.
final Temp frame = new Temp();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
//The standard main method.
public static void main(String[] args) {
//Schedule a job for the event dispatch thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
You need to remove the ItemListener before you make any changes to the combo-box and add it back when you are done.
Something like this:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
public class Suggestions {
private JFrame frame;
private JTextPane textPane;
private JComboBox suggestionComboBox;
private SuggestionComboBoxListener selectionListener;
public Suggestions() {
frame = new JFrame("Snort Ruleset IDE");
textPane = new JTextPane();
textPane.setCaretPosition(0);
textPane.setMargin(new Insets(5, 5, 5, 5));
textPane.addCaretListener(new SuggestionCaretListener());
JScrollPane textEntryScrollPane = new JScrollPane(textPane);
textEntryScrollPane.setPreferredSize(new Dimension(300, 400));
selectionListener = new SuggestionComboBoxListener(frame);
suggestionComboBox = new JComboBox();
suggestionComboBox.setEditable(false);
suggestionComboBox.setPreferredSize(new Dimension(25, 25));
suggestionComboBox.addItemListener(selectionListener);
JPanel suggestionPanel = new JPanel(new BorderLayout());
suggestionPanel.add(suggestionComboBox, BorderLayout.PAGE_END);
frame.getContentPane().add(textEntryScrollPane, BorderLayout.NORTH);
frame.getContentPane().add(suggestionPanel, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private final class SuggestionCaretListener implements CaretListener {
#Override
public void caretUpdate(CaretEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
generateSuggestions();
}
});
}
}
public static final class SuggestionComboBoxListener implements ItemListener {
Component parent;
public SuggestionComboBoxListener(Component parent) {
this.parent = parent;
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
JComboBox cb = (JComboBox) e.getSource();
String selection = (String) cb.getSelectedItem();
JOptionPane.showMessageDialog(parent, "The selected item is: " + selection, "Information",
JOptionPane.INFORMATION_MESSAGE);
}
}
}
void generateSuggestions() {
suggestionComboBox.removeItemListener(selectionListener);
suggestionComboBox.removeAllItems();
for (int i = 0; i < 5; i++) {
suggestionComboBox.addItem(Integer.toString(i));
}
suggestionComboBox.setEnabled(true);
suggestionComboBox.addItemListener(selectionListener);
}
public static void main(String[] args) {
new Suggestions();
}
}
BTW, what you posted is not an SSCCE it is a dump of your code. An SSCCE should only have enough code to reproduce the issue you are experiencing.
use
setSelectedItem(null);
Please try with ItemListener instead of ActionListener.
if You want that after 1st entry you made and immediately you combox is empty then just write down the under mentioned code which is:
jComboBox1.setSelectedIndex(0);
and your combox will reset Automatically

Categories

Resources