Home>

Hello
This question is related to the Python GUI.

1. I want to write the processing details of buttons etc. in a subclass that inherits the class that describes GUI
2. In addition to the above conditions, I want to change the main screen display by pressing the button from the sub screen side
・ The contents of this time are [Press the button on the sub screen ⇒ Change the label content of the main screen] and write it with the GUI part name
[Press pushButton of TestWindow (sub window) ⇒ Text of TestLabel and TestLabelinFrame of TestMainWindow (main window) changes].

After creating GUI with QtDesigner, it is converted to py file.
Considering the trouble of GUI maintenance, I would like to manage it with inheritance and override without changing this file.

Your code
# File name: TestStartUp.py
#For file execution
import sys
from PyQt5 import QtCore as Qc, QtGui as Qg, QtWidgets as Qw
from PyQt5.QtCore import Qt
from Controller.TestController import TestControll
if __name__ == '__main__':
    app = Qw.QApplication (sys.argv)
    TestControll (). ShowWindow ()
# File name: TestController.py
#Class that summarizes start/end of screen
import sys
from PyQt5 import QtCore as Qc, QtGui as Qg, QtWidgets as Qw
from PyQt5.QtCore import Qt
from .screen import TestMainWindow, TestWindow_or, TestWindow
class TestControll (Qw.QMainWindow):
    # Initial setting
    def __init __ (self, parent = None):
        super () .__ init __ (parent)
        print (self .__ class __.__ name__ + "init")
        self.ui = TestMainWindow.Ui_MainWindow ()
        self.ui.setupUi (self)
        #Subwindow
        self.test = Qw.QWidget ()
        # 1.Overwrite subwindow
        self.test.ui = TestWindow_or.FormOverride ()
        self.test.ui.eventMethod (self.test, "" "Problem I don't know the value to enter" "")
        # 2. Display the subwindow without overwriting it
        # self.test.ui = TestWindow.Ui_Form ()
        # self.test.ui.setupUi (self.test)
    # For screen startup
    def showWindow (self):
        print (self .__ class __.__ name__ + "launch")
        app = Qw.QApplication ([])
        self.show ()
        self.test.show ()
        sys.exit (app.exec ())
# File name: TestWindow_or.py
#Class to embed events by inheriting screen information
from .import TestWindow
class FormOverride (TestWindow.Ui_Form):
    def setupUi (self, From):
        super (). setupUi (From)
    def eventMethod (self, Form, ui):
        self.setupUi (Form)
        #List overwriting here
        self.pushButton.clicked.connect (ui.TestLabel.setToolTip ("A: Clicked on sub screen."))
        self.pushButton.clicked.connect (ui.TestLabelinFrame.setToolTip ("B: Clicked on sub screen"))
From here, the source (GUI, screen structure) created and converted with Qt Designer
# File name: TestMainWindw.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow (object):
    def setupUi (self, MainWindow):
        MainWindow.setObjectName ("MainWindow")MainWindow.resize (510, 359)
        self.centralwidget = QtWidgets.QWidget (MainWindow)
        self.centralwidget.setObjectName ("centralwidget")
        self.TestFrame = QtWidgets.QFrame (self.centralwidget)
        self.TestFrame.setGeometry (QtCore.QRect (20, 60, 321, 181))
        self.TestFrame.setFrameShape (QtWidgets.QFrame.StyledPanel)
        self.TestFrame.setFrameShadow (QtWidgets.QFrame.Raised)
        self.TestFrame.setObjectName ("TestFrame")
        self.TestLabelinFrame = QtWidgets.QLabel (self.TestFrame)
        self.TestLabelinFrame.setGeometry (QtCore.QRect (20, 20, 151, 51))
        self.TestLabelinFrame.setObjectName ("TestLabelinFrame")
        self.TestLabel = QtWidgets.QLabel (self.centralwidget)
        self.TestLabel.setGeometry (QtCore.QRect (30, 10, 121, 31))
        self.TestLabel.setObjectName ("TestLabel")
        MainWindow.setCentralWidget (self.centralwidget)
        self.menubar = QtWidgets.QMenuBar (MainWindow)
        self.menubar.setGeometry (QtCore.QRect (0, 0, 510, 17))
        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.TestLabelinFrame.setText (_translate ("MainWindow", "B"))
        self.TestLabel.setText (_translate ("MainWindow", "A"))
