Python (QtDesigner) Opening multiple .py files in MdiArea window with buttons - python

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)

Related

How avoid change tab in QTabWidget | PyQt5

I'm trying to implement a tab with the name "+" in which if I click on it opens a ApplicationModal window for configurate the content in that tab. I want to avoid the change of tab when i click in it until press "Accept" in the ApplicationModal window. How can I block this change? I don't know if I explain me.
This it's de code
tabs.py for the MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(628, 504)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setGeometry(QtCore.QRect(36, 34, 541, 396))
self.tabWidget.setObjectName("tabWidget")
self.tab1 = QtWidgets.QWidget()
self.tab1.setObjectName("tab1")
self.tabWidget.addTab(self.tab1, "")
self.tab2 = QtWidgets.QWidget()
self.tab2.setObjectName("tab2")
self.tabWidget.addTab(self.tab2, "")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 628, 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)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab1), _translate("MainWindow", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab2), _translate("MainWindow", "+"))
win0.py for the ApplicationModal window
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Win0(object):
def setupUi(self, Win0):
Win0.setObjectName("Win0")
Win0.setWindowModality(QtCore.Qt.ApplicationModal)
Win0.resize(255, 203)
self.centralwidget = QtWidgets.QWidget(Win0)
self.centralwidget.setObjectName("centralwidget")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(17, 9, 154, 22))
self.comboBox.setObjectName("comboBox")
self.accpet_button = QtWidgets.QPushButton(self.centralwidget)
self.accpet_button.setGeometry(QtCore.QRect(43, 130, 75, 23))
self.accpet_button.setObjectName("accpet_button")
self.cancel_button = QtWidgets.QPushButton(self.centralwidget)
self.cancel_button.setGeometry(QtCore.QRect(135, 131, 75, 23))
self.cancel_button.setObjectName("cancel_button")
Win0.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(Win0)
self.menubar.setGeometry(QtCore.QRect(0, 0, 255, 21))
self.menubar.setObjectName("menubar")
Win0.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(Win0)
self.statusbar.setObjectName("statusbar")
Win0.setStatusBar(self.statusbar)
self.retranslateUi(Win0)
QtCore.QMetaObject.connectSlotsByName(Win0)
def retranslateUi(self, Win0):
_translate = QtCore.QCoreApplication.translate
Win0.setWindowTitle(_translate("Win0", "New Window"))
self.accpet_button.setText(_translate("Win0", "Accept"))
self.cancel_button.setText(_translate("Win0", "Cancel"))
And the main.py for develop the functionality
from tabs import Ui_MainWindow
from win0 import Ui_Win0
from PyQt5 import QtCore, QtGui, QtWidgets
class Win0(Ui_Win0):
win0 = None
def __init__(self, win):
self.win0 = win
super().__init__()
self.setupUi(self.win0)
class Main(Ui_MainWindow):
win0 = None
win1 = None
def __init__(self, win):
self.win = win
super().__init__()
self.setupUi(self.win)
self.tabWidget.tabBarClicked.connect(self.tabClick)
def tabClick(self, event):
if event == 1:
print("New tab")
self.win1 = QtWidgets.QMainWindow()
new_window = Win0(self.win1)
self.win1.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Main(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
If you want a window that blocks the others until it's closed, you're looking for a modal dialog.
A modal window creates a mode that disables the main window but keeps it visible, with the modal window as a child window in front of it. Users must interact with the modal window before they can return to the parent application. This avoids interrupting the workflow on the main window.
[From the wikipedia article about modal windows]
It is relatively easy to achieve that in Qt, by using a QDialog.
Designer already provides two basic templates with basic Ok/Cancel buttons when you create a new form, so create a new dialog with buttons on right or bottom (this will automatically connect the button box with the dialog's accept/reject slots), add the combobox, save and convert the file with pyuic (in the following example, I exported the file as dialog.py and used the default Ui_Dialog).
Then the implementation is very easy. The important thing is to add the parent argument to the QDialog instance: this ensures that the dialog uses the parent as a reference for the "window modality", so that that parent is blocked until the dialog is closed by accepting or rejecting it (rejection is usually done by clicking on a RejectRole button like Cancel or by closing the dialog in any way, including pressing Esc).
Do note that I changed your approach by using multiple inheritance in order to make things easier (see the guidelines on using Designer about this approach, which is usually the better and most suggested method when using pyuic generated files).
from tabs import Ui_MainWindow
from dialog import Ui_Dialog
from PyQt5 import QtCore, QtGui, QtWidgets
class SelectDialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
class Main(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.tabWidget.tabBarClicked.connect(self.tabClick)
def tabClick(self, tab):
if tab == 1:
dialog = SelectDialog(self)
if dialog.exec_():
print(dialog.comboBox.currentIndex())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = Main()
mainWindow.show()
sys.exit(app.exec_())

How to work with multiple windows in PyQt5? Passing Values through multiple windows and Calling Modules in Other Modules

I have created a GUI with PyQt5. I have total three windows. first window has one push button (**btn_OpenSecondWIndow**) which opens a second window. second window has one push button (**btn_OpenCalendar**) which opens third (Calendar) window. user picks a date from there and select a button (**btn_selecteddate**) on third window, I want to display that selection in the label (label_Date) in the second window.
Snippet to get the flow
Now I'm at this point where the first window works just fine and the second window opens BUT pushbuttons doesn't work.
The button in the second window does nothing when the window is opened from the first one but when the class "SecondWindow" is called by its own and not from the first window, it works.
here is the code:
from PyQt5 import QtWidgets
from FirstWindow import Ui_FirstWindow
from SecondWindow import Ui_SecondWindow
from Calendar import Ui_CalendarWindow
class Calendar(QtWidgets.QMainWindow, Ui_CalendarWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
class FirstWindow(QtWidgets.QMainWindow, Ui_FirstWindow):
def __init__(self):
super(FirstWindow,self).__init__()
self.setupUi(self)
self.btn_OpenSecondWIndow.clicked.connect(self.open_SecondWindow)
def open_SecondWindow(self):
self.window = QtWidgets.QMainWindow()
self.ui = SecondWindow()
self.ui.setupUi(self.window)
self.window.show()
self.setEnabled(False)
self.window.setEnabled(True)
class SecondWindow(QtWidgets.QMainWindow, Ui_SecondWindow):
def __init__(self):
super(SecondWindow, self).__init__()
self.setupUi(self)
self.btn_OpenCalendar.clicked.connect(self.Open_Calendar)
def Open_Calendar(self):
self.window = Calendar()
self.window.setupUi(self.window)
self.window.show()
self.window.btn_Selecteddate.clicked.connect(self.PickedDate)
def PickedDate(self):
self.selecteddate = self.window.CalendarBox.selectedDate()
self.label_Date.setText(self.selecteddate.toString('MMM')+'-'+self.selecteddate.toString('yyyy'))
self.window.hide()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = FirstWindow()
window.show()
sys.exit(app.exec_())
Reference Ui Class codes are as below:
First Window:
from PyQt5 import QtCore, QtWidgets
class Ui_FirstWindow(object):
def setupUi(self, FirstWindow):
FirstWindow.setObjectName("FirstWindow")
FirstWindow.resize(380, 195)
self.centralwidget = QtWidgets.QWidget(FirstWindow)
self.centralwidget.setObjectName("centralwidget")
self.btn_OpenSecondWIndow = QtWidgets.QPushButton(self.centralwidget)
self.btn_OpenSecondWIndow.setGeometry(QtCore.QRect(80, 60, 221, 61))
self.btn_OpenSecondWIndow.setObjectName("btn_OpenSecondWIndow")
FirstWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(FirstWindow)
self.statusbar.setObjectName("statusbar")
FirstWindow.setStatusBar(self.statusbar)
self.retranslateUi(FirstWindow)
QtCore.QMetaObject.connectSlotsByName(FirstWindow)
def retranslateUi(self, FirstWindow):
_translate = QtCore.QCoreApplication.translate
FirstWindow.setWindowTitle(_translate("FirstWindow", "MainWindow"))
self.btn_OpenSecondWIndow.setText(_translate("FirstWindow", "Open Second Window"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
FirstWindow = QtWidgets.QMainWindow()
ui = Ui_FirstWindow()
ui.setupUi(FirstWindow)
FirstWindow.show()
sys.exit(app.exec_())
Second WIndow:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_SecondWindow(object):
def setupUi(self, SecondWindow):
SecondWindow.setObjectName("SecondWindow")
SecondWindow.resize(654, 242)
self.centralwidget = QtWidgets.QWidget(SecondWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_Date = QtWidgets.QLabel(self.centralwidget)
self.label_Date.setGeometry(QtCore.QRect(330, 60, 281, 131))
font = QtGui.QFont()
font.setPointSize(16)
font.setBold(True)
font.setWeight(75)
self.label_Date.setFont(font)
self.label_Date.setLayoutDirection(QtCore.Qt.LeftToRight)
self.label_Date.setObjectName("label_Date")
self.btn_OpenCalendar = QtWidgets.QPushButton(self.centralwidget)
self.btn_OpenCalendar.setGeometry(QtCore.QRect(80, 90, 191, 61))
self.btn_OpenCalendar.setObjectName("btn_OpenCalendar")
SecondWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(SecondWindow)
self.statusbar.setObjectName("statusbar")
SecondWindow.setStatusBar(self.statusbar)
self.retranslateUi(SecondWindow)
QtCore.QMetaObject.connectSlotsByName(SecondWindow)
def retranslateUi(self, SecondWindow):
_translate = QtCore.QCoreApplication.translate
SecondWindow.setWindowTitle(_translate("SecondWindow", "MainWindow"))
self.label_Date.setText(_translate("SecondWindow", "Date"))
self.btn_OpenCalendar.setText(_translate("SecondWindow", "Open Calendar"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
SecondWindow = QtWidgets.QMainWindow()
ui = Ui_SecondWindow()
ui.setupUi(SecondWindow)
SecondWindow.show()
sys.exit(app.exec_())
Third (Calendar) Window:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_CalendarWindow(object):
def setupUi(self, CalendarWindow):
CalendarWindow.setObjectName("CalendarWindow")
CalendarWindow.resize(512, 458)
self.centralwidget = QtWidgets.QWidget(CalendarWindow)
self.centralwidget.setObjectName("centralwidget")
self.CalendarBox = QtWidgets.QCalendarWidget(self.centralwidget)
self.CalendarBox.setGeometry(QtCore.QRect(20, 20, 464, 289))
self.CalendarBox.setObjectName("CalendarBox")
self.btn_Selecteddate = QtWidgets.QPushButton(self.centralwidget)
self.btn_Selecteddate.setGeometry(QtCore.QRect(160, 330, 181, 60))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.btn_Selecteddate.setFont(font)
self.btn_Selecteddate.setObjectName("btn_Selecteddate")
CalendarWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(CalendarWindow)
self.statusbar.setObjectName("statusbar")
CalendarWindow.setStatusBar(self.statusbar)
self.retranslateUi(CalendarWindow)
QtCore.QMetaObject.connectSlotsByName(CalendarWindow)
def retranslateUi(self, CalendarWindow):
_translate = QtCore.QCoreApplication.translate
CalendarWindow.setWindowTitle(_translate("CalendarWindow", "MainWindow"))
self.btn_Selecteddate.setText(_translate("CalendarWindow", "Select"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
CalendarWindow = QtWidgets.QMainWindow()
ui = Ui_CalendarWindow()
ui.setupUi(CalendarWindow)
CalendarWindow.show()
sys.exit(app.exec_())
Thanks in Advance. :)
In FirstWindow.open_SecondWindow you don't need to create a separate QMainWindow object for the second window. SecondWindow() already returns a QMainWindow object with the proper UI set up and a slot connected to btn_OpenCalendar for opening the calendar window. Therefore it is sufficient to do something like:
def open_SecondWindow(self):
self.window = SecondWindow()
self.window.show()
self.setEnabled(False)
self.window.setEnabled(True)

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_())

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) ---
...

Connection between from QDialog to QMainWindow - PyQt5

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.

Categories