You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5:如何在QTableWidget跨两单元格添加进度条并实现文本对齐?

解决股票Level2行情QTableWidget进度条跨列对齐问题

核心思路

放弃直接用QProgressBar跨列覆盖单元格的方案,改用自定义复合Widget:将进度条作为背景层,在上方叠加两个独立标签分别对应需要显示的文本,既能实现进度条跨列效果,又能单独控制每个标签的对齐方式。


步骤实现

1. 编写自定义进度条Widget

创建包含进度条+双标签的复合控件,分别处理左右文本的对齐逻辑:

from PyQt5.QtWidgets import QWidget, QProgressBar, QLabel
from PyQt5.QtCore import Qt

class AskProgressWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        # 进度条作为背景,隐藏自带文本
        self.progress_bar = QProgressBar(self)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setStyleSheet("QProgressBar {border: none;}")
        
        # 左对齐的ask volume标签
        self.label_volume = QLabel(self.progress_bar)
        self.label_volume.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.label_volume.setStyleSheet("color: #ffffff; padding-left: 4px;")
        
        # 右对齐的ask price标签
        self.label_price = QLabel(self.progress_bar)
        self.label_price.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.label_price.setStyleSheet("color: #ffffff; padding-right: 4px;")

    def resizeEvent(self, event):
        # 跟随Widget大小调整控件位置,匹配原表格列区域
        self.progress_bar.setGeometry(0, 0, self.width(), self.height())
        # 按原列宽比例分配标签宽度(可根据实际列宽调整)
        volume_col_width = self.width() * 120 / (120 + 100)
        self.label_volume.setGeometry(0, 0, volume_col_width, self.height())
        self.label_price.setGeometry(volume_col_width, 0, self.width() - volume_col_width, self.height())

    def update_data(self, volume, price, max_volume):
        self.progress_bar.setMaximum(max_volume)
        self.progress_bar.setValue(volume)
        self.label_volume.setText(f"{volume:,}")
        self.label_price.setText(f"{price:,}")

# Bid侧进度条Widget,仅标签对齐逻辑调整
class BidProgressWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.progress_bar = QProgressBar(self)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setStyleSheet("QProgressBar {border: none;}")
        
        # 左对齐的bid price标签
        self.label_price = QLabel(self.progress_bar)
        self.label_price.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        self.label_price.setStyleSheet("color: #ffffff; padding-left: 4px;")
        
        # 右对齐的bid volume标签
        self.label_volume = QLabel(self.progress_bar)
        self.label_volume.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.label_volume.setStyleSheet("color: #ffffff; padding-right: 4px;")

    def resizeEvent(self, event):
        self.progress_bar.setGeometry(0, 0, self.width(), self.height())
        price_col_width = self.width() * 100 / (100 + 120)
        self.label_price.setGeometry(0, 0, price_col_width, self.height())
        self.label_volume.setGeometry(price_col_width, 0, self.width() - price_col_width, self.height())

    def update_data(self, price, volume, max_volume):
        self.progress_bar.setMaximum(max_volume)
        self.progress_bar.setValue(volume)
        self.label_price.setText(f"{price:,}")
        self.label_volume.setText(f"{volume:,}")

2. 嵌入表格并配置格式

在表格中设置单元格跨度,插入自定义Widget,并配置非进度条列的对齐:

from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem

# 假设stock_data是行情数据列表,每条格式:(ask_count, ask_volume, ask_price, bid_price, bid_volume, bid_count)
table_widget = QTableWidget(len(stock_data), 6)
table_widget.setHorizontalHeaderLabels(["ask count", "ask volume", "ask", "bid", "bid volume", "bid count"])

# 计算进度条最大值
max_ask_volume = max([row[1] for row in stock_data])
max_bid_volume = max([row[4] for row in stock_data])

# 遍历每行设置内容
for row_idx, data in enumerate(stock_data):
    ask_count, ask_volume, ask_price, bid_price, bid_volume, bid_count = data
    
    # 设置ask count列(居中对齐)
    item = QTableWidgetItem(f"{ask_count:,}")
    item.setTextAlignment(Qt.AlignCenter)
    table_widget.setItem(row_idx, 0, item)
    
    # 插入ask侧跨列进度条
    ask_widget = AskProgressWidget()
    ask_widget.update_data(ask_volume, ask_price, max_ask_volume)
    table_widget.setSpan(row_idx, 1, 1, 2)  # 跨列1和列2
    table_widget.setCellWidget(row_idx, 1, ask_widget)
    
    # 插入bid侧跨列进度条
    bid_widget = BidProgressWidget()
    bid_widget.update_data(bid_price, bid_volume, max_bid_volume)
    table_widget.setSpan(row_idx, 3, 1, 2)  # 跨列3和列4
    table_widget.setCellWidget(row_idx, 3, bid_widget)
    
    # 设置bid count列(居中对齐)
    item = QTableWidgetItem(f"{bid_count:,}")
    item.setTextAlignment(Qt.AlignCenter)
    table_widget.setItem(row_idx, 5, item)

# 设置固定列宽(匹配自定义Widget中的比例)
table_widget.setColumnWidth(0, 80)
table_widget.setColumnWidth(1, 120)
table_widget.setColumnWidth(2, 100)
table_widget.setColumnWidth(3, 100)
table_widget.setColumnWidth(4, 120)
table_widget.setColumnWidth(5, 80)

方案优势

  • 完全独立控制两个文本标签的对齐方式,解决格式化字符串无法精准对齐的问题;
  • 进度条作为背景层,完美实现跨列填充效果;
  • 自定义Widget可灵活调整样式(如颜色、内边距),适配Level2行情的视觉需求。

内容的提问来源于stack exchange,提问作者Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:37:10