How to clear table selection when clicking on right of table - java

I have a JTable which is held in a scrollpane, which in turn sits in a panel, which is embedded in a JFrame. If the JFrame is expanded, then there is empty space, both below, as well as to the right of the JTable.
I want to clear the selection on the table if the user clicks outside the table, either below the table, or to the right of the table.
In order to clear the selection when the user clicks BELOW the table, I configured the table to fill the height of the scrollpane viewport, and added a MouseListener to the table, so that when the user clicks below the table, "rowAtPoint" returns -1, and then I clear the selection. However, this doesn't work for the RHS of the table. The table doesn't even receive these Mouse Events. How should I detect a click on the right of the JTable and clear the selection on the table? See code below. Please note that I haven't bothered to make the code pretty and do things the "right way". My focus was just on creating a SSCCE that illustrated the issue. :)
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TableTest {
public static void main(String args[]) {
JFrame f = new JFrame();
JPanel p = new JPanel(new BorderLayout());
JScrollPane sp = new JScrollPane();
final JTable t = new JTable(5,5);
t.setFillsViewportHeight(true);
t.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for(int i = 0; i < 5; i++) {
t.getColumnModel().getColumn(i).setWidth(50);
t.getColumnModel().getColumn(i).setMaxWidth(75);
}
t.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
int row = t.rowAtPoint(e.getPoint());
if(row == -1) {
t.clearSelection();
}
}
});
sp.getViewport().add(t);
p.add(sp, BorderLayout.CENTER);
f.add(p);
f.pack();
f.setVisible(true);
}
}
EDIT : I understand that I could probably just add a mouselistener to the scrollpane or panel as well, so that the table selection is cleared when I click on them. I'm just wondering if there's a better / cleaner solution out there, to make sure that the JTable selection is cleared when I click outside its bounds.

Investigate using focus listener (table.addFocusListener( ... );) to find out when the table/cells no longer have the focus, and when that is the case call: table.getSelectionModel().clearSelection();

You could try adding a global mouse listener like below:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener(){
#Override
public void eventDispatched(AWTEvent event) {
if(event.getID() == MouseEvent.MOUSE_CLICKED) {
MouseEvent mevent = (MouseEvent) event;
int row = t.rowAtPoint(mevent.getPoint());
if(row == -1) {
t.clearSelection();
}
}
}
}, AWTEvent.MOUSE_EVENT_MASK);

You can probably use the FocusListener.
When the table loses Focus, you can clear the selection.
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/event/FocusListener.html

Related

Prepend text to JTextArea without scrolling up (java swing)

If I want to prevent the JTextArea from scrolling to the bottom when I add text to the end, the solution is very simple: Just set the caret's update policy to DefaultCaret.NEVER_UPDATE before calling the JTextArea's append method. I am trying to do the same thing (load the text without scrolling), but for prepending text instead of appending text.
I have tried lots of things. One of them is this, but it doesn't work:
public void loadMoreUp(){
caret = (DefaultCaret)ta.getCaret(); // ta is a JTextArea
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE); //doesn't work
String s = "The new text\n";
ta.setText(s + ta.getText()); // I have also tried with ta.getDocument().insertString(0,s,null)
}
The behavior I want is that "The new text" gets prepended to the top, but the JTextArea doesn't scroll up with it. "The new text" should not be visible unless the user manually scrolls up to see it.
How can I prepend text to the top of a JTextArea, without it scrolling up? My JTextArea is in a JScrollPane if that is relevant.
So it turns out that making your JTextArea uneditable is what's keeping the scrollbar at the top. I don't think prepending text is moving it -- it's more the case that it never moves at all.
If the goal is simply to keep the scrollbar scrolled all the way down the scrollpane, however, all you really have to do is set the caret position, and no one should be the wiser.
You can even set the caret position to some previous position by saving .getCaretPosition() and using that value later.
textArea.insert("Mein Hund frisst Nuesse\n", 0);
textArea.setCaretPosition(textArea.getDocument().getLength());
You can see my full example here, which you can use to reconcile against your implementation.
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.Dimension;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Foo extends JFrame implements ActionListener
{
JTextArea textArea;
JScrollPane scrollPane;
JButton button;
public Foo()
{
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setText("a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\nl\nm\nn\no\np\nq\nr\ns\nt\nu\nv\nw\nx\ny\nz\n");
scrollPane = new JScrollPane(textArea);
scrollPane.setPreferredSize(new Dimension(400, 200));
button = new JButton("Prepend");
button.addActionListener(this);
this.add(button, BorderLayout.PAGE_END);
this.add(scrollPane, BorderLayout.PAGE_START);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == button)
{
textArea.insert("Mein Hund frisst Nuesse\n", 0);
textArea.setCaretPosition(textArea.getDocument().getLength());
//textArea.setText("Mein Hund frisst Nuesse\n" + textArea.getText());
}
}
public static void main(String[] args)
{
Foo f = new Foo();
f.setPreferredSize(new Dimension(500, 300));
f.pack();
f.setVisible(true);
}
}
The following code seems to work:
public void loadMoreUp(){
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
String s = "The new text\n";
JScrollBar vbar = scrollPane.getVerticalScrollBar();
int diff = vbar.getMaximum() - vbar.getValue();
try{
ta.getDocument().insertString(0, s, null);
}
catch(BadLocationException e){
logger.error("Bad Location");
}
SwingUtilities.invokeLater(new Runnable(){
public void run(){
vbar.setValue(vbar.getMaximum()-diff);
}
});
}
The basic idea is to remember the position relative to the END of the document (vbar.getMaximum() - vbar.getValue()), and then restore this value after prepending the text.
invokeLater is needed, otherwise getMaximum runs before its value gets updated. The drawback with this method is that invokeLater makes the text briefly flicker.

