Переместить строку вверх и вниз в PyQT4 - PullRequest
2 голосов
/ 06 февраля 2012

Рассмотрим QTableWidget и две кнопки «двигаться вверх» и «двигаться вниз». Нажав на движение вверх, текущая строка должна двигаться вверх на одну строку, аналогично «двигаться вниз».

Какой самый простой способ реализовать соответствующие функции перемещения вверх и вниз?

Ответы [ 2 ]

5 голосов
/ 13 августа 2012

Мне удалось сделать это, используя только 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_())
3 голосов
/ 06 февраля 2012

Я пересмотрел свой ответ, потому что ранее у него не было достаточно деталей

Процесс включает в себя подключение кнопок к слоту (или слотам), который будет смотреть на текущий выбор, ипереместите их, взяв их из вида и вставив в новые местоположения.

В следующем примере фактически используется QTableView + QStandardItemModel.Причина в том, что QTableWidget намного более ограничен, поскольку вы можете использовать только методы из виджета.Намного проще иметь возможность работать непосредственно с моделью и моделью выбора.Хотя, возможно, переделать этот пример для QTableWidget, если вы используете takeItem() несколько раз для построения каждой строки ...

Вот полностью рабочий пример:

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, что действительно удобно для переноса одного и того же вызова функции разными аргументами.Затем таблица просто заполняется данными размером 20x6.

При нажатии кнопки мы проверяем, что они выбрали строки.Для каждой выбранной строки мы разрешаем ее элемент (для повторного выбора позже после его перемещения) и определяем новый номер строки, добавляя или вычитая его.Мы также проверяем, чтобы он находился в допустимом диапазоне, иначе мы его пропускаем.Наконец, мы вызываем takeRow(), чтобы удалить всю строку в виде списка индексов, а затем вставляем эту строку обратно в новый номер строки.После этого цикла мы используем сохраненные элементы для поиска новых индексов и повторного их выбора.

...