How do I modify a QLayout of a QGroupBox to remove or add parameter QTextEdit input? (Python, PyQt)

1.6k views Asked by At

I'm trying to implement a window that is able to get parameters from a user. In this window, the user should give a number of lines (to have N parameter sets). From this number I would like to have the automatically generation of QTextEdit sets for each N parameter set. So from now I have this code

# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from PyQt4 import QtGui
import sys
import numpy as np

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

        # General Window
        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        self.mainHBOX_param_scene = QtGui.QVBoxLayout()

        # parameter2
        self.horizontalGroupBox_Param2 = QtGui.QGroupBox("Set range Parameter 2 for matrix method")
        self.horizontalGroupBox_Param2.setMaximumHeight(80)
        self.Param2_layout = QtGui.QVBoxLayout()
        grid2 = QtGui.QGridLayout()
        self.Param2_layout.addLayout(grid2)
        self.Param2_Label = QtGui.QLabel('Name')
        self.Param2 = QtGui.QComboBox()
        self.Param2.addItems(["a","b","c"])
        self.Param2.setMinimumWidth(100)
        # self.Param2_layout.addWidget(self.Param2)
        self.Param2_min_Label = QtGui.QLabel('min')
        self.Param2_min_Edit = QtGui.QTextEdit('1')
        self.Param2_min_Edit.setMaximumWidth(40)
        self.Param2_max_Label = QtGui.QLabel('max')
        self.Param2_max_Edit = QtGui.QTextEdit('5')
        self.Param2_max_Edit.setMaximumWidth(40)
        self.Param2_step_Label = QtGui.QLabel('step')
        self.Param2_step_Edit = QtGui.QTextEdit('1')
        self.Param2_step_Edit.setMaximumWidth(40)
        grid2.addWidget(self.Param2_Label, 0, 0)
        grid2.addWidget(self.Param2, 1, 0)
        grid2.addWidget(self.Param2_min_Label, 0, 1)
        grid2.addWidget(self.Param2_min_Edit, 1, 1)
        grid2.addWidget(self.Param2_max_Label, 0, 2)
        grid2.addWidget(self.Param2_max_Edit, 1, 2)
        grid2.addWidget(self.Param2_step_Label, 0, 3)
        grid2.addWidget(self.Param2_step_Edit, 1, 3)
        self.horizontalGroupBox_Param2.setLayout(self.Param2_layout)

          #action button
        self.horizontalGroupBox_Actions = QtGui.QGroupBox("Actions")
        self.horizontalGroupBox_Actions.setMaximumHeight(100)
        self.layout_Actions = QtGui.QHBoxLayout()
        self.Button_Run=QtGui.QPushButton('Run')
        self.nbparam = QtGui.QTextEdit('2')
        self.nbparam.setMaximumHeight(30)
        self.nbparam.setMaximumWidth(50)
        self.layout_Actions.addWidget(self.Button_Run)
        self.layout_Actions.addWidget(self.nbparam)
        self.horizontalGroupBox_Actions.setLayout(self.layout_Actions)

        # set layout

        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Actions)
        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Param2)
        self.centralWidget.setLayout(self.mainHBOX_param_scene)

        self.Button_Run.clicked.connect(self.Runclick)

    def Runclick(self):

         # parameter2
        self.horizontalGroupBox_Param = QtGui.QGroupBox("Set range Parameter 2 for matrix method")
        nbparam = int(self.nbparam.toPlainText())
        self.Param_layout = QtGui.QVBoxLayout()
        grid2 = QtGui.QGridLayout()
        self.Param_layout.addLayout(grid2)
        self.Param_Label = QtGui.QLabel('Names')
        self.Param_min_Label = QtGui.QLabel('mins')
        self.Param_max_Label = QtGui.QLabel('maxs')
        self.Param_step_Label = QtGui.QLabel('steps')
        grid2.addWidget(self.Param_Label, 0, 0)
        grid2.addWidget(self.Param_min_Label, 0, 1)
        grid2.addWidget(self.Param_max_Label, 0, 2)
        grid2.addWidget(self.Param_step_Label, 0, 3)

        self.listofedit = []
        text=["a","b","c"]
        for i in np.arange(nbparam):
            print(i)
            self.listofedit.append([QtGui.QComboBox(),QtGui.QTextEdit('10'),QtGui.QTextEdit('50'),QtGui.QTextEdit('10')])
            self.listofedit[i][0].addItems(text)
            self.listofedit[i][0].setMinimumWidth(100)
            self.listofedit[i][1].setMaximumWidth(40)
            self.listofedit[i][2].setMaximumWidth(40)
            self.listofedit[i][3].setMaximumWidth(40)
            grid2.addWidget(self.listofedit[i][0], i+1, 0)
            grid2.addWidget(self.listofedit[i][1], i+1, 1)
            grid2.addWidget(self.listofedit[i][2], i+1, 2)
            grid2.addWidget(self.listofedit[i][3], i+1, 3)

        self.horizontalGroupBox_Param.setLayout(self.Param_layout)
        # while self.horizontalGroupBox_Param2.layout().count():
        #     self.horizontalGroupBox_Param2.layout().itemAt(0).widget().deleteLater()
        self.horizontalGroupBox_Param2.layout().clear()
        self.horizontalGroupBox_Param2.setLayout(self.Param_layout)
        return

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = SurfViewer(app)
    ex.show()
    sys.exit(app.exec_())

