考虑一个QTableWidget,两个按钮“向上移动”和“向下移动”。单击向上移动,当前行应向上移动一行,类似于“向下移动”。
实施相应的上移和下移功能的最简单方法是什么?
答案 0 :(得分:5)
我设法只使用QTableWidget
,这是一个完整的例子:
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_())
答案 1 :(得分:3)
我已经修改了我的答案,因为它之前没有足够的细节
此过程涉及将按钮连接到将查看当前选择的插槽(或插槽),并通过从视图中取出它们并将它们插入新位置来移动它们。
以下示例实际上使用的是QTableView + QStandardItemModel。原因是因为您只能使用窗口小部件中的方法,因此QTableWidget更受限制。能够直接使用模型和选择模型更容易。虽然如果您多次使用takeItem()
来构建每一行,可以为QTableWidget重做此示例......
这是一个完整的例子:
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_()
init非常简单,只需设置表格,模型和按钮即可。我们使用functools.partial
将两个按钮连接到同一个方法,这对于使用不同的args包装相同的函数调用非常方便。然后表格中只填充了20x6数据。
单击按钮时,我们确保他们选择了行。对于每个选定的行,我们解析其项目(稍后在移动后重新选择),并通过添加或减去一个来确定新的行号。我们还确保它在有效范围内移动,否则我们跳过它。最后,我们调用takeRow()
将整行删除为索引列表,然后将该行插回新行号。在该循环之后,我们使用我们保存的项目来查找新索引并再次重新选择它们。