In the mouseMoveEvent method I've seen code like below to check if either the left or right mouse buttons are being pushed (as shown below). Is there a way to check if certain keyboard keys are currently being pressed? Ideally I would like to have the action performed when the mouse is leftclicked and moved and a certain key is being pushed. I don't see a way to use keyPressEvent as this is called separately from the mouseMoveEvent (just like mousePressEvent is not used in this example).
def mouseMoveEvent(self, event):
if event.buttons() & QtCore.Qt.LeftButton:
#run this when mouse is moved with left button clicked
elif event.buttons() & QtCore.Qt.RightButton:
#run this when mouse is moved with right button clicked
Edit: Based on ekhumoro's comment method now looks like this. It only works for key modifiers:
def mouseMoveEvent(self, event):
modifiers = QtGui.QApplication.keyboardModifiers()
if bool(event.buttons() & QtCore.Qt.LeftButton) and (bool(modifiers == QtCore.Qt.ControlModifier)):
#run this when mouse is moved with left button and ctrl clicked
elif event.buttons() & QtCore.Qt.LeftButton:
#run this when mouse is moved with left button clicked
elif event.buttons() & QtCore.Qt.RightButton:
#run this when mouse is moved with Right button clicked
If anyone is able to get this to work with any key a response would be greatly appreciated
def mouseMoveEvent(self, event):
modifiers = QApplication.keyboardModifiers()
Mmodo = QApplication.mouseButtons()
if bool(Mmodo == QtCore.Qt.LeftButton) and (bool(modifiers == QtCore.Qt.ControlModifier)):
print 'yup'
Related
I would like to recognize a single mouse click over a QWidget in PyQt5. In the docs there is either mouseDoubleClickEvent or mousePressEvent but there is no mouseClickEvent function for a single click. How do I get that functionality? Thank you
BTW I've noticed PyQtGraph does have a mouseClickEvent function.
Qt doesn't provide a "click" event on its own, you have to implement such a feature based on mousePressEvent and mouseReleaseEvent, by checking that the release has happened within the geometry of the widget (and, possibly, that the correct mouse button was pressed and released).
class ClickWidget(QWidget):
pressPos = None
clicked = pyqtSignal()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.pressPos = event.pos()
def mouseReleaseEvent(self, event):
# ensure that the left button was pressed *and* released within the
# geometry of the widget; if so, emit the signal;
if (self.pressPos is not None and
event.button() == Qt.LeftButton and
event.pos() in self.rect()):
self.clicked.emit()
self.pressPos = None
I'm trying to make volume button, on click it should mute/unmute and and on hover it should popup QSlider, so user can set whatever level he wants. Now I'm trying to achieve this by showing slider window in enterEvent and hiding it in leaveEvent:
class VolumeButton(QToolButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setIcon(volumeicon)
self.slider = QSlider()
self.slider.setWindowFlags(Qt.FramelessWindowHint)
self.slider.setWindowModality(Qt.NonModal)
def enterEvent(self, event):
self.slider.move(self.mapToGlobal(self.rect().topLeft()))
self.slider.show()
def leaveEvent(self, event):
self.slider.hide()
The problem is that mapToGlobal seems to be connected in some way with enterEvent and it creates recursion, but without mapToGlobal I can't place slider at the right position.
I'm not sure that QToolButton and FramelessWindow are the right widgets to achieve wished result, so let me know if there a better ways to do that.
The problem is not from mapToGlobal, but from the fact that the leaveEvent is fired as soon as the slider is shown: since the slider is in the same coordinates of the mouse, Qt considers that the mouse has "left" the button (and "entered" the slider).
You cannot use the simple leaveEvent for this, as you need to check the cursor position against both the button and the slider.
A possible solution is to create a QRegion that contains the geometry of both widgets and check if the cursor is inside it. In order to process the mouse events of the slider, an event filter must be installed on it:
class VolumeButton(QToolButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setIcon(volumeicon)
self.slider = QSlider()
self.slider.setWindowFlags(Qt.FramelessWindowHint)
self.slider.setWindowModality(Qt.NonModal)
self.slider.installEventFilter(self)
def isInside(self):
buttonRect = self.rect().translated(self.mapToGlobal(QPoint()))
if not self.slider.isVisible():
return QCursor.pos() in buttonRect
region = QRegion(buttonRect)
region |= QRegion(self.slider.geometry())
return region.contains(QCursor.pos())
def enterEvent(self, event):
if not self.slider.isVisible():
self.slider.move(self.mapToGlobal(QPoint()))
self.slider.show()
def leaveEvent(self, event):
if not self.isInside():
self.slider.hide()
def eventFilter(self, source, event):
if source == self.slider and event.type() == event.Leave:
if not self.isInside():
self.slider.hide()
return super().eventFilter(source, event)
Note that self.rect() is always at coordinates (0, 0), so you can just use self.mapToGlobal(QPoint()) to get the widget's global position. On the other hand, you might want to show the slider "outside" the button, so you could use self.mapToGlobal(self.rect().bottomLeft()).
Be aware that trying to place the slider "outside" the button geometry might result in a problem if the user moves the mouse in the gap between the button and the slider; in that case, you will need to create a valid region that covers both widgets and a reasonable space between them.
I have a QGraphicsScene and many selectable items. But when I click the right mouse button - deselects all objects. I want show menu and edit selected objects but have automatic deselect any time when right click at mouse...
Perhaps the problem is that I have included an rubber selection. selection of objects in the end is how the right and the left mouse button when I pull the frame and therefore is reset at single time you press the right button...
How to leave objects highlighted when you click on the right mouse button? Or it may be necessary to disable the rubber selection of the right button?
Daniele Pantaleone answer gave me an idea and I have modified the function of mousePressEvent() and immediately got the desired effect me
def mousePressEvent(self, event):
if event.button() == Qt.MidButton:
self.__prevMousePos = event.pos()
elif event.button() == Qt.RightButton: # <--- add this
print('right')
else:
super(MyView, self).mousePressEvent(event)
A possible solution would be to use mouseReleaseEvent to display the contextual menu instead of contextMenuEvent:
def mouseReleaseEvent(self, mouseEvent):
if mouseEvent.button() == Qt.RightButton:
# here you do not call super hence the selection won't be cleared
menu = QMenu()
menu.exec_(mouseEvent.screenPos())
else:
super().mouseReleaseEvent(mouseEvent)
I haven't been able to test it but I guess it should work. The point is that the selection is cleared by default by QGraphicsScene, so what you need to do is to prevent the clearing from happening when certain conditions are met, in your case when the contextual menu needs to be displayed.
I can't seem to get any mouse clicks in a QTreeWidget. I have tried...
...overriding mousePressEvent, but it never runs at all. Not even to log a message.
...using an event filer. It works for everything but mouse clicks.
...using delegates. Their editor events work fine, but only when over an item, which isn't enough
...making sure everything is being added to layouts. I used QTCreator and the output is using layout.addWidget(). I am also adding the widget instance to a layout in the main window.
I was able to use the answer to register the widget as an event filter for the QTreeWidget like so:
# In __init___
# self.tree is the QTreeWidget
self.tree.viewport().installEventFilter(self)
def eventFilter(self, target, event):
"""
This widget is an event filter for the tree, so this function is triggered
automatically
"""
# Print on right-click
if (event.type() == QEvent.MouseButtonPress and
event.button() == Qt.RightButton):
print("Right Click")
# Don't block/accept the event
return False
because what you can see (and click) on QTreeWidget is actually it's viewport(). You sholud install event filter on it's viewport() instead.
So I'm still fairly new to Python, and have been learning for a couple months, but one thing I'm trying to figure out is say you have a basic window...
#!/usr/bin/env python
import sys, os
import pygtk, gtk, gobject
class app:
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.set_title("TestApp")
window.set_default_size(320, 240)
window.connect("destroy", gtk.main_quit)
window.show_all()
app()
gtk.main()
I wanna right click inside this window, and have a menu pop up like alert, copy, exit, whatever I feel like putting down.
How would I accomplish that?
There is a example for doing this very thing found at http://www.pygtk.org/pygtk2tutorial/sec-ManualMenuExample.html
It shows you how to create a menu attach it to a menu bar and also listen for a mouse button click event and popup the very same menu that was created.
I think this is what you are after.
EDIT: (added further explanation to show how to respond to only right mouse button events)
To summarise.
Create a widget to listen for mouse events on. In this case it's a button.
button = gtk.Button("A Button")
Create a menu
menu = gtk.Menu()
Fill it with menu items
menu_item = gtk.MenuItem("A menu item")
menu.append(menu_item)
menu_item.show()
Make the widget listen for mouse press events, attaching the menu to it.
button.connect_object("event", self.button_press, menu)
Then define the method which handles these events. As is stated in the example in the link, the widget passed to this method is the menu that you want popping up not the widget that is listening for these events.
def button_press(self, widget, event):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
#make widget popup
widget.popup(None, None, None, event.button, event.time)
pass
You will see that the if statement checks to see if the button was pressed, if that is true it will then check to see which of the buttons was pressed. The event.button is a integer value, representing which mouse button was pressed. So 1 is the left button, 2 is the middle and 3 is the right mouse button. By checking to see if the event.button is 3, you are only responding to mouse press events for the right mouse button.