# File name: TestWindow.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form (object):
    def setupUi (self, Form):
        Form.setObjectName ("Form")
        Form.resize (400, 300)
        self.pushButton = QtWidgets.QPushButton (Form)
        self.pushButton.setGeometry (QtCore.QRect (20, 20, 75, 23))
        self.pushButton.setObjectName ("pushButton")
        self.retranslateUi (Form)
        QtCore.QMetaObject.connectSlotsByName (Form)
    def retranslateUi (self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle (_translate ("Form", "Form"))
        self.pushButton.setText (_translate ("Form", "PushButton"))
File structure

TestStartUp.py
Controller
| ∟ screen
| ∟TestMainWindow.py
| ∟TestWindow.py
| ∟TestWindow_or.py
∟TestController.py

Problems

The problem is theself.test.ui.eventMethod ...in theTestControllclass of theTestControllerfile br /> I want to link the information of UI in this class to the second argument of this part and link it in eventMethod.
'self.ui'gave [TypeError: argument 1 has unexpected type'NoneType'] and the screen did not start.

Tried

Commented out both the contents of 1. in the'TestController.py'file and enabled the contents of 2. below, the screen started.
Of course, there is no operation because there are no events.

Supplemental information (FW/tool version etc.)

QtDesigner 5.9.5
Python 3.6.5
PyQt5-5.11.2
PyCharm 2018.2.1

  • Answer # 1

    It was solved by changing as follows.

    # TestController.py
    import sys
    from PyQt5 import QtCore as Qc, QtGui as Qg, QtWidgets as Qw
    from PyQt5.QtCore import Qt
    from .screen import TestMainWindow, TestWindow, TestWindow_or, TestWindow_or2
    from .screen.TestShare import textValues
    class TestControll (Qw.QMainWindow):
        # Initial setting
        def __init __ (self, parent = None):
            super () .__ init __ (parent)
            print (self .__ class __.__ name__ + "init")
            self.ui = TestMainWindow.Ui_MainWindow ()
            self.ui.setupUi (self)
            #Method 1. Only screen configuration is inherited
            self.test = Qw.QWidget ()
            self.test .__ init __ (None)
            self.test.ui = TestWindow_or.FormOverride ()
            self.test.ui.setupUi (self.test)
            #Set an event on the screen inheriting side
            self.test.ui.eventMethod (self)
            #Method 2. Inherit screen structure and widget
            self.test2 = TestWindow_or2.FormOverride2 ()
            self.test2.eventMethod (self)
        #Change label A
        def labelChangeA (self):
            self.ui.TestLabel.setText (textValues.textA)
            # textValues.textA = "A: Clicked on a subscreen."
        #Change label B
        def labelChangeB (self):
            self.ui.TestLabelinFrame.setText (textValues.textB)
            # textValues.textB = "B: Clicked on subscreen"
        # For screen startup
        def showWindow (self):
            print (self .__ class __.__ name__ + "launch")
            app = Qw.QApplication ([])
            self.show ()
            self.test.show ()
            self.test2.show ()
            sys.exit (app.exec ())
    # TestWindow_or.py
    from PyQt5.QtWidgets import QWidget
    from .import TestWindow, MainForm
    from .TestShare import textValues
    from .. import TestController
    class FormOverride (TestWindow.Ui_Form):
        def __init __ (self):
            print ("FormOverride init")
        def eventMethod (self, main):
            self.pushButton.clicked.connect (self.changeText)
            self.pushButton.clicked.connect (main.labelChangeA)def changeText (self):
            if textValues.textA == "A":
                textValues.textA = "A: Clicked on the subscreen"
            else:
                textValues.textA = "A"
    Additional files

    I also found a different form of the method, so I'll post it.

    # TestWindow_or2.py
    from PyQt5.QtWidgets import QWidget
    from .import TestWindow
    from .TestShare import textValues
    class FormOverride2 (QWidget, TestWindow.Ui_Form):
        def __init __ (self, parent = None):
            super (FormOverride2, self) .__ init __ (parent)
            self.setupUi (self)
        def eventMethod (self, main):
            self.pushButton.clicked.connect (self.changeText)
            self.pushButton.clicked.connect (main.labelChangeB)
        def changeText (self):
            if textValues.textB == "B":
                textValues.textB = "B: Clicked on the subscreen."
            else:
                textValues.textB = "B"

    Since the only function that can be set when connecting is (), we prepared a class for sharing numerical values.

    # TestShare.py
    class textValues ​​():
        textA = "A"
        textB = "B"
    File structure

    TestStartUp.py
    Controller
    | ∟ screen
    | ∟TestMainWindow.py
    | ∟TestWindow.py
    | ∟TestWindow_or.py
    |TestWindow_or2.py
    |TestShare.py
    ∟TestController.py

    The previous notation has changed a little and the problem is not clear enough. ・ Self.test = Qw.QWidget () and self.test.init(None) cannot be instantiated unless they exist in a set (?)
    If you proceed as it is, you cannot process ui.
    -The function specified when connecting must be without () (argument is only self)
    -Do not change the screen contents in the external class, but write the process in the class to be changed

    I was caught like this.
    There may be another way, but I can't think of it.

  • Answer # 2

    The error content is that there are few arguments for FormOverride :: eventMethod, right?
    The presented code requires Form and ui.

    """Problem I don't know what value to enter""")
    However, since I do not know the screen configuration and dependencies, I can not point out what arguments are required for eventMethod in the first place, but it is necessary to pass what is necessary for processing.

    self.test.ui.eventMethod (self.test, self.ui)
    Wonder?