Swing Mouse scroll does not scroll drop down menu - java

I am trying to scroll down a drop down box. Altough mouseWheelListener is invoked, scrollBar is not moved and dropdown box is just closed after scrool event. Problem is value of scrollBar is not changed after setting in the event handler, it is always 0.
Here is the part of code:
public MyClas extends JPopupMenu implements AdjustmentListener, ContainerListener, ChangeListener{
public MyClass(){
.....
setLayout(new ScrollablePopupMenuLayout(this, defaultWidth));
JScrollBar scrollBar = new JScrollBar(JScrollBar.VERTICAL);
scrollBar.setFocusable(false);
scrollBar.addAdjustmentListener(this);
addContainerListener(this);
addMouseWheelListener(new MouseWheelListener(){
// Here is invoked after scrolling
public void mouseWheelMoved(MouseWheelEvent e){
{
int x = 1;
scrollBar.setValue(scrollBar.getValue() + x)
}
});
}

It worked after adding following line to the mouseWheelEvent method:
e.consume();

Related

Remove Panel from layout only

I have a frame where the layout is null. There is a panel attached to it that has a flow layout.
My code has it so that a button press creates a new panel that gets added to the first panel (the one attached to the frame). Then I have a mouse listener that lets you drag the newly created panel around.
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent me) {
x = me.getX();
y = me.getY();
}
});
panel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent me) {
me.translatePoint(me.getComponent().getLocation().x-x, me.getComponent().getLocation().y-y);
panel.setLocation(me.getX(), me.getY());
}
});
However, when I press the button for it to create a new panel, it creates a new panel while returning the it to the flow layout. I've tried removing the panel but when I drag the new panel over it, it gets erased. While if I revalidate and repaint the panel after removing it, it vanishes.
So how do I prevent it from getting erased or remove it from the layout only?
Try changing the layout to null, I don't think what you're asking is possible.

Java Swing JScrollPane not scrolling when shift held down and using mouse wheel

I have a simple Java Swing program defined below:
import javax.swing.*;
import java.awt.*;
public class Test implements Runnable {
public static void main(String[] args) {
Test main = new Test();
SwingUtilities.invokeLater(main);
}
#Override
public void run() {
// Application window.
JFrame mainFrame = new JFrame();
// Set up window.
mainFrame.setPreferredSize(new Dimension(600,700));
mainFrame.setFocusable(true);
mainFrame.requestFocus();
JScrollPane scrollPane = new JScrollPane();
scrollPane.setPreferredSize(new Dimension(600,700));
JPanel scrollPanel = new JPanel();
scrollPanel.setLayout(new GridLayout(0,1));
// Add buttons.
for (int i = 0; i < 40; i ++) {
JButton button = new JButton("Button " + i);
button.setPreferredSize(new Dimension(600,100));
scrollPanel.add(button);
}
scrollPane.setViewportView(scrollPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel mainPanel = new JPanel();
mainPanel.add(scrollPane);
// Fill up window.
mainFrame.getContentPane().setLayout(new BorderLayout());
mainFrame.getContentPane().add(mainPanel, BorderLayout.CENTER);
SwingUtilities.updateComponentTreeUI(mainFrame);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.pack();
mainFrame.setVisible(true);
}
}
The program consists of a simple JScrollPane with multiple buttons inside of it. Only vertical scrolling is enabled. It works fine.
However, the problem is, when I am holding down the 'shift' key, vertical scrolling does not work when I am using the mouse wheel to scroll. Vertical scrolling only works when I drag the scrollbar or let go of the 'shift' key.
Usually, in a JScrollPane, when the 'shift' key is held down, and the mouse wheel is used, it scrolls horizontally instead of vertically. However, I have disabled horizontal scrolling.
How would I go about enabling vertical scrolling using the mouse wheel if the user is holding down 'shift'?
I don't think there is a simple way to do this because normally you would only need the shift scroll when scrolling in more than one direction.
You could try adding a key listener to your JFrame and setting the wheel on your mouse to scroll vertically whenever the shift key is pressed. I tried it with this code and it worked just fine:
frame.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
if(arg0.isShiftDown()) {
frame.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent arg0) {
// TODO Auto-generated method stub
pane.getVerticalScrollBar().setValue(pane.getVerticalScrollBar().getValue()+arg0.getWheelRotation());
}
});
}
if(!arg0.isShiftDown()) {
frame.removeMouseWheelListener(frame.getMouseWheelListeners()[0]);
}
}
}
I have figured out a cleaner and simpler answer to my question. Here is the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CustomScrollPane extends JScrollPane {
public CustomScrollPane(Component component) {
super(component);
initialize();
}
private void initialize() {
// Set up the scroll bar.
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// Disable scrolling so we can do it manually.
setWheelScrollingEnabled(false);
addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
// Manually scroll.
getVerticalScrollBar().setValue(getVerticalScrollBar().getValue() + (e.getWheelRotation()));
}
});
}
}
The solution involves disabling JScrollPane from scrolling. It detects when the mousewheel is being rotated, and manually scrolls. This way, it will scroll when the mousewheel is rotated; it does not matter if 'shift' is being held down or not. The only drawback that I can see is that getVerticalScrollBar().setUnitIncrement() will not change the scrolling speed. The scrolling speed has to be changed manually, perhaps with a constant multiplier.

JSplitPane Resize Cursor

