PyQt5 all button signals/events? - python-3.x

The signal for MOUSE1 on the button is widget.clicked, what are the ones for MOTION and MOUSE2? Also if anyone knows a site with all signals listed it would really help
import sys, pyautogui
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def pressed_mouse2():
pass
def window():
app = QApplication(sys.argv)
root = QMainWindow()
root.setGeometry(200, 200, 500, 500)
root.setWindowTitle('Test')
root.setWindowFlags(QtCore.Qt.FramelessWindowHint)
root.setAttribute(Qt.WA_TranslucentBackground)
button = QtWidgets.QPushButton(root)
#i need here to signal when user has pressed on MOUSE2 on the button
button.clicked.connect(clicked)
button.move(50,50)
root.show()
sys.exit(app.exec_())
window()

You just need to connect the button's clicked signal to your function.
button.clicked.connect(pressed_mouse2)
Now when you click the button you can execute any code here:
def pressed_mouse2():
print('Button clicked')
There are many kinds of widgets, each with different signals. You can find them in the Qt documentation. Here are the signals for QAbstractButton, which is inherited by QPushButton.
There is no predefined signal for a right click on the button, but you can subclass QPushButton and emit your own signal in the mousePressEvent().
class Button(QPushButton):
right_clicked = pyqtSignal()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.RightButton:
self.right_clicked.emit()
And it will respond with:
button = Button(root)
button.right_clicked.connect(pressed_mouse2)

Related

Stop a Qthread PyQt5

I've tried several methods to stop a Qthread, but none seem to work. When I look at the Call Stack, the thread has not ended, and while click again, another thread starts, thus getting infinite active threads and consuming more unnecessary memory. I tried to put terminate() and quit() and nothing stops the thread. So I also tried all of them together and no result
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import QThread
from PyQt5 import QtWidgets
from PyQt5 import QtCore
import time
import sys
class MyThread(QThread):
def run(self):
x=0
print("Starting...")
while x<5:
time.sleep(1.5)
print("Running...")
x=x+1
def close(self):
self.isRunning=False
self.terminate()
self.wait()
self.quit()
self.wait()
print("Done")
class Ui_MainWindow(QMainWindow):
def __init__(self):
super(Ui_MainWindow, self).__init__()
self.btn = QtWidgets.QPushButton(self)
self.btn.setGeometry(QtCore.QRect(77, 30, 50, 30))
self.btn.setText("CLICK")
self.btn.clicked.connect(self.doSomething)
def doSomething(self,event):
self.worker=MyThread()
self.worker.setTerminationEnabled(True)
self.worker.finished.connect(self.worker.close)
self.worker.start()
if __name__ == "__main__":
app = QApplication([])
ui = Ui_MainWindow()
ui.show()
sys.exit(app.exec_())
I managed to solve my problem using threading native library and with pyqtSignal. When clicking on the button, it loses its connection and starts the thread. After the end of the loop in the thread, a signal is issued and thus returning the connection to the button. This way, it prevents the user from clicking the button several times.
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import pyqtSignal
from PyQt5 import QtWidgets
from PyQt5 import QtCore
import time
import sys
import threading
class Ui_MainWindow(QMainWindow):
signal=pyqtSignal(str)
def __init__(self):
super(Ui_MainWindow, self).__init__()
self.btn = QtWidgets.QPushButton(self)
self.btn.setGeometry(QtCore.QRect(77, 30, 50, 30))
self.btn.setText("CLICK")
self.signal.connect(self.signalResponse)
self.btn.clicked.connect(self.doSomething)
def doSomething(self,event):
print("Starting...")
self.btn.disconnect()
worker=threading.Thread(target=self.worker)
worker.start()
def signalResponse(self,response):
if response=="Finished":
self.btn.clicked.connect(self.doSomething)
print(response)
def worker(self):
x=0
while x<5:
time.sleep(0.5)
print("Running...")
x=x+1
self.signal.emit("Finished")
if __name__ == "__main__":
app = QApplication([])
ui = Ui_MainWindow()
ui.show()
sys.exit(app.exec_())

