Need help understanding inheritance in PyQt5 - python

I'm trying to organize my code into classes. In the example below, B and C need to inherit the names of the push buttons from A so that the buttons echo a statement when pushed. In order for me to get this to work properly, I had to create Dummy and inherit B and C and then created in instance of Dummy. It doesn't seem like this is the way I should be doing it. Is there a "better" or "more accepted" way of using multiple classes in PyQt5?
inheritance.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'inheritance.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(452, 246)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.b_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.b_pushButton.setGeometry(QtCore.QRect(40, 50, 151, 81))
self.b_pushButton.setObjectName("b_pushButton")
self.c_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.c_pushButton.setGeometry(QtCore.QRect(230, 50, 151, 81))
self.c_pushButton.setObjectName("c_pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 452, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
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", "MainWindow"))
self.b_pushButton.setText(_translate("MainWindow", "B"))
self.c_pushButton.setText(_translate("MainWindow", "C"))
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_())
Main script:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
from inheritance import Ui_MainWindow
class A(QMainWindow):
def __init__(self):
super(A, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
class B(A):
def __init__(self):
super(B, self).__init__()
self.ui.b_pushButton.clicked.connect(self.pushB)
def pushB(self):
print('You pushed the "B" button')
print()
class C(A):
def __init__(self):
super(C, self).__init__()
self.ui.c_pushButton.clicked.connect(self.pushC)
def pushC(self):
print('You pushed the "C" button')
print()
class Dummy(B, C):
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
main = Dummy()
main.show()
sys.exit(app.exec_())

I ended up doing what eyllanesc suggested. I was initially trying to keep everything related to B and C in their own class because my actual code is really long, but this will do.
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
from inheritance import Ui_MainWindow
class A(QMainWindow):
def __init__(self):
super(A, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.B = B()
self.C = C()
self.ui.b_pushButton.clicked.connect(self.B.pushB)
self.ui.c_pushButton.clicked.connect(self.C.pushC)
class B:
def pushB(self):
print('You pushed the "B" button')
print()
class C:
def pushC(self):
print('You pushed the "C" button')
print()
if __name__ == "__main__":
app = QApplication(sys.argv)
main = A()
main.show()
sys.exit(app.exec_())

Here is the final code that does what I was trying to do - access the attributes from ui so I could access them in other classes.
I ended up passing the ui object from A into the __init__ of B and C. Not sure if this proper coding, but it works.
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
from inheritance import Ui_MainWindow
class A(QMainWindow):
def __init__(self):
super(A, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.B = B(self.ui)
self.C = C(self.ui)
self.ui.b_pushButton.clicked.connect(self.B.pushB)
self.ui.c_pushButton.clicked.connect(self.C.pushC)
class B():
def __init__(self, ui):
self.ui = ui
def pushB(self):
if self.ui.b_checkBox.isChecked():
print('You pushed the "B" button')
print()
else:
print('Check the check box to print the correct statement.')
class C():
def __init__(self, ui):
self.ui = ui
def pushC(self):
if self.ui.c_checkBox.isChecked():
print('You pushed the "C" button')
print()
else:
print('Check the check box to print the correct statement.')
if __name__ == "__main__":
app = QApplication(sys.argv)
main = A()
main.show()
sys.exit(app.exec_())

Related

How do You get a third script to handle information of two other scripts related to GUIs in pyqt5?

I have recreated a problem I am encountering as a minimal example below.
The situation: I have two Qt Designer generated GUI, each being called by their own separated scripts. A third script is meant to collect information from the first script upon the click of a button on the second script. I does not, yet there is no errors.
I have also attempted to solve this by using signals, but these does not seem to communicate between scripts. I provided a simpler version here that doesn't use signals per se.
My question is: How do You get a third script to handle information of two other scripts related to GUIs in pyqt5 ?
Here is the minimal example:
The first GUI script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(504, 223)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.TypeHere = QtWidgets.QTextEdit(self.centralwidget)
self.TypeHere.setObjectName("TypeHere")
self.verticalLayout.addWidget(self.TypeHere)
self.HelloButton = QtWidgets.QPushButton(self.centralwidget)
self.HelloButton.setObjectName("HelloButton")
self.verticalLayout.addWidget(self.HelloButton)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 504, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
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", "MainWindow"))
self.HelloButton.setText(_translate("MainWindow", "Say hello"))
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 GUI script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(282, 392)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton01 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton01.setObjectName("pushButton01")
self.verticalLayout.addWidget(self.pushButton01)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 282, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
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", "MainWindow"))
self.pushButton01.setText(_translate("MainWindow", "PushButton"))
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_())
JustSomeTextv01, the script of the first GUI:
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess, QThreadPool
from TypingUIv01 import Ui_MainWindow
import JustSomeButtonsv01 as JSB
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.HelloButton.pressed.connect(self.openButtons)
self.Display = JSB.Window()
self.ButtonsThread()
def openButtons(self):
self.Display.show()
def ButtonsThread(self):
self.threadpoolbutt = QThreadPool()
self.threadpoolbutt.start(self.runButtons)
def runButtons(self):
self.butt = QProcess()
print("Buttons Running")
self.butt.execute('python',['JustSomeButtonsv01.py'])
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
JustSomeButtonsv01, the script of the second GUI:
from PyQt5 import QtWidgets
from PyQt5.QtCore import QProcess, QThreadPool
from ButtonsUIv01 import Ui_MainWindow
# import JustSomeRecordv01 as JSR
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.RecordThread()
def RecordThread(self):
self.threadpoolrec = QThreadPool()
self.threadpoolrec.start(self.runRecord)
def runRecord(self):
self.rec = QProcess()
print("Record Running")
self.rec.execute('python',['JustSomeRecordv01.py'])
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
# window.show()
sys.exit(app.exec())
And finally, JustSomeRecordv01, the third script trying to interact with the other two:
from PyQt5 import QtWidgets
import sys
from TypingUIv01 import Ui_MainWindow as JSTWin
from ButtonsUIv01 import Ui_MainWindow as ButtWin
class Record(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# self.setupUi(self)
app2 = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
self.Win = JSTWin()
self.Win.setupUi(MainWindow)
self.Text = self.Win.TypeHere.toPlainText()
print("Running")
self.Butt = ButtWin()
self.Butt.setupUi(MainWindow)
self.Butt.pushButton01.pressed.connect(self.PrintIT)
def PrintIT(self):
print("Texting")
print(self.Text)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Record()
# window.show()
sys.exit(app.exec())
How to reproduce the problem:
You execute the JustSomeTextv01 script. Press the "Hello Button" and a second window will show up. You type anything in the QTextEdit of the first window and then click the button of the second window. The intent is that this second button would print what You wrote, but it doesn't work.
Thank You for your time,
I managed to do it within the example scripts, but the only solution was to put everything not-GUI into the same script as so:
# To test textbox related function
from PyQt5 import QtWidgets, QtCore
from TypingUIv01 import Ui_MainWindow
from ButtonsUIv01 import Ui_MainWindow as Ui2
import sys
class Window(QtWidgets.QMainWindow, Ui_MainWindow):
PatchSignal = QtCore.pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.HelloButton.pressed.connect(self.openButtons)
self.PatchSignal.connect(self.printIT)
def openButtons(self):
self.w2 = Wintwo()
self.w2.show()
def printIT(self):
self.Text = self.TypeHere.toPlainText()
# print("PRINTING")
print(self.Text)
class Wintwo(QtWidgets.QMainWindow, Ui2):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setupUi(self)
self.pushButton01.pressed.connect(self.Emit)
self.emitter = window
def Emit(self):
# print("EMITTING")
self.emitter.PatchSignal.emit()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())
It seems sending Signals between scripts is simply not possible in pyqt5!
Somehow this doesn't work in my actual script since "window" isn't recognized, but that's another question for another day.

Updating label text from another class

I'm new at python and i need some help ;-)
I created a window with a label with the QT designer en generated the py file (window.py):
'''
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(847, 283)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.lblMain = QtWidgets.QLabel(self.centralwidget)
self.lblMain.setGeometry(QtCore.QRect(160, 60, 311, 51))
self.lblMain.setObjectName("lblMain")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 847, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
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", "MainWindow"))
self.lblMain.setText(_translate("MainWindow", "label main window"))
'''
I created main.py which calls the window:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = window()
win.show()
sys.exit(app.exec_())
So far so good.
From within main.py i can set the text of the label using:
self.ui.lblMain.setText('some text')
This works also.
Now i would like to create another file with another class which can update the label.
class update.py:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def settext(self):
self.ui.lblMain.setText('updated')
And here i'm stuck.
Can anyone give a hand ?
Cheers John
A function to update a label no matter where it came from:
def update_label(label, new_text):
label.setText(new_text)
You can save this function anywhere you like including inside a new class. The function or the new class don't need to know anything about the ui to do this.
If it's in a class you'll have to create an instance of that class before using it.
The class you show should work perfectly, simply call the function settext somewhere.
Under update.py:
class Updater:
def __init__(self, label):
self.label = label
def settext(self):
self.label.setText('updated')
Notice that this class is not another window, it accepts the label object from the Ui_MainWindow class as an argument and saves it as a property. To use it add under main, after you create the app:
my_instance = Updater(win.ui.lblMain)
my_instance.settext()
You could even pass the whole win.ui as an argument. As long as all the classes share the same instance of ui then they will change the same widgets
For completeness, a full program that uses the updater class to change the text in the GUI:
from PyQt5 import QtWidgets,QtGui
from window import Ui_MainWindow
class window(QtWidgets.QMainWindow):
def __init__(self):
super(window, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
class Updater:
def __init__(self, label):
self.label = label
def settext(self):
self.label.setText('updated')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = window()
win.show()
my_instance = Updater(win.ui.lblMain)
my_instance.settext()
sys.exit(app.exec_())

Master PyQt5 GUI with pushbuttons that open additional GUI

Using Python3 and PyQt5, I want to have a GUI that has a button on it that, when pressed, opens another widget which also has buttons and other controls. In the future, the master GUI will have many buttons that will open many additional widgets. I'm looking at having one widget with an embedded matplotlib.pyplot. At the moment, I am struggling to open a second widget.
Main Program
import sys
from PyQt5 import QtWidgets
from gui import Ui_MainWindow as Ui_MainWindow1
from gui2 import Ui_MainWindow as Ui_MainWindow2
class Window(QtWidgets.QMainWindow, Ui_MainWindow1):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.ui_gui = Ui_MainWindow1()
self.ui_gui.setupUi(self)
self.pb.clicked.connect(self.on_pb_clicked)
self.graph = Graph(self)
def on_pb_clicked(self):
print('pb clicked')
self.graph.show()
class Graph(QtWidgets.QMainWindow, Ui_MainWindow2):
def __init__(self, parent=None):
super(Graph, self).__init__(parent)
self.ui_graph = Ui_MainWindow2()
self.ui_graph.setupUi(self)
if __name__ == "__main__":
#import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow1()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
gui = gui2. Both look like the below.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(282, 219)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.pb = QtWidgets.QPushButton(self.centralWidget)
self.pb.setGeometry(QtCore.QRect(100, 60, 75, 23))
self.pb.setObjectName("pb")
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 282, 21))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.mainToolBar = QtWidgets.QToolBar(MainWindow)
self.mainToolBar.setObjectName("mainToolBar")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
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", "MainWindow"))
self.pb.setText(_translate("MainWindow", "pb"))
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_())
I want to click the button on gui and have the gui2 appear. NB gui will not equal gui2 in the future.
Since Window and Graph inherit from Ui_Window1 and Ui_Window2, respectively, you should call self.setupUi(self) in Window.__init__ and Graph.__init__ instead of creating separate instances of Ui_Window1 and Ui_Window2, i.e.
class Window(QtWidgets.QMainWindow, Ui_MainWindow1):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setupUi(self)
self.pb.clicked.connect(self.on_pb_clicked)
self.graph = Graph(self)
# just to see the two windows side-by-side
self.move(500, 400)
self.graph.move(self.x()+self.width()+20, self.y())
def on_pb_clicked(self):
print('pb clicked')
self.graph.show()
class Graph(QtWidgets.QMainWindow, Ui_MainWindow2):
def __init__(self, parent=None):
super(Graph, self).__init__(parent)
self.setupUi(self)
The main part of the program should then be something like
if __name__ == "__main__":
#import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = Window()
MainWindow.show()
app.exec()
You use QMetaObject::connectSlotsByName() to enable the automatic calling of the on_pb_clicked() slot.
You do not need to use self.pb.clicked.connect(self.on_pb_clicked)
You need #QtCore.pyqtSlot()
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from gui_1 import Ui_MainWindow as Ui_MainWindow1
from gui_2 import Ui_MainWindow as Ui_MainWindow2
class Graph(QtWidgets.QMainWindow, Ui_MainWindow2):
def __init__(self, parent=None):
super(Graph, self).__init__(parent)
self.setupUi(self)
self.setWindowTitle("window Graph")
self.setGeometry(QtCore.QRect(850, 260, 282, 219))
# self.pb.clicked.connect(self.on_pb_clicked) # ---
#QtCore.pyqtSlot() # +++
def on_pb_clicked(self):
print('pb clicked -> Graph')
class Window(QtWidgets.QMainWindow, Ui_MainWindow1):
def __init__(self):
super().__init__()
self.setupUi(self)
self.setWindowTitle("main Window")
# self.pb.clicked.connect(self.on_pb_clicked) # ---
self.graph = Graph(self)
#QtCore.pyqtSlot() # +++
def on_pb_clicked(self):
print('pb clicked -> "main Window')
self.graph.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

