python - Mueve la fila hacia arriba y hacia abajo en PyQT4
qtablewidgetitem pyqt (2)
Considere un QTableWidget y dos botones "mover hacia arriba" y "mover hacia abajo". Al hacer clic en mover hacia arriba, la fila actual debe avanzar una fila, análogamente para "mover hacia abajo".
¿Cuál es la forma más fácil de implementar las funciones correspondientes de subir y bajar?
QTableWidget
hacerlo usando QTableWidget
, aquí hay un ejemplo completo:
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
class mtable(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.move_up = QtGui.QAction("Move_Up", self)
self.connect(self.move_up, QtCore.SIGNAL(''triggered()''), self.moveUp)
self.move_down = QtGui.QAction("Move_Down",self)
self.connect(self.move_down, QtCore.SIGNAL(''triggered()''), self.moveDown)
self.toolbar = self.addToolBar(''Toolbar'')
self.toolbar.addAction(self.move_up)
self.toolbar.addAction(self.move_down)
##Init Table
self.table = QtGui.QTableWidget(4,3)
for i in range(0,4):
for j in range(0,4):
self.table.setItem(i,j,QtGui.QTableWidgetItem("a_"+str(i)+str(j)))
self.setCentralWidget(self.table)
def moveDown(self):
row = self.table.currentRow()
column = self.table.currentColumn();
if row < self.table.rowCount()-1:
self.table.insertRow(row+2)
for i in range(self.table.columnCount()):
self.table.setItem(row+2,i,self.table.takeItem(row,i))
self.table.setCurrentCell(row+2,column)
self.table.removeRow(row)
def moveUp(self):
row = self.table.currentRow()
column = self.table.currentColumn();
if row > 0:
self.table.insertRow(row-1)
for i in range(self.table.columnCount()):
self.table.setItem(row-1,i,self.table.takeItem(row+1,i))
self.table.setCurrentCell(row-1,column)
self.table.removeRow(row+1)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
tb = mtable()
tb.show()
sys.exit(app.exec_())
He revisado mi respuesta porque no tenía suficiente detalle previamente
El proceso implica conectar los botones a una ranura (o ranuras) que observará la selección actual y moverlos tomándolos de la vista e insertándolos en nuevas ubicaciones.
El siguiente ejemplo está usando un QTableView + QStandardItemModel. La razón es porque QTableWidget es mucho más limitado ya que solo puedes usar métodos del widget. Es mucho más fácil poder trabajar directamente con el modelo y el modelo de selección. Aunque, es posible volver a trabajar este ejemplo para un QTableWidget si usa takeItem()
varias veces para crear cada fila ...
Aquí hay un ejemplo completamente funcional:
from PyQt4 import QtCore, QtGui
from functools import partial
class Dialog(QtGui.QDialog):
DOWN = 1
UP = -1
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.resize(800,600)
self.table = QtGui.QTableView(self)
self.table.setSelectionBehavior(self.table.SelectRows)
self.model = QtGui.QStandardItemModel(20, 6, self)
self.table.setModel(self.model)
self.upBtn = QtGui.QPushButton(''Up'', self)
self.downBtn = QtGui.QPushButton(''Down'', self)
self.mainLayout = QtGui.QVBoxLayout(self)
self.mainLayout.addWidget(self.table)
self.buttonLayout = QtGui.QHBoxLayout()
self.buttonLayout.addWidget(self.upBtn)
self.buttonLayout.addWidget(self.downBtn)
self.mainLayout.addLayout(self.buttonLayout)
self.upBtn.clicked.connect(partial(self.moveCurrentRow, self.UP))
self.downBtn.clicked.connect(partial(self.moveCurrentRow, self.DOWN))
self._initTable()
def _initTable(self):
for row in xrange(self.model.rowCount()):
for col in xrange(self.model.columnCount()):
item = QtGui.QStandardItem(''%d_%d'' % (row+1, col+1))
self.model.setItem(row, col, item)
def moveCurrentRow(self, direction=DOWN):
if direction not in (self.DOWN, self.UP):
return
model = self.model
selModel = self.table.selectionModel()
selected = selModel.selectedRows()
if not selected:
return
items = []
indexes = sorted(selected, key=lambda x: x.row(), reverse=(direction==self.DOWN))
for idx in indexes:
items.append(model.itemFromIndex(idx))
rowNum = idx.row()
newRow = rowNum+direction
if not (0 <= newRow < model.rowCount()):
continue
rowItems = model.takeRow(rowNum)
model.insertRow(newRow, rowItems)
selModel.clear()
for item in items:
selModel.select(item.index(), selModel.Select|selModel.Rows)
if __name__ == "__main__":
app = QtGui.QApplication([])
d = Dialog()
d.show()
d.raise_()
app.exec_()
El init es simple y solo configura la tabla, el modelo y los botones. Conectamos ambos botones al mismo método utilizando functools.partial
, lo cual es muy conveniente para functools.partial
la misma llamada de función con diferentes argumentos. Luego, la tabla está llena de datos de 20x6.
Cuando se hace clic en un botón, nos aseguramos de que tengan filas seleccionadas. Para cada fila seleccionada, resolvemos su ítem (para volver a seleccionarlo más adelante una vez que se ha movido) y determinamos el nuevo número de fila agregando o restando uno. También nos aseguramos de que esté dentro del rango válido para moverse, de lo contrario, nos salteamos. Finalmente, llamamos a takeRow()
para eliminar toda la fila como una lista de índices, y luego insertamos esa fila nuevamente en el nuevo número de fila. Después de ese ciclo, usamos los elementos que guardamos para buscar los nuevos índices y volver a seleccionarlos.