I have created two widgets (QMainWindow as win_one and QDialog as win_two) with qtdesigner and PyQt5.
From win_one, I open win_two, fill-in the lineEdit and press OK to transfer the entry into a label displayed in win_one. Everything works well except two problems:
win_one window is opened as .showMaximized() but after filled-in the label, the dimension of the window changes.
the button from win_one stops to work
front_win_one.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_win_one(object):
def setupUi(self, win_one):
win_one.setObjectName("win_one")
win_one.resize(1147, 234)
self.centralwidget = QtWidgets.QWidget(win_one)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(50, 50, 111, 51))
self.pushButton.setObjectName("pushButton")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(40, 160, 131, 31))
self.label.setObjectName("label")
win_one.setCentralWidget(self.centralwidget)
self.retranslateUi(win_one)
QtCore.QMetaObject.connectSlotsByName(win_one)
def retranslateUi(self, win_one):
_translate = QtCore.QCoreApplication.translate
win_one.setWindowTitle(_translate("win_one", "MainWindow"))
self.pushButton.setText(_translate("win_one", "To qdialog"))
self.label.setText(_translate("win_one", "TextLabel"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win_one = QtWidgets.QMainWindow()
ui = Ui_win_one()
ui.setupUi(win_one)
win_one.show()
sys.exit(app.exec_())
front_win_two.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_win_two(object):
def setupUi(self, win_two):
win_two.setObjectName("win_two")
win_two.resize(317, 278)
self.pushButton = QtWidgets.QPushButton(win_two)
self.pushButton.setGeometry(QtCore.QRect(40, 120, 121, 23))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(win_two)
self.lineEdit.setGeometry(QtCore.QRect(30, 50, 161, 21))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(win_two)
QtCore.QMetaObject.connectSlotsByName(win_two)
def retranslateUi(self, win_two):
_translate = QtCore.QCoreApplication.translate
win_two.setWindowTitle(_translate("win_two", "Dialog"))
self.pushButton.setText(_translate("win_two", "OK"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win_two = QtWidgets.QDialog()
ui = Ui_win_two()
ui.setupUi(win_two)
win_two.show()
sys.exit(app.exec_())
back.py
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QDialog
from front_win_1 import Ui_win_one
from front_win_2 import Ui_win_two
class win_two(QDialog, Ui_win_two):
def __init__(self, parent=None):
super(win_two, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.vers_main)
def vers_main(self):
entry = self.lineEdit.text()
win_one().label.setText(entry)
class win_one(QMainWindow, Ui_win_one):
def __init__(self, parent=None):
super(win_one, self).__init__(parent)
self.setupUi(dialog)
self.pushButton.clicked.connect(self.open_qdialog)
def open_qdialog(self):
self.dialog_win_2 = win_two()
self.dialog_win_2.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
dialog = QMainWindow()
prog = win_one(dialog)
dialog.showMaximized()
sys.exit(app.exec_())
Thank you
Your code has some inconsistencies:
You should not do this dialog = QMainWindow(), since it is enough to create an object of the class win_one, for this you must change self.setupUi(dialog) to self.setupUi(self).
With the statement win_one().label.setText(entry) you are creating a new object, which is unnecessary, besides that you are losing the previous object so when you press the window again, QDialog is not opened, a simple solution is to pass it as parent to win_one to win_two and use the self.parent() function to access it.
All of the above is implemented in the following part:
class win_two(QDialog, Ui_win_two):
def __init__(self, parent=None):
super(win_two, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.vers_main)
def vers_main(self):
entry = self.lineEdit.text()
self.parent().label.setText(entry)
class win_one(QMainWindow, Ui_win_one):
def __init__(self, parent=None):
super(win_one, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.open_qdialog)
def open_qdialog(self):
self.dialog_win_2 = win_two(self)
self.dialog_win_2.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
prog = win_one()
prog.showMaximized()
sys.exit(app.exec_())
Note: I could never reproduce the first bug, only the second one.
Related
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.
I am trying to get Qcombobox selected variable data from onewindow.py to anotherWindow.py. i am stuck when i use signal/slot mechanism.
i have two files mainWindow.py and connection.py, in mainWindow i have a combobox where user can choose a server, i want, when user choose a server from combobox then then selected item(variable) will be sent to the connection.py
mainwindow.py:
from PyQt5 import QtCore, QtGui, QtWidgets
class ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(310, 230, 151, 22))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(310, 300, 281, 20))
self.label.setObjectName("label")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
# combobox selected
self.comboBox.activated[str].connect(self.onChanged)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.comboBox.setItemText(0, _translate("MainWindow", "TFUS3"))
self.comboBox.setItemText(1, _translate("MainWindow", "TFUSD"))
self.label.setText(_translate("MainWindow", "TextLabel"))
#-----------
def onChanged(self,text):
self.label.setText(text)
message=text
return message
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_())
and connection.py
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
from PyQt5.QtWidgets import QTableView, QApplication
import mainWindow
from mainWindow import *
class Example(QWidget):
def get_value(self,text):
message=text
print(message)
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.lbl = QLabel("select server from mainwindow is:",self )
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QComboBox')
self.show()
def onActivated(self, text):
createConnection(self,text)
self.lbl.adjustSize()
------server part----------------------------
USERNAME = 'XXXXXX'
PASSWORD = '000000'
def selectedServer(server):
switcher ={
'Server1': 'x.x.x.x,1433',
'Server2': 'x.x.x.x,1433',
}
return switcher.get(server,"Invalid Server ")
def createConnection(self,server):
SERVER= selectedServer(server)
global db
db = QSqlDatabase.addDatabase('QODBC')
db.setDatabaseName(f'Driver={{SQL SERVER}}; Server={SERVER}; UID={USERNAME}; PWD={PASSWORD}')
if db.open():
self.lbl.setText(f'{server} Server connected successfully')
print(f'{server} Server connected successfully')
else:
print('connection failed')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
i tried many time to show selected server in textlabe in connection window.but failed. don't know where i did mistake.
First of all it must be clear that information is not sent between files but between objects, the application is not the files but the interaction between the objects or other elements that are described in the source code(files).
On the other hand you should not modify the code generated by Qt Designer so you will have to restore the mainWindow.py file.
Considering the above, an instance of each class must be created (in the case of Ui_MainWindow it is better to create a new class that inherits from the appropriate widget and use Ui_MainWindow to fill it). And then there make the connection between the components.
connection.py
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtSql
USERNAME = "XXXXXX"
PASSWORD = "000000"
def selectedServer(server):
switcher = {
"Server1": "x.x.x.x,1433",
"Server2": "x.x.x.x,1433",
}
return switcher.get(server, "Invalid Server ")
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.lbl = QtWidgets.QLabel("select server from mainwindow is:", self)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle("QComboBox")
def setServer(self, name):
self.createConnection(name)
self.lbl.adjustSize()
def createConnection(self, server):
SERVER = selectedServer(server)
db = QtSql.QSqlDatabase.addDatabase("QODBC")
db.setDatabaseName(
f"Driver={{SQL SERVER}}; Server={SERVER}; UID={USERNAME}; PWD={PASSWORD}"
)
if db.open():
self.lbl.setText(f"{server} Server connected successfully")
self.lbl.adjustSize()
print(f"{server} Server connected successfully")
else:
print("connection failed")
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
main.py
import sys
from PyQt5 import QtWidgets
from mainWindow import ui_MainWindow
from connection import Example
class MainWindow(QtWidgets.QMainWindow, ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
ex = Example()
ex.show()
w.comboBox.currentTextChanged.connect(ex.setServer)
sys.exit(app.exec_())
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_())
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) ---
...
I used QtDesigner to create all of my windows, the main window uses mdiArea so that other windows fit inside of it when called. My main problem is when I close a window inside the mdiArea it disappears and I can't reopen it, id either like the window to not have a exit button or make a window with buttons that will open the files if its not there.
Output Screenshot
The window that is minimized is ValveSimulator and if I close it it doesn't exist anymore and I can't open it
my main code: CreateWindow makes the window with the buttons and CreateValveSimulator is my main program that I want to open from the button when I close it
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget,QWidget, QMdiSubWindow
import ValveSim
import MainWindow
import Window
class Win1(QMainWindow):
def __init__(self):
QWidget.__init__(self)
self.vtn = MainWindow.Ui_MainWindow()
self.vtn.setupUi(self)
self.subwindow = QMdiSubWindow()
self.CreateValveSimulator()
self.CreateWindow()
def CreateValveSimulator(self):
widget = QMainWindow()
self.VSim_subwindow = ValveSim.Ui_ValveSim()
self.VSim_subwindow.setupUi(widget)
self.subwindow = QMdiSubWindow(self.vtn.mdiArea)
widget.setParent(self.subwindow)
self.subwindow.setWidget(widget)
self.vtn.mdiArea.addSubWindow(self.subwindow)
widget.show()
self.subwindow.show()
self.subwindow.widget().show()
def CreateWindow(self):
widget = QMainWindow()
self.win_subwindow = Window.Ui_MainWindow()
self.win_subwindow.setupUi(widget)
self.subwindow = QMdiSubWindow(self.vtn.mdiArea)
widget.setParent(self.subwindow)
self.subwindow.setWidget(widget)
self.vtn.mdiArea.addSubWindow(self.subwindow)
widget.show()
self.subwindow.show()
self.subwindow.widget().show()
if __name__=='__main__':
app =QApplication(sys.argv)
win = Win1()
win.show()
sys.exit(app.exec_())
I connected the self.pushbutton to a function called openvs which I hope to open the Valve Simulator window when its closed as shown in my main code,however it just crashes when I click the button
Table with buttons code:
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QWidget, QMdiSubWindow, QAction
import Untitled
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowModality(QtCore.Qt.WindowModal)
MainWindow.resize(351, 442)
MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(85, 125, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(85, 195, 75, 23))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setGeometry(QtCore.QRect(200, 125, 75, 23))
self.pushButton_3.setObjectName("pushButton_3")
MainWindow.setCentralWidget(self.centralwidget)
self.pushButton.clicked.connect(self.openvs)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Open Valve Simulator"))
self.pushButton_2.setText(_translate("MainWindow", "Open Module Program"))
self.pushButton_3.setText(_translate("MainWindow", "Open Metal Sizing"))
def openvs(self):
Untitled.Win1.CreateValveSimulator()
You must create the windows independently, and add them to each QMdiSubWindow. When the widget is displayed in the subwindow this will cause the subwindow to be displayed. To open normally with the button you must use the clicked signal and call the showNormal function.
The complete code is here.
class HomeWindow(QMainWindow, Ui_HomeWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
class ValveSim(QMainWindow, Ui_ValveSim):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
class Win1(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent)
self.setupUi(self)
self.vs = ValveSim()
self.hw = HomeWindow()
self.CreateValveSimulator()
self.CreateWindow()
def CreateValveSimulator(self):
subwindow = QMdiSubWindow()
subwindow.setWidget(self.vs)
self.mdiArea.addSubWindow(subwindow)
subwindow.setFixedSize(500, 500)
# self.subwindow.close()
def CreateWindow(self):
self.hw.pushButton.clicked.connect(self.vs.showNormal)
subwindow = QMdiSubWindow()
subwindow.setWindowFlags(Qt.CustomizeWindowHint | Qt.Tool)
subwindow.setWidget(self.hw)
self.mdiArea.addSubWindow(subwindow)