如何为QTableWidget的列设置多级表头?
If you need a two-level header structure for your QTableWidget (with "Failed" and "Undefined" as top-level headers covering your existing four columns), here's a straightforward way to implement it:
Approach Overview
Since Qt's default QHeaderView doesn't natively support spanning sections for multi-level headers, we'll create a custom header bar widget that sits above the table, then hide the original horizontal header. This keeps things simple and avoids complex subclassing.
Step-by-Step Implementation (PyQt5/PySide2)
1. Set Up the Basic QTableWidget
First, create your table with the 4 columns and original headers:
from PyQt5.QtWidgets import (QApplication, QTableWidget, QTableWidgetItem, QWidget, QHBoxLayout, QLabel, QVBoxLayout, QSizePolicy, QHeaderView) import sys app = QApplication(sys.argv) # Create main window widget main_widget = QWidget() main_layout = QVBoxLayout(main_widget) # Create table with 4 columns table = QTableWidget() table.setColumnCount(4) original_headers = ["Failed DIPS", "Failed Outputs", "Extra DIPS", "Extra Outputs"] table.setHorizontalHeaderLabels(original_headers) # Optional: Add some sample data table.setRowCount(3) for row in range(3): for col in range(4): table.setItem(row, col, QTableWidgetItem(f"Row {row}, Col {col}"))
2. Create the Top-Level Header Bar
Next, build a horizontal layout to hold the two top-level headers, each spanning two columns:
# Create top header widget top_header_widget = QWidget() top_header_layout = QHBoxLayout(top_header_widget) top_header_layout.setContentsMargins(0,0,0,0) top_header_layout.setSpacing(0) # Style the header labels to match Qt's default header look header_style = """ QLabel { background-color: #f0f0f0; border: 1px solid #cccccc; padding: 4px; font-weight: bold; text-align: center; } """ # Add "Failed" header (covers columns 0 and 1) failed_header = QLabel("Failed") failed_header.setStyleSheet(header_style) # Make it stretch to fit two columns' width failed_header.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) top_header_layout.addWidget(failed_header) # Add "Undefined" header (covers columns 2 and 3) undefined_header = QLabel("Undefined") undefined_header.setStyleSheet(header_style) undefined_header.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) top_header_layout.addWidget(undefined_header)
3. Combine Everything and Hide Original Header
Add the top header and table to the main layout, then hide the original horizontal header:
# Add top header and table to main layout main_layout.addWidget(top_header_widget) main_layout.addWidget(table) # Hide the original horizontal header (since we have our custom top header) table.horizontalHeader().setVisible(False) # Adjust table column widths to match top header sections table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) main_widget.show() sys.exit(app.exec_())
Alternative: Subclass QHeaderView (for Tighter Integration)
If you want the multi-level headers to be part of the table's native header (instead of a separate widget), you can subclass QHeaderView to draw the top-level sections. Here's a quick snippet:
from PyQt5.QtGui import QPainter, QPen from PyQt5.QtCore import Qt class MultiLevelHeader(QHeaderView): def __init__(self, parent=None): super().__init__(Qt.Horizontal, parent) self.top_level_headers = [("Failed", 0,1), ("Undefined",2,3)] def paintSection(self, painter, rect, logicalIndex): # Draw original section first super().paintSection(painter, rect, logicalIndex) # Draw top-level headers if we're in the first section of a group for header_text, start_col, end_col in self.top_level_headers: if logicalIndex == start_col: # Calculate the total width of the group group_width = 0 for col in range(start_col, end_col+1): group_width += self.sectionSize(col) # Draw the top header painter.save() painter.setPen(QPen(Qt.gray)) painter.setBrush(Qt.lightGray) painter.drawRect(rect.x(), 0, group_width, 20) painter.setPen(QPen(Qt.black)) painter.drawText(rect.x(), 0, group_width, 20, Qt.AlignCenter, header_text) painter.restore() # Usage: table.horizontalHeader().setVisible(True) table.setHorizontalHeader(MultiLevelHeader(table)) # Adjust header height to fit both levels table.horizontalHeader().setMinimumHeight(40)
Key Notes
- The widget-based approach is simpler and works well for most cases, especially if you don't need interactive top-level headers.
- The subclassed
QHeaderViewapproach integrates more tightly with the table, allowing for features like sorting while keeping the multi-level headers visible. - Tweak the styles and sizes to match your application's design system.
内容的提问来源于stack exchange,提问作者Gurushant

