ventanas ventana gui funciones funcion for eventos español cerrar botones python layout pyqt4 pyside qgridlayout

python - ventana - pyside: cómo eliminar widgets de gridLayout



tkinter 8.5 reference a gui for python español (3)

Construí una interfaz de usuario en QT Designer y luego usé pyside-uic para convertirlo en un archivo python y luego escribí código para editarlo programáticamente. En otras palabras, tengo un botón Add Row que, al hacer clic, se renombrará a Remove1 y creará otro nombre de botón de comando: Add Row y lo agregará al diseño.

Código al hacer clic en Add Row , cambia el nombre y las señales / ranuras:

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 )

El código al hacer clic en Remove , elimina el botón seleccionado:

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)

Esto funciona bien hasta que agregue al menos uno y luego lo elimine, la próxima vez que lo arruine. Básicamente, se comporta mal cuando tengo dos botones y elimino uno y luego trato de agregar uno. Por mal comportamiento me refiero a que el nuevo botón termina encima del anterior, a veces aparece debajo en lugar de arriba.

Además, con las líneas tal como están actualmente, en realidad no reorganiza las cosas en el gridlayout, si utilizo la función .hide() lo hace. No estoy muy seguro de cuál debería estar usando.

¡Gracias!

Aquí hay una secuencia que produce resultados indeseables:

Nuevo comienzo

Después de hacer clic en Agregar

Después de hacer clic en Eliminar (todo bien hasta el momento), haga clic en Agregar (sin diferencia visible)

Después de hacer clic en Agregar una segunda vez

Después de hacer clic en Eliminar2, aparece Eliminar1 debajo de él

Ejemplo de "trabajo" de código

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_() )


El problema aquí es causado por un detalle de implementación de QGridLayout.

Cada vez que se eliminan elementos de un QGridLayout, el número de filas y columnas lógicas nunca disminuirá, aunque sí lo haga el número de filas o columnas visuales . Debido a esto, siempre debe trabajar directamente con los elementos en QGridLayout utilizando métodos como getItemPosition y itemAtPosition .

Debajo hay una re-escritura de la clase DesignerMainWindow del ejemplo que usa este enfoque. Obviamente, puede necesitar un ajuste para trabajar con su aplicación real.

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)


Parece que no llamó a QGridLayout :: removeWidget () para todas las celdas en la fila que desea eliminar. Luego, debido a PySide, el diseño seguirá haciendo referencia a los widgets y en realidad no se eliminan / eliminan cuando se llama a setParent (ninguno).

Además, cuando intentes eliminar eliminar () del widget en la celda sin QLayout :: removeWidget (), la celda no se eliminará sino que se mantendrá activa (quedará QLayoutItem en la celda)


EDITAR: Esto no resuelve el problema , también encontré la fuente de mi conocimiento: ¿hay alguna manera de eliminar un QWidget en un QGridLayout?

- Por alguna razón, eliminar widgets de diseños es difícil. Pasé mucho tiempo buscando la respuesta una vez, y ya no recuerdo dónde la encontré, pero estoy divagando ...

Lo que debes hacer es lo siguiente. Primero encuentra el artículo que deseas eliminar. Puede usar layout.itemAt() o layout.itemAtPosition para obtener una referencia.

Ahora, para eliminar el elemento del diseño, simplemente llame a item.widget().setParent(None) . ¡Esto tendrá el efecto de eliminar el elemento del diseño!

Nota: Si ya tiene una referencia al widget, probablemente pueda simplemente llamar a setParent sin tener que encontrarlo desde el diseño. Aunque no lo intenté (pero no veo por qué no funcionaría).