Как вставить элементы в QGridLayout чтобы они не наползали друг на друга?

Рейтинг: 1Ответов: 1Опубликовано: 22.02.2023

Мне необходимо вставлять элемент в QGridLayout при нажатии на кнопку.
Эта часть у меня получилась, однако при добавлении на форму нескольких элементов подряд они начинают наползать друг на друга.

Я не могу понять в чем проблема и как можно ее решить?

pulseinfoUI.py:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(985, 300)
        MainWindow.setMinimumSize(QtCore.QSize(985, 300))
        MainWindow.setMaximumSize(QtCore.QSize(985, 16777215))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.generalGridLayout = QtWidgets.QGridLayout()
        self.generalGridLayout.setObjectName("generalGridLayout")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.generalGridLayout.addItem(spacerItem, 2, 1, 1, 1)
        self.saveButton = QtWidgets.QPushButton(self.centralwidget)
        self.saveButton.setMinimumSize(QtCore.QSize(100, 30))
        self.saveButton.setMaximumSize(QtCore.QSize(100, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.saveButton.setFont(font)
        self.saveButton.setObjectName("saveButton")
        self.generalGridLayout.addWidget(self.saveButton, 2, 2, 1, 1)
        self.addPulseButton = QtWidgets.QPushButton(self.centralwidget)
        self.addPulseButton.setMinimumSize(QtCore.QSize(340, 30))
        self.addPulseButton.setMaximumSize(QtCore.QSize(340, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.addPulseButton.setFont(font)
        self.addPulseButton.setObjectName("addPulseButton")
        self.generalGridLayout.addWidget(self.addPulseButton, 0, 0, 1, 1)
        self.pulsesGroupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.pulsesGroupBox.setMinimumSize(QtCore.QSize(960, 140))
        self.pulsesGroupBox.setMaximumSize(QtCore.QSize(960, 16777215))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.pulsesGroupBox.setFont(font)
        self.pulsesGroupBox.setObjectName("pulsesGroupBox")
        self.layoutWidget = QtWidgets.QWidget(self.pulsesGroupBox)
        self.layoutWidget.setGeometry(QtCore.QRect(10, 20, 941, 121))
        self.layoutWidget.setObjectName("layoutWidget")
        self.pulsesGridLayout = QtWidgets.QGridLayout(self.layoutWidget)
        self.pulsesGridLayout.setContentsMargins(0, 0, 0, 0)
        self.pulsesGridLayout.setObjectName("pulsesGridLayout")
        self.pulseGroupBox = QtWidgets.QGroupBox(self.layoutWidget)
        self.pulseGroupBox.setMinimumSize(QtCore.QSize(930, 50))
        self.pulseGroupBox.setMaximumSize(QtCore.QSize(930, 50))
        self.pulseGroupBox.setTitle("")
        self.pulseGroupBox.setObjectName("pulseGroupBox")
        self.chanelComboBox = QtWidgets.QComboBox(self.pulseGroupBox)
        self.chanelComboBox.setGeometry(QtCore.QRect(120, 10, 70, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.chanelComboBox.setFont(font)
        self.chanelComboBox.setObjectName("chanelComboBox")
        self.nameLineEdit = QtWidgets.QLineEdit(self.pulseGroupBox)
        self.nameLineEdit.setGeometry(QtCore.QRect(200, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.nameLineEdit.setFont(font)
        self.nameLineEdit.setObjectName("nameLineEdit")
        self.plaseComboBox = QtWidgets.QComboBox(self.pulseGroupBox)
        self.plaseComboBox.setGeometry(QtCore.QRect(350, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.plaseComboBox.setFont(font)
        self.plaseComboBox.setObjectName("plaseComboBox")
        self.starttimeDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.pulseGroupBox)
        self.starttimeDoubleSpinBox.setGeometry(QtCore.QRect(500, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.starttimeDoubleSpinBox.setFont(font)
        self.starttimeDoubleSpinBox.setDecimals(4)
        self.starttimeDoubleSpinBox.setSingleStep(0.0001)
        self.starttimeDoubleSpinBox.setObjectName("starttimeDoubleSpinBox")
        self.durationDoubleSpinBox = QtWidgets.QDoubleSpinBox(self.pulseGroupBox)
        self.durationDoubleSpinBox.setGeometry(QtCore.QRect(650, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.durationDoubleSpinBox.setFont(font)
        self.durationDoubleSpinBox.setDecimals(4)
        self.durationDoubleSpinBox.setSingleStep(0.0001)
        self.durationDoubleSpinBox.setObjectName("durationDoubleSpinBox")
        self.loopSpinBox = QtWidgets.QSpinBox(self.pulseGroupBox)
        self.loopSpinBox.setGeometry(QtCore.QRect(800, 10, 90, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.loopSpinBox.setFont(font)
        self.loopSpinBox.setMaximum(32767)
        self.loopSpinBox.setObjectName("loopSpinBox")
        self.deleteButton = QtWidgets.QPushButton(self.pulseGroupBox)
        self.deleteButton.setGeometry(QtCore.QRect(10, 10, 100, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.deleteButton.setFont(font)
        self.deleteButton.setObjectName("deleteButton")
        self.processingCheckBox = QtWidgets.QCheckBox(self.pulseGroupBox)
        self.processingCheckBox.setGeometry(QtCore.QRect(900, 10, 20, 30))
        self.processingCheckBox.setText("")
        self.processingCheckBox.setObjectName("processingCheckBox")
        self.pulsesGridLayout.addWidget(self.pulseGroupBox, 0, 0, 1, 1)
        self.pulseGroupBox_2 = QtWidgets.QGroupBox(self.layoutWidget)
        self.pulseGroupBox_2.setMinimumSize(QtCore.QSize(930, 50))
        self.pulseGroupBox_2.setMaximumSize(QtCore.QSize(930, 50))
        self.pulseGroupBox_2.setTitle("")
        self.pulseGroupBox_2.setObjectName("pulseGroupBox_2")
        self.chanelComboBox_2 = QtWidgets.QComboBox(self.pulseGroupBox_2)
        self.chanelComboBox_2.setGeometry(QtCore.QRect(120, 10, 70, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.chanelComboBox_2.setFont(font)
        self.chanelComboBox_2.setObjectName("chanelComboBox_2")
        self.nameLineEdit_2 = QtWidgets.QLineEdit(self.pulseGroupBox_2)
        self.nameLineEdit_2.setGeometry(QtCore.QRect(200, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.nameLineEdit_2.setFont(font)
        self.nameLineEdit_2.setObjectName("nameLineEdit_2")
        self.plaseComboBox_2 = QtWidgets.QComboBox(self.pulseGroupBox_2)
        self.plaseComboBox_2.setGeometry(QtCore.QRect(350, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.plaseComboBox_2.setFont(font)
        self.plaseComboBox_2.setObjectName("plaseComboBox_2")
        self.starttimeDoubleSpinBox_2 = QtWidgets.QDoubleSpinBox(self.pulseGroupBox_2)
        self.starttimeDoubleSpinBox_2.setGeometry(QtCore.QRect(500, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.starttimeDoubleSpinBox_2.setFont(font)
        self.starttimeDoubleSpinBox_2.setDecimals(4)
        self.starttimeDoubleSpinBox_2.setSingleStep(0.0001)
        self.starttimeDoubleSpinBox_2.setObjectName("starttimeDoubleSpinBox_2")
        self.doubleSpinBox_2 = QtWidgets.QDoubleSpinBox(self.pulseGroupBox_2)
        self.doubleSpinBox_2.setGeometry(QtCore.QRect(650, 10, 140, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.doubleSpinBox_2.setFont(font)
        self.doubleSpinBox_2.setDecimals(4)
        self.doubleSpinBox_2.setSingleStep(0.0001)
        self.doubleSpinBox_2.setObjectName("doubleSpinBox_2")
        self.loopSpinBox_2 = QtWidgets.QSpinBox(self.pulseGroupBox_2)
        self.loopSpinBox_2.setGeometry(QtCore.QRect(800, 10, 90, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.loopSpinBox_2.setFont(font)
        self.loopSpinBox_2.setMaximum(32767)
        self.loopSpinBox_2.setObjectName("loopSpinBox_2")
        self.deleteButton_2 = QtWidgets.QPushButton(self.pulseGroupBox_2)
        self.deleteButton_2.setGeometry(QtCore.QRect(10, 10, 100, 30))
        font = QtGui.QFont()
        font.setPointSize(10)
        self.deleteButton_2.setFont(font)
        self.deleteButton_2.setObjectName("deleteButton_2")
        self.processingCheckBox_2 = QtWidgets.QCheckBox(self.pulseGroupBox_2)
        self.processingCheckBox_2.setGeometry(QtCore.QRect(900, 10, 20, 30))
        self.processingCheckBox_2.setText("")
        self.processingCheckBox_2.setObjectName("processingCheckBox_2")
        self.pulsesGridLayout.addWidget(self.pulseGroupBox_2, 1, 0, 1, 1)
        self.generalGridLayout.addWidget(self.pulsesGroupBox, 1, 0, 1, 3)
        self.gridLayout.addLayout(self.generalGridLayout, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.saveButton.setText(_translate("MainWindow", "Save"))
        self.addPulseButton.setText(_translate("MainWindow", "Add Pulse"))
        self.pulsesGroupBox.setTitle(_translate("MainWindow", "Group of pulses"))
        self.deleteButton.setText(_translate("MainWindow", "Delete"))
        self.deleteButton_2.setText(_translate("MainWindow", "Delete"))

main.py:

import sys

import numpy as np
import numpy as np
import pyqtgraph as pg
import scipy.stats as stats

from PyQt5.Qt import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from matplotlib.pyplot import *

from PyQt5 import QtWidgets, QtCore

from pulseinfoUI import Ui_MainWindow

class Impuls(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Impuls, self).__init__()
        self.setupUi(self)

        self.elementNumber = 2
        self.addPulseButton.clicked.connect(self.add_new_pulse)

    def add_new_pulse(self):
        print(self.elementNumber, self.pulsesGroupBox.height())
        newPulseGroupBox = QtWidgets.QGroupBox(self.pulsesGroupBox)
        newPulseGroupBox.setTitle("")
        newPulseGroupBox.setMinimumSize(QtCore.QSize(930, 50))
        newPulseGroupBox.setMaximumSize(QtCore.QSize(930, 50))
        self.pulsesGroupBox.setMinimumHeight(self.pulsesGroupBox.height() + 60)
        self.pulsesGridLayout.addWidget(newPulseGroupBox, self.elementNumber, 0,
                                        1, 1)
        self.elementNumber += 1

def main():
    app = QtWidgets.QApplication(sys.argv) 
    window = Impuls()
    window.show() 
    app.exec_()  

if __name__ == '__main__': 
    app = QtWidgets.QApplication(sys.argv) 
    main() 

Как я хочу, чтобы это выглядело:

введите сюда описание изображения

Как это выглядит у меня: введите сюда описание изображения

Возможно есть другой вариант реализации данного проекта, поэтому, если не сложно, подскажите, пожалуйста.

Ответы

▲ 1Принят

Класс QScrollArea обеспечивает просмотр другого виджета с прокруткой.

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


class GroupBox(QtWidgets.QGroupBox): 
    clicked = QtCore.pyqtSignal(str, object)
    
    def __init__(self, title):              
        super(GroupBox, self).__init__()
        self.title = title
#        self.setTitle(self.title)       # эту строку можете закомментировать
        
    def mousePressEvent(self, event):
        child = self.childAt(event.pos())
        if not child:
            child = self
        self.clicked.emit(self.title, child)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.centralwidget = QtWidgets.QWidget()
        self.centralwidget.setObjectName("centralwidget")
        self.setCentralWidget(self.centralwidget)
        self.elementNumber = 1

        scroll = QtWidgets.QScrollArea()                             # !!! +++
#        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)  # 
        scroll.setWidgetResizable(True)                              # !!! +++
        
        scrollW = QtWidgets.QWidget()                                # !!! +++
        scrollW.setObjectName("scrollW")
        scroll.setWidget(scrollW)                                    # !!! +++
        self.scrollLayout = QtWidgets.QVBoxLayout(scrollW)           # !!! +++
        self.scrollLayout.setAlignment(QtCore.Qt.AlignTop)
        
        self.saveButton = QtWidgets.QPushButton("Save")
        self.addPulseButton = QtWidgets.QPushButton("Add Pulse")
        self.addPulseButton.clicked.connect(self.add_new_pulse)

        layout = QtWidgets.QGridLayout(self.centralwidget)
        layout.addWidget(scroll, 0, 0, 1, 4)                         # !!! +++
        layout.addWidget(self.addPulseButton, 1, 2, alignment=Qt.AlignRight)
        layout.addWidget(self.saveButton, 1, 3, alignment=Qt.AlignLeft)
        
        self.setStyleSheet("""
            #centralwidget {
                background-color: #D98C00;
            }
            #scrollW {
                background-color: #D9008C;
            }
            QGroupBox {
                background-color: #008CD9;
            }
            QLabel {
                color: #fff;
                font-size: 17px;
            }
        """)
        
    def add_new_pulse(self):
        fooGroup = GroupBox(f'GroupBox_{self.elementNumber}')                        
        fooGroup.setObjectName(f'fooGroup {self.elementNumber}')
        fooGroup.clicked.connect(self.onFooGroupClick)  
        
        deleteButton = QtWidgets.QPushButton("Delete", objectName="deleteButton")
        deleteButton.clicked.connect(
            lambda ch, btn=deleteButton, gr=fooGroup: print(
                f'Нажата {btn.text()}; GroupBox: {gr.objectName()};'))
                
        chanelComboBox = QtWidgets.QComboBox(objectName="chanelComboBox")
        nameLineEdit = QtWidgets.QLineEdit(objectName="nameLineEdit")
        plaseComboBox = QtWidgets.QComboBox(objectName="plaseComboBox")
        plaseComboBox.setMinimumWidth(140)
        starttimeDoubleSpinBox = QtWidgets.QDoubleSpinBox(objectName="starttimeDoubleSpinBox")        
        starttimeDoubleSpinBox.setDecimals(4)
        starttimeDoubleSpinBox.setSingleStep(0.0001)
        durationDoubleSpinBox = QtWidgets.QDoubleSpinBox(objectName="durationDoubleSpinBox")
        durationDoubleSpinBox.setDecimals(4)
        durationDoubleSpinBox.setSingleStep(0.0001)
        loopSpinBox = QtWidgets.QSpinBox(objectName="loopSpinBox")
        loopSpinBox.setMinimumWidth(90)
        
        fooItem1 = QtWidgets.QLabel("fooItem1", objectName="fooItem1")   # тест
        
        processingCheckBox = QtWidgets.QCheckBox(objectName="processingCheckBox")
        
        fooLayout = QtWidgets.QHBoxLayout(fooGroup)
        fooLayout.addWidget(deleteButton)
        fooLayout.addWidget(chanelComboBox)
        fooLayout.addWidget(nameLineEdit)
        fooLayout.addWidget(plaseComboBox)
        fooLayout.addWidget(starttimeDoubleSpinBox)
        fooLayout.addWidget(durationDoubleSpinBox)
        fooLayout.addWidget(loopSpinBox)
        fooLayout.addWidget(fooItem1)              # тест
        fooLayout.addWidget(processingCheckBox)
        
        self.scrollLayout.addWidget(fooGroup)
        self.elementNumber += 1

    def onFooGroupClick(self, title, obj):         
        print(f"Group: {title}; objectName=`{obj.objectName()}`") 


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    app.setFont(QtGui.QFont("Times", 12))
    w = MainWindow()
    w.resize(985, 322)
    w.show()
    sys.exit(app.exec())  

введите сюда описание изображения

введите сюда описание изображения