How to turn off a key listener in NetBeans wizard panels?

I developed a simple plugin for NetBeans IDE. I have a little problem with default key event on TopComponenet of Wizard panel:
For example:
I have a wizard with 3 steps. In second step I have a JTextField where user put some values and after that appear a JList below this text field. Everything is okay until user choose a some value from list and than press key ENTER then my panel goes to next Step 3. I attach a key listener to list something like:
list = new JList(new PackagesListModel());
list.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(java.awt.event.KeyEvent evt) {
int keyCode = evt.getKeyCode();
if(keyCode == KeyEvent.VK_ENTER){
JList list = (JList)evt.getSource();
Object selectedPackage = list.getSelectedValue();
typePackageField.setText((String)selectedPackage);
}
}
});
But this listener probably is invoking after default listener of TopComponenet on wizard. How can I prevent moving user to next step using ENTER key?
I don't want this action (when user press ENTER then they go to the next step).
UPDATE:
Forwarding to Kraal answer:
Problem is that i dont know where i can lookking for a JButton Next (to shuting down a listener). It sound strange but how i wrote. Im using a Netbeans Plaform WizzardDescriptor to generate a Wizzard (with 3 steps) . WizzardDescriptor is from package:
org.openide.WizardDescriptor; // Dialogs API
i puted to him a 3 instances of panels: WizardDescriptor.Panel from same package:
org.openide.WizardDescriptor // Dialogs API
it looks like:
panels = new ArrayList<>();
panels.add(new LayoutWizardPanel1(selectedLayout));
panels.add(new LayoutWizardPanel2(selectedLayout));
panels.add(new LayoutWizardPanel3(selectedLayout));
WizardDescriptor wiz = new WizardDescriptor(new WizardDescriptor.ArrayIterator<>(panels));
After this will generated something like:
in my program i have access to WizardDescriptor
http://bits.netbeans.org/dev/javadoc/org-openide-dialogs/org/openide/WizardDescriptor.html
I'm not sure but if you know which JComponent causes this behaviour, try this:
suspectedComponent.getInputMap().put(KeyStroke.getKeyStrokeForEvent(KeyEvent.VK_ENTER),"none");
To check which keystrokes are bound on a JComponent:
suspectedComponent.getInputMap().keys()
Or in the parent InputMap:
suspectedComponent.getInputMap().getParent().keys()
See the docs for InputMap for details.
Everything is okay until user choose a some value from list and than press key ENTER then my panel goes to next Step 3. I attach a key
listener to list something like [...]
If you want Enter key in your list has precedence over the default Next -> button then you have to use Key binding to attach an action to your list when it's focused:
KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
Action updateTextfieldAction = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
JList list = (JList)evt.getSource();
Object selectedPackage = list.getSelectedValue();
typePackageField.setText((String)selectedPackage );
}
};
list = new JList(new PackagesListModel());
list.getInputMap().put(enterKeyStroke, "enter");
list.getActionMap().put("enter", updateTextfieldAction);
Note that getInputMap() is a shortcut for getInputMap(JComponent.WHEN_FOCUSED). This means that if your list has focus and Enter key is pressed, then the action attached to this key stroke will be performed.
By this way your action will always have precedence over the next button's action, either if this button is the default button or it has attached an action using key bindings using WHEN_IN_FOCUSED_WINDOW like this:
JButton button = new JButton(nextStepAction);
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(enterKeyStroke, "enter");
button.getActionMap().put("enter", nextStepAction);
Where nextStepAction would be the action to go to wizard's next step.
See also Key bindings vs. key listeners in Java
Example
Please cosider the example below. Note if you focus another component but list the the default action is performed. I've set the button as frame's root pane default button and I've attached an action using WHEN_IN_FOCUSED_WINDOW just to prove that WHEN_FOCUSED action has precedence over those.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Demo {
private JList list;
private JTextField textField;
private void createAndShowGUI() {
KeyStroke enterKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
Action nextStepAction = new AbstractAction("Next") {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "Going to step 3!", "Message", JOptionPane.INFORMATION_MESSAGE);
}
};
Action updateTextfieldAction = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
textField.setText((String)list.getSelectedValue());
}
};
list = new JList(new String[]{"Item 1", "Item 2", "Item 3"});
list.setPrototypeCellValue("This is a list's prototype cell value.");
list.getInputMap().put(enterKeyStroke, "enter");
list.getActionMap().put("enter", updateTextfieldAction);
textField = new JTextField(15);
JPanel listPanel = new JPanel();
listPanel.add(new JScrollPane(list));
listPanel.add(textField);
JButton button = new JButton(nextStepAction);
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(enterKeyStroke, "enter");
button.getActionMap().put("enter", nextStepAction);
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
buttonsPanel.add(button);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(listPanel);
frame.add(buttonsPanel, BorderLayout.PAGE_END);
frame.getRootPane().setDefaultButton(button);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
Other comments
Please note that if you want avoid all this matter, you could attach a ListSelectionListener to your list and update the text field on selection change with no need to press Enter key at all. In fact if you have access to the next step action you could enable/disable it based on list selection. By doing this you'll be sure that wizard can't continue if no item is selected in your list. IMHO that would be a more elegant way to handle this situation. See Selecting Items in a List for further details.

