【问题标题】:Move row up and down in PyQT4在 PyQT4 中上下移动行
【发布时间】:2012-02-28 06:44:12
【问题描述】:

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

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

【问题讨论】:

    标签: python pyqt pyqt4 qtablewidget


    【解决方案1】:

    我只使用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_())
    

    【讨论】:

    • 是的,这就是我所指的必须单独携带每件物品。我的答案有更多代码,因为它还保留了选择。很好地解决了这个问题。
    • @student : 你在哪里使用 self.table.setItem(row-1,i,self.table.takeItem(row+1,i)) QListWidget 时应该使用什么,因为 QListWidget 没有设置项?
    • @san 我不知道。我想最好问一个新问题。您可以复制并粘贴我的示例,参考我的答案的链接,并在新问题中询问您想要什么。我相信你会得到一些有用的答案。
    • 或者更好的是,使用 QListWidget 将我的示例修改为不工作的示例,在您的问题中显示并询问如何解决它...
    • @san 太好了!如果您愿意:只需提出您的问题,您自己的答案就是与社区分享您的知识。
    【解决方案2】:

    我已经修改了我的答案,因为它之前没有足够的细节

    该过程涉及将您的按钮连接到一个插槽(或多个插槽),该插槽将查看当前选择,并通过将它们从视图中取出并将它们插入新位置来移动它们。

    下面的例子实际上是使用了一个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_()
    

    初始化很简单,只需设置表格、模型和按钮。我们使用functools.partial 将两个按钮连接到同一个方法,这对于用不同的参数包装同一个函数调用非常方便。然后表格就填满了 20x6 的数据。

    当一个按钮被点击时,我们确保他们已经选择了行。对于每个选定的行,我们解析其项目(稍后在它移动后重新选择),并通过加或减一个来确定新的行号。我们还要确保它在移动的有效范围内,否则我们跳过它。最后,我们调用takeRow() 将整行作为索引列表删除,然后将该行插入新的行号。在那个循环之后,我们使用我们保存的项目来查找新索引并再次重新选择它们。

    【讨论】:

    • @student:用一个完整的例子重写
    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多