pyside – как удалить виджеты из gridLayout

Я построил ui в QT Designer, а затем использовал pyside-uic, превратив его в файл python, а затем написал код для его программного редактирования. В других словах у меня есть кнопка Add Row которая при щелчке переименует себя в Remove1 и создаст другое имя pusbutton, а Add Row и добавит ее в макет.

Код при нажатии « Add Row , измените имя и сигналы / слоты:

 self.pb_Row[-1].setText('Remove'+str(self.nRows)) self.pb_Row[-1].clicked.disconnect( self.addRow ) self.pb_Row[-1].clicked.connect( self.removeRow ) 

Код при нажатии Remove , удаляет выбранную кнопку:

 iRow = int(self.sender().objectName().split('_')[-1])-1 ind = self.PropertyLayout.indexOf(self.pb_Row[iRow]) t = self.PropertyLayout.takeAt(ind) t.widget().deleteLater() # self.pb_Row[iRow].hide() # self.pb_Row[iRow].deleteLater() self.pb_Row.pop(iRow) 

Это работает отлично, пока вы не добавите хотя бы один, а затем удалите его, а в следующий раз он испортится. В принципе, это неправильно, когда у меня есть две кнопки, и удалите одну, а затем попытайтесь добавить ее. По неправильным правилам я подразумеваю, что новая кнопка заканчивается поверх старой, иногда она появляется ниже, а не сверху.

Кроме того, с линиями, поскольку в настоящее время они не реорганизуют вещи в gridlayout, если я использую .hide() она делает это. Я не совсем уверен, что я должен использовать.

Благодаря!

Вот последовательность, которая приводит к нежелательным результатам:

Новый старт Изображение 1

После нажатия кнопки Добавить После нажатия кнопки Добавить

После нажатия удаления (все до сих пор), нажмите «Добавить» (нет видимой разницы) после удаления 1

После нажатия «Добавить второй раз» введите описание изображения здесь

После нажатия Remove2 из-под него появляется Remove1 введите описание изображения здесь

