使用 PyQt5 合并类似 excel 的表格中的单元格无法按预期工作

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

我正在尝试使用 PyQt5 在 GUI 应用程序中制作类似 excel 的表格。我正在努力添加合并/取消合并功能。 添加一些打印语句后,我注意到合并第一组单元格将起作用,但是当我尝试合并第二组单元格时,它会由于某种原因仅选择一个单元格(即使我选择了多个单元格)并且合并不会成功。 一旦我取消合并第一组单元格,我可以再次合并另一组,但就是这样,只是一组。

有人遇到过这个问题或者知道解决办法吗?我似乎无法在 stackoverflow 或 youtube 上找到任何有用的帖子。

提前致谢:)

我尝试这样做,以便选择整行。 在这种情况下,我能够合并多个不同的行组。 但我希望它是单元格,就像在 Excel 中一样。但这是行不通的。

添加 self.tableWidget.clearSelection() 似乎也没有帮助。

我真的很困惑。

import sys
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QVBoxLayout, QWidget, QPushButton


class ExcelLikeTable(QMainWindow):
    def __init__(self):
        super().__init__()

        self.mergeButton = None
        self.unmergeButton = None
        self.tableWidget = QTableWidget()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("Excel-like Table with PyQt5")
        self.setGeometry(100, 100, 800, 600)

        self.tableWidget.setColumnCount(10)
        self.tableWidget.setHorizontalHeaderLabels([f'Column {chr(65+i)}' for i in range(10)])
        self.tableWidget.setRowCount(1)

        self.tableWidget.clearSelection()
        self.tableWidget.setSelectionMode(QTableWidget.ContiguousSelection)
        self.tableWidget.setSelectionBehavior(QTableWidget.SelectItems)

        self.mergeButton = QPushButton("Merge Cells")
        self.unmergeButton = QPushButton("Unmerge Cells")
        self.mergeButton.clicked.connect(self.mergeCells)
        self.unmergeButton.clicked.connect(self.unmergeCells)

        layout = QVBoxLayout()
        layout.addWidget(self.tableWidget)
        layout.addWidget(self.mergeButton)
        layout.addWidget(self.unmergeButton)

        centralWidget = QWidget()
        centralWidget.setLayout(layout)
        self.setCentralWidget(centralWidget)

        self.tableWidget.installEventFilter(self)

    def mergeCells(self):
        if not self.tableWidget.selectedRanges():
            print("No cells selected for merging.")
            return

        selectedRange = self.tableWidget.selectedRanges()[0]
        topRow, leftColumn = selectedRange.topRow(), selectedRange.leftColumn()
        rowCount, columnCount = selectedRange.rowCount(), selectedRange.columnCount()

        print(
            f"Selected range - Top Row: {topRow}, Left Column: {leftColumn}, Row Count: {rowCount}, Column Count: {columnCount}")

        if rowCount == 1 and columnCount == 1:
            print("Only a single cell selected, no merge performed.")
            return

        self.tableWidget.setSpan(topRow, leftColumn, rowCount, columnCount)
        print(
            f"Merge completed from Cell {chr(65 + leftColumn)}{topRow + 1} to Cell {chr(65 + leftColumn + columnCount - 1)}{topRow + rowCount}")

    def unmergeCells(self):
        for i in range(self.tableWidget.rowCount()):
            for j in range(self.tableWidget.columnCount()):
                self.tableWidget.setSpan(i, j, 1, 1)

    def addRow(self):
        rowCount = self.tableWidget.rowCount()
        self.tableWidget.insertRow(rowCount)

    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Return:
            currentRow = self.tableWidget.currentRow()
            currentColumn = self.tableWidget.currentColumn()
            if currentRow == self.tableWidget.rowCount() - 1:
                self.addRow()
            self.tableWidget.setCurrentCell(currentRow + 1, currentColumn)
            return True
        return super(ExcelLikeTable, self).eventFilter(source, event)

    def debugPrintCellSpans(self):
        print("Debugging cell spans:")
        for i in range(self.tableWidget.rowCount()):
            for j in range(self.tableWidget.columnCount()):
                rowSpan = self.tableWidget.rowSpan(i, j)
                colSpan = self.tableWidget.columnSpan(i, j)
                if rowSpan > 1 or colSpan > 1:
                    print(f"Cell at ({i+1}, {chr(65+j)}) has row span: {rowSpan}, column span: {colSpan}")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ExcelLikeTable()
    ex.show()
    sys.exit(app.exec_())

user-interface pyqt5 qtablewidget
1个回答
0
投票

如名称所示,selectedRanges返回一个范围列表,但文档没有说明在什么精确情况下会出现多个范围。似乎合并后,后续选择中的每个单元格形成一个单独的范围,但这种行为是否符合预期,或者是一个错误,尚不清楚。无论情况如何,selectedIndexes 的行为更加直观,因此最好使用它。

我已经展示了如何使用下面选定的索引来修复您的示例。看来清除当前选定单元格的跨度first效果最好,否则可能会导致相当混乱的嵌套跨度。

class ExcelLikeTable(QMainWindow):
    ...
    def unmergeCells(self):
        self.tableWidget.clearSpans()

    def mergeCells(self):
        selection = self.tableWidget.selectedIndexes()

        if not selection:
            print("No cells selected for merging.")
            return

        if len(selection) == 1:
            print("Only a single cell selected, no merge performed.")
            return

        for index in selection:
            row, column = index.row(), index.column()
            if (self.tableWidget.rowSpan(row, column) > 1 or
                self.tableWidget.columnSpan(row, column) > 1):
                self.tableWidget.setSpan(row, column, 1, 1)

        # clearing the spans may have changed the selection
        selection = sorted(self.tableWidget.selectedIndexes())

        topRow, leftColumn = selection[0].row(), selection[0].column()
        bottomRow, rightColumn = selection[-1].row(), selection[-1].column()
        rowCount = bottomRow - topRow + 1
        columnCount = rightColumn - leftColumn + 1

        print(
            f"Selected range - Top Row: {topRow}, Left Column: {leftColumn}, Row Count: {rowCount}, Column Count: {columnCount}")

        self.tableWidget.setSpan(topRow, leftColumn, rowCount, columnCount)
        print(
            f"Merge completed from Cell {chr(65 + leftColumn)}{topRow + 1} to Cell {chr(65 + leftColumn + columnCount - 1)}{topRow + rowCount}")
© www.soinside.com 2019 - 2024. All rights reserved.