I can't seem to change the resize cursor of JSplitPane by calling setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); Does anyone know how to get around this? I am using Nimbus UI.
Calling setCursor on a JSplitPane component will set the cursor only for left & right (or top & bottom) components.
To set the cursor for the divider component, you can use:
Component divider = ((BasicSplitPaneUI)splitPane.getUI()).getDivider();
divider.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
We can add code for mouse listener in addPropertyChangeListener() listener of JSplitPane and after loading of GUI we can fire this event to bind mouse listener to divider. Here is my code:
splitPanehor.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, (pce) -> {
Component divider1 = ((JSplitPane) pce.getSource()).getComponent(2);
divider1.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
ExomDataGUI.f.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
}
#Override
public void mouseExited(MouseEvent e) {
ExomDataGUI.f.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
});
And we can fire this event after showing GUI in following way:
splitPanehor.firePropertyChange(JSplitPane.DIVIDER_LOCATION_PROPERTY, 219, 220);

Java JScrollPane Detect Scroll Near Bottom

I've been unable to find anything related to my question on the Internet.
I have a JScrollPane which adds a JPanel, and the JPanel gets populated with JLabels.
Currently, the user scrolls to the bottom of the JScrollPane, and then clicks the 'Next' button.
What I would like to do is to detect when the user is at/near the bottom of the JScrollPane, so that I can then trigger the 'Next' behaviour without any input from the user.
Is this even possible?
Thanks in advance everyone.
You could use an AdjustmentListener registered with your the vertical scrollbar in your JScrollPane and take action based on the event value.
Here is an example.
JScrollBar uses a BoundedRangeModel, and this will accept a ChangeListener -- so you can listen for changes to the scrollbar and respond accordingly.
Here is an example showing how to trigger an event when the scrollpane is near the bottom (90% of the height):
final JScrollPane scrollPane = new JScrollPane(panel);
scrollPane.getViewport().addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent event) {
JScrollBar scrollbar = scrollPane.getVerticalScrollBar();
if (scrollbar.getValue() + scrollbar.getVisibleAmount() > scrollbar.getMaximum() * 0.9) {
// trigger the 'Next' behaviour here
}
}
});
Alternatively, the listener can also be added to the model:
final BoundedRangeModel model = scrollPane.getVerticalScrollBar().getModel();
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent event) {
if (model.getValue() + model.getExtent() > model.getMaximum() * 0.9) {
// trigger the 'Next' behaviour here
}
}
});

How can I create a "Drop-Down" menu in a Java Swing toolbar?

I've created a drop-down menu on my Swing JToolBar. But it doesn't create behave the way I want. I'm aiming for it to work like Firefox's "Smart Bookmarks" button.
It disappears when the user selects a menu item: CORRECT!
It disappears when the user presses ESC: CORRECT!
It disappears when the user clicks somewhere in the main frame outside of the menu: CORRECT!
But it doesn't disappear when the user clicks a second time on the button that shows the drop-down menu: INCORRECT... :-(
My question is how can I add this behaviour, that it does disappear when the clicks on the button that shows the menu a second time.
Here's my current code, from Java 6 on the Mac:
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class ScratchSpace {
public static void main(String[] arguments) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Toolbar with Popup Menu demo");
final JToolBar toolBar = new JToolBar();
toolBar.add(createMoreButton());
final JPanel panel = new JPanel(new BorderLayout());
panel.add(toolBar, BorderLayout.NORTH);
panel.setPreferredSize(new Dimension(600, 400));
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private static AbstractButton createMoreButton() {
final JToggleButton moreButton = new JToggleButton("More...");
moreButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
createAndShowMenu((JComponent) e.getSource(), moreButton);
}
}
});
moreButton.setFocusable(false);
moreButton.setHorizontalTextPosition(SwingConstants.LEADING);
return moreButton;
}
private static void createAndShowMenu(final JComponent component, final AbstractButton moreButton) {
JPopupMenu menu = new JPopupMenu();
menu.add(new JMenuItem("Black"));
menu.add(new JMenuItem("Red"));
menu.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
moreButton.setSelected(false);
}
public void popupMenuCanceled(PopupMenuEvent e) {
moreButton.setSelected(false);
}
});
menu.show(component, 0, component.getHeight());
}
}
Well, here is a potential solution that is not without it's drawbacks. Only you can decide if this is acceptable for your application. The issue is that the popup closing occurs before other mouse-handling events are fired so clicking on your More.. button again causes the popup to hide, thus resetting the buttons state to deselected BEFORE the button even gets told it was pressed.
The easy workaround is to add the following call within your main program:
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE);
The result of this is that whenever a popup menu is closed because of a mouse-pressed event, that mouse event will be consumed at the time the menu is closed and won't be passed on to any other components under the mouse. If you can live with limitation, this is an easy solution.
What's happening is that when you click off the menu, it cancels the popup menu, so you deselect the button, but the next immediate event is clicking the button, and now its deselected so it shows the menu again.
I don't have the exact solution yet, but give me a little bit ...
I don't use Firefox so I don't know what the Smart Bookmarks button looks like, but maybe use a JMenu as the "button". You could try using the Border of a JButton to make it look more like a button.
Well, the listener on the button reacts only when it is pushed down, because you listen for ItemEvent.SELECTED events only. How about adding another if clause to listen for ItemEvent.DESELECTED events here:
moreButton.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
createAndShowMenu((JComponent) e.getSource(), moreButton);
}
}
});
You could either store a reference to the menu somewhere, or you could make the menu itself add another listener to the button. The latter solution could be more straightforward, since you already seem to send a button reference to the menu.

Categories