在PyQt4中如何从QTableView复制/粘贴多个项目?

5
我们可以使用self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)从QTableView中选择多个项目(部分行和部分列),但是在选择一些行和列(部分和部分)之后,如果我按CTRL+C并将其粘贴到记事本中,它只会粘贴一个项目(来自tableView的一个值)?
我的代码:
tab_table_view = QtGui.QWidget()
self.Tab.insertTab(0, tab_table_view, self.File_Name)
self.tableView = QtGui.QTableView(tab_table_view)
self.tableView.setGeometry(QtCore.QRect(0, 0, 721, 571))
self.model = QtGui.QStandardItemModel(self)
self.model.setSortRole(QtCore.Qt.UserRole)
self.tableView.setModel(self.model)

    self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection) '''this helps for selecting multiple items but not able to copy and paste multiple values to a text/ excel (it only copies single value)'''

我们如何复制和粘贴多个项目?
5个回答

10
self.tableView.installEventFilters(self)

现在,添加事件筛选器:

def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.KeyPress and
            event.matches(QtGui.QKeySequence.Copy)):
            self.copySelection()
            return True
        return super(Window, self).eventFilter(source, event)

复制函数:

def copySelection(self):
        selection = self.tableView.selectedIndexes()
        if selection:
            rows = sorted(index.row() for index in selection)
            columns = sorted(index.column() for index in selection)
            rowcount = rows[-1] - rows[0] + 1
            colcount = columns[-1] - columns[0] + 1
            table = [[''] * colcount for _ in range(rowcount)]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                table[row][column] = index.data()
            stream = io.StringIO()
            csv.writer(stream).writerows(table)
            QtGui.qApp.clipboard().setText(stream.getvalue())       

部分代码“.writerows(table)”抛出错误“TypeError: unicode argument expected, got str”。令人困惑的是,变量table是一个列表,其项是包含Unicode的列表。 - Ciasto piekarz

8

非常感谢@learncode上面的评论,我成功地实现了复制部分。此外,我稍作修改以支持按单元格对应顺序复制到Excel:

def copySelection(self):
    selection = self.selectedIndexes()
    if selection:
        rows = sorted(index.row() for index in selection)
        columns = sorted(index.column() for index in selection)
        rowcount = rows[-1] - rows[0] + 1
        colcount = columns[-1] - columns[0] + 1
        table = [[''] * colcount for _ in range(rowcount)]
        for index in selection:
            row = index.row() - rows[0]
            column = index.column() - columns[0]
            table[row][column] = index.data()
        stream = io.StringIO()
        csv.writer(stream, delimiter='\t').writerows(table)
        QtWidgets.qApp.clipboard().setText(stream.getvalue())
    return

除了复制,我还创建粘贴部分。根据用户选择的单元格范围(单个单元格或一系列单元格),此代码片段支持不同形状数据的粘贴。

def pasteSelection(self):
    selection = self.selectedIndexes()
    if selection:
        model = self.model()

        buffer = QtWidgets.qApp.clipboard().text() 
        rows = sorted(index.row() for index in selection)
        columns = sorted(index.column() for index in selection)
        reader = csv.reader(io.StringIO(buffer), delimiter='\t')
        if len(rows) == 1 and len(columns) == 1:
            for i, line in enumerate(reader):
                for j, cell in enumerate(line):
                    model.setData(model.index(rows[0]+i,columns[0]+j), cell)
        else:
            arr = [ [ cell for cell in row ] for row in reader]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                model.setData(model.index(index.row(), index.column()), arr[row][column])
    return

部分代码“.writerows(table)”抛出错误“TypeError:期望Unicode参数,但得到了str”。令人困惑的是,变量table是一个列表,其项是包含Unicode的列表。 - Ciasto piekarz

2
这个答案扩展了@learncode和@Frederick Li的答案,以适应以下情况:
  1. 行和列没有按升序排列
  2. 视图中有一些行和/或列是隐藏的。
