How can I correctly write the event function to pass from one QLineEdit to another one by pressing the enter key?
I know how to do that in this way:
Working Example
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLineEdit, QFormLayout
from PyQt5.QtCore import Qt, QEvent
class working(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.show()
self.x = QLineEdit(self)
self.x1 = QLineEdit(self)
layout = QFormLayout(self)
layout.addRow("x:", self.x)
layout.addRow("x1:", self.x1)
def event(self, event):
if event.type() == QEvent.KeyPress:
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
self.focusNextPrevChild(True)
return super().event(event)
def main():
app = QApplication(sys.argv)
ex = working()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Now i want to understand how to do the same with this code (i think that the problem is with super() and init but i don't know why).
UNWorking Basic Example
from PyQt5 import QtCore, QtWidgets, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(193, 119)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.x = QtWidgets.QLineEdit()
self.verticalLayout_2.addWidget(self.x)
self.x1 = QtWidgets.QLineEdit()
self.verticalLayout_2.addWidget(self.x1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "0"))
def event(self, event):
if event.type() == QEvent.KeyPress:
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
self.focusNextPrevChild(True)
return super().event(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
The second example does not work because you're trying to override the event method, which is a method available only for QWidget subclasses, while your Ui_MainWindow is a simple python object subclass, so it will never be called.
The event() method is called by Qt on any QWidget, and since you are overriding it in the first example, your method is actually called. In the second example you're not overriding the QWidget event, but you're just creating a function that is never called by anything.
Theoretically you could overwrite the event method of the MainWindow object in setupUi (that's what's called "monkey patching"):
def setupUi(self, MainWindow):
# ...
MainWindow.event = self.event
But that won't work as the self you're referring to in that function is actually the Ui_MainWindow instance, not the actual QMainWindow instance. While you could use a lambda, and add the argument with the MainWindow instance, I'd strongly advise against that, and the following explanation will clarify why you shouldn't do it.
There's no point in doing what you're trying to achieve, for a simple reason: modifying or trying to mimic the behavior of `pyuic` generated files is something that should **NEVER** be done.
Editing is discouraged mostly because whenever you need to change something in the UI from Designer, you'll end up trying to integrate the new generated code (hoping that you've not overwritten the file in the meantime) with the existing one, which will normally result in tons of errors, issues, crashes and headaches.
Editing or mimicking is discouraged as it makes very hard to implement simple class operations or override existing methods. Also, while I can understand you're interest in studying how it works, except for reading how the interface is created within the setupUi, there's nothing more to learn there. The pyuic files are intended only as an "utility layer" to ease up programming in PyQt, they should always only be imported and used as suggested in the official guidelines about using Designer.
If you want to implement the event of the first example, you'll need to use your own subclass and use one of the approaches suggested in the link above. The most common and easy to use is the multiple inheritance approach:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QFormLayout
from PyQt5.QtCore import Qt, QEvent
from ui_mainwindow import Ui_MainWindow
class Working(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
def event(self, event):
if event.type() == QEvent.KeyPress:
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
self.focusNextPrevChild(True)
return super().event(event)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
mainWindow = Working()
mainWindow.show()
sys.exit(app.exec_())
Note: I'm assuming that you've generated the file again with pyuic and that is named ui_mainwindow.py; also, note that if you're using a QMainWindow in designer, you must subclass from the same class (QMainWindow, not QWidget); finally, since you're already subclassing from QMainWindow and Ui_MainWindow, you have to create an instance of Working, not one of QMainWindow, nor one of Ui_MainWindow.
Another possibility is to use the uic module, which allows to import the .ui file directly without the need to rebuild the whole interface everytime.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QFormLayout
from PyQt5.QtCore import Qt, QEvent
from PyQt5.uic import loadUi
class Working(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
loadUi('mainWindow.ui', self)
# ...
Related
It might be a very simple question but I can't figure out how to do it.
The context:
I am making an application that can draw polygons in a QGraphicsScene. I would like to implement interactive actions. For example, the user clicks on a button, then clicks on the scene to draw temporary lines, finally the app cuts the polygon with the line.
What I try to achieve
What I did
Since I didn't find anything here or in the doc, I looked in the LibreCad repository to know how they do it.
https://github.com/LibreCAD/LibreCAD/blob/768285653c46e734a75460928142cda1a33c2c53/librecad/src/lib/actions/rs_actioninterface.h
Their base class inherits from QObject to handle events. It seems that they don't inherit from QAction despite line 40 where one can read "class QAction;". My C++ skills end here.
In an act of faith, I wrote the following minimal non-working example in python with PySide.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from PySide2.QtCore import QObject
from PySide2.QtWidgets import (QApplication, QMainWindow, QWidget,
QGraphicsView, QGraphicsScene,
QToolBar, QAction)
class Action(QAction, QObject):
def __init__(self, name, parent=None):
super().__init__(name, parent)
# I also tried to add this, obviously I don't know what I am doing
#QObject.__init__(parent)
def keyPressEvent(self, event):
print("Event handled")
super().keyPressEvent(event)
class MainWindow(QMainWindow,):
def __init__(self):
super(MainWindow, self).__init__()
self.centralwidget = QWidget()
self.graphicsView = QGraphicsView(self.centralwidget)
self.setCentralWidget(self.centralwidget)
self.scene = QGraphicsScene(0,0,1000,1000)
self.graphicsView.setScene(self.scene)
toolbar = QToolBar("My toolbar")
self.addToolBar(toolbar)
knifeActionButton = Action("Knife", self)
knifeActionButton.setShortcut("K")
knifeActionButton.triggered.connect(self.cutPolygon)
toolbar.addAction(knifeActionButton)
def cutPolygon(self):
print("Action triggered")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
The question:
How to handle events in a QAction to make it interactive?
Please excuse my English, I am a non-native speaker
I have multiple windows in a Python GUI application using PyQt5.
I need to hide current window when a button is clicked and show the next window.
This works fine from WindowA to WindowB but I get an error while going from WindowB to WindowC.
I know there is some problem in initialization as the initialization code in WindowB is unreachable, but being a beginner with PyQt, i can't figure out the solution.
WindowA code:
from PyQt5 import QtCore, QtGui, QtWidgets
from WindowB import Ui_forWindowB
class Ui_forWindowA(object):
def setupUi(self, WindowA):
# GUI specifications statements here
self.someButton = QtWidgets.QPushButton(self.centralwidget)
self.someButton.clicked.connect(self.OpenWindowB)
# More GUI specifications statements here
def retranslateUi(self, WindowA):
# More statements here
def OpenWindowB(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_forWindowB()
self.ui.setupUi(self.window)
WindowA.hide()
self.window.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
WindowA = QtWidgets.QMainWindow()
ui = Ui_forWindowA()
ui.setupUi(WindowA)
MainWindow.show()
sys.exit(app.exec_())
WindowB code:
from PyQt5 import QtCore, QtGui, QtWidgets
from WindowB import Ui_forWindowB
class Ui_forWindowB(object):
def setupUi(self, WindowB):
# GUI specifications statements here
self.someButton = QtWidgets.QPushButton(self.centralwidget)
self.someButton.clicked.connect(self.OpenWindowC)
# More GUI specifications statements here
def retranslateUi(self, WindowB):
# More statements here
def OpenWindowB(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_forWindowC()
self.ui.setupUi(self.window)
WindowB.hide() # Error here
self.window.show()
# The below code doesn't get executed when Ui_forWindowB is called from A
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
WindowB = QtWidgets.QMainWindow()
ui = Ui_forWindowB()
ui.setupUi(WindowB)
MainWindow.show()
sys.exit(app.exec_())
It works fine from A to B where
WindowA.hide() # Works Properly
While calling WindowC from WindowB
WindowB.hide() # Shows error: name 'WindowB' is not defined
I understand that the initialization isn't done as the "if" statement doesn't get executed.
How to get this working?
I have many more windows to connect in this flow
When you run a Python script, the first file executed will be assigned the name __main__, therefore, if you first execute WindowA the code inside the block if __name__ == "__main__" gets executed and the application is started using WindowA as the main window, similarly if you execute your WindowB script first, the application will be started usingWindowB as the main window.
You cannot start two applications within the same process so you have to choose which one you want to be the main window, all the others will be secondary windows (even if they inherit from QMainWindow).
Nevertheless, you should be able to instantiate new windows from a method in your main window.
As a good practice, you could create a main script to handle the initialization of your application and start an empty main window that will then handle your workflow, also, you may want to wrap your UI classes, specially if they are generated using Qt creator, here is an example:
main.py
import PyQt5
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication
from views.main_window import MainWindow
class App(QApplication):
"""Main application wrapper, loads and shows the main window"""
def __init__(self, sys_argv):
super().__init__(sys_argv)
# Show main window
self.main_window = MainWindow()
self.main_window.show()
if __name__ == '__main__':
app = App(sys.argv)
sys.exit(app.exec_())
main_window.py
This is the main window, it doesn't do anything, just control the workflow of the application, i.e. load WindowA, then WindowB etc., notice that I inherit from Ui_MainWindow, by doing so, you can separate the look and feel from the logic and use Qt Creator to generate your UI:
from PyQt5.QtWidgets import QWidget, QMainWindow
from views.window_a import WindowA
from views.window_b import WindowB
from widgets.main_window import Ui_MainWindow
class MainWindow(Ui_MainWindow, QMainWindow):
"""Main application window, handles the workflow of secondary windows"""
def __init__(self):
Ui_MainWindow.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# start hidden
self.hide()
# show window A
self.window_a = WindowA()
self.window_a.actionExit.triggered.connect(self.window_a_closed)
self.window_a.show()
def window_a_closed(self):
# Show window B
self.window_b = WindowB()
self.window_b.actionExit.triggered.connect(self.window_b_closed)
self.window_b.show()
def window_b_closed(self):
#Close the application if window B is closed
self.close()
window_a.py
from PyQt5.QtWidgets import QWidget, QMainWindow
from widgets.main_window import Ui_forWindowA
class WindowA(Ui_forWindowA, QMainWindow):
"""Window A"""
def __init__(self):
Ui_forWindowA.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# Do some stuff
window_b.py
from PyQt5.QtWidgets import QWidget, QMainWindow
from widgets.main_window import Ui_forWindowB
class WindowA(Ui_forWindowB, QMainWindow):
"""Window B"""
def __init__(self):
Ui_forWindowB.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# Do some stuff
Hopefully should give you an idea to get you going.
I am trying to get a button event handler working using Qt Designer.
I am using Anaconda-Spyder with Python 3.6
The form appears but the button btn_browse does not function. The line edit box has a cursor in it and you can type into it.
The Python file generated automatically from the ui is below. It is called file_reader.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(640, 320)
self.btn_browse = QtWidgets.QPushButton(Dialog)
self.btn_browse.setGeometry(QtCore.QRect(220, 50, 113, 32))
self.btn_browse.setObjectName("btn_browse")
self.lineEdit = QtWidgets.QLineEdit(Dialog)
self.lineEdit.setGeometry(QtCore.QRect(170, 120, 241, 131))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.btn_browse.setText(_translate("Dialog", "MyButton"))
The code I have used (pretty much from the QtDesigner Docs site) is
from PyQt5 import QtGui
from PyQt5.QtWidgets import QDialog, QApplication
from file_reader import Ui_Dialog
class Dialog(QDialog):
def __init__(self):
super(Dialog, self).__init__()
# Set up the user interface from Designer.
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Make some local modifications.
self.ui.colorDepthCombo.addItem("2 colors (1 bit per pixel)")
# Connect up the buttons.
self.ui.btn_browse.clicked.connect(self.browse_folder)
def browse_folder(self):
#exit
print("Hello")
#self.textBrowser.clear() # In case there are any existing elements in the list
directory = QtGui.QFileDialog.getExistingDirectory(self,"Pick a folder")
# execute getExistingDirectory dialog and set the directory variable to be equal
# to the user selected directory
if directory: # if user didn't pick a directory don't continue
for file_name in os.listdir(directory): # for all files, if any, in the directory
self.listWidget.addItem(file_name) # add file to the listWidget
import sys
app = QApplication(sys.argv)
window = Dialog() #Also tried QDialog() here
ui = Ui_Dialog()
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
I don't think the function browse_folder is being called. I think the issue might be the QDialog class being used rather than QMainForm. I
I am working on that. Also, I am unsure what the x switch in the ui convertor does.
I have looked at several answers here and can't see what I am doing wrong.
Your code has the following problems:
You are not creating a Dialog object, but a QDialog filled with Ui_Dialog that does not have the browse_folder method or the connection.
QFileDialog is part of QtWidgets, it is not part of QtGui, you are probably using an example of PyQt4.
I'm assuming that listWidget is from Ui_Dialog so you must sign in through ui.
from PyQt5.QtWidgets import QDialog, QApplication, QFileDialog
from file_reader import Ui_Dialog
import os
class Dialog(QDialog):
def __init__(self):
super(Dialog, self).__init__()
# Set up the user interface from Designer.
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Make some local modifications.
self.ui.colorDepthCombo.addItem("2 colors (1 bit per pixel)")
# Connect up the buttons.
self.ui.btn_browse.clicked.connect(self.browse_folder)
def browse_folder(self):
#exit
print("Hello")
#self.textBrowser.clear() # In case there are any existing elements in the list
directory = QFileDialog.getExistingDirectory(self,"Pick a folder")
# execute getExistingDirectory dialog and set the directory variable to be equal
# to the user selected directory
if directory: # if user didn't pick a directory don't continue
for file_name in os.listdir(directory): # for all files, if any, in the directory
self.ui.listWidget.addItem(file_name) # add file to the listWidget
import sys
app = QApplication(sys.argv)
window = Dialog()
window.show()
sys.exit(app.exec_())
I understand (more or less) content of the page of official documentation except the the final example, which is essencially as follows (I do not care the button):
from ui_imagedialog import ImageDialog
class MyImageDialog(ImageDialog):
def __init__(self):
super(MyImageDialog, self).__init__()
# Connect up the buttons.
self.okButton.clicked.connect(self.accept)
Problem: I'm stuck a bit trying to understand how to make this snippet work. It rises an error: 'cannon import name ImageDialog'.
What should I add from the first example of the aforementioned documentation page to make this code to show up a Dialog window?
What I've tried:
I've made the file with generated Python code with the name ui_imagedialog.py as requiered. It has the the following content, which obviously works on its own:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImageDialog(object):
def setupUi(self, ImageDialog):
ImageDialog.setObjectName("ImageDialog")
ImageDialog.resize(303, 204)
self.pushButton = QtWidgets.QPushButton(ImageDialog)
self.pushButton.setGeometry(QtCore.QRect(200, 160, 75, 23))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(ImageDialog)
QtCore.QMetaObject.connectSlotsByName(ImageDialog)
def retranslateUi(self, ImageDialog):
_translate = QtCore.QCoreApplication.translate
ImageDialog.setWindowTitle(_translate("ImageDialog", "Dialog"))
self.pushButton.setText(_translate("ImageDialog", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ImageDialog = QtWidgets.QDialog()
ui = Ui_ImageDialog()
ui.setupUi(ImageDialog)
ImageDialog.show()
sys.exit(app.exec_())
Any constructive help is appreciated.
Qt Designer is used to create the graphic part, but not for the logic, you must create the logical part depending on the widget you used in the design. In your case by the name I think it is QDialog.
from ui_imagedialog import Ui_ImageDialog
from PyQt5 import QtCore, QtGui, QtWidgets
class ImageDialog(QtWidgets.QDialog, Ui_ImageDialog):
def __init__(self, parent=None):
super(ImageDialog, self).__init__(parent=parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.accept)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = ImageDialog()
w.show()
sys.exit(app.exec_())
Observations: In the ui_imagedialog.py file there is no ImageDialog class, only the Ui_ImageDialog class, so I generated the error. Also in the design the button is called self.pushButton, so you can not call it self.okButton.
I couldn't understand the connectSlotsByName() method which is predominently used by pyuic4.. As far the class is single in a PyQt file it's ok since we can use self which will be associated with a single object throughout.. But when we try to use various classes from different files the problem and the need to use connectSlotsByName() arises.. Here's what i encountered which is weird..
I created a stacked widget..
I placed my first widget on it.. It
has a button called "Next >".
On clicking next it hides the current
widget and adds another widget which has the "click me" button..
The problem here is the click event for "click me" button in second is not captured.. It's a minimal example that i can give for my original problem.. Please help me..
This is file No.1..(which has the parent stacked widget and it's first page). On clicking next it adds the second page which has "clickme" button in file2..
from PyQt4 import QtCore, QtGui
import file2
class Ui_StackedWidget(QtGui.QStackedWidget):
def __init__(self,parent=None):
QtGui.QStackedWidget.__init__(self,parent)
self.setObjectName("self")
self.resize(484, 370)
self.setWindowTitle(QtGui.QApplication.translate("self", "stacked widget", None, QtGui.QApplication.UnicodeUTF8))
self.createWidget1()
def createWidget1(self):
self.page=QtGui.QWidget()
self.page.setObjectName("widget1")
self.pushButton=QtGui.QPushButton(self.page)
self.pushButton.setGeometry(QtCore.QRect(150, 230, 91, 31))
self.pushButton.setText(QtGui.QApplication.translate("self", "Next >", None, QtGui.QApplication.UnicodeUTF8))
self.addWidget(self.page)
QtCore.QMetaObject.connectSlotsByName(self.page)
QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.showWidget2)
def showWidget2(self):
self.page.hide()
obj=file2.widget2()
obj.createWidget2(self)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
ui = Ui_StackedWidget()
ui.show()
sys.exit(app.exec_())
Here's file2
from PyQt4 import QtGui,QtCore
class widget2():
def createWidget2(self,parent):
self.page = QtGui.QWidget()
self.page.setObjectName("page")
self.parent=parent
self.groupBox = QtGui.QGroupBox(self.page)
self.groupBox.setGeometry(QtCore.QRect(30, 20, 421, 311))
self.groupBox.setObjectName("groupBox")
self.groupBox.setTitle(QtGui.QApplication.translate("self", "TestGroupBox", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton = QtGui.QPushButton(self.groupBox)
self.pushButton.setGeometry(QtCore.QRect(150, 120, 92, 28))
self.pushButton.setObjectName("pushButton")
self.pushButton.setText(QtGui.QApplication.translate("self", "Click Me", None, QtGui.QApplication.UnicodeUTF8))
self.parent.addWidget(self.page)
self.parent.setCurrentWidget(self.page)
QtCore.QMetaObject.connectSlotsByName(self.page)
QtCore.QObject.connect(self.pushButton,QtCore.SIGNAL('clicked()'),self.printMessage)
def printMessage(self):
print("Hai")
Though in both the widgets(i mean pages)
QtCore.QMetaObject.connectSlotsByName(self.page)
the clicked signal in second dialog isn't getting processed. Thanks in advance.. Might be a beginner question..
A better question is "Why not just use new-style signals and slots?". They're much simpler and don't require any weird naming conventions:
from sys import argv, exit
from PyQt4 import QtCore, QtGui
class MyWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self._layout = QtGui.QVBoxLayout()
self.setLayout(self._layout)
self._button = QtGui.QPushButton()
self._button.setText('Click NOW!')
self._layout.addWidget(self._button)
self._button.clicked.connect(self._printMessage)
#QtCore.pyqtSlot()
def _printMessage(self):
print("Hai")
if __name__ == "__main__":
app = QtGui.QApplication(argv)
main = MyWidget()
main.show()
exit(app.exec_())
At first, here is the minimal working example:
from sys import argv, exit
from PyQt4 import QtCore, QtGui
class widget2(QtGui.QWidget):
def __init__(self, args):
self.app = MainApp(args)
QtGui.QWidget.__init__(self)
self.setObjectName('I')
self._layout = QtGui.QVBoxLayout(self)
self.setLayout(self._layout)
self.pushButtoninWidget2 = QtGui.QPushButton(self)
self.pushButtoninWidget2.setObjectName("pushButtoninWidget2")
self.pushButtoninWidget2.setText('Click NOW!')
self._layout.addWidget(self.pushButtoninWidget2)
QtCore.QMetaObject.connectSlotsByName(self)
#QtCore.pyqtSlot()
def on_pushButtoninWidget2_clicked(self):
print("Hai")
class MainApp(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self, args)
if __name__ == "__main__":
main = widget2(argv)
main.show()
exit(main.app.exec_())
When you trying to connect slots by name, you must give proper names to the slots and then someone (moc, uic, or you by calling connectSlotsByName) must connect them. Proper name for such a slot is: "on_PyQtObjectName_PyQtSignalName".
Note, that, if I'd omitted #QtCore.pyqtSlot() in the example, slot would be executed once for every appropriate overload (twice in this case).
You DO need to call connectSlotsByNames directly, cause there is no moc, which do it for you when you use QT in C++, and you do not use uic and .ui file. If you want to connect slots implicitly (I'm always doing so, except slots, connected directly in .ui), you'd better use more pytonish syntaxe: button.clicked.connect(self._mySlot).
And take a look at https://riverbankcomputing.com/static/Docs/PyQt5/signals_slots.html#connecting-slots-by-name
You do not need to call connectSlotsByName(), just remove those lines.
In file2, calling QtCore.QMetaObject.connectSlotsByName(self.page) tries to do this:
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL('clicked()'), self.on_pushButton_clicked())
That will not work for you since self.on_pushBotton_clicked() slot is not defined.
I find it is easiest to create your own connections in PyQt... I recommend removing the calls to connectSlotsByName from your both classes... you do not need it.
Also, your wdiget1 class should set the name of it's pushButton (preferably something other then "pushButton" to avoid confusion with the button in widget2).
Thank you so much jcoon for your reply.. But after a very long time banging my head against the wall i found the solution..
The problem was..
self.obj=test_reuse_stacked1.widget2()
self.obj.createWidget2(self)
instead of obj..
Here is #MarkVisser's QT4 code updated to QT5:
from sys import argv, exit
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget
class MyWidget(QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self._layout = QtWidgets.QVBoxLayout()
self.setLayout(self._layout)
self._button = QtWidgets.QPushButton()
self._button.setText('Click NOW!')
self._layout.addWidget(self._button)
self._button.clicked.connect(self._print_message)
#QtCore.pyqtSlot()
def _print_message(self):
print("Hai")
if __name__ == "__main__":
app = QApplication(argv)
main = MyWidget()
main.show()
exit(app.exec_())
Another minimal working example with Qt for Python aka PySide2/6.
Key ingredients:
widget to connect MUST have .setObjectName
function to connect MUST be decorated with #QtCore.Slot()
both objects (function AND widget) MUST be members of passed object (self here)
from PySide2 import QtCore, QtWidgets
# or from PySide6 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self):
super(Widget, self).__init__()
layout = QtWidgets.QVBoxLayout(self)
self.button = QtWidgets.QPushButton(self)
self.button.setObjectName('button')
self.button.setText('Click Me!')
layout.addWidget(self.button)
QtCore.QMetaObject.connectSlotsByName(self)
#QtCore.Slot()
def on_button_clicked(self):
print(f'Hai from {self.sender()}')
if __name__ == '__main__':
app = QtWidgets.QApplication([])
main = Widget()
main.show()
app.exec_()
I couldn't get mit any smaller really 🤔