«Рабочий» пример кода

 import numpy as np import sys from PySide import QtCore, QtGui import matplotlib.pyplot as plt from ModesInFiber import Ui_fiberModesMainWindow class Ui_fiberModesMainWindow(object): def setupUi(self, fiberModesMainWindow): fiberModesMainWindow.setObjectName("fiberModesMainWindow") fiberModesMainWindow.resize(653, 597) self.centralwidget = QtGui.QWidget(fiberModesMainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout_2 = QtGui.QHBoxLayout(self.centralwidget) self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.MainLayout = QtGui.QGridLayout() self.MainLayout.setObjectName("MainLayout") self.PropertyLayout = QtGui.QGridLayout() self.PropertyLayout.setObjectName("PropertyLayout") self.lbl_Name = QtGui.QLabel(self.centralwidget) self.lbl_Name.setObjectName("lbl_Name") self.PropertyLayout.addWidget(self.lbl_Name, 0, 1, 1, 1) self.pb_addRow_1 = QtGui.QPushButton(self.centralwidget) self.pb_addRow_1.setObjectName("pb_addRow_1") self.PropertyLayout.addWidget(self.pb_addRow_1, 1, 5, 1, 1) self.ledit_Name_1 = QtGui.QLineEdit(self.centralwidget) self.ledit_Name_1.setObjectName("ledit_Name_1") self.PropertyLayout.addWidget(self.ledit_Name_1, 1, 1, 1, 1) self.MainLayout.addLayout(self.PropertyLayout, 0, 0, 1, 1) spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.MainLayout.addItem(spacerItem2, 1, 0, 1, 1) self.horizontalLayout_2.addLayout(self.MainLayout) fiberModesMainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(fiberModesMainWindow) QtCore.QMetaObject.connectSlotsByName(fiberModesMainWindow) # fiberModesMainWindow.setTabOrder(self.ledit_Name_1, self.ledit_Width_1) # fiberModesMainWindow.setTabOrder(self.ledit_Width_1, self.cmb_RIType_1) # fiberModesMainWindow.setTabOrder(self.cmb_RIType_1, self.ledit_RIParam_1) # fiberModesMainWindow.setTabOrder(self.ledit_RIParam_1, self.pb_addRow_1) def retranslateUi(self, fiberModesMainWindow): fiberModesMainWindow.setWindowTitle(QtGui.QApplication.translate("fiberModesMainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) self.lbl_Name.setText(QtGui.QApplication.translate("fiberModesMainWindow", "Name", None, QtGui.QApplication.UnicodeUTF8)) self.pb_addRow_1.setText(QtGui.QApplication.translate("fiberModesMainWindow", "Add Row", None, QtGui.QApplication.UnicodeUTF8)) class DesignerMainWindow(QtGui.QMainWindow, Ui_fiberModesMainWindow): def __init__(self, parent = None): super(DesignerMainWindow, self).__init__(parent) self.setupUi(self) self.pb_addRow_1.clicked.connect( self.addRow ) self.ledit_Name = [ self.ledit_Name_1 ] self.pb_Row = [ self.pb_addRow_1 ] # number of rows self.nRows = 1 def addRow( self ): self.ledit_Name[-1].setEnabled(False) self.pb_Row[-1].setText('Remove'+str(self.nRows)) self.pb_Row[-1].clicked.disconnect( self.addRow ) self.pb_Row[-1].clicked.connect( self.removeRow ) self.nRows += 1 self.ledit_Name.append( QtGui.QLineEdit(self.centralwidget) ) self.ledit_Name[-1].setObjectName('ledit_Name_'+str(self.nRows)) self.PropertyLayout.addWidget( self.ledit_Name[-1], self.nRows, 1, 1, 1) self.pb_Row.append( QtGui.QPushButton(self.centralwidget) ) self.pb_Row[-1].setObjectName( 'pb_addRow_'+str(self.nRows) ) self.pb_Row[-1].setText('Add Row') self.pb_Row[-1].clicked.connect( self.addRow ) self.PropertyLayout.addWidget( self.pb_Row[-1], self.nRows, 5, 1, 1) def removeRow( self ): iRow = int(self.sender().objectName().split('_')[-1])-1 self.nRows -= 1 ind = self.PropertyLayout.indexOf(self.ledit_Name[iRow]) t = self.PropertyLayout.takeAt(ind) t.widget().setParent(None) # t.widget().deleteLater() # self.ledit_Name[iRow].hide() # self.ledit_Name[iRow].deleteLater() # self.ledit_Name[iRow].setParent(None) self.ledit_Name.pop(iRow) ind = self.PropertyLayout.indexOf(self.pb_Row[iRow]) t = self.PropertyLayout.takeAt(ind) t.widget().setParent(None) # t.widget().deleteLater() # self.pb_Row[iRow].hide() # self.pb_Row[iRow].deleteLater() # self.pb_Row[iRow].setParent(None) self.pb_Row.pop(iRow) for iAfterRow in range(iRow, self.nRows): self.ledit_Name[iAfterRow].setObjectName( 'ledit_Name_' + str(iAfterRow+1) ) self.pb_Row[iAfterRow].setObjectName( 'ledit_Name_' + str(iAfterRow+1) ) print 'Remove row', iRow if __name__ == '__main__': app = QtGui.QApplication( sys.argv ) dmw = DesignerMainWindow() dmw.show() sys.exit( app.exec_() ) 

3 Solutions collect form web for “pyside – как удалить виджеты из gridLayout”

Проблема здесь вызвана детальностью реализации QGridLayout.

Всякий раз, когда элементы удаляются из QGridLayout, количество логических строк и столбцов никогда не будет уменьшаться, даже если количество визуальных строк или столбцов может быть выполнено. Из-за этого вы всегда должны работать непосредственно с элементами в QGridLayout, используя такие методы, как getItemPosition и itemAtPosition .

Ниже приведена перезапись класса DesignerMainWindow из примера с использованием этого подхода. Очевидно, что это может потребоваться несколько изменить для работы с вашим реальным приложением.

 class DesignerMainWindow(QtGui.QMainWindow, Ui_fiberModesMainWindow): def __init__(self, parent = None): super(DesignerMainWindow, self).__init__(parent) self.setupUi(self) self.pb_addRow_1.clicked.connect( self.addRow ) def addRow( self ): rows = self.PropertyLayout.rowCount() columns = self.PropertyLayout.columnCount() for column in range(columns): layout = self.PropertyLayout.itemAtPosition(rows - 1, column) if layout is not None: widget = layout.widget() if isinstance(widget, QtGui.QPushButton): widget.setText('Remove %d' % (rows - 1)) widget.clicked.disconnect(self.addRow) widget.clicked.connect(self.removeRow) else: widget.setEnabled(False) widget = QtGui.QLineEdit(self.centralwidget) self.PropertyLayout.addWidget(widget, rows, 1, 1, 1) widget = QtGui.QPushButton(self.centralwidget) widget.setText('Add Row') widget.clicked.connect(self.addRow) self.PropertyLayout.addWidget(widget, rows, columns - 1, 1, 1) def removeRow(self): index = self.PropertyLayout.indexOf(self.sender()) row = self.PropertyLayout.getItemPosition(index)[0] for column in range(self.PropertyLayout.columnCount()): layout = self.PropertyLayout.itemAtPosition(row, column) if layout is not None: layout.widget().deleteLater() self.PropertyLayout.removeItem(layout) 

Похоже, вы не вызывали QGridLayout :: removeWidget () для всех ячеек в строке, которые вы хотели бы удалить. Затем из-за PySide макет будет продолжать ссылаться на виджеты, и они не удаляются / удаляются при вызове setParent (None).

Также при попытке deleteLater () виджета в ячейке без QLayout :: removeWidget () ячейка не будет удалена, но останется в живых (в ячейке останется QLayoutItem)

EDIT: Это не решает проблему , также я нашел источник моих знаний: есть ли способ удалить QWidget в QGridLayout?

– По какой-то причине удаление виджетов из макетов сложно. Я долго искал ответ один раз и больше не помню, где я его нашел, но я отвлекся …

Что вам нужно сделать, так это следующее. Сначала найдите элемент, который хотите удалить. Вы можете использовать layout.itemAt() или layout.itemAtPosition чтобы получить ссылку на него.

Теперь, чтобы удалить элемент из макета, просто вызовите item.widget().setParent(None) . Это приведет к удалению элемента из макета!

Примечание. Если у вас уже есть ссылка на виджет, вы можете просто вызвать setParent на нем, не найдя его из макета. Я не пробовал это хотя (но не понимаю, почему это не сработает).

Python - лучший язык программирования в мире.