0

I am trying to add a custom widget to a layout. I can successfully add many PushButtons to my GridLayout, but when I attempt to add the custom widget it does not show.

I have attempted to provide a minimal example:

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class moduleForm(QtWidgets.QWidget):

    def __init__(self, parent = None):

        self.parent = parent

        self.setObjectName("moduleForm")
        self.resize(300, 400)
        self.fModule = QtWidgets.QPushButton("Test")
        self.fModule.setGeometry(QtCore.QRect(0, 0, 80, 20))

        self.retranslateUi(self.parent)

        QtCore.QMetaObject.connectSlotsByName(self)

    def retranslateUi(self, moduleForm):
        _translate = QtCore.QCoreApplication.translate

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):

        MainWindow.setObjectName("Rb Controller")
        MainWindow.resize(900, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.loMainTab = QtWidgets.QHBoxLayout(self.centralwidget)
        self.centralwidget.setLayout(self.loMainTab)

        self.saChannels = QtWidgets.QScrollArea(self.centralwidget)
        self.saChannels.setWidgetResizable(True)
        self.saChannels.setGeometry(QtCore.QRect(10,10,10,10))

        self.fButtons = QtWidgets.QFrame(self.centralwidget)
        self.fButtons.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.pbAddModule = QtWidgets.QPushButton(self.fButtons)
        self.pbAddModule.setGeometry(QtCore.QRect(10, 10, 80, 20))
        self.pbAddModule.setObjectName("pbAddModule")
        self.loButtons = QtWidgets.QHBoxLayout(self.fButtons)
        self.loButtons.addWidget(self.pbAddModule)
        self.loButtons.addStretch()
        self.fButtons.setLayout(self.loButtons)

        self.hlwChannelsContents = QtWidgets.QWidget()
        self.hlwChannelsContents.setObjectName("hlwChannelsContents")
        self.hloChannelsContents = QtWidgets.QHBoxLayout(self.hlwChannelsContents)
        self.hloChannelsContents.setObjectName("hloChannelsContents")
        self.gloChannelsContents = QtWidgets.QGridLayout()
        self.hloChannelsContents.addLayout(self.gloChannelsContents)
        self.saChannels.setWidget(self.hlwChannelsContents)

        self.loMainTab.addWidget(self.fButtons)
        self.loMainTab.addWidget(self.saChannels,1)

        for ii in range(10):
            for jj in range(10):
                self.r_button = QtWidgets.QPushButton("Element %s,%s " % (ii, jj))
                self.gloChannelsContents.addWidget(self.r_button,ii,jj)

        MainWindow.setCentralWidget(self.centralwidget)


        self.retranslateUi(MainWindow)
        self.pbAddModule.clicked.connect(self.createModule)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Rb Controller"))
        self.pbAddModule.setText(_translate("MainWindow", "Add Module"))


    def createModule(self):
        createModule = moduleForm()
        self.gloChannelsContents.addWidget(createModule)
        createModule.show()


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(ApplicationWindow, self).__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)


def main():
    app = QtWidgets.QApplication(sys.argv)
    application = ApplicationWindow()
    application.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

I have added the super().__init__ function but it is still not working. The PushButton in my custom widget gets displayed if I add it not the custom widget, so all the other code is fine.

If I have:

self.gloChannelsContents.addWidget(createModule.fModule,self.i,self.j)    

in createModule then I get a dynamic PushButton, however, if I try to use the custom widget

self.gloChannelsContents.addWidget(createModule,self.i,self.j)        

nothing appears.