Update JPopupMenu height while visible

I have a popup menu in my application that I want to replace with a customized one so that it matches the look & feel of the rest of the application. Essentially, instead of having the normal menu items in the popup, I want reuse a component that already exist elsewhere in the application that lets you navigate through a hierarchy of items in a "paging" way instead of with sub-menus. So if you click on an item in the list that contains children then the next page will be displayed replacing the current items in the list with a list of the children of the clicked item.
The advantage of using the "paging" component is that it will fit in well with the rest of the application (it is already used in other places that are not popups) and it has some nice looking animation effects when navigating between pages.
The problem I'm having is that the preferred height of the paging component changes when showing different pages (the amount of items in the list change) and I want the popup menu height to update so that it fits the paging component exactly, but so far my attempts to update the height of the popup menu while it is visible have failed.
Below is an example application that demonstrates the problem:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class PopupSizeTestFrame extends JFrame {
private static final int PREFFERED_WIDTH = 300;
private static JPanel resizingPanel;
private static JPopupMenu popupMenu;
private static PopupSizeTestFrame frame;
private static void resizePopupMenu() {
// What should I do here so that the size of the popup menu is updated?
/**
* Calling pack() works in this example, but I cannot call pack in the
* actual application since there is a smooth transition animation when
* clicking on the inner panel and pack() essentially re-adds the
* components of the popup menu (removeNotify and addNotify is called),
* which interferes with the animation and causes the menu to flicker.
* The flickering when clicking the inner panel can also be seen in this
* example when uncommenting the pack() call.
*/
//popupMenu.pack();
//
// I tried combinations of the following, without success:
//popupMenu.invalidate();
//popupMenu.revalidate();
//popupMenu.validate();
//popupMenu.doLayout();
// Repaint
popupMenu.repaint();
}
public static void main(String args[]) {
// Create popup child panel with height that changes when clicked
resizingPanel = new JPanel(new BorderLayout());
int initialHeight = 30;
final JLabel label = new JLabel("Click me (" + initialHeight + "px)");
resizingPanel.add(label);
resizingPanel.setBackground(Color.GREEN);
resizingPanel.setPreferredSize(new Dimension(PREFFERED_WIDTH, initialHeight));
resizingPanel.addMouseListener(new MouseAdapter() {
private int clickCount = 0;
#Override
public void mouseClicked(MouseEvent e) {
int height = ((clickCount % 3) + 1) * 50;
resizingPanel.setPreferredSize(new Dimension(PREFFERED_WIDTH, height));
clickCount++;
label.setText("Click me (" + height + "px)");
resizePopupMenu();
}
});
// Create popup
popupMenu = new JPopupMenu();
popupMenu.setLayout(new BorderLayout());
popupMenu.add(new JLabel("Header"), BorderLayout.NORTH);
popupMenu.add(resizingPanel, BorderLayout.CENTER);
popupMenu.add(new JLabel("Footer"), BorderLayout.SOUTH);
// Create frame
frame = new PopupSizeTestFrame();
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(400, 400));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
popupMenu.show(frame, e.getX(), e.getY());
}
}
});
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
}
}
When running the example above you will see that the popup menu size is updated if it is closed and opened after the inner panel was clicked, but it is not updated while the popup is visible.
What can I do in resizePopupMenu() to update the height of the JPopupMenu?
For the test app in the question the popup was always a heavyweight component and the following worked (as suggested by mKorbel)
private static void resizePopupMenu() {
SwingUtilities.getWindowAncestor(popupMenu).pack();
}
For the actual application when the popup was inside the bounds the application it was created as a lightweight component which prevented it from being resized with pack() and also prevented it from resizing past the application bounds.
I tried setting this property...
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
but then a mediumweight component was created and it would still not resize past the application bounds.
So I had to first force all popups of the "owner" component to be heavyweight with the following piece of unfortunate code
// Set owner to component on which popup is shown or any of its parents
final Component owner = ...;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
#Override
public Void run() {
try {
Field field;
if (System.getProperty("java.version").startsWith("1.6.0")) {
Class clazz = Class.forName("javax.swing.PopupFactory");
field = clazz.getDeclaredField("forceHeavyWeightPopupKey");
} else { //JDK 1.7.0, 1.8.0
Class clazz = Class.forName("javax.swing.ClientPropertyKey");
field = clazz.getDeclaredField("PopupFactory_FORCE_HEAVYWEIGHT_POPUP");
}
field.setAccessible(true);
owner.putClientProperty(field.get(null), Boolean.TRUE);
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
return null;
}
});
After forcing the popup menu to always be a heavyweight component this
SwingUtilities.getWindowAncestor(popupMenu).pack();
also worked to update the size of the popup, even beyond the bounds of the application.
I think you can add a PopupMenuListener to the popup menu and handle the menuWillBecomeVisible(...) event to set the size of the popup.

