0

So I'm lost ... again. I have a QMainWindow with a empty QStackedWidget. I would like to dynamically populate the QStackedWidget using a custom widget that I created in Qt Creator. I tried following Creating a custom widget in PyQT5 in another thread, but that doesn't really cover importing from a UI file in this case. I keep receiving:

AttributeError: 'QStackedWidget' object has no attribute 'addItemWidget'

Here is the code for the Widget...

# ItemWidget.py

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget


class Widget:

    def __init__(self):
        self.text = None
        self.data = None


class ItemWidget(QWidget):

    def __init_(self, parent = None):
        self.WidgetList = []
        QWidget.__init__(self, parent = parent)
        uic.loadUi(r'interface/ItemWidget.ui', self)

    def addItemWidget(self, index, text):
        widget = Widget()
        widget.text = text
        self.WidgetList.append([])
        self.WidgetList[index].append(widget)

        # TESTING
        print(self.WidgetList)

Relevant code from main.py:

from ItemWidget import *

for key, value in self.ItemIndexList.items():
    self.ItemStackedWidget.addItemWidget(value, key)

I understand that I'm getting this error because QStackedWidget has no defined attribute called 'addItemWidget, but I don't know what I need to do to get this to work as intended. When I try overriding the method using 'addWidget', I get an unexpected value error.

Any ideas? I'm fairly new to Python and still learning, so if I'm missing some important information please let me know.

I have a few different revisions of my MainWindow.ui. One just has a QStackedWidget where I want the pages to go, the other is completely laid out how I would imagine the final product to look. The ItemWidget.ui file just contains the elements I want to add to each QStackedWidget page. I have not promoted any of them to a custom class, which I suspect I will need to do.

I'm currently using Python 3.6 and PyQt5

** EDIT TO ADD MVCE **

TestApp.py

from PyQt5.QtWidgets import QApplication
import TestMain
import sys


class MCVE(QApplication):

    def __init__(self):
        args = sys.argv
        QApplication.__init__(self, args)
        self.application = TestMain.TestMainWindow()

    def initApp(self):
        self.application.show()


if __name__ == '__main__':
    app = MCVE()
    app.initApp()
    sys.exit(app.exec_())

TestMain.py

from PyQt5.Qt import Qt
from PyQt5.QtWidgets import QMainWindow
from TestItemWidget import *


class TestMainWindow(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self, None, Qt.Window)
        uic.loadUi(r'interface/TestMainWindow.ui', self)

        SlotList = {('Header1', 0),('Header2', 1)}

        for key, value in SlotList:
            self.ItemStackedWidget.addItemWidget(value, key)

TestItemWidget.py

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget


class Widget:

    def __init__(self):
        self.text = None
        self.data = None


class ItemWidget(QWidget):

    def __init_(self, parent = None):
        self.WidgetList = []
        QWidget.__init__(self, parent = parent, flags = None)
        uic.loadUi(r'interface/TestItemWidget.ui', self)

    def addItemWidget(self, index, text):
        widget = Widget()
        widget.text = text
        self.WidgetList.append([])
        self.WidgetList[index].append(widget)
        print(self.WidgetList)

if __name__ == '__main__':
    pass

TestItemWidget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item alignment="Qt::AlignHCenter">
    <widget class="QLabel" name="label">
     <property name="text">
      <string>ItemWidget</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

TestMainWindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>417</width>
    <height>288</height>
   </rect>
  </property>
  <property name="MainWindowUI" stdset="0">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="widget">
   <layout class="QVBoxLayout">
    <item>
     <widget class="QStackedWidget" name="ItemStackedWidget"/>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
