My requirement is to use addDocumentListener, the doSearchCmb basically narrows down items in combobox, function is working if keypressed is used. If I remove the function Runnable doSearchCmb and put the narrowing down of items in insertUpdate without using invokeLater, I get an error of 'Attempt to mutate notification' exception.
In my current code, my screen freezes after I type a letter. After waiting several minutes, I get the error of java.lang.OutOfMemoryError: Java heap space.
I tried to add return; after combo.repaint();, my screen didn't freeze, there's no java heap space error but nothing happened at all. I attached the code without the return.
What can I do here to remain the use of addDocumentListener and the function which narrows down the items of the combobox?
TCombo combo = new TCombo();
JTextComponent editor = (JTextComponent) combo.getEditor().getEditorComponent();
editor.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent arg0) {
}
public void insertUpdate(DocumentEvent arg0) {
searchCmb();
}
public void removeUpdate(DocumentEvent arg0) {
searchCmb();
}
private void searchCmb() {
Runnable doSearchCmb = new Runnable() {
#Override
public void run() {
String item = combo.getEditor().getItem().toString().trim();
boolean isEmpty = item.equals("");
CmbElement[] foundList = null;
String toFind = "";
List list = new ArrayList(0);
if (!isEmpty) {
combo.removeAllItems();
combo.setItems(elements);
for (int i = 1; i < elements.length; i++) {
if (elements[i].getName().contains(toFind)) {
if (i == 1) {
list.add("");
}
list.add(elements[i]);
}
foundList = (CmbElement[]) list.toArray(new CmbElement[list.size()]);
}
if (list.size() > 0) {
combo.removeAllItems();
combo.setItems(foundList);
} else {
combo.removeAllItems();
if (toFind.equals("")) {
combo.setItems(elements);
}
list.add(new DCmbElement("", ""));
foundList = (CmbElement[]) list.toArray(new CmbElement[list.size()]);
combo.setItems(foundList);
}
combo.repaint();
}
}
};
SwingUtilities.invokeLater(doSearchCmb);
}
});
CmbElement:
public abstract interface CmbElement {
public abstract String getKey();
public abstract String getName();
}
Note: Narrow down items in combo box means when user inputs a letter, or paste a word, the items in combo box gets filtered using the current letter or word as parameter. It searches through the items and narrows it down.
For reference the behavior is like the image here: jcombobox filter in java - Look and feel independent
My function indicated in run() is working fine if keypressed of keylistener is used, but my requirement is to use addDocumentListener
Related
I've been trying to make a listener (I'm not really sure whether I should be using an ItemListener or ActionListener) respond to changes in a JComboBox by changing a JLabel image next to the box.
I tried defining the actionPerformed method in the constructor of the class under the addActionListener call on the combo box, as well as outside the constructor, and the actionPerformed never seems to execute. I've added a println to each one to test whether the method is actually working when I select an item in the box, but neither one appears to output anything, leading me to believe the actionPerformed method is not executing for some reason. A lot of different answers elsewhere have defined actionListeners and actionPerformed in multiple different places, such as a separate class or in an instance variable declaration.
public class MainBattle
{
//instance variables
public MainBattle() throws FileNotFoundException,IOException
{
//creation of ArrayLists used later
for(JComboBox<String> j : party1)
{
j.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Listener active");
if(e.getSource() instanceof JComboBox)
{
JComboBox<String> cb = (JComboBox<String>)e.getSource();
String content = (String)cb.getSelectedItem();
if(party1.indexOf(cb) != -1)
{
party1Image.get(party1.indexOf(cb)).setIcon(new ImageIcon(".\\res\\sprites_small\\"
+ content.substring(0,content.indexOf(" ")) + ".png"));
}
}
selectFrame.revalidate();
selectFrame.repaint();
}
});
}
createUI();
}
public void createUI()
{
//building GUI elements and displaying
for(int i = 0; i < 6; i++)
{
party1.add(new JComboBox<String>());
party2.add(new JComboBox<String>());
}
for(int i = 0; i < 6; i++)
{
party1Image.add(new JLabel(new ImageIcon(".\\res\\sprites_small\\0.png")));
party2Image.add(new JLabel(new ImageIcon(".\\res\\sprites_small\\0.png")));
}
//building GUI elements and displaying
}
// Commented out to make sure existence of multiple methods is not problematic
/*
public void actionPerformed(ActionEvent e)
{
System.out.println("Action");
}
*/
public static void main(String[] args) throws IOException
{
new MainBattle();
}
}
I have a Java application used to run tournaments in which I built an auto-suggestion feature that gets names from a database and displays them in a JPopupMenu. I haven't been able to replicate this bug on demand, but once in a while one of the JPopupMenus will disappear like normal with the exception that an outline of where it was is still on the screen and is displayed over everything including other programs even if my application is minimized.
Here is a screenshot of what I'm talking about:
You can see that underneath "Espinoza" some remnant of the JPopupMenu is still being displayed. This sometimes contains text inside and other times just has the background color only in an empty box. This remnant is purely cosmetic and I haven't found any way of interacting with it either physically or programatically (hot-coding).
Here is the method I'm using to display the JPopupMenu:
private void resetLastNamePopup() {
Thread t = new Thread() {
#Override
public void run() {
lnPopup.setVisible(false);
lnPopup.removeAll();
if(DBHSDatabaseIntermediary.isConnected()) {
if(!(fnTextField.getText().equals("") && lnTextField.getText().equals(""))) {
JMenuItem item = null;
String[] names = DBHSDatabaseIntermediary.getLastNames(fnTextField.getText(), lnTextField.getText());
for(int i=0; i < names.length; i++) {
if(!names[i].equals(lnTextField.getText().trim())) {
item = new JMenuItem(names[i]);
item.addActionListener(lnActionListener);
item.addMouseListener(NewPlayerPanel.this);
lnPopup.add(item);
}
}
if(names.length > 0 && !names[0].equals("")) {
lnPopup.setVisible(true);
}
lnPopup.grabFocus();
}
}
}// ends run()
};
t.start();
}
Thank you in advance.
Swing methods and constructors must be called on the AWT event dispatch thread. You are calling those methods on a different thread. The result is “undefined behavior”—which usually means things will work sometimes, but not all the time.
You need to separate Swing calls from database calls, which is done using EventQueue.invokeLater (or its alias, SwingUtilities.invokeLater):
private void resetLastNamePopup() {
lnPopup.setVisible(false);
lnPopup.removeAll();
final String fn = fnTextField.getText();
final String ln = lnTextField.getText();
Thread t = new Thread() {
#Override
public void run() {
if(DBHSDatabaseIntermediary.isConnected()
&& !fn.isEmpty() && !ln.isEmpty()) {
final String[] names =
DBHSDatabaseIntermediary.getLastNames(fn, ln);
// Rebuild JPopupMenu in AWT event thread.
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
for (String name : names) {
if (!name.equals(ln)) {
JMenuItem item = new JMenuItem(name);
item.addActionListener(lnActionListener);
lnPopup.add(item);
}
}
if (names.length > 0 && !names[0].isEmpty()) {
lnPopup.setVisible(true);
lnPopup.grabFocus();
}
}
});
}
}// ends run()
};
t.start();
}
For more information, see the javax.swing package contract, and Concurrency in Swing in the Java Tutorials.
I am having an issue implementing a double click handler for my Datagrid. I have found a solution posted on Stack overflow that should fix my problem i believe, however, I can not figure out:
1. How exactly do I implement it?
2. What is <T>?
I am getting various errors I do not understand. The issue is almost certainly with the way I add the CellPreviewHandler (Line 6)
Errors (line 6 & 8)
-the Type new CellPreviewEvent.Handler(){} must implement the inherited abstract method CellPreviewEvent.Handler.onCellPreview(CellPreviewEvent)
-The method onCellPreview(CellPreviewEvent) of type new AsynCallBack(String[][]>(){} must override or implement a supertype method
MyCode:
Public Class DataGrid extends Widget{
Timer singleClickTimer;
int clickCount = 0;
int clickDelay = 300;
myDataTable = new DataGrid<String[]>(result.length, resources, KEY_PROVIDER);
myDataTable.addCellPreviewHandler(new Handler<T>(){
#Override
public void onCellPreview(final CellPreviewEvent<T> event) {
if (Event.getTypeInt(event.getNativeEvent().getType()) == Event.ONMOUSEOVER) {
handleOnMouseOver(event);
} else if (Event.getTypeInt(event.getNativeEvent().getType()) == Event.ONCLICK) {
clickCount++;
if (clickCount == 1) {
singleClickTimer = new Timer() {
#Override
public void run() {
clickCount = 0;
handleOnClick(event);
}
};
singleClickTimer.schedule(clickDelay);
} else if (clickCount == 2) {
singleClickTimer.cancel();
clickCount = 0;
handleOnDblClick(event);
}
}
}
});
private void handleOnMouseOver(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("mouse over event");
}
private void handleOnClick(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("click event");
}
private void handleOnDblClick(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("double click event");
}
Link to original solution:
adding Double click event in CellTable cell - GWT
This is not a very good code (a better option would be to extend DataGrid class), but if you don't want to change much, simply replace <T> with <String[]>.
I have the following problem:
There are 2 JLists in my frame:
listModel = new DefaultListModel();
ownlistModel = new DefaultListModel();
fillList();
ownBookList = new JList(ownlistModel);
ownBookList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
ownBookList.setLayoutOrientation(JList.VERTICAL);
ownBookList.setSelectedIndex(-1);
userlist = new JList(listModel);
userlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
userlist.setLayoutOrientation(JList.VERTICAL);
userlist.setSelectedIndex(0);
Now, these are mutually exclusive, so if someone clicks an item in the one list, the previous selection in the other list should be cleared.
ls2Handler = new ListSelectionListener(){
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
// System.out.println(ownBookList.getSelectedValue().toString().length());
Global.selectedUser = ownBookList.getSelectedValue().toString();
Global.selectedIndex = ownBookList.getSelectedIndex();
userlist.clearSelection();
updateFields(Global.selectedUser, 1);
}
}
};
lsHandler = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
// System.out.println(userlist.getSelectedValue().toString().length());
Global.selectedUser = userlist.getSelectedValue().toString();
Global.selectedIndex = userlist.getSelectedIndex();
ownBookList.clearSelection();
updateFields(Global.selectedUser, 0);
}
}
};
userlist.addListSelectionListener(lsHandler);
ownBookList.addListSelectionListener(ls2Handler);
On calling the Value is adjusting function I always get the nullpointerException:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Books$3.valueChanged(Books.java:199) at
javax.swing.JList.fireSelectionValueChanged(Unknown Source)
Why is that? As you can see, they have been declared and should be accessible.
The getSelectedValue() method can return null, and you are calling toString() on that null object
userlist.getSelectedValue().toString();
See the documentation of that method:
Returns the value for the smallest selected cell index; the selected value when only a single item is selected in the list. When multiple items are selected, it is simply the value for the smallest selected index. Returns null if there is no selection.
And since you clear the selection on list B when you select something on list A, you will quickly run into this exception.
Thanks to Robin I figured it out. I wasn't aware that the method clearselection() triggers the listener.
It's quick and dirty but it works:
ls2Handler = new ListSelectionListener(){
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (ownBookList.getSelectedValue()!=null) {
userlist.clearSelection();
Global.selectedUser = ownBookList.getSelectedValue().toString();
Global.selectedIndex = ownBookList.getSelectedIndex();
updateFields(Global.selectedUser);
}
else {
}
}
}
};
lsHandler = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (userlist.getSelectedValue()!=null) {
ownBookList.clearSelection();
Global.selectedUser = userlist.getSelectedValue().toString();
Global.selectedIndex = userlist.getSelectedIndex();
updateFields(Global.selectedUser);
}
else {
}
}
}
};
Thanks again!
I'm trying to use threads to run a lenghty operation in the background and update the UI.
Here's what i'm trying to do:
on a button click, display a popupjframe with a message "Inserting into DB"
create a new thread to insert 1000s of entries into a database.
when the entries are inserted, i want the popupjframe to disappear and display a joptionpane with yes, no buttons
on clicking the yes button i want to display another frame with a report/details about the insertion process
Here's my code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//display popupframe first
jFrame1.pack();
jFrame1.setVisible(true);
jFrame1.setLocationRelativeTo(getFrame());
Thread queryThread = new Thread() {
public void run() {
runQueries();
}};
queryThread.start();
}
//runqueries method inserts into DB
private void runQueries() {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
updateProgress(i);
}
}
//update the popupjframe
private void updateProgress(final int queryNo) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (queryNo == 50000) { //means insertion is done
jFrame1.setVisible(false);
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;}
else
//display another popupframe with details/report of inserting process
}});
}
Is my approach correct??
How and when do i stop/interrupt the "queryThread"??
Is it correct if i make the popupjframe in the runqueries method itself (after the for loop) and display the joptionpane??
Thanks in advance.
Look at the documentation for SwingWorker. It does exactly what you are trying to do. Create a subclass, and call runQueries from doInBackground(), and then do what your runnable does (minus the if queryNo check) in done(). There are third party versions of this class if you are not using java 1.6.
class DbSwingWorker extends SwingWorker<Void, Integer> {
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i <= 50000; i++) {
insertintoDB();
publish(i); //if you want to do some sort of progress update
}
return null;
}
#Override
protected void done() {
int n = JOptionPane.showConfirmDialog(getFrame(), menuBar, null, JOptionPane.YES_NO_OPTION);
if (n == 1) { //NO option was selected
return;
} else {
//display another popupframe with details/report of inserting process
}
}
}
The original, non-1.6 version can be found here: https://swingworker.dev.java.net/