Which generate me this window :

enter image description here

So What I would like is when I click on Run (the number to the top right corner is the number of lines N), I modify the number of parameter sets in the lower part of the window. So in this case I should have two lines to enter two names, two min, two max and two step values. I started to do the update of the window but I'm struggling to find the correct code to put in def Runclick(self):

I already write the code to generate the correct number of parameter set lines but I cannot manage to update my window with them.

I clearly doing something wrote with the final part :

self.horizontalGroupBox_Param.setLayout(self.Param_layout)
# while self.horizontalGroupBox_Param2.layout().count():
# self.horizontalGroupBox_Param2.layout().itemAt(0).widget().deleteLater() 
self.horizontalGroupBox_Param2.setLayout(self.Param_layout)

I think I'm not taking things in the correct way. So If somebody have a solution to that, I will be grateful

UPDATE

Hi @jgorosdev, thanks for your answer. Although, it not corresponding exactly to what I would like. In the code you gave me, it work correctly because the parameter sets are always update at the bottom of the window but in my more advance soft, there are some others QGroupBox after. For instance if I add a console like part:

 # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from PyQt4 import QtGui

import sys
import numpy as np

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

        # General Window
        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        self.mainHBOX_param_scene = QtGui.QVBoxLayout()

        #action button
        self.horizontalGroupBox_Actions = QtGui.QGroupBox("Actions")
        self.horizontalGroupBox_Actions.setMaximumHeight(100)
        self.layout_Actions = QtGui.QHBoxLayout()
        self.Button_Run=QtGui.QPushButton('Run')
        self.nbparam = QtGui.QTextEdit('3')
        self.nbparam.setMaximumHeight(30)
        self.nbparam.setMaximumWidth(50)
        self.layout_Actions.addWidget(self.Button_Run)
        self.layout_Actions.addWidget(self.nbparam)
        self.horizontalGroupBox_Actions.setLayout(self.layout_Actions)

        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Actions)
        self.centralWidget.setLayout(self.mainHBOX_param_scene)
        self.updateWidget = None

        # Param2 layout
        self.horizontalGroupBox_Param2 = QtGui.QGroupBox("Set range Parameter 2 for matrix method")
        self.Param2_layout = QtGui.QVBoxLayout()
        self.Button_Run.clicked.connect(self.UpdateLayout)
        self.UpdateLayout()

        # console
        self.horizontalGroupBox_Console2 = QtGui.QGroupBox("Console ")
        self.layout_Consol_Label2 = QtGui.QVBoxLayout()
        self.Consol_Label2 = QtGui.QTextEdit('Console :')
        self.layout_Consol_Label2.addWidget(self.Consol_Label2)
        self.horizontalGroupBox_Console2.setLayout(self.layout_Consol_Label2)
        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Console2)

        # parameter2
        # From now on everything well be created inside a function that updates the layout
    def UpdateLayout(self):
        if (self.updateWidget == None):
            self.updateWidget = QtGui.QWidget()
        else:
            self.mainHBOX_param_scene.removeWidget(self.updateWidget)
            self.updateWidget.deleteLater()
            self.updateWidget = None

        cnt =  self.mainHBOX_param_scene.layout().count()
        print("Widget count:" +str(cnt)+ "")
        nbparam = int(self.nbparam.toPlainText())
        #self.horizontalGroupBox_Param2.setMaximumHeight(150)
        grid2 = QtGui.QGridLayout()
        self.Param2_Label = QtGui.QLabel('Name')
        self.Param2 = QtGui.QComboBox()
        self.Param2.addItems(["a","b","c"])
        self.Param2.setMinimumWidth(100)


        # self.Param2_layout.addWidget(self.Param2)
        self.Param2_min_Label = QtGui.QLabel('min')
        self.Param2_max_Label = QtGui.QLabel('max')
        self.Param2_step_Label = QtGui.QLabel('step')

        grid2.addWidget(self.Param2_Label, 0, 0)
        grid2.addWidget(self.Param2_min_Label, 0, 1)
        grid2.addWidget(self.Param2_max_Label, 0, 2)
        grid2.addWidget(self.Param2_step_Label, 0, 3)

        self.listofedit = []
        text=["a","b","c"]
        for i in np.arange(nbparam):
            print(i)
            self.listofedit.append([QtGui.QComboBox(),QtGui.QTextEdit('20'),QtGui.QTextEdit('50'),QtGui.QTextEdit('10')])
            self.listofedit[i][0].addItems(text)
            self.listofedit[i][0].setMinimumWidth(100)
            self.listofedit[i][1].setMaximumWidth(40)
            self.listofedit[i][1].setMaximumHeight(40)
            self.listofedit[i][2].setMaximumWidth(40)
            self.listofedit[i][2].setMaximumHeight(40)
            self.listofedit[i][3].setMaximumWidth(40)
            self.listofedit[i][3].setMaximumHeight(40)
            grid2.addWidget(self.listofedit[i][0], i+1, 0)
            grid2.addWidget(self.listofedit[i][1], i+1, 1)
            grid2.addWidget(self.listofedit[i][2], i+1, 2)
            grid2.addWidget(self.listofedit[i][3], i+1, 3)

        self.updateWidget = QtGui.QWidget()
        self.updateWidget.setLayout(grid2)
        #self.updateWidget.setMaximumHeight(nbparam*60)
        self.Param2_layout.addWidget(self.updateWidget)
        self.horizontalGroupBox_Param2.setLayout(self.Param2_layout)
        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Param2)
        return

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = SurfViewer(app)
    ex.show()
    sys.exit(app.exec_())

