0

I've been trying to make this work, but it just doesn't. I get no errors, just plain noncompliance. It just does not want to add the QListWidget items, or change the QLabel.

I made a MainWindowClass. It it's main widget I have a layout and a button. In it's dockwidget I have a QListWidget. I made a signal from the button and connected it to a slot in the dockwidget's list. The connection is there. When I press the button, the method in the dockwidgetcontents class is running. But it does not add the items to the listwidget. And does not produce any errors.

Here is the code:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

class AppClass:

    def __init__(self):
        super().__init__()
        app = QApplication(sys.argv)
        window = MainWindowClass()
        window.show()
        sys.exit(app.exec_())


class MainWindowClass(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_UI()
        self.TheDockWidget()

    def init_UI(self):
        self.setGeometry(100, 100, 400, 200)
        self.setWindowTitle("Test App")
        self.setCentralWidget(MainWidgetClass())

    def TheDockWidget(self):
        self.dockWidget = QDockWidget('Status:')
        self.dockWidget.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)
        self.dockWidget.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum))
        self.dockWidget.setWidget(DockWidgetContents())


class DockWidgetContents(QWidget):

    def __init__(self):
        super().__init__()
        self.init_UI()

    def init_UI(self):
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.button3 = QPushButton()
        self.button3.setText("button3")
        layout.addWidget(self.button3)
        self.listwidget = QListWidget()
        layout.addWidget(self.listwidget)
        self.listwidget.addItem("Ready.")
        self.label = QLabel("initial")
        layout.addWidget(self.label)

    @pyqtSlot(str, str, int)
    def _add_item(self, strA, strB, int1):
        self.label.setText("yes")           # why does this not work??
        self.listwidget.addItem(strA)       # why does this not work??
        self.listwidget.addItem(strB)       # why does this not work??
        self.listwidget.addItem(str(int1))  # why does this not work??
        print(strA, strB, int1)             # but this works fine.


class MainWidgetClass(QWidget):

    def __init__(self):
        super().__init__()
        self.init_UI()

    def init_UI(self):
        mainLayout = QGridLayout()
        self.setLayout(mainLayout)
        mainLayout.addWidget(TopLeftWidgetClass(), 0, 0)


class TopLeftWidgetClass(QWidget):
    signal = pyqtSignal(str, str, int)

    def __init__(self):
        super().__init__()
        self.init_UI()

    def init_UI(self):
        layout = QHBoxLayout()
        self.setLayout(layout)
        self.button1 = QPushButton("button1")
        layout.addWidget(self.button1)
        self.button1.clicked.connect(self.start)

    def start(self):
        otherClass = DockWidgetContents()
        self.signal.connect(otherClass._add_item)
        self.signal.emit("one", "two", 3)


if __name__ == '__main__':
    AppClass()

I also read all the suggested questions when I typed my question into the form, but I must be not understanding something vital or prerequisite to this.

While I find all your answers to other questions extremely valuable, I'd appreciate if the answer would point me to the reference that I'm missing, so I can understand the problem, rather than just copy/paste the fixed code.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user122121
  • 130
  • 6

1 Answers1

1

The main problem is that you're trying to connect to a new instance of DockWidgetContents, which gets also immediately deleted as soon as start() returns.

That new instance is obviously useless, as one already exists, but you have no direct ways to get it, because you create all classes "on the fly" when you add widgets to layouts and parents.
Remember that, while creating "instances on the fly" is not technically a problem, it doesn't allow you to keep references to those instances.

You have to create appropriate references to widgets and correctly connect them.

Here you can see the modifications required:

class MainWindowClass(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_UI()
        self.TheDockWidget()
        self.mainWidget.topLeftWidget.signal.connect(
            self.dockWidgetContents._add_item)

    def init_UI(self):
        self.setGeometry(100, 100, 400, 200)
        self.setWindowTitle("Test App")
        self.mainWidget = MainWidgetClass()
        self.setCentralWidget(self.mainWidget)

    def TheDockWidget(self):
        self.dockWidget = QDockWidget('Status:')
        self.dockWidget.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)
        self.dockWidget.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum))
        self.dockWidgetContents = DockWidgetContents()
        self.dockWidget.setWidget(self.dockWidgetContents)


class MainWidgetClass(QWidget):

    def __init__(self):
        super().__init__()
        self.init_UI()

    def init_UI(self):
        mainLayout = QGridLayout()
        self.setLayout(mainLayout)
        self.topLeftWidget = TopLeftWidgetClass()
        mainLayout.addWidget(self.topLeftWidget, 0, 0)
musicamante
  • 41,230
  • 6
  • 33
  • 58
  • Thank you, now I get it. And I see that I also missed the connection between the dock and the button in the MainWindowClass. It makes sense, as that is the parent of all the classes, so the connection has to go through it. It's hard for me to wrap my head around all this stuff, as I only used bash before I started learning python. – user122121 Feb 08 '21 at 19:56
  • @user122121 then a couple of suggestions, if I may: do not exaggerate in creating functions: while separating functions can (sometimes) allow better "visualization" and tidyness of your code, the most important benefit of a function is that it can and should be used again. In your code, except from `_add_item` and `start`, all the other functions are useless, as they are going to be called just once in the `__init__` and do not actually improve readability. Just move all those `init_UI` in the `__init__`. – musicamante Feb 08 '21 at 20:03
  • Then, there's no need for the "Class" suffix for classes, as it's reduntant: you can clearly know that they're classes from the fact that their names are capitalized (and, in fact, `TheDockWidget` should have a lower case "T", as functions and variables should not be capitalized). – musicamante Feb 08 '21 at 20:04
  • I learned this `init_UI` from someone. I see that it's functionally useless. I only did it for the neatness. But if it's bad practice, I'll drop it. Thanks. The Class suffix was only for my own sanity. Somehow it made it easier for me. But as you said, the capitalized name already indicates a class well enough. Thank you for the advice. – user122121 Feb 08 '21 at 20:34