Kai Winkler
Kai Winkler

Reputation: 89

How can I use the input of another window in my mainwindow (using PyQt5 and qt-designer)?

I have a main window that displays a number, when clicking a button a second window should appear where you can input a scaling factor. When pressing "Ok" on the second window, the number in the main window should be multiplied by the scaling factor of the 2nd window and it should be closed.

enter image description here

This is the code I used for generating the MainApp and the creation of the 2nd window:

from ui_Stackoverflow1 import *
from ui_Stackoverflow2 import *
import sys

class ScaleApp(Ui_ScaleWindow):

    def __init__(self, window2):

        self.setupUi(window2)

    # Todo: see below


class ButtonConnection(Ui_MainWindow):

    def __init__(self, window):

        self.setupUi(window)
        self.pushButton.clicked.connect(self.open_scale_window)

        self.important_number = 5
        self.lineEdit.setText(str(self.important_number))

    def open_scale_window(self):

        self.scale_window = QMainWindow()
        self.scale_ui = ScaleApp(self.scale_window)
        self.scale_window.show()

        # TODO
        # open new window (ui_Stackoverflow2)
        # wait for "ok" being pressed
        # take the input of the QSpinBox
        # use the input to scale self.important_number by this input

        self.lineEdit.setText(str(self.important_number))


if __name__ == "__main__":

    app = QApplication(sys.argv)
    MainWindow = QMainWindow()

    ui = ButtonConnection(MainWindow)

    MainWindow.show()
    app.exec_()

How can I achieve the scaling of the number?


________________________________________________________

I used Qt-designer to create both UIs using the following code:

# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'Stackoverlow1tsISdv.ui'
##
## Created by: Qt User Interface Compiler version 5.15.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(440, 275)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.pushButton = QPushButton(self.centralwidget)
        self.pushButton.setObjectName(u"pushButton")
        self.pushButton.setGeometry(QRect(90, 10, 261, 151))
        self.lineEdit = QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName(u"lineEdit")
        self.lineEdit.setGeometry(QRect(160, 180, 113, 20))
        self.lineEdit.setAlignment(Qt.AlignCenter)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(MainWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 440, 21))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(MainWindow)
        self.statusbar.setObjectName(u"statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.pushButton.setText(QCoreApplication.translate("MainWindow", u"PushButton", None))
        self.lineEdit.setText(QCoreApplication.translate("MainWindow", u"1", None))
    # retranslateUi


class Ui_ScaleWindow(object):
    def setupUi(self, ScaleWindow):
        if not ScaleWindow.objectName():
            ScaleWindow.setObjectName(u"ScaleWindow")
        ScaleWindow.resize(419, 201)
        self.centralwidget = QWidget(ScaleWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.ok_button = QPushButton(self.centralwidget)
        self.ok_button.setObjectName(u"ok_button")
        self.ok_button.setGeometry(QRect(120, 110, 75, 23))
        self.cancel_button = QPushButton(self.centralwidget)
        self.cancel_button.setObjectName(u"cancel_button")
        self.cancel_button.setGeometry(QRect(210, 110, 75, 23))
        self.scaling_box = QDoubleSpinBox(self.centralwidget)
        self.scaling_box.setObjectName(u"scaling_box")
        self.scaling_box.setGeometry(QRect(170, 50, 62, 22))
        ScaleWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(ScaleWindow)
        self.menubar.setObjectName(u"menubar")
        self.menubar.setGeometry(QRect(0, 0, 419, 21))
        ScaleWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(ScaleWindow)
        self.statusbar.setObjectName(u"statusbar")
        ScaleWindow.setStatusBar(self.statusbar)

        self.retranslateUi(ScaleWindow)

        QMetaObject.connectSlotsByName(ScaleWindow)
    # setupUi

    def retranslateUi(self, ScaleWindow):
        ScaleWindow.setWindowTitle(QCoreApplication.translate("ScaleWindow", u"Scaling", None))
        self.ok_button.setText(QCoreApplication.translate("ScaleWindow", u"OK", None))
        self.cancel_button.setText(QCoreApplication.translate("ScaleWindow", u"Cancel", None))
    # retranslateUi

Upvotes: 0

Views: 1215

Answers (1)

musicamante
musicamante

Reputation: 48384

In order to achieve what you want, you cannot use a QMainWindow for the second window, but a QDialog, which creates a modal dialog over the main window and, once "executed" waits until it's closed.

Then, the classes created with pyside-uic are intended for direct instance creation or multiple inheritance. Subclassing from them is pointless.

First of all, create again the second window, but starting from a "Dialog", not a "Main Window", then generate its python code again.

This is a possible implementation of what you're trying to achieve:

class ScaleWindow(QDialog, Ui_ScaleWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.ok_button.clicked.connect(self.close)


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.important_number = 5
        self.lineEdit.setText(str(self.important_number))
        self.pushButton.clicked.connect(self.open_scale_window)

    def open_scale_window(self):
        scale_window = ScaleWindow(self)
        scale_window.exec_()
        self.important_number *= scale_window.scaling_box.value()
        self.lineEdit.setText(str(self.important_number))

if __name__ == "__main__":

    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    app.exec_()

An even better approach is to use a QDialogButtonBox. Designer provides three templates for QDialog: one empty, and two with the buttons (vertically or horizontally placed).

If you create the dialog with buttons, it will automatically connect the button box signals to those of the dialog, so if you press Ok the dialog will be accepted, if you press Cancel it will be rejected.

This can be also done manually by adding the button box to the dialog, and using the edit signal/slot mode of Designer (connect the accepted signal to the accept slot of the dialog, and the rejected signal to the reject slot). Alternatively, it can also be done by code:

class ScaleWindow(QDialog, Ui_ScaleWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

Note: if the signals are already connected in Designer, you should NOT connect them again in your code

This allows checking if the user actually pressed Ok in the dialog, otherwise the value will be ignored:

class MainWindow(QMainWindow, Ui_MainWindow):
    # ...
    def open_scale_window(self):
        scale_window = ScaleWindow(self)
        if scale_window.exec_() and scale_window.scaling_box.value():
            self.important_number *= scale_window.scaling_box.value()
            self.lineEdit.setText(str(self.important_number))

Note that I added a further check in the if statement: if the value is 0, important_number will become 0 and it could not be multiplied ever again.

Upvotes: 1

Related Questions