I'm currently connecting this signal with a function that handles the click. For example:
QtCore.QObject.connect(self.ui.webView, QtCore.SIGNAL("linkClicked (const QUrl&)"), self.navigate)
def navigate(self, url):
#do something
What I'd like to is for the for the navigate function to know if the link was clicked on by the left or right mouse button. Something like
def navigate(self, url, event):
if event == Qt.LeftClick:
#do something
if event == Qt.MidClick:
#do something else
Is this possible?
Another method is reimplementing the mousePressEvent and filtering mouse events there:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtCore, QtGui
class myWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(myWindow, self).__init__(parent)
self.label = QtGui.QLabel(self)
self.label.setText("Click Me")
self.layout = QtGui.QHBoxLayout(self)
self.layout.addWidget(self.label)
def mousePressEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
self.label.setText("Left Mouse Click!")
elif event.buttons() == QtCore.Qt.RightButton:
self.label.setText("Right Mouse Click!")
return super(myWindow, self).mousePressEvent(event)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('myWindow')
main = myWindow()
main.resize(150, 150)
main.show()
sys.exit(app.exec_())
You should subclass QWebView, and override mousePressEvent. You could store in a variable the button that was pressed using the button() function of the QMouseEvent .
In your slot you can simply check the value of the last button pressed and handle it the way you want.
If you take a look at the docs there's some information on which buttons have been pressed in the QMouseEvent and you can handle them inside an event filter: QMouseEvent.button docs.
Related
I have a QTableWidget that gets enabled and disabled depending on certain data.
I have a button I want to be enabled when the QTableWidget is enabled, and disabled when the widget is disabled.
Is there any event handler that would let me do this?
Such as (and this does not work):
myTable.changeEvent.connect(lambda: print("test"))
Ideally in the above code, 'test' would be printed every time the table gets enabled or disabled.
The simplest solution is that the moment you deactivate the QTableWidget you also deactivate the button (or use a signal to transmit the information).
Instead, another solution is to use an event filter that allows to emit a signal every time the widget's state changes and then use that information to change the button's state.
import random
import sys
from PyQt5 import QtCore, QtWidgets
class EnableHelper(QtCore.QObject):
enableChanged = QtCore.pyqtSignal(bool)
def __init__(self, widget):
super().__init__(widget)
self._widget = widget
self.widget.installEventFilter(self)
#property
def widget(self):
return self._widget
def eventFilter(self, obj, event):
if obj is self.widget and event.type() == QtCore.QEvent.EnabledChange:
self.enableChanged.emit(self.widget.isEnabled())
return super().eventFilter(obj, event)
class Widget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.table = QtWidgets.QTableWidget(5, 4)
self.button = QtWidgets.QPushButton("Hello world")
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.table)
lay.addWidget(self.button)
helper = EnableHelper(self.table)
helper.enableChanged.connect(self.button.setEnabled)
self.test()
def test(self):
self.table.setEnabled(random.choice([True, False]))
QtCore.QTimer.singleShot(1000, self.test)
def main():
app = QtWidgets.QApplication(sys.argv)
win = Widget()
win.show()
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()
Note: changeEvent is not a signal so you should not use connect as this is a class method. Also it is not good to use it if you only want to detect if the widget changes state from enabled to disabled, or vice versa, since this is also called in other cases.
I am trying implement a feature such that when a mouse is clicked on the gui, a function is triggered
Below is my mouse click detection, it doesn't work when I click on any part of the gui
from PySide.QtCore import *
from PySide.QtGui import *
import sys
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QHBoxLayout(self)
layout.addWidget(QLabel("this is the main frame"))
layout.gui_clicked.connect(self.anotherSlot)
def anotherSlot(self, passed):
print passed
print "now I'm in Main.anotherSlot"
class MyLayout(QHBoxLayout):
gui_clicked = Signal(str)
def __init__(self, parent=None):
super(MyLayout, self).__init__(parent)
def mousePressEvent(self, event):
print "Mouse Clicked"
self.gui_clicked.emit("emit the signal")
a = QApplication([])
m = Main()
m.show()
sys.exit(a.exec_())
This is my goal
Mouseclick.gui_clicked.connect(do_something)
Any advice would be appreciated
Define mousePressEvent inside Main:
from PySide.QtCore import *
from PySide.QtGui import *
import sys
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QHBoxLayout(self)
layout.addWidget(QLabel("this is the main frame"))
def mousePressEvent(self, QMouseEvent):
#print mouse position
print QMouseEvent.pos()
a = QApplication([])
m = Main()
m.show()
sys.exit(a.exec_())
This can get complicated depending on your needs. In short, the solution is an eventFilter installed on the application. This will listen the whole application for an event. The problem is "event propagation". If a widget doesn't handle an event, it'll be passed to the parent (and so on). You'll see those events multiple times. In your case, for example QLabel doesn't do anything with a mouse press event, therefore the parent (your main window) gets it.
If you actually filter the event (i.e. you don't want the original widget to respond to the event), you won't get that problem. But, I doubt that this is your intent.
A simple example for just monitoring:
import sys
from PySide import QtGui, QtCore
class MouseDetector(QtCore.QObject):
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.MouseButtonPress:
print 'mouse pressed', obj
return super(MouseDetector, self).eventFilter(obj, event)
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
layout = QtGui.QHBoxLayout()
layout.addWidget(QtGui.QLabel('this is a label'))
layout.addWidget(QtGui.QPushButton('Button'))
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mouseFilter = MouseDetector()
app.installEventFilter(mouseFilter)
main = MainWindow()
main.show()
sys.exit(app.exec_())
You can see that, clicking on the QLabel will give you something like:
mouse pressed <PySide.QtGui.QLabel object at 0x02B92490>
mouse pressed <__main__.MainWindow object at 0x02B92440>
Because, QLabel receives the event and since it doesn't do anything with it, it's ignored and passed to the parent (MainWindow). And it's caught by the filter/monitor again.
Clicking on the QPushButton doesn't have any problem because it uses that event and does not pass to the parent.
PS: Also note that this can cause performance problems since you are inspecting every single event in the application.
I have tried to implement in Pyside the method described in How to distinguish between mouseReleaseEvent and mousedoubleClickEvent on QGrapnhicsScene, but I had to add a crufty flag to keep it from showing single click after the second button release in a double click.
Is there a better way?
import sys
from PySide import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
"""an attempt to implement
https://stackoverflow.com/questions/18021691/how-to-distinguish-between-mousereleaseevent-and-mousedoubleclickevent-on-qgrapn
main()
connect(timer, SIGNAL(timeout()), this, SLOT(singleClick()));
mouseReleaseEvent()
timer->start();
mouseDoubleClickEvent()
timer->stop();
singleClick()
// Do single click behavior
"""
self.timer = QtCore.QTimer()
self.timer.setSingleShot(True)
# had to add a "double_clicked" flag
self.double_clicked = False
self.timer.timeout.connect(self.singleClick)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Single click, double click')
self.show()
def mouseReleaseEvent(self, event):
if not self.double_clicked:
self.timer.start(200)
else:
self.double_clicked = False
def mouseDoubleClickEvent(self, event):
self.timer.stop()
self.double_clicked = True
print 'double click'
def singleClick(self):
print 'singleClick'
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Well, as you've discovered, the original description is incomplete.
It gives a solution for distinguishing between the first click of a double-click and single-click, but not the second click of a double-click and a single-click.
The simplest solution for distinguishing the second click is to use a flag.
PS: you could slightly improve your example by using QtGui.qApp.doubleClickInterval for the timer interval.
How can i simulate mouse release action using Qt.SIGNAL?
I need to simulate a mouseRelease without user's interaction.
Thanks in advance!
Here is an example using the clicked signal of a QPushButton:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonSimulate = QtGui.QPushButton(self)
self.pushButtonSimulate.setText("Simulate Mouse Release!")
self.pushButtonSimulate.clicked.connect(self.on_pushButtonSimulate_clicked)
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addWidget(self.pushButtonSimulate)
#QtCore.pyqtSlot()
def on_pushButtonSimulate_clicked(self):
mouseReleaseEvent = QtGui.QMouseEvent(
QtCore.QEvent.MouseButtonRelease,
self.cursor().pos(),
QtCore.Qt.LeftButton,
QtCore.Qt.LeftButton,
QtCore.Qt.NoModifier,
)
QtCore.QCoreApplication.postEvent(self, mouseReleaseEvent)
def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
print "Mouse Release"
super(MyWindow, self).mouseReleaseEvent(event)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
You can use:
from PyQt4.QtTest import QTest
#(...) Where you want to release
QTest.mouseRelease(widget_to_release, Qt.LeftButton)
This will release the mouse at the center of the widget.
There are also methods for mousePress(), mouseClick(), and others. However, if you're testing Drag & Drop on Windows, be careful that the equivalent QTest.mousePress() will block, since QDrag.exec_() blocks.
Is there a way to minimize to tray in PyQt4? I've already worked with the QSystemTrayIcon class, but now I would like to minimize or "hide" my app window, and show only the tray icon.
Has anybody done this? Any direction would be appreciated.
Using Python 2.5.4 and PyQt4 on Window XP Pro
It's pretty straightforward once you remember that there's no way to actually minimize to the system tray.
Instead, you fake it by doing this:
Catch the minimize event on your window
In the minimize event handler, create and show a QSystemTrayIcon
Also in the minimize event handler, call hide() or setVisible(false) on your window
Catch a click/double-click/menu item on your system tray icon
In your system tray icon event handler, call show() or setVisible(true) on your window, and optionally hide your tray icon.
Code helps, so here's something I wrote for an application, except for the closeEvent instead of the minimize event.
Notes:
"closeEvent(event)" is an overridden Qt event, so it must be put in the class that implements the window you want to hide.
"okayToClose()" is a function you might consider implementing (or a boolean flag you might want to store) since sometimes you actually want to exit the application instead of minimizing to systray.
There is also an example of how to show() your window again.
def __init__(self):
traySignal = "activated(QSystemTrayIcon::ActivationReason)"
QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated)
def closeEvent(self, event):
if self.okayToClose():
#user asked for exit
self.trayIcon.hide()
event.accept()
else:
#"minimize"
self.hide()
self.trayIcon.show() #thanks #mojo
event.ignore()
def __icon_activated(self, reason):
if reason == QtGui.QSystemTrayIcon.DoubleClick:
self.show()
Just to add to the example by Chris:
It is crucial that you use the Qt notation when declaring the signal, i.e.
correct:
self.connect(self.icon, SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.iconClicked)
and not the PyQt one
incorrect and won't work:
self.connect(self.icon, SIGNAL("activated(QSystemTrayIcon.ActivationReason)"), self.iconClicked)
Note the :: in the signal string. This took me about three hours to figure out.
Here's working code..Thanks Matze for Crucial, the SIGNAL took me more hours of curiosity.. but doing other things. so ta for a #! moment :-)
def create_sys_tray(self):
self.sysTray = QtGui.QSystemTrayIcon(self)
self.sysTray.setIcon( QtGui.QIcon('../images/corp/blip_32.png') )
self.sysTray.setVisible(True)
self.connect(self.sysTray, QtCore.SIGNAL("activated(QSystemTrayIcon::ActivationReason)"), self.on_sys_tray_activated)
self.sysTrayMenu = QtGui.QMenu(self)
act = self.sysTrayMenu.addAction("FOO")
def on_sys_tray_activated(self, reason):
print "reason-=" , reason
This was an edit of vzades response, but it was rejected on a number of grounds. It does the exact same thing as their code but will also obey the minimize event (and run without syntax errors/missing icons).
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
style = self.style()
# Set the window and tray icon to something
icon = style.standardIcon(QtGui.QStyle.SP_MediaSeekForward)
self.tray_icon = QtGui.QSystemTrayIcon()
self.tray_icon.setIcon(QtGui.QIcon(icon))
self.setWindowIcon(QtGui.QIcon(icon))
# Restore the window when the tray icon is double clicked.
self.tray_icon.activated.connect(self.restore_window)
def event(self, event):
if (event.type() == QtCore.QEvent.WindowStateChange and
self.isMinimized()):
# The window is already minimized at this point. AFAIK,
# there is no hook stop a minimize event. Instead,
# removing the Qt.Tool flag should remove the window
# from the taskbar.
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.Tool)
self.tray_icon.show()
return True
else:
return super(Example, self).event(event)
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(
self,
'Message',"Are you sure to quit?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
self.tray_icon.show()
self.hide()
event.ignore()
def restore_window(self, reason):
if reason == QtGui.QSystemTrayIcon.DoubleClick:
self.tray_icon.hide()
# self.showNormal will restore the window even if it was
# minimized.
self.showNormal()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This is the correct way to handle double click on a tray icon for PyQt5.
def _create_tray(self):
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.activated.connect(self.__icon_activated)
def __icon_activated(self, reason):
if reason in (QSystemTrayIcon.Trigger, QSystemTrayIcon.DoubleClick):
pass
This is the code and it does help i believe in show me the code
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QDialog, QApplication, QPushButton, QLineEdit, QFormLayout, QSystemTrayIcon
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.icon = QSystemTrayIcon()
r = self.icon.isSystemTrayAvailable()
print r
self.icon.setIcon(QtGui.QIcon('/home/vzades/Desktop/web.png'))
self.icon.show()
# self.icon.setVisible(True)
self.setGeometry(300, 300, 250, 150)
self.setWindowIcon(QtGui.QIcon('/home/vzades/Desktop/web.png'))
self.setWindowTitle('Message box')
self.show()
self.icon.activated.connect(self.activate)
self.show()
def closeEvent(self, event):
reply = QtGui.QMessageBox.question(self, 'Message', "Are you sure to quit?", QtGui.QMessageBox.Yes |
QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
event.accept()
else:
self.icon.show()
self.hide()
event.ignore()
def activate(self, reason):
print reason
if reason == 2:
self.show()
def __icon_activated(self, reason):
if reason == QtGui.QSystemTrayIcon.DoubleClick:
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()