PyQt5 - cannot create new widgets dynamically on button press to function [duplicate]

I have a method named 'test()' that loads 3 one-row tables into a scrollbar.
For some reason that I cannot figure out, however, the while it works if I simply activate test() on load, it doesn't work if I comment it out and then try to activate it via the push of a button.
Here is the main module (with test())
from PyQt5 import QtCore, QtWidgets
from design import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
#test(self)
def test(self):
from random import randint
x = randint(0, 99)
print(x)
height = 30
yPos = 0
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.setObjectName("tbl%s" % (i))
qTbl.setGeometry(QtCore.QRect(0, yPos, 880, height))
qTbl.horizontalHeader().setVisible(False)
qTbl.verticalHeader().setVisible(False)
yPos += height
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
And here is the design module (with the button)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(896, 453)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.scrDoc = QtWidgets.QScrollArea(self.centralwidget)
self.scrDoc.setGeometry(QtCore.QRect(0, 0, 891, 391))
self.scrDoc.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrDoc.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scrDoc.setWidgetResizable(False)
self.scrDoc.setObjectName("scrTest")
self.sawDoc = QtWidgets.QWidget()
self.sawDoc.setGeometry(QtCore.QRect(0, 0, 869, 300))
self.sawDoc.setObjectName("sawDoc")
self.scrDoc.setWidget(self.sawDoc)
self.btnTest = QtWidgets.QPushButton(self.centralwidget)
self.btnTest.setGeometry(QtCore.QRect(430, 400, 80, 15))
self.btnTest.setObjectName("btnTest")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.btnTest.clicked.connect(self.test)
def test(self):
import main
main.test(self)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "昊珩のCAT工具"))
self.btnTest.setText(_translate("MainWindow", "Test"))
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_())
Simply nothing happens when I push the button (except for the print out working successfully).
Can someone tell what's wrong?
The parents show the children at the beginning, but afterwards it is the responsibility of the children to show themselves, the simple solution is to use show():
qTbl = QtWidgets.QTableWidget(self.sawDoc)
qTbl.show()
But I see that you are implementing the solution in an inelegant way, the connection do it in main.py, do not modify the file generated by Qt Designer (delete the connection and the test method in design.py)
You must use a layout and there add the QTableWidget.
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.btnTest.clicked.connect(self.test)
def test(self):
from random import randint
x = randint(0, 99)
lay = QtWidgets.QVBoxLayout(self.sawDoc)
for i in range(3):
rowVals = ['test%s' % str(x + i)]
qTbl = QtWidgets.QTableWidget()
qTbl.setObjectName("tbl%s" % (i))
qTbl.horizontalHeader().hide()
qTbl.verticalHeader().hide()
qTbl.setRowCount(1)
qTbl.setColumnCount(len(rowVals))
for r, cell in enumerate(rowVals):
item = QtWidgets.QTableWidgetItem()
item.setText(str(cell))
qTbl.setItem(0, r, item)
qTbl.resize(qTbl.sizeHint())
lay.addWidget(qTbl)

