0

I'm trying to create checkbox, frame, and grid layout objects and store them in their own list.

The output from Qt Designer looks like: enter image description here

Essentially, I want to create Checkbox1, then create a frame and grid layout to store Checkbox2 and Checkbox3.

My approach was to first create an empty list to store the objects I'm creating: checkboxList = [] Then to append it with a call to create the appropriate object checkboxList.append(CreateCheckBox(self.frame_main, self.gridLayout_main, 0, 'Checkbox 1') (for example)

This produces the output: enter image description here

The frame I created isn't visible! I'm guessing there are a few possible reasons for this:

  1. I'm creating the classes incorrectly
  2. I'm storing the objects I created incorrectly (i.e. init doesn't return anything so I'm not actually storing anything?)
  3. I'm not adding my objects to the main frame properly so they're not showing up

Why isn't my class implementation working like the code from Qt Designer and what/how do I make the changes to get a similar output?

The code imported from Qt Designer looks like this:

from PySide import QtCore, QtGui

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(494, 210)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.frame_main = QtGui.QFrame(self.centralwidget)
        self.frame_main.setGeometry(QtCore.QRect(20, 10, 435, 141))
        self.frame_main.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame_main.setFrameShadow(QtGui.QFrame.Raised)
        self.frame_main.setObjectName("frame_main")
        self.gridLayout_2 = QtGui.QGridLayout(self.frame_main)
        self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_2.setSpacing(0)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.gridLayout_main = QtGui.QGridLayout()
        self.gridLayout_main.setSpacing(0)
        self.gridLayout_main.setObjectName("gridLayout_main")
        self.frame2 = QtGui.QFrame(self.frame_main)
        self.frame2.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame2.setFrameShadow(QtGui.QFrame.Raised)
        self.frame2.setObjectName("frame2")
        self.gridLayout_16 = QtGui.QGridLayout(self.frame2)
        self.gridLayout_16.setContentsMargins(0, 0, 0, 0)
        self.gridLayout_16.setObjectName("gridLayout_16")
        self.gridLayout2 = QtGui.QGridLayout()
        self.gridLayout2.setObjectName("gridLayout2")
        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
        self.gridLayout2.addItem(spacerItem, 0, 0, 1, 1)
        self.checkBox2 = QtGui.QCheckBox(self.frame2)
        self.checkBox2.setObjectName("checkBox2")
        self.gridLayout2.addWidget(self.checkBox2, 0, 1, 1, 1)
        self.checkBox3 = QtGui.QCheckBox(self.frame2)
        self.checkBox3.setObjectName("checkBox3")
        self.gridLayout2.addWidget(self.checkBox3, 1, 1, 1, 1)
        self.gridLayout_16.addLayout(self.gridLayout2, 0, 0, 1, 1)
        self.gridLayout_main.addWidget(self.frame2, 1, 1, 1, 1)
        self.checkBox1 = QtGui.QCheckBox(self.frame_main)
        self.checkBox1.setObjectName("checkBox1")
        self.gridLayout_main.addWidget(self.checkBox1, 0, 1, 1, 1)
        spacerItem1 = QtGui.QSpacerItem(50, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
        self.gridLayout_main.addItem(spacerItem1, 0, 0, 1, 1)
        self.gridLayout_2.addLayout(self.gridLayout_main, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 494, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox2.setText(QtGui.QApplication.translate("MainWindow", "Checkbox2", None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox3.setText(QtGui.QApplication.translate("MainWindow", "Checkbox3", None, QtGui.QApplication.UnicodeUTF8))
        self.checkBox1.setText(QtGui.QApplication.translate("MainWindow", "Checkbox1", None, QtGui.QApplication.UnicodeUTF8))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

And my code with classes looks like:

from PySide import QtCore, QtGui


class CreateCheckBox(QtGui.QCheckBox):
    def __init__(self, frame, grid, gridLoc, name, parent=None):
        #QtGui.QCheckBox.__init__(self, parent=parent)  Is this the same as the super below?
        super(CreateCheckBox, self).__init__(parent)
        self.checkbox = QtGui.QCheckBox(frame)
        grid.addWidget(self.checkbox, gridLoc, 2, 1, 1)
        self.checkbox.setText(name)


class CreateFrame(QtGui.QFrame):
    def __init__(self, parentFrame, parentGridLayout, gridLoc, parent=None):
        #QtGui.QFrame.__init__(self, parent=parent)  Is this the same as the super below?
        super(CreateFrame, self).__init__(parent)
        self.frame = QtGui.QFrame(parentFrame)
        self.frame.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtGui.QFrame.Raised)
        parentGridLayout.addWidget(self.frame, gridLoc, 2, 1, 1)


class CreateGridLayout(QtGui.QGridLayout):
    def __init__(self, parentFrame, parent=None):
        super(CreateGridLayout, self).__init__(parent)
        #QtGui.QGridLayout.__init__(self)  # This line throws an error if I include parent=parent, why?..
        self.gridLayoutSecondary = QtGui.QGridLayout(parentFrame)
        self.gridLayoutSecondary.setContentsMargins(0, 0, 0, 0)
        self.gridLayoutPrimary = QtGui.QGridLayout()
        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
        self.gridLayoutPrimary.addItem(spacerItem, 0, 0, 1, 1)
        self.gridLayoutSecondary.addLayout(self.gridLayoutPrimary, 0, 0, 1, 1)


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(494, 210)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.frame_main = QtGui.QFrame(self.centralwidget)
        self.frame_main.setGeometry(QtCore.QRect(20, 10, 435, 141))
        self.frame_main.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame_main.setFrameShadow(QtGui.QFrame.Raised)
        self.frame_main.setObjectName("frame_main")
        self.gridLayout_main = QtGui.QGridLayout()
        self.gridLayout_main.setSpacing(0)
        self.gridLayout_main.setObjectName("gridLayout_main")
        spacerItem1 = QtGui.QSpacerItem(50, 20, QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum)
        self.gridLayout_main.addItem(spacerItem1, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 494, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        # List that contains new checkboxes
        checkboxList = []
        # List that contains new frames
        frameList = []
        # List than contains grid layouts for new frames
        gridLayoutList = []

        # Create 'checkBox1'
        checkboxList.append(CreateCheckBox(self.frame_main, self.gridLayout_main, 0, 'Checkbox 1'))
        # Create 'frame2'
        frameList.append(CreateFrame(self.frame_main, self.gridLayout_main, 1))
        # Create 'gridLayout2'
        gridLayoutList.append(CreateGridLayout(frameList[0]))
        # Create 'checkBox2'
        checkboxList.append(CreateCheckBox(frameList[0], gridLayoutList[0], 0, 'Checkbox 2'))
        # Create 'checkBox3'
        checkboxList.append(CreateCheckBox(frameList[0], gridLayoutList[0], 1, 'Checkbox 3'))

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
Arda Arslan
  • 1,331
  • 13
  • 24
  • Could you explain me better, say you apply 2 times your functionality, what should be the output? – eyllanesc Jun 26 '17 at 19:30
  • I believe you should correct your custom classes, when you declare a class `CreateCheckBox(QtGui.QCheckBox)`, this is already a checkbox, no need to assign a new `self.checkbox = QtGui.QCheckBox`. – PRMoureu Jun 26 '17 at 19:35
  • 1
    I don't understand your question. I'm basically trying to use classes to recreate the original design imported from Qt Designer. – Arda Arslan Jun 26 '17 at 19:36
  • And then why use the lists? – eyllanesc Jun 26 '17 at 19:40
  • 1
    @PRMoureu When I removed the line `self.checkbox = QtGui.QCheckBox(frame)`, and changed `self.checkbox` to `self`, nothing shows up in MainWindow – Arda Arslan Jun 26 '17 at 19:40
  • What is the reason for using lists? – eyllanesc Jun 26 '17 at 19:41
  • @eyllanesc I'm planning on adding hundreds of checkboxes into an application so I thought adding them to a list was the best way to hold onto the checkboxes for later use. I'm also implementing a show/hide button to show/hide the frame certain checkboxes are in. If the frame is hidden, the checkboxes in it are also hidden. – Arda Arslan Jun 26 '17 at 19:42
  • try with `super(CreateCheckBox, self).__init__(frame)` (this `frame` is the parent widget) – PRMoureu Jun 26 '17 at 19:43
  • Suppose you want to show 5 QCheckbox, how should it show? – eyllanesc Jun 26 '17 at 19:44
  • I think the approach you're using is wrong, and fixing it is tedious, I'd rather give you the right approach. – eyllanesc Jun 26 '17 at 19:46
  • From the figure I notice that the checkbox2 and checkbox3 are aligned, but the checkbox1 is not, so I ask if they add more checkboxes as they should be placed? – eyllanesc Jun 26 '17 at 19:48
  • The alignment is on purpose - there is a spacer in the grid layout that makes it like that – Arda Arslan Jun 26 '17 at 19:50
  • Explain better please, you could put pictures for the case that there are 4 or 5 chekboxes – eyllanesc Jun 26 '17 at 19:53
  • It would look something like [this](http://i.imgur.com/bkXiOLG.png) – Arda Arslan Jun 26 '17 at 19:58
  • To answer your doubts, i think you mixed up _function_ and _classes_ (when you say "init doesn't return anything"). When you instance/create a class, the purpose of `__init__` is to build and return an object (checkbox, frame, whatever..). You can store this object in a list if you need to control it, but when you create a widget in Qt, it is already stored in the _parent_ widget and the _gridlayout_ you've specified. When you assign a widget to a new attribute like `self.frame` and then call `frameList[0]`, your app cannot find the real frame which "hidden in self.frame" in your custom class. – PRMoureu Jun 26 '17 at 20:32
  • see my answer, please. – eyllanesc Jun 26 '17 at 20:35
  • @PRMoureu Thanks for your comments. As far as storing the widgets goes, if frameList[0] won't work, what will? I turned the `self.frame` into just `self`. Does that change anything? And is there a way to "see" the widgets inside a QFrame? – Arda Arslan Jun 26 '17 at 21:22
  • in your first pattern, you would need to call `frameList[0].frame` to refer to the real frame you've shaped (but don't keep that design). Now if you replaced the `self.frame =...` part by `super(CreateFrame, self).__init__(parentFrame)`, `self.setFrameShape(QtGui.QFrame.StyledPanel) ...`, you should be able to call `frameList[0]` – PRMoureu Jun 26 '17 at 22:09
  • Inside a view object like Qframe, i think QFrame.items() returns the list of all widgets, but i can't test it right now. You also need to use more logs in your code to control and analyse what you're playing with. i.e : begin with adding `print(frameList[0])` or `print(dir(frameList[0]))` and `print(dir(frameList[0].frame))` to see what's inside, the next step will be the logging module... – PRMoureu Jun 26 '17 at 22:29

1 Answers1

2

El problema se soluciona maquetando correctamente tu aplicación, en la siguiente imagen se muestra el maquetado de QMainWindow, la imagen muestra que QMainWindow varias secciones.

enter image description here

In your case you should design the centralwidget,

enter image description here

Then, the answer can be implemented, observing that it is not necessary to use QGridLayout since it is used to distribute it as a matrix. I have created the addCheckbox function that adds the widget and stores it in the list.

from PyQt4 import QtGui, QtCore


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent=parent)

        # add menubar
        self.menubar = QtGui.QMenuBar(self)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 494, 21))
        self.setMenuBar(self.menubar)
        # add statusbar
        self.statusbar = QtGui.QStatusBar(self)
        self.setStatusBar(self.statusbar)

        # set central widget
        self.centralwidget = QtGui.QWidget(self)
        self.setCentralWidget(self.centralwidget)

        lay = QtGui.QVBoxLayout(self.centralwidget)
        self.checkBox = QtGui.QCheckBox("checkbox1", self)
        lay.addWidget(self.checkBox)

        self.frame = QtGui.QFrame(self)
        lay.addWidget(self.frame)

        self.layout_of_frame = QtGui.QVBoxLayout(self.frame)

        self.checkBoxList = []
        self.addCheckbox("checkbox2")
        self.addCheckbox("checkbox3")
        self.addCheckbox("checkbox4")
        self.addCheckbox("checkbox5")

    def addCheckbox(self, text):
        checkbox = QtGui.QCheckBox(text, self)
        self.layout_of_frame.addWidget(checkbox)
        self.checkBoxList.append(checkbox)

Screenshot:

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241