复制pyqt表选择,包括列标题和行标题

问题描述 投票:0回答:2

我想复制 qt 表的选定部分,包括标题。默认的qt表复制仅复制一个单元格,而我需要整个选择,可以是多列和多行。我从不同的地方(主要是here)将一些代码拼接在一起,它似乎工作得很好,只是它只复制单元格(数据),而不是标题。我还需要一些帮助来获取选择的标题。这是我的瘦身样本:

from PyQt4 import QtGui, QtCore
import sys

class MainWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)

        self.table = QtGui.QTableWidget(parent=self)
        self.table.setColumnCount(2)
        self.table.setRowCount(2)
        self.table.setHorizontalHeaderLabels(['col1','col2'])
        self.table.setVerticalHeaderLabels(['row1','row2'])
        self.table.setItem(0,0,QtGui.QTableWidgetItem('foo'))
        self.table.setItem(0,1,QtGui.QTableWidgetItem('bar'))
        self.table.setItem(1,0,QtGui.QTableWidgetItem('baz'))
        self.table.setItem(1,1,QtGui.QTableWidgetItem('qux'))

        layout = QtGui.QGridLayout()
        layout.addWidget(self.table, 1, 0)
        self.setLayout(layout)

        self.clip = QtGui.QApplication.clipboard()


    def keyPressEvent(self, e):
        if (e.modifiers() & QtCore.Qt.ControlModifier):
            selected = self.table.selectedRanges()

            if e.key() == QtCore.Qt.Key_C: #copy
                s = ""

                for r in xrange(selected[0].topRow(), selected[0].bottomRow()+1):
                    for c in xrange(selected[0].leftColumn(), selected[0].rightColumn()+1):
                        try:
                            s += str(self.table.item(r,c).text()) + "\t"
                        except AttributeError:
                            s += "\t"
                    s = s[:-1] + "\n" #eliminate last '\t'
                self.clip.setText(s)


if __name__ == '__main__':

    # Initialize the application
    app = QtGui.QApplication(sys.argv)
    mw = MainWidget()
    mw.show()
    app.exec_()

示例表如下所示:

     col1 col2
row1 foo  bar
row2 baz  qux

例如,如果我选择

bar
bux
,我希望副本为:

\t col2\n
row1 \t bar\n
row2 \t qux\n

我的实际案例有很多列和行。我的困难在于找出所选单元格的标题;我可以处理格式。非常感谢任何帮助或建议。预先感谢!

python pyqt
2个回答
5
投票

线索在标题项中:

class MainWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)

        self.table = QtGui.QTableWidget(parent=self)
        self.table.setColumnCount(2)
        self.table.setRowCount(2)
        self.table.setHorizontalHeaderLabels(['col1','col2'])
        self.table.setVerticalHeaderLabels(['row1','row2'])
        self.table.setItem(0,0,QtGui.QTableWidgetItem('foo'))
        self.table.setItem(0,1,QtGui.QTableWidgetItem('bar'))
        self.table.setItem(1,0,QtGui.QTableWidgetItem('baz'))
        self.table.setItem(1,1,QtGui.QTableWidgetItem('qux'))

        layout = QtGui.QGridLayout()
        layout.addWidget(self.table, 1, 0)
        self.setLayout(layout)

        self.clip = QtGui.QApplication.clipboard()


    def keyPressEvent(self, e):
        if (e.modifiers() & QtCore.Qt.ControlModifier):
            selected = self.table.selectedRanges()

            if e.key() == QtCore.Qt.Key_C: #copy
                s = '\t'+"\t".join([str(self.table.horizontalHeaderItem(i).text()) for i in xrange(selected[0].leftColumn(), selected[0].rightColumn()+1)])
                s = s + '\n'

                for r in xrange(selected[0].topRow(), selected[0].bottomRow()+1):
                    s += self.table.verticalHeaderItem(r).text() + '\t'
                    for c in xrange(selected[0].leftColumn(), selected[0].rightColumn()+1):
                        try:
                            s += str(self.table.item(r,c).text()) + "\t"
                        except AttributeError:
                            s += "\t"
                    s = s[:-1] + "\n" #eliminate last '\t'
                self.clip.setText(s)

0
投票

我知道这个问题有点老了,但是对于正在寻找一种解决方案的人来说,允许他们选择不一定连接的多个范围,以下代码对我有用。

def copy_selection_to_clipboard(self) -> None:
    def intersects_with_ranges(ranges: list[tuple[int, int, int, int]], row: int, col: int) -> bool:
        # Checks if given row and col is in any given range
        for range_ in ranges:
            top, left, bottom, right = range_

            in_between_rows = row >= top and row <= bottom
            in_between_cols = col >= left and col <= right

            if in_between_rows and in_between_cols:
                return True

        return False

    model = self.model()
    ranges = [(r.topRow(), r.leftColumn(), r.bottomRow(), r.rightColumn()) for r in self.selectedRanges()]

    is_whole_table_selected = (
        len(ranges) == 1
        and ranges[0][0] == 0
        and ranges[0][1] == 0
        and ranges[0][2] == self.rowCount() - 1
        and ranges[0][3] == self.columnCount() - 1
    )

    row_start = min(ranges, key=lambda r: r[0])[0]
    col_start = min(ranges, key=lambda r: r[1])[1]
    row_end = max(ranges, key=lambda r: r[2])[2]
    col_end = max(ranges, key=lambda r: r[3])[3]

    rows = []
    for row_idx in range(row_start, row_end + 1):
        row = []
        for col_idx in range(col_start, col_end + 1):
            # empty value for not selected columns
            if not is_whole_table_selected and not intersects_with_ranges(ranges, row_idx, col_idx):
                value = ""
            else:
                # could also use EditRole if you have a customed model and want the raw value
                value = model.index(row_idx, col_idx).data(QtCore.Qt.ItemDataRole.DisplayRole)

            row.append(value)
        rows.append(row)

    if is_whole_table_selected:
        rows.insert(0, [self.horizontalHeaderItem(i).text() for i in range(self.columnCount())])

    clipboard_text = "\r\n".join("\t".join(row) for row in rows)
    QtWidgets.QApplication.clipboard().setText(clipboard_text)

然后只需向表中添加一个操作即可

Ctrl + C

action = self.addAction("Auswahl kopieren")
action.setShortcut(QtGui.QKeySequence("Ctrl+C"))
action.triggered.connect(self.copy_selection_to_clipboard)

(代码假设您继承了

QTableWidget

© www.soinside.com 2019 - 2024. All rights reserved.