How to create Signal for QDockWidget?

When QTabWidget is used, it is straightforward to call a function (e.g. on_tab_changed) when any of the tabs is clicked on with something like self.currentChanged.connect(self.on_tab_changed). However, I cannot figure out how to do similarly with QDockWidget. I was able to come up with a simplified MRE that reads:
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("OOP")
self.uinterface()
self.show()
def uinterface(self):
self.dock = QDockWidget("OOP example", self)
self.listWidget = QListWidget()
self.listWidget.addItem("One")
self.listWidget.addItem("Two")
self.listWidget.addItem("Three")
self.dock.setWidget(self.listWidget)
self.dock.currentChanged.connect(self.on_tab_changed) # This is the line that I'd like to modify
def on_tab_changed(self, index: int) -> None:
print ("DO SOMETHING")
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
This doesn't work because currentChanged is not a Signal for QDockWidget (which is for QTabWidget) although both derive from QWidget. I want to come up with a relatively simple way to accomplish this task as converting QDockWidget into QTabWidget is relatively straightforward for the MRE but a lot more complex and time consuming for the whole app.
P.S. Based on some of the comments, maybe the code could have read
...
self.dock.setWidget(self.listWidget)
self.dock.Clicked.connect(self.on_dockwidget_clicked)
def on_dockwidget_clicked(self) -> None:
print ("DO SOMETHING")
albeit this still would not work and it'd be necessary to use the accepted solution.
You could overwrite the the event method a QDockWidget subclass and listen for mousePressEvents and emit a custom signal that sends some kind of identifier, in case you have multiple dockWidgets and you need to know which one sent the signal. Then you can set your mainWindow to listen for the custom signal and connect you method slot to it.
For Example:
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class DockWidget(QDockWidget):
hasFocus = pyqtSignal([QDockWidget])
def __init__(self, text, parent=None):
super().__init__(text, parent=parent)
self.setObjectName(text)
def event(self, event):
if event.type() == QEvent.MouseButtonPress and event.button() == 1:
self.hasFocus.emit(self)
return super().event(event)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("OOP")
self.uinterface()
self.show()
def uinterface(self):
self.dock = DockWidget("OOP example", self)
self.listWidget = QListWidget()
self.listWidget.addItem("One")
self.listWidget.addItem("Two")
self.listWidget.addItem("Three")
self.dock.setWidget(self.listWidget)
self.dock.hasFocus.connect(self.on_dock_focus)
def on_dock_focus(self, dockwidget):
print(f"DO SOMETHING WITH {dockwidget.objectName()}")
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

PyQt5 QPushButton fires more than once

is there a way in Python3 PyQt5 to get the number of times a signal is connected to a slot i.e.:
QPushButton.clicked.connect(foo)
to have an idea of how many times the slot (foo) will be called upon emitting the signal ?
I am not talking of counters inside my code but a way to get that number from
where PyQt5 stores that info
Mechanically I would consider placing a
print('any message') #like this you are directly notified via the console console or terminal,...
in each methode you will be calling, for example:
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QPushButton
import sys
#import other modules
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# Geometry of main window:
self.setGeometry(200, 200, 300, 400)
# create a Button Btn1
self.Btn1 = QPushButton('Fire Button :)', self)
self.Btn1.clicked.connect(self.Fire1)
self.Btn1.move(0, 0)
self.Btn2 = QPushButton('2nd Fire_Button :)', self)
self.Btn2.clicked.connect(self.Fire2)
self.Btn2.move(130, 0)
def Fire1(self):
print('Worked, Fired once!...details(...)')
def Fire2(self):
print('It is Working, but he needs to add his code! Thanks')
self.setStyleSheet('background:rgba(80, 97, 15, 184);')
self.resize(600, 210)
pass
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
it's my answer is helping you (it's good!), otherwise provide us with more detailed infomations or sample of code you are working-on in order to better help you...

