-1

Problem:

I'm trying to write my first application with GUI in Python. I split my program to two files: one with GUI (GUI.py) and second one with program logic (Test.py).

I would like to change something in my GUI during program execution (for example QLabel text with status) from Test.py level.

I don't know how to get access to any controls.

Code:

GUI.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QLabel, QPushButton, QGridLayout


class Ui_Widget(object):
    def setupUi(self):

        # controls
        statusLbl = QLabel("Status", self)
        changeBtn = QPushButton("&Change text", self)
        closeBtn = QPushButton("&Close", self)

        #statusLbl.setText("working") # <- here it works, but not in Test.py

        # GridLayout
        CtrLayout = QGridLayout()
        CtrLayout.addWidget(statusLbl, 0, 0)
        CtrLayout.addWidget(changeBtn, 0, 1)
        CtrLayout.addWidget(closeBtn, 0, 2)       
        self.setLayout(CtrLayout)

        # onClick events
        changeBtn.clicked.connect(self.changeText)
        closeBtn.clicked.connect(self.closeApp)

        #self.setGeometry(20, 20, 300, 100)
        #self.setWindowTitle("TEST APP")
        self.show()

Test.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QApplication, QWidget
from GUI import Ui_Widget

class TestApp(QWidget, Ui_Widget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setupUi()

    def changeText(self):
        generateReport(self) # code moved to separate function for better clarity

    def closeApp(self):
        self.close()

def generateReport(obj):
    statusLbl.setText("working") # <- change of statusLbl.setText is not working

    # ...
    # 200 lines of code here
    #...

    statusLbl.setText("not " + statusLbl.text() )

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    WND = TestApp()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
mgu
  • 1
  • 3

2 Answers2

0

You should point that you want to access ui. Instead of:

statusLbl.setText("working")

You should use:

obj.statusLbl.setText("working")

While on initiation you should pass self:

self.statusLbl = QLabel("Status", self)
Karls
  • 731
  • 7
  • 17
  • statusLbl is a QLabel object. after using your code in `def generateReport(obj)` function I'm receiving this error: NameError: name 'self' is not defined – mgu Mar 10 '19 at 18:31
  • Ah ok, you passed `self` as `obj`, like @S.Nick noticed above. So it will be `obj.statusLbl.setText("working")` or `obj.ui.statusLbl.setText("working")` – Karls Mar 10 '19 at 18:47
  • still something not ok. For `obj.statusLbl.setText("working")` I'm receiving `AttributeError: 'TestApp' object has no attribute 'statusLbl'` error. For `obj.ui.statusLbl.setText("working")` there is `AttributeError: 'TestApp' object has no attribute 'ui'` error. – mgu Mar 10 '19 at 19:01
  • I bet the first syntax (without `ui` is correct), but you need add `self` also on initiation of object. I mean: `self.statusLbl = QLabel("Status", self)`. Let us know if it's working now. – Karls Mar 10 '19 at 19:08
  • Works perfectly! One more question: which terms I should google to understand how it works? Is there any tutorial with explanation about it? – mgu Mar 10 '19 at 19:23
  • The keywords you are looking for are probably "classes" and "instances". You can start [here](https://medium.com/quick-code/understanding-self-in-python-a3704319e5f0) – Karls Mar 10 '19 at 20:30
0

Try it:

from PyQt5.QtWidgets import QLabel, QPushButton, QGridLayout
from PyQt5.QtWidgets import QApplication, QWidget
#from GUI import Ui_Widget


class Ui_Widget(object):
    def setupUi(self):
        # controls
        self.statusLbl = QLabel("Status", self)                    # + self.
        changeBtn = QPushButton("&Change text", self)
        closeBtn  = QPushButton("&Close", self)
        #statusLbl.setText("working") # <- here it works, but not in Test.py

        # GridLayout
        CtrLayout = QGridLayout()
        CtrLayout.addWidget(self.statusLbl, 0, 0)    # self.
        CtrLayout.addWidget(changeBtn, 0, 1)
        CtrLayout.addWidget(closeBtn, 0, 2)       
        self.setLayout(CtrLayout)

        # onClick events
        changeBtn.clicked.connect(self.changeText)
        closeBtn.clicked.connect(self.closeApp)

        #self.setGeometry(20, 20, 300, 100)
        #self.setWindowTitle("TEST APP")
        self.show()


class TestApp(QWidget, Ui_Widget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setupUi()   

    def changeText(self):
        generateReport(self)  # code moved to separate function for better clarity

    def closeApp(self):
        self.close()

def generateReport(obj):

    if obj.statusLbl.text() != "working":
        obj.statusLbl.setText("working")                      # <- + obj.

    # ...
    # 200 lines of code here
    #...

    else:
        obj.statusLbl.setText("not " + obj.statusLbl.text())  # <- + obj.


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    WND = TestApp()
    WND.show()                   
    sys.exit(app.exec_())

enter image description here

S. Nick
  • 12,879
  • 8
  • 25
  • 33
  • Thank you very much, this works fine! Now I have all code in one file. To be honest this is not a big issue, this should be a small app with very simple GUI. BTW I'm curious if its possible to separate GUI from program logic anyhow. – mgu Mar 10 '19 at 18:45