在PyQT4中上下移动行

时间:2012-02-06 19:34:32

标签: python pyqt pyqt4 qtablewidget

考虑一个QTableWidget,两个按钮“向上移动”和“向下移动”。单击向上移动,当前行应向上移动一行,类似于“向下移动”。

实施相应的上移和下移功能的最简单方法是什么?

2 个答案:

答案 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()将整行删除为索引列表,然后将该行插回新行号。在该循环之后,我们使用我们保存的项目来查找新索引并再次重新选择它们。