slot to right click menu action does does not work

I have written the below code to which I finally managed to add menu but connecitn menu to a function doesnt seem to work:
import os
from PyQt5 import uic
from PyQt5 import QtWidgets
from PyQt5 import QtCore
FILE_LOCATION = os.path.dirname(os.path.realpath(__file__))
class MainDialogWindow(QtWidgets.QDialog):
def __init__(self):
super(MainDialogWindow,self).__init__()
ui_file = os.path.join(FILE_LOCATION, "example.ui")
self._ui = uic.loadUi(ui_file, self)
self.registerCallbacks()
self.initUI()
def initUI(self):
"""Initialize the UI.
"""
self.textBrowser.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def registerCallbacks(self):
self.textBrowser.customContextMenuRequested.connect(self.context_menu)
# self.connect(self.textBrowser, QtCore.Signal('customContextMenuRequested(const QPoint &)'), self.context_menu)
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
menu.exec_(self.mapToGlobal(pos))
action.trigered.connect(self.clear)
def clear(self):
"""Slot to claer text.
"""
print("clear")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainDialogWindow()
window.show()
window.setGeometry(500, 300, 300, 300)
sys.exit(app.exec_())
please helpp,, I want call the clear function from the right click menu
I don't seem to understand how the menu.exec_() method works, that method blocks the execution of sequential tasks until the user selects a QAction from the QMenu. In your case, for example, until when you press "clear" and the triggered signal is emitted (note: you have a typo), but at that moment there is no connection, so the clear method will not be called. The solution is to make the connection before invoking the QMenu exec_():
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
action.triggered.connect(self.clear)
menu.exec_(self.mapToGlobal(pos))

QMainWindow flashes and disappears when called from another QMainWindow