它还包括扩展事件过滤器以处理粘贴的代码。
class TableView(QTableView):
    def __init__(self, *args, **kwargs):
        super(TableView, self).__init__(*args, **kwargs)
        self.installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress and event.matches(QKeySequence.Copy):
            self.copy_selection()
            return True
        elif event.type() == QEvent.KeyPress and event.matches(QKeySequence.Paste):
            self.paste_selection()
            return True
        return super(TableView, self).eventFilter(source, event)

    def copy_selection(self):
        selection = self.selectedIndexes()
        if selection:
            all_rows = []
            all_columns = []
            for index in selection:
                if not index.row() in all_rows:
                    all_rows.append(index.row())
                if not index.column() in all_columns:
                    all_columns.append(index.column())
            visible_rows = [row for row in all_rows if not self.isRowHidden(row)]
            visible_columns = [
                col for col in all_columns if not self.isColumnHidden(col)
            ]
            table = [[""] * len(visible_columns) for _ in range(len(visible_rows))]
            for index in selection:
                if index.row() in visible_rows and index.column() in visible_columns:
                    selection_row = visible_rows.index(index.row())
                    selection_column = visible_columns.index(index.column())
                    table[selection_row][selection_column] = index.data()
            stream = io.StringIO()
            csv.writer(stream, delimiter="\t").writerows(table)
            QApplication.clipboard().setText(stream.getvalue())

    def paste_selection(self):
        selection = self.selectedIndexes()
        if selection:
            model = self.model()

            buffer = QApplication.clipboard().text()
            all_rows = []
            all_columns = []
            for index in selection:
                if not index.row() in all_rows:
                    all_rows.append(index.row())
                if not index.column() in all_columns:
                    all_columns.append(index.column())
            visible_rows = [row for row in all_rows if not self.isRowHidden(row)]
            visible_columns = [
                col for col in all_columns if not self.isColumnHidden(col)
            ]

            reader = csv.reader(io.StringIO(buffer), delimiter="\t")
            arr = [[cell for cell in row] for row in reader]
            if len(arr) > 0:
                nrows = len(arr)
                ncols = len(arr[0])
                if len(visible_rows) == 1 and len(visible_columns) == 1:
                    # Only the top-left cell is highlighted.
                    for i in range(nrows):
                        insert_rows = [visible_rows[0]]
                        row = insert_rows[0] + 1
                        while len(insert_rows) < nrows:
                            row += 1
                            if not self.isRowHidden(row):
                                insert_rows.append(row)                              
                    for j in range(ncols):
                        insert_columns = [visible_columns[0]]
                        col = insert_columns[0] + 1
                        while len(insert_columns) < ncols:
                            col += 1
                            if not self.isColumnHidden(col):
                                insert_columns.append(col)
                    for i, insert_row in enumerate(insert_rows):
                        for j, insert_column in enumerate(insert_columns):
                            cell = arr[i][j]
                            model.setData(model.index(insert_row, insert_column), cell)
                else:
                    # Assume the selection size matches the clipboard data size.
                    for index in selection:
                        selection_row = visible_rows.index(index.row())
                        selection_column = visible_columns.index(index.column())
                        model.setData(
                            model.index(index.row(), index.column()),
                            arr[selection_row][selection_column],
                        )
        return

1

QAbstractItemView.ExtendedSelection 当用户以通常方式选择一个项目时,选择将被清除并选择新的项目。但是,如果用户在单击项目时按下Ctrl键,则单击的项目将被切换,而所有其他项目都将保持不变。如果用户在单击项目时按下Shift键,则当前项目和单击项目之间的所有项目将根据单击项目的状态选择或取消选择。可以通过拖动鼠标来选择多个项目。 你也可以使用

QAbstractItemView.MultiSelection

1
谢谢您的回答,但我不是在询问多个选择,而是要复制和粘贴多个项目中的单个选择。 - learncode
1
您能复制并粘贴所选内容吗? - learncode

0

在C++中,可以通过重写QTableView的Keypressevent来实现单选多项的复制和粘贴。

void CustomTableView::keyPressEvent(QKeyEvent *event)
{

    this->setSelectionBehavior(QAbstractItemView::SelectRows);
        this->setSelectionMode(QAbstractItemView::MultiSelection);
        QModelIndexList selectedRows = selectionModel()->selectedRows();
        QModelIndexList selectedColumns = selectionModel()->selectedColumns();
    if(event->key() == Qt::Key_Insert)
    {
        tblview_model->customInsertRows();
    }
    else if(event->key() == Qt::Key_Delete)
    {  if(!selectedRows.isEmpty())
            model()->removeRows(selectedRows.at(0).row(),
                                selectedRows.size());
    }
    else if(event->matches(QKeySequence::Paste)) {
        if(copyPasteEnabled == true){
            text = QApplication::clipboard()->text();
            if(!text.isEmpty()){
                tblview_model->pasteData(text);
            }
        }
    }

    if(!selectedIndexes().isEmpty()){
        if(event->matches(QKeySequence::Copy)){
            QString text;
            QStringList hdr_lst;
            const std::vector<std::string>& hdrs = tblview_model->getHeader();

            QItemSelectionRange range = selectionModel()->selection().first();
            if (!selectedColumns.isEmpty())
            {
                for (auto j = 0; j < selectedColumns.size(); ++j)
                {
                    std::string hd = hdrs[selectedColumns.at(j).column()];
                    if (std::find(hdrs.begin(), hdrs.end(), hd) != hdrs.end())
                        hdr_lst << QString::fromStdString(hd);
                }
                text += hdr_lst.join("\t");
                text += "\n";

                for (auto i = 0; i < tblview_model->rowCount(); ++i)
                {
                    QStringList rowContents;
                    for (auto j = 0; j < selectedColumns.size(); ++j)
                    {
                        if (!isColumnHidden(j)) {
                            rowContents << model()->index(i, selectedColumns.at(j).column()).data().toString();
                        }
                    }
                    text += rowContents.join("\t");
                    text += "\n";
                }
            }
            else if (!selectedRows.isEmpty())
            {
                for (auto h : hdrs)
                {
                    hdr_lst << QString::fromStdString(h);
                }

                text += hdr_lst.join("\t");
                text += "\n";
                //for (auto i = range.top(); i <= range.bottom(); ++i)
                for (auto i = 0; i < selectedRows.size(); ++i)
                {
                    QStringList rowContents;
                    for (auto j = 0; j <= tblview_model->columnCount(); ++j)
                    {
                        if (!isColumnHidden(j)) {
                            rowContents << model()->index(selectedRows.at(i).row(), j).data().toString();
                        }
                    }
                    text += rowContents.join("\t");
                    text += "\n";
                }
            }
            QApplication::clipboard()->setText(text);
        }
        else
            QTableView::keyPressEvent(event);
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接