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.
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
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'
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.
I've want to implement a scroll/pan-feature on a QGraphicsView in my (Py)Qt application. It's supposed to work like this: The user presses the middle mouse button, and the view scrolls as the user moves the mouse (this is quite a common feature).
I tried using the scroll() method inherited from QWidget. However, this somehow moves the view instead - scrollbars and all. See picture.
So, given that this is not the way I'm supposed to do this, how should I? Or is it the correct way, but I do something else wrong? The code I use:
def __init__(self):
...
self.ui.imageArea.mousePressEvent=self.evImagePress
self.ui.imageArea.mouseMoveEvent=self.evMouseMove
self.scrollOnMove=False
self.scrollOrigin=[]
...
def evImagePress(self, event):
if event.button() == Qt.LeftButton:
self.evImageLeftClick(event)
if event.button() == Qt.MidButton:
self.scrollOnMove=not self.scrollOnMove
if self.scrollOnMove:
self.scrollOrigin=[event.x(), event.y()]
...
def evMouseMove(self, event):
if self.scrollOnMove:
self.ui.imageArea.scroll(event.x()-self.scrollOrigin[0],
event.y()-self.scrollOrigin[1])
It works as I expect, except for the whole move-the-widget business.
Fails to scroll http://img55.imageshack.us/img55/3222/scrollfail.jpg
My addition to translate() method.
It works great unless you scale the scene. If you do this, you'll notice, that the image is not in sync with your mouse movements. That's when mapToScene() comes to help. You should map your points from mouse events to scene coordinates. Then the mapped difference goes to translate(), voila viola- your scene follows your mouse with a great precision.
For example:
QPointF tmp2 = mapToScene(event->pos());
QPointF tmp = tmp2.mapToScene(previous_point);
translate(tmp.x(),tmp.y());
I haven't done this myself but this is from the QGraphicsView documentation
... When the scene is larger
than the scroll bars' values, you can
choose to use translate() to navigate
the scene instead.
By using scroll you are moving the widget, translate should achieve what you are looking for, moving the contents of the QGraphicsScene underneath the view
Answer given by denis is correct to get translate to work. The comment by PF4Public is also valid: this can screw up scaling. My workaround is different than P4FPublc's -- instead of mapToScene I preserve the anchor and restore it after a translation:
previousAnchor = view.transformationAnchor()
#have to set this for self.translate() to work.
view.setTransformationAnchor(QGraphicsView.NoAnchor)
view.translate(x_diff,y_diff)
#have to reset the anchor or scaling (zoom) stops working:
view.setTransformationAnchor(previousAnchor)
You can set the QGraphicsScene's area that will be displayed by the QGraphicsView with the method QGraphicsView::setSceneRect(). So when you press the button and move the mouse, you can change the center of the displayed part of the scene and achieve your goal.