我正在尝试使用 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_())
如名称所示,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}")