vivian
  • 1,434
  • 1
  • 10
  • 13
  • 1
    Your current code has class inheritance problems, for example in moduleForm you inherit from QWidget but you do not call super, besides it seems that you are modifying Qt Designer code but PyQt clearly states that you should not do it, I recommend you check the second or third example of the docs: http://pyqt.sourceforge.net/Docs/PyQt5/designer.html – eyllanesc Jan 14 '19 at 19:29
  • 1
    add super(moduleForm, self).__init__(parent) after of def __init__(self, parent = None): and change self.fModule = QtWidgets.QPushButton("Test") to self.fModule = QtWidgets.QPushButton("Test", self) – eyllanesc Jan 14 '19 at 19:33
  • 1
    It is always nice to point out with a feedback to the comments made by the community to help you :-), on the other hand it seems that you did not understand what I indicated so I created the solution code and uploaded it to gist: https://gist.github.com/eyllanesc/4c23d2a5c13705338a3f4dbe81ad416a , getting the following result: https://user-images.githubusercontent.com/4896200/51142263-6e94b800-1819-11e9-9e03-22d3832bb7a8.png – eyllanesc Jan 14 '19 at 21:30
  • @eyllanesc: Thank you for your help. I had added a `super().__init__()` call but I was failing to pass the parent to it. Once I did that it worked. Do you want to post an answer so I can upvote it? – vivian Jan 14 '19 at 23:11
  • No, I have marked it as a duplicate because I used the 2 post to find the solution, if you read the concept that is based on the code that you provided, also read the Pycs docs because you have simple errors that could in the future be terrible – eyllanesc Jan 14 '19 at 23:14
  • @eyllanesc: The code works with `addWidget(createModule)` but when I try to add a grid position argument it doesn't work. – vivian Jan 14 '19 at 23:23
  • 1
    What position are you giving? Is it a new position or are you overwriting an earlier one? Please give details to help you. – eyllanesc Jan 14 '19 at 23:28
  • 1
    As you point out you need to learn the basics, for example the use of layouts, in your case fModule is a child of moduleForm but moduleForm does not handle its position or size, nor does it know when it changes or how much, so the minimum size of moduleForm is 0, 0 and that is the one that will use the gridlayout so magically sometimes it will disappear, so the solution is to establish the fModule with a layout https://gist.github.com/eyllanesc/4c23d2a5c13705338a3f4dbe81ad416a – eyllanesc Jan 14 '19 at 23:39
  • Adding the layout worked, thanks. – vivian Jan 14 '19 at 23:57
  • It would be advisable that you eliminate your question – eyllanesc Jan 15 '19 at 00:09
  • To get a custom widget to display properly within a layout and frame I had to set the size of the custom widget to `fixed` and manually set sizes if it resized. – vivian Feb 11 '19 at 00:27

1 Answers1

0

Try it:

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class moduleForm(QtWidgets.QWidget):

    def __init__(self, row, parent = None):                            # + row
        super().__init__()

        self.parent = parent

        self.setObjectName("moduleForm")
        self.resize(300, 400)
        self.fModule = QtWidgets.QPushButton("Test {}".format(row))    # + row
        self.fModule.setGeometry(QtCore.QRect(0, 0, 80, 20))

        self.retranslateUi(self.parent)

        QtCore.QMetaObject.connectSlotsByName(self)

    def retranslateUi(self, moduleForm):
        _translate = QtCore.QCoreApplication.translate

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):

        self.i = 11                                               # + self.i

        MainWindow.setObjectName("Rb Controller")
        MainWindow.resize(900, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.loMainTab = QtWidgets.QHBoxLayout(self.centralwidget)
        self.centralwidget.setLayout(self.loMainTab)

        self.saChannels = QtWidgets.QScrollArea(self.centralwidget)
        self.saChannels.setWidgetResizable(True)
        self.saChannels.setGeometry(QtCore.QRect(10,10,10,10))

        self.fButtons = QtWidgets.QFrame(self.centralwidget)
        self.fButtons.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.pbAddModule = QtWidgets.QPushButton(self.fButtons)
        self.pbAddModule.setGeometry(QtCore.QRect(10, 10, 80, 20))
        self.pbAddModule.setObjectName("pbAddModule")
        self.loButtons = QtWidgets.QHBoxLayout(self.fButtons)
        self.loButtons.addWidget(self.pbAddModule)
        self.loButtons.addStretch()
        self.fButtons.setLayout(self.loButtons)

        self.hlwChannelsContents = QtWidgets.QWidget()
        self.hlwChannelsContents.setObjectName("hlwChannelsContents")
        self.hloChannelsContents = QtWidgets.QHBoxLayout(self.hlwChannelsContents)
        self.hloChannelsContents.setObjectName("hloChannelsContents")
        self.gloChannelsContents = QtWidgets.QGridLayout()
        self.hloChannelsContents.addLayout(self.gloChannelsContents)
        self.saChannels.setWidget(self.hlwChannelsContents)

        self.loMainTab.addWidget(self.fButtons)
        self.loMainTab.addWidget(self.saChannels,1)

        for ii in range(10):
            for jj in range(10):
                self.r_button = QtWidgets.QPushButton("Element %s,%s " % (ii, jj))
                self.gloChannelsContents.addWidget(self.r_button, ii, jj)

        MainWindow.setCentralWidget(self.centralwidget)


        self.retranslateUi(MainWindow)
        self.pbAddModule.clicked.connect(self.createModule)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Rb Controller"))
        self.pbAddModule.setText(_translate("MainWindow", "Add Module"))


    def createModule(self):
        self.createModule = moduleForm(self.i)                                   # +
        self.gloChannelsContents.addWidget(self.createModule.fModule, self.i, 0) # +
        self.i += 1                                                              # +
#        self.createModule.show()  # ???


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(ApplicationWindow, self).__init__()

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)


def main():
    app = QtWidgets.QApplication(sys.argv)
    application = ApplicationWindow()
    application.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()  

enter image description here

S. Nick
  • 12,879
  • 8
  • 25
  • 33
  • Following your example I can add a PushButton dynamically, but only when I `addWidget` the `fModule` from `moduleForm`. I need to be able to add the whole custom widget, not just the PushButton. – vivian Jan 14 '19 at 19:16