GUI - How do I switch between panels or frames while saving user input

So I have a layout made with buttons,textfields, and labels. A user is supposed to put input into the textfields. When he hits a button, I want it so that the input is cleared and a new "page" is shown with the layout i have made. The user can input as much information into new "pages" as he wants until he hits an "finished" button. In short, I want to switch between panels or frames (i dont know which, probably panels??). Now, I was thinking of using card layout to do this but since i'm reading user input it wouldn't really make sense since cardlayout is made based on a predetermined amount of panels and what will be in the panels. Since I won't know when the user is "finished", I won't know how many panels to use.
Anyways, I'm just a beginner with GUI so any help would be great!
Now, I was thinking of using card layout to do this but since i'm
reading user input it wouldn't really make sense since cardlayout is
made based on a predetermined amount of panels and what will be in the
panels. Since I won't know when the user is "finished", I won't know
how many panels to use.
You can dinamically add components to CardLayout on next button's click. If all the pages have the same structure you can have a class for those pages and add a new one every time next button is pressed. When finish button is pressed do something with all those pages iterating over the panel (with CardLayout) components. Take a look to Container.getComponents() method. You don't even need to keep any kind of array nor list because the container already do so.
Example
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Demo {
private void createAndShowGUI() {
final JPanel cardPanel = new JPanel(new CardLayout());
cardPanel.add(new Page(), "1");
final JButton nextButton = new JButton("Next");
nextButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardPanel.add(new Page(), String.valueOf(cardPanel.getComponentCount() + 1));
CardLayout layout = (CardLayout)cardPanel.getLayout();
layout.next(cardPanel);
}
});
final JButton finishButton = new JButton("Finish");
finishButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
nextButton.setEnabled(false);
for(Component comp : cardPanel.getComponents()) {
if(comp instanceof Page) {
Page page = (Page)comp;
page.printData();
}
}
}
});
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(nextButton);
buttonsPanel.add(finishButton);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(cardPanel, BorderLayout.CENTER);
frame.getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class Page extends JPanel {
final private JTextField data;
public Page() {
super();
add(new JLabel("Please add some info:"));
data = new JTextField(20);
add(data);
}
public void printData() {
System.out.println(data.getText());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
As far as I understand from your description you do not need multiple panels. I am assuming that you have some sort of object hierarchy for your model layer. So, let's say you use those input values to create AnObject objects.
You can create an ArrayList<AnObject> in your top class. And as user inputs and clicks done you just create one more AnObject with given input and add it to the ArrayList you defined in top class.
BTW, you can also define ArrayList whereever it is reachable. But you must think carefully, to keep your data persistent. If the object of the class that you defined ArrayList is "gone", your data is also "gone". I think this should be clear enough.
The next step is just trivially clearing out those input fields.
This is the most straightforward way, it may not be the smartest way to do that depending on your use case. But it would give you an idea for what to look and learn for.

Scrolling on a JComboBox popup hide it

My client is complaining that JComboBox popups often close when the scroll is being used over a JComboBox popup with no vertical scrollbar. (He seems to accidently use scrolling over it because he is using an Apple Magic Mouse.)
Any way to prevent this to happen ?
I know it has to do with the ComboBoxUI, but I would like a few pointer where to start. BasicComboPopup.handler is private (not reusable) and I don't see any code relative to any a MouseWhellListener in BasicComboPopup.
As seen in the source, BasicPopupMenuUI contains a nested class, MouseGrabber, that implements the AWTEventListener interface. The receipt of MouseEvent.MOUSE_WHEEL in eventDispatched() cancels the popup as a function of isInPopup(). I know of no simple way to defeat the behavior.
Empirically, this example invokes show() from the actionPerformed() handler of a JButton; mouse wheel events are ignored. This might be a reasonable alternative for your user, perhaps combined with a suitable ActionEvent modifier mask.
In contrast, this example invokes show() in response to isPopupTrigger() in a MouseAdapter; as expected, mouse wheel events cancel the popup.
Thanks to your suggestion, I've got an idea an found a solution by hacking AWTEventListeners.
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener()
{
public void eventDispatched(AWTEvent event)
{
if (event instanceof MouseWheelEvent)
{
Object source = event.getSource();
if ((source instanceof JScrollPane) &&
(((JScrollPane) source).getParent().getClass().
getName().equals("com.apple.laf.AquaComboBoxPopup")))
{
JViewport viewport = ((JScrollPane) source).getViewport();
if (viewport.getViewSize().height <= viewport.getHeight())
// prevent consuming if there is a vertical scrollbar
((MouseWheelEvent) event).consume();
}
}
}
}, AWTEvent.MOUSE_WHEEL_EVENT_MASK);
Thanks guys !
I have tested default behaviour of a combobox. And when I am scrolling over the popup it is fine it will not close it. But when I scroll outside it or even over the combobox itself then it disappears.
I do not know if you are after something like this but I have added the mouse wheel listener to the combobox this way if I detect the movement over the combobox there I am reshowing the popup. -- This bit only partially solves the issue that the mouse wheeling will not show the combo box when scrolling over the combobox.
import java.awt.HeadlessException;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ComboBoxMouseWheel
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createGUI();
}
});
}
private static void createGUI() throws HeadlessException
{
String[] items = new String[]
{
"oasoas", "saas", "saasas"
};
final JComboBox jcb = new JComboBox(items);
jcb.addMouseWheelListener(new MouseWheelListener()
{
#Override
public void mouseWheelMoved(MouseWheelEvent e)
{
System.out.println("ohjasajs");
e.consume();
jcb.showPopup();
}
});
JPanel p = new JPanel();
p.add(jcb);
JPanel contentPane = new JPanel();
contentPane.add(p);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(300, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
I hope this is helpful even a bit. If you manage to solve other way please do share it with us.
The solution provided by #trashgod seems doable but it looks so elaborated :), thus I propose mine approach an alternative.
Good luck, Boro.
Here is a solution that will work in most cases
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseWheelEvent) {
Object source = event.getSource();
if (source instanceof JScrollPane) {
JScrollPane scroll = (JScrollPane) source;
if (scroll.getName().equals("ComboBox.scrollPane")) {
MouseWheelEvent sourceEvent = ((MouseWheelEvent) event);
for (MouseWheelListener listener : scroll.getListeners(MouseWheelListener.class)) {
listener.mouseWheelMoved(sourceEvent);
}
sourceEvent.consume();
}
}
}
}
}, AWTEvent.MOUSE_WHEEL_EVENT_MASK);

Categories