I have this window at the beginning :

enter image description here

Which is what I would like but i get this image after clicking on the Run button :

enter image description here

So the console and the parameter set are inverted. I'm wondering if it is possible to replace a part of the layout without build all the layout again?

1

There are 1 answers

1
jgorostegui On BEST ANSWER

I have made some minor changes in the code and now works well.

You were creating the bottom groupbox two times in your code, and I think that this is a better way. I have packed everything in the UpdateLayout function.

You'll probably need to re-check the resizing qt policy to properly resize the main window.

The code with UPDATE:

 # -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from PyQt4 import QtGui

import sys
import numpy as np

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

        # General Window
        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        self.mainHBOX_param_scene = QtGui.QVBoxLayout()

        #action button
        self.horizontalGroupBox_Actions = QtGui.QGroupBox("Actions")
        self.horizontalGroupBox_Actions.setMaximumHeight(100)
        self.layout_Actions = QtGui.QHBoxLayout()
        self.Button_Run=QtGui.QPushButton('Run')
        self.nbparam = QtGui.QTextEdit('3')
        self.nbparam.setMaximumHeight(30)
        self.nbparam.setMaximumWidth(50)
        self.layout_Actions.addWidget(self.Button_Run)
        self.layout_Actions.addWidget(self.nbparam)
        self.horizontalGroupBox_Actions.setLayout(self.layout_Actions)

        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Actions)
        self.centralWidget.setLayout(self.mainHBOX_param_scene)
        self.updateWidget = None

        # Param2 layout
        self.horizontalGroupBox_Param2 = QtGui.QGroupBox("Set range Parameter 2 for matrix method")
        self.Param2_layout = QtGui.QVBoxLayout()
        self.Button_Run.clicked.connect(self.UpdateLayout)
        self.UpdateLayout()

        # console
        self.horizontalGroupBox_Console2 = QtGui.QGroupBox("Console ")
        self.layout_Consol_Label2 = QtGui.QVBoxLayout()
        self.Consol_Label2 = QtGui.QTextEdit('Console :')
        self.layout_Consol_Label2.addWidget(self.Consol_Label2)
        self.horizontalGroupBox_Console2.setLayout(self.layout_Consol_Label2)
        self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Console2)

        # parameter2
        # From now on everything well be created inside a function that updates the layout
    def UpdateLayout(self):
        if (self.updateWidget == None):
            self.updateWidget = QtGui.QWidget()
        else:
            self.mainHBOX_param_scene.removeWidget(self.updateWidget)
            self.updateWidget.deleteLater()
            self.updateWidget = None

        cnt =  self.mainHBOX_param_scene.layout().count()
        print("Widget count:" +str(cnt)+ "")
        nbparam = int(self.nbparam.toPlainText())
        #self.horizontalGroupBox_Param2.setMaximumHeight(150)
        grid2 = QtGui.QGridLayout()
        self.Param2_Label = QtGui.QLabel('Name')
        self.Param2 = QtGui.QComboBox()
        self.Param2.addItems(["a","b","c"])
        self.Param2.setMinimumWidth(100)


        # self.Param2_layout.addWidget(self.Param2)
        self.Param2_min_Label = QtGui.QLabel('min')
        self.Param2_max_Label = QtGui.QLabel('max')
        self.Param2_step_Label = QtGui.QLabel('step')

        grid2.addWidget(self.Param2_Label, 0, 0)
        grid2.addWidget(self.Param2_min_Label, 0, 1)
        grid2.addWidget(self.Param2_max_Label, 0, 2)
        grid2.addWidget(self.Param2_step_Label, 0, 3)

        self.listofedit = []
        text=["a","b","c"]
        for i in np.arange(nbparam):
            print(i)
            self.listofedit.append([QtGui.QComboBox(),QtGui.QTextEdit('20'),QtGui.QTextEdit('50'),QtGui.QTextEdit('10')])
            self.listofedit[i][0].addItems(text)
            self.listofedit[i][0].setMinimumWidth(100)
            self.listofedit[i][1].setMaximumWidth(40)
            self.listofedit[i][1].setMaximumHeight(40)
            self.listofedit[i][2].setMaximumWidth(40)
            self.listofedit[i][2].setMaximumHeight(40)
            self.listofedit[i][3].setMaximumWidth(40)
            self.listofedit[i][3].setMaximumHeight(40)
            grid2.addWidget(self.listofedit[i][0], i+1, 0)
            grid2.addWidget(self.listofedit[i][1], i+1, 1)
            grid2.addWidget(self.listofedit[i][2], i+1, 2)
            grid2.addWidget(self.listofedit[i][3], i+1, 3)

        self.updateWidget = QtGui.QWidget()
        self.updateWidget.setLayout(grid2)
        #self.updateWidget.setMaximumHeight(nbparam*60)
        self.Param2_layout.addWidget(self.updateWidget,)
        self.horizontalGroupBox_Param2.setLayout(self.Param2_layout)
        #self.mainHBOX_param_scene.addWidget(self.horizontalGroupBox_Param2)
        # NEW
        self.mainHBOX_param_scene.insertWidget(1,self.horizontalGroupBox_Param2)

        return

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = SurfViewer(app)
    ex.show()
    sys.exit(app.exec_())

Answer to UPDATE

If you are willing to have the updating QGroupBox without chaning the position, instead of addWidget() the function you are going to need is the insertWidget() function.

I have updated the line in the UpdateLayout function that was adding the widget. Hope that suits fine for you.

The reference of the function is next:

http://doc.qt.io/qt-4.8/qboxlayout.html#insertWidget