Stdout stops showing in QTextEdit once another window has opened

I am trying to get stdout and error messages to show on my main window. The window is by pyqt and made via designer. I have a QTextEdit on it. This is where the output should show itself. Also I have a dialog box (again made via designer) where i set some settings for my program before running it. The dialog box is opened like this:
def open_settings(self):
dialog = SettingsDialog()
dialog.open_settings_tab() # its on a tab widget
I already read and used the info on these links to achieve my goal:
Print out python console output to Qtextedit
How to capture output of Python's interpreter and show in a Text widget?
Both are pretty much the same with different object names. The issue I'm having is that whenever I open a dialog box and return to the main window the stdout no longer shows itself on the QTextEdit. Instead it goes back to showing itself on Sublime Editor.
I believe it has something to do with the class instancing.
Here is how the Dialog class starts:
class SettingsDialog(QDialog):
def __init__(self, parent=None):
super(SettingsDialog, self).__init__(parent)
self.ui = Ui_SettingsDialog()
self.ui.setupUi(self)
and finally here is how my main window (form) class starts:
class MyForm(QMainWindow):
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten)
self.ui = Ui_MyForm()
self.ui.setupUi(self)
Any ideas of why the stdout stops working (in qtextedit) once i go into the dialog screen and come back?
NEW Update:
The code is very long. I made a small program thats showing the issue:
PS: I found that the problem is related with this line shown below:
self.ui.pushButton_path.clicked.connect(Form(self).change_path)
if i comment it out the problem goes away.. But I need to call that function (which opens a QDialog, from the main form). What is the proper way?
main:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtGui import QTextCursor
from ui_form import Ui_Form
from ui_dialog import Ui_Dialog
class EmittingStream(QObject): # test
textWritten = pyqtSignal(str)
def write(self, text):
self.textWritten.emit(str(text))
class Form(QMainWindow):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Install the custom output stream
sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) # test
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton_open.clicked.connect(self.open_dialog)
self.ui.pushButton_text.clicked.connect(self.test_write)
def __del__(self): # test
# Restore sys.stdout
sys.stdout = sys.__stdout__
def normalOutputWritten(self, text): # test
"""Append text to the QTextEdit."""
# Maybe QTextEdit.append() works as well, but this is how I do it:
# self.ui.tEdit_cli.insertPlainText(text)
cursor = self.ui.textEdit.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.ui.textEdit.setTextCursor(cursor)
self.ui.textEdit.ensureCursorVisible()
def open_dialog(self):
dialog = Dialog()
dialog.open_tab()
def test_write(self):
print("something written")
def change_path(self):
pass
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButton_close.clicked.connect(self.close_dialog)
self.ui.pushButton_path.clicked.connect(Form(self).change_path) # this is what causes the issue. but i need to use it!
def open_tab(self):
self.ui.tabWidget.setCurrentIndex(0)
self.exec_()
def close_dialog(self):
self.close()
def main():
app = QApplication(sys.argv)
form = Form()
form.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
ui_dialog:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'dialog.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
self.horizontalLayout.setObjectName("horizontalLayout")
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.pushButton_close = QtWidgets.QPushButton(self.tab)
self.pushButton_close.setGeometry(QtCore.QRect(100, 80, 211, 131))
self.pushButton_close.setObjectName("pushButton_close")
self.pushButton_path = QtWidgets.QPushButton(self.tab)
self.pushButton_path.setGeometry(QtCore.QRect(30, 30, 75, 23))
self.pushButton_path.setObjectName("pushButton_path")
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.horizontalLayout.addWidget(self.tabWidget)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton_close.setText(_translate("Dialog", "close"))
self.pushButton_path.setText(_translate("Dialog", "path"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Tab 2"))
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
"""
ui_form:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'form.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(Form)
self.centralwidget.setObjectName("centralwidget")
self.textEdit = QtWidgets.QTextEdit(self.centralwidget)
self.textEdit.setGeometry(QtCore.QRect(90, 230, 601, 271))
self.textEdit.setObjectName("textEdit")
self.pushButton_open = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_open.setGeometry(QtCore.QRect(140, 80, 241, 81))
self.pushButton_open.setObjectName("pushButton_open")
self.pushButton_text = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_text.setGeometry(QtCore.QRect(440, 80, 251, 81))
self.pushButton_text.setObjectName("pushButton_text")
Form.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(Form)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
Form.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(Form)
self.statusbar.setObjectName("statusbar")
Form.setStatusBar(self.statusbar)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "MainWindow"))
self.pushButton_open.setText(_translate("Form", "open dialog"))
self.pushButton_text.setText(_translate("Form", "write somthing"))
"""
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QMainWindow()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
"""
You must use the object to invoke a method, you must not use the class, so the instruction Form(self) is not valid.
You must make the connection where you can access the signal and the slot simultaneously, for example open_dialog would be a good place:
class Form(QMainWindow):
...
def open_dialog(self):
dialog = Dialog(self)
dialog.ui.pushButton_path.clicked.connect(self.change_path) # +++
dialog.open_tab()
def test_write(self):
print("something written")
def change_path(self):
pass
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.pushButton_close.clicked.connect(self.close_dialog)
# self.ui.pushButton_path.clicked.connect(Form(self).change_path) ---
...

Categories