artomason
  • 3,625
  • 5
  • 20
  • 43
  • Show your ItemWidget.ui – eyllanesc Dec 05 '17 at 00:41
  • How have you defined ItemStackedWidget? – eyllanesc Dec 05 '17 at 00:42
  • I want a code with which I can reproduce your error, and in your case I need you to show ItemWidget.ui and also place an appropriate code of main.py, we need a [mcve], that is, a code that when copied can execute it I do not want to guess codes. – eyllanesc Dec 05 '17 at 00:58
  • To understand the dynamics I use to help: first I try to obtain a code that can be executed, then I try to reproduce your error, when I have it, I debug your code and check what the error is. But if you do not show the right code I'll be guessing, I do not know your code, I do not know why you're talking about QML, I do not understand why you're talking about mainwindow.ui – eyllanesc Dec 05 '17 at 01:01
  • @eyllanesc updated. Please let me know if I'm missing something. – artomason Dec 05 '17 at 01:49
  • What does addItemWidget have to do? – eyllanesc Dec 05 '17 at 01:58
  • I will add the widgets to ItemStackedWidget as a page. I just haven't gotten to that part. – artomason Dec 05 '17 at 02:02
  • What widget???? – eyllanesc Dec 05 '17 at 02:02
  • You can answer? – eyllanesc Dec 05 '17 at 02:13
  • @eyllanesc Sorry, the Stack Overflow phone app stopped displaying comments and I didn't hear the notifications on my end. TestItemWidget.ui is essentially the widget I want to add to ItemStackedWidget, I'm not overly concerned about adding the widget just yet, and I think I have that covered, but I would like to try before I ask beyond the scope of this question. Sorry for the late reply, I hope this isn't wasting your time. – artomason Dec 05 '17 at 04:25
  • In your code you show the variable SlotList which is a list of tuples, what is the meaning of those numbers and strings? – eyllanesc Dec 05 '17 at 04:28
  • It is a index that I'm using to tie items from a QTreeView to the index of a QStackedWidget object index. My plan is to populate a QListTree with a tuple, generate a index based on elements in the tuple, and then add the pages to QStackedWidget. This way any change made to the first tuple will reverberate down the line. I figured the easiest way to represent that was to include it in the example. – artomason Dec 05 '17 at 04:35
  • If it would help make the picture a clearer, I can link my GitHub for the code that I currently working on. I know that's not standard practice though. – artomason Dec 05 '17 at 04:41
  • I do not want to see your additional code (I remember being gigantic and messy), just answer the question I asked you. – eyllanesc Dec 05 '17 at 04:43
  • I think I answered your questions before, **but from what I understand the purpose of this question is that you want to add some ItemWidget to the QStackedWidget that is TestMainWindow.ui. I am right?** – eyllanesc Dec 05 '17 at 04:44
  • Correct, that is exactly what I want it to do in the end. The ItemWidget will be it's page. You answered a similar question in https://stackoverflow.com/questions/47600467/automatically-create-qstackedwidget-pages-based-on-tuple, but I had to approach this differently. To be fair the code you saw was not mine, I'm just trying to fix all the issues and clean it up which is what my second GitHub is for lol. To answer you question directly, the string identifies the piece and the text contained in the QTreeView, and the integer is the index to ItemStackedWidget. – artomason Dec 05 '17 at 04:45
  • See my answer.. – eyllanesc Dec 05 '17 at 04:58

1 Answers1

1

If you want to interact with a widget you must do it where the widget exists and in your case QStackedWidget exists in TestMain.py so you must use it with your addWidget method, it does not have the addItemWidget method, I also recommend verifying your syntax, for example the init method is placed with 2 underscores on each side, but in your code ItemWidget has only one on the right side: __init_, in conclusion your code should be as follows, add the text to the labels to make it visible:

TestMain.py

from PyQt5.Qt import Qt
from PyQt5.QtWidgets import QMainWindow, QMenu, QToolBar, QTreeWidgetItem
from TestItemWidget import *

class TestMainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, None, Qt.Window)
        uic.loadUi(r'interface/TestMainWindow.ui', self)

        SlotList = {('Header1', 0),('Header2', 1)}

        for key, value in SlotList:
            w = ItemWidget(self)
            w.label.setText(key)
            self.ItemStackedWidget.insertWidget(value, w)

TestItemWidget.py

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget

class ItemWidget(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent = parent)
        uic.loadUi(r'interface/TestItemWidget.ui', self)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you! Your example works, and should do exactly what I need. For simplicity reasons, would it be better to put the ItemWidget class under TestMainWindow, and if I did so, would creating a method such as addItemWidget work in that instance? I just want to understand that a little more – artomason Dec 05 '17 at 05:13
  • ItemWidget must not have the addItemWidget method. – eyllanesc Dec 05 '17 at 05:15
  • Noted. Sorry for the 1000 questions, I'm just trying to understand how the original author of the source code I'm working with achieved that. I still have a lot to learn. – artomason Dec 05 '17 at 05:18
  • If a code is not documented as I saw the code that you showed me it is impossible to understand how it works. If they gave me back a similar job (sometimes they gave me a similar job) I would not accept it, or I would accept it with the condition that the project would do from scratch as it tires, bores and the cost-time analysis tells me that it is cheaper to do it from scratch that rebuild a messy project. – eyllanesc Dec 05 '17 at 05:22
  • That is actually what I'm doing with it (starting from scratch) lol. The repo I showed you is the original, I'm attempting to work off that, but as you said.. it is a mess. – artomason Dec 05 '17 at 05:25