I want to disable scrolling with the mousewheel in my JScrollPane while ctrl is pressed.
When you press ctrl and move the wheel you will zoom in/out AND also scroll the panel, which is not what I wanted.
Here's the working code:
scroller = new JScrollPane(view);
scroller.removeMouseWheelListener(scroller
.getMouseWheelListeners()[0]);
scroller.addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(final MouseWheelEvent e) {
if (e.isControlDown()) {
if (e.getWheelRotation() < 0) {
// Zoom +
} else {
// Zoom -
}
} else if (e.isShiftDown()) {
// Horizontal scrolling
Adjustable adj = getScroller().getHorizontalScrollBar();
int scroll = e.getUnitsToScroll() * adj.getBlockIncrement();
adj.setValue(adj.getValue() + scroll);
} else {
// Vertical scrolling
Adjustable adj = getScroller().getVerticalScrollBar();
int scroll = e.getUnitsToScroll() * adj.getBlockIncrement();
adj.setValue(adj.getValue() + scroll);
}
}
});
Edited my question and resolved it myself.
If you have any tweaks go ahead and tell me!
Take a look at Mouse Wheel Controller. You won't be able to use the exact code but you should be able to use the concept of the class.
The code replaces the default MouseWheelListener with a custom listener. Then it recreates the event with one different parameter in redispatches the event to the default listeners.
In your case you won't need to create a new event you will just need to prevent any event with a Control modifier from being redispatched to the default listeners and instead you invoke the code you posted in your question.
In order to temporarily disable scrolling you could manipulate the scrollbar's unit increment value and, respectively, restore it again.
Just add a key listener to the view port panel and react to Ctrl key pressed:
editorPane.addKeyListener(new KeyAdapter(){
#Override
public void keyPressed(KeyEvent e) {
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
getVerticalScrollBar().setUnitIncrement(0);
else
getVerticalScrollBar().setUnitIncrement(15);
}
#Override
public void keyReleased(KeyEvent e) {
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
getVerticalScrollBar().setUnitIncrement(0);
else
getVerticalScrollBar().setUnitIncrement(15);
}
});
Related
I have a JPanel with many JButton components inside. Is there a way to get the panel mouse event when a button is pressed? Another point of view: How to make button transparent to panel mouse event? I specifically need to capture mousePressed() event of panel.
EDIT
Context:
I'm dragging the panel content through a JScrollPane (actually working), to accomplish that I needed to capture the point where mouse is pressed, so both panel and buttons have MouseListener and MouseMotionListener to capture the point and do other stuff.
Issue:
When I press -> drag -> release the mouse button, if the mouse is still over the button it executes whatever the button does. So I want the mouse listener of the panel to be 'independent' of the button, to remove the mouse listener from the buttons.
EDIT 2
I just realize reading my own issue... that it will make no difference removing MouseListener to the JButton. When pressing the button if the mouse it stil over it, the actionPerformed will be executed anyway...What can I do?
EDIT 3
Edited question title, according to the solution.
Kipping in mind that the event execution order in this case is: mousePressed->mouseDragged->actionPerformed->mouseReleased , I get it working at the moment, adding a boolean:
#Override
public void mousePressed(MouseEvent e) {
origin = new Point(e.getPoint());
}
//each time the user stops dragging set dragged to false
#Override
public void mouseReleased(MouseEvent arg0) {
dragged = false;
}
#Override
public void mouseDragged(MouseEvent e) {
dragged=true;
if(((Component) e.getSource()).getParent().equals(myPanel)
|| e.getSource().equals(myPanel)){
if (origin != null) {
JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, myPanel);
if (viewPort != null) {
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = viewPort.getViewRect();
view.x += deltaX;
view.y += deltaY;
myPanel.scrollRectToVisible(view);
}
}
}
#Override
public void actionPerformed(ActionEvent e){
//stuff do detect the button...
//..in case there is more than one panel, if the component belong to myPanel and dragg is false
if(((Component) e.getSource()).getParent().equals(myPanel)&& dragged==false ){
//do stuff
}
}
I have a situation where I have a popup menu created when a JTable is right clicked on. Standard way of creating the popup menu:
aJTable.setComponentPopupMenu(rightClickMenu);
Now afterwards in the action that gets registered, I am unable to find out which cell was right clicked on to get that popup menu to appear.
rightClickMenuItem.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// Work out what cell was right clicked to generate the menu
}
});
Any ideas on how you do this?
Astonishing fact: with a componentPopupMenu installed, a mouseListener never sees the mouseEvent that is the popupTrigger (reason is that showing the componentPopup is handled globally by a AWTEventListener installed by BasicLookAndFeel, and that listener consumes the event).
The only place which sees the mousePosition of that trigger is the getPopupLocation(MouseEvent), so the only reliable way to get hold of it (for doing location dependent config/actions) is #Mad's suggestion to override that method and store the value somewhere for later use.
The snippet below uses a clientProperty as storage location:
final JTable table = new JTable(new AncientSwingTeam()) {
#Override
public Point getPopupLocation(MouseEvent event) {
setPopupTriggerLocation(event);
return super.getPopupLocation(event);
}
protected void setPopupTriggerLocation(MouseEvent event) {
putClientProperty("popupTriggerLocation",
event != null ? event.getPoint() : null);
}
};
JPopupMenu popup = new JPopupMenu();
Action action = new AbstractAction("show trigger location") {
#Override
public void actionPerformed(ActionEvent e) {
JPopupMenu parent = (JPopupMenu) SwingUtilities.getAncestorOfClass(
JPopupMenu.class, (Component) e.getSource());
JTable invoker = (JTable) parent.getInvoker();
Point p = (Point) invoker.getClientProperty("popupTriggerLocation");
String output = p != null ? "row/col: "
+ invoker.rowAtPoint(p) + "/" + invoker.columnAtPoint(p) : null;
System.out.println(output);
}
};
popup.add(action);
popup.add("dummy2");
table.setComponentPopupMenu(popup);
#MadProgrammer's suggestion of getPopupLocation looked promising, but I couldn't work out how to get the information across between the table and the actionEvent...
I got around this by making sure that the row was selected when you rightclicked on it -> since the popup menu prevents the selection of the row, you can add in a mouse listener that makes sure the row gets selected no matter what click (left or right) is pressed.
aTable.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
int r = aTable.rowAtPoint(e.getPoint());
if (r >= 0 && r < clt.getRowCount()) {
aTable.setRowSelectionInterval(r, r);
} else {
aTable.clearSelection();
}
}
});
This means that in the rightClickMenuItem's action listener, you can grab the table's selected cell / row
rightClickMenuItem.addActionListener(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
aTable.get details about the selected one....
}
});
Too easy! Thanks everyone for the help.
JTable has methods
int row = rowAtPoint(p);
int col = columnAtPoint(p);
So pass the MouseEvent's point and use the values
Add a MouseListener and store the last right click point somewhere.
I want to override the mouse wheel listener in Swing but only if they have the Control button pressed. The listener will be attached to a JPanel so that when they scroll the wheel it will scroll the JScrollPane and when they have the control button pressed and scroll the wheel it will zoom in. The default scroll of JScrollPane works (obviously) before I override it with my own listener. Here is my code:
mainPanel.addMouseWheelListener(new MouseWheelListener(){
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
if ((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) {
int notches = e.getWheelRotation();
if (notches < 0) {
redrawOnZoom(true);
} else {
redrawOnZoom(false);
}
}
}
});
Is there a way of saying something like "If mouse is scrolled on its own then do default JScrollPane scrolling behaviour but If Ctrl is pressed then zoom"?
you can dispatch the event to its parent if you don't want to handle it:
final MouseWheelListener wheel = new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
// handle some events here and dispatch others
if (shouldHandleHere(e)) {
LOG.info("do-my-own-stuff");
} else {
LOG.info("dispatch-to-parent");
e.getComponent().getParent().dispatchEvent(e);
}
}
public boolean shouldHandleHere(MouseWheelEvent e) {
return (e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0;
}
};
Hint:
Override the mouseWheelListener.
two functions : scroll() and other zoom.
Check for CTRL keyPress inside listener.
If pressed, call zoom() elsescroll()
refer tohow to write swing listener for guidence.
Let's say I have JTabbedPane with a ChangeListener
JTabbedPane tabbedPane = new JTabbedPane();
// Add few tabs
.....
.....
tabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent changeEvent) {
// How to determine if the changeEvent was fired because of a tab remove/add ?
}
});
and somewhere I am doing a
tabbedPane.removeTabAt(2);
and somewhere else
tabbedPane.add(panel, 0);
The ChangeListener should get fired now, is there any way to determine within the listener if it was called due to a tab remove/add ?
EDIT: I am basically trying to do some actions only when the user switches between tabs and not when adding or removing.
If I remember correctly, JTabbedPane will fire a componentAdded() event (defined in Container) when a new tab is added and a componentRemoved() event if a tab is removed.
You should be able to listen for adding or removal of a tab by registering a ContainerListener
http://docs.oracle.com/javase/7/docs/api/java/awt/Container.html#addContainerListener(java.awt.event.ContainerListener)
The stateChanged() event is just a side-effect of the add because the JTabbedPanel automatically switches to the new tab.
Depending on the exact requirement, you might keep track of the selected component and only do stuff if that has changed:
ChangeListener l = new ChangeListener() {
Component lastSelected = tabbedPane.getSelectedComponent();
#Override
public void stateChanged(ChangeEvent e) {
if (lastSelected != tabbedPane.getSelectedComponent()) {
LOG.info("changed: " + tabbedPane.getSelectedIndex());
lastSelected = tabbedPane.getSelectedComponent();
}
}
};
tabbedPane.addChangeListener(l);
Might not be good enough, though, as it will trigger if the selected tab itself is removed.
You might also want to examine the client property __index_to_remove__, which is set by removeTabAt().
By keeping track of the current number of tabs, you can detect a selection change based on add or delete
ChangeListener l = new ChangeListener() {
int lastTabCount = tabbedPane.getTabCount();
Component lastSelected = tabbedPane.getSelectedComponent();
#Override
public void stateChanged(ChangeEvent e) {
if (lastSelected != tabbedPane.getSelectedIndex())
{
int currentTabCount = tabbedPane.getTabCount();
if (lastTabCount == currentTabCount ) {
LOG.info("changed: " + tabbedPane.getSelectedIndex());
} else if (lastTabCount < currentTabCount)
LOG.info("changed due to delete: " + tabbedPane.getSelectedIndex());
} else if (lastTabCount > currentTabCount)
LOG.info("changed due to add: " + tabbedPane.getSelectedIndex());
}
lastTabCount = tabbedPane.getTabCount();
lastSelected = tabbedPane.getSelectedComponent();
}
}
};
tabbedPane.addChangeListener(l);
I have three different jtable on three diffenernt jscrollpane - one next to the other.
I successfuly written some code that makes them all scroll together when I scroll the mouse wheel.
I inherrited JScrollpane and overriden its processMouseWheelEvent methos as follows:
public void processMouseWheelEvent(MouseWheelEvent e) {
...
if (e.getSource() == this) {
for (BTSJScrollPane other : effected) {
other.processMouseWheelEvent(e);
}
}
}
I have canelled the pageup pagedown using
final InputMap inputMap =
comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke("PAGE_DOWN"), EMPTY);
inputMap.put(KeyStroke.getKeyStroke("PAGE_UP"), EMPTY);
comp.getActionMap().put(EMPTY, emptyAction);
But,
my only problem now is that when the user clicks up and down, they dont go together but rather scroll indipently.
Any suggestions ?
So far I wrote in my scrollpane something like
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
#Override public boolean dispatchKeyEvent(KeyEvent e) {
if (thisIsThesourceTable) {
if (e.getKeyCode() == 38 || e.getKeyCode() == 40) {
}
}
return false;
}
});
But :
1. is there a better way?
2. maybe I should do it somehow in the actionMap?
3. how do I pass the key up/down event to the other scrollpane?
4. can I know if I am near the end of the viewing part in the scroll pane? is it needed
1, 2, & 3: You should use listeners on the scrollbars so it works with mouse, keyboard, and scrollbar interaction. That way you won't need key or mouse listeners. Here is one way:
scroll1.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
scroll2.getVerticalScrollBar().setValue(e.getValue());
}
});
4: Look at JScrollPane's getVerticalScrollBar().getMaximumSize() and getModel() to find out if you're near the end.