This fairly minimal code creates a systray item with three right click options. One is an instance of QDialog, another QMainWindow, and also Quit. It's for a systray-driven app that will have some qdialogs and also a qmainwindow containing a table widget (or, is it possible to create a table into a qdialog?). I've been stuck on this for a week or so, read a lot of related materials and do not understand how to resolve it.
From the systray icon menu, clicking on QDialog, the dialog opens, waits for user action, and clicking the Ok or Cancel buttons will print which one was clicked. It would seem this works because QDialog has its own exec_(). Great so far.
However, clicking on the QMainWindow menu option, the main window dialog appears briefly and disappears with no chance for user input, of course. Maybe instead, the qmainwindow dialog would need to rely on the QApplication's exec_() where the object would instead be initialized just before app.exec_() perhaps? If that would work, I'm not clear on how def qmainwindow() would retrieve the information back from the user.
Hopefully a simple matter for someone who knows, a few changes, bingo.
Current environment: Windows 7 or XP, Python 2.7, Pyside
If you run this, there will be a blank place-holder in the systray that is clickable (right click), or you can also give it an actual image in place of 'sample.png'.
#!python
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow
def qdialog():
qdialog_class_obj = TestClassQDialog()
qdialog_class_obj.show()
qdialog_class_obj.exec_() # wait for user
print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action
def qmainwindow():
qmainwindow_class_obj = TestClassQMainWindow()
qmainwindow_class_obj.show()
#qmainwindow_class_obj.exec_() # 'TestClassQMainWindow' object has no attribute 'exec_'
class TestClassQDialog(QDialog):
def __init__(self, parent=None):
super(TestClassQDialog, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)
def button_ok(self):
self.qdialog_user_action = 'ok'
self.hide()
def button_cancel(self):
self.qdialog_user_action = 'cancel'
self.hide()
class TestClassQMainWindow(QMainWindow):
def __init__(self, parent=None):
super(TestClassQMainWindow, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("accepted()"), self.button_ok)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL("rejected()"), self.button_cancel)
def button_ok(self):
self.hide()
def button_cancel(self):
self.hide()
class SysTrayIcon(QMainWindow):
def __init__(self, parent=None):
super(SysTrayIcon, self).__init__(parent)
self.qdialog_action = QtGui.QAction("QDialog", self, triggered=qdialog)
self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=qmainwindow)
self.quit_action = QtGui.QAction("Quit", self, triggered=QtGui.qApp.quit)
self.createSystrayIcon()
self.systrayIcon.show()
def createSystrayIcon(self):
self.systrayIconMenu = QtGui.QMenu(self)
self.systrayIconMenu.addAction(self.qdialog_action)
self.systrayIconMenu.addAction(self.qmainwindow_action)
self.systrayIconMenu.addSeparator()
self.systrayIconMenu.addAction(self.quit_action)
self.systrayIcon = QtGui.QSystemTrayIcon(self)
self.systrayIcon.setContextMenu(self.systrayIconMenu)
self.systrayIcon.setIcon(QtGui.QIcon('sample.png')) # point to a valid image if you want.
self.systrayIcon.setVisible(True)
if __name__ == '__main__':
app = QtGui.QApplication([])
systrayicon = SysTrayIcon()
app.exec_()
I've got it working. What I did was move your external method qmainwindow inside of your
SysTrayIcon and created the class parameter self.qmainwindow_class_obj = TestClassQMainWindow(). I've attached the working code below. Also, you're using the old style signal slot method, I take it you're coming from old school PyQt. The new method if very nice, clean and pythonic. I've also put the new style methods in the below code. Another thing I would do is move your qdialog method inside the SysTrayIcon class. I don't really understand why you have it outside the class but maybe I'm missing something. Hope this helps.
#!python
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication, QDialog, QMainWindow
def qdialog():
qdialog_class_obj = TestClassQDialog()
qdialog_class_obj.show()
qdialog_class_obj.exec_() # wait for user
print "qdialog_user_action: ", qdialog_class_obj.qdialog_user_action
class TestClassQDialog(QDialog):
def __init__(self, parent=None):
super(TestClassQDialog, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel)
self.ok_cancel.accepted.connect(self.button_ok)
self.ok_cancel.rejected.connect(self.button_cancel)
def button_ok(self):
self.qdialog_user_action = 'ok'
self.hide()
def button_cancel(self):
self.qdialog_user_action = 'cancel'
self.hide()
class TestClassQMainWindow(QMainWindow):
def __init__(self, parent=None):
super(TestClassQMainWindow, self).__init__(parent)
self.ok_cancel = QtGui.QDialogButtonBox(self)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.ok_cancel.accepted.connect(self.button_ok)
self.ok_cancel.rejected.connect(self.button_cancel)
def button_ok(self):
self.hide()
def button_cancel(self):
self.hide()
class SysTrayIcon(QMainWindow):
def __init__(self, parent=None):
super(SysTrayIcon, self).__init__(parent)
self.qmainwindow_class_obj = TestClassQMainWindow()
self.qdialog_action = QtGui.QAction("QDialog", self, triggered=qdialog)
self.qmainwindow_action = QtGui.QAction("QMainWindow", self, triggered=self.qmainwindow)
self.quit_action = QtGui.QAction("Quit", self, triggered=QtGui.qApp.quit)
self.createSystrayIcon()
self.systrayIcon.show()
def createSystrayIcon(self):
self.systrayIconMenu = QtGui.QMenu(self)
self.systrayIconMenu.addAction(self.qdialog_action)
self.systrayIconMenu.addAction(self.qmainwindow_action)
self.systrayIconMenu.addSeparator()
self.systrayIconMenu.addAction(self.quit_action)
self.systrayIcon = QtGui.QSystemTrayIcon(self)
self.systrayIcon.setContextMenu(self.systrayIconMenu)
self.systrayIcon.setIcon(QtGui.QIcon('linux.jpeg')) # point to a valid image if you want.
self.systrayIcon.setVisible(True)
def qmainwindow(self):
self.qmainwindow_class_obj.show()
if __name__ == '__main__':
app = QtGui.QApplication([])
systrayicon = SysTrayIcon()
app.exec_()

Resources