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

QTableWidget适配内容无滚动及单元格图片缩放质量问题咨询

QTableWidget嵌入QGraphicsProxyWidget适配问题及图片显示优化

我用PySide6实现了一个QGraphicsView场景,其中通过QGraphicsProxyWidget嵌入了QTableWidget。尝试让表格完全适配内容且不显示滚动条,但始终无法实现;另外,单元格添加图片的机制是否合理?小图片缩放后画质损失严重,求解决办法。

我的实现代码:

from PySide6.QtCore import Qt
from PySide6.QtGui import QIcon, QPixmap, QBrush
from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsRectItem, QGraphicsTextItem, \
    QTableWidget, QTableWidgetItem, QGraphicsProxyWidget, QStyledItemDelegate
import sys


class ImageDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(ImageDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        pixmap = index.data(Qt.DecorationRole)
        if pixmap:
            rect = option.rect
            scaled_pixmap = pixmap.scaled(rect.width(), rect.height(), Qt.KeepAspectRatio, Qt.SmoothTransformation)
            x = rect.x() + (rect.width() - scaled_pixmap.width()) / 2
            y = rect.y() + (rect.height() - scaled_pixmap.height()) / 2
            painter.drawPixmap(x, y, scaled_pixmap)
        else:
            super().paint(painter, option, index)


class Table(QTableWidget):
    def __init__(self, rows, columns):
        super().__init__(rows, columns)
        self.setItemDelegate(ImageDelegate(self))

        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        for i in range(rows):
            for j in range(columns):
                if i == 0 and j == 0:  # 给第一个单元格添加图片
                    item = QTableWidgetItem()
                    pixmap = QPixmap('D:\\User\\AaCePbBf.png')  # 替换成你的图片路径
                    if not pixmap.isNull():  # 检查图片是否加载成功
                        item.setData(Qt.DecorationRole, pixmap)
                    self.setItem(i, j, item)
                else:
                    self.setItem(i, j, QTableWidgetItem(f"({j}, {i})"))

        total_width = sum([self.columnWidth(i) for i in range(self.columnCount())])
        total_height = sum([self.rowHeight(i) for i in range(self.rowCount())])

        # 设置总宽高
        self.setMinimumWidth(total_width)
        self.setMinimumHeight(total_height)


app = QApplication(sys.argv)

scene = QGraphicsScene()

table = Table(10, 10)
proxy = QGraphicsProxyWidget()
proxy.setWidget(table)
proxy.setMinimumSize(table.minimumWidth(), table.minimumHeight())
scene.addItem(proxy)

view = QGraphicsView()
view.setScene(scene)
view.setSceneRect(0, 0, 5000, 5000)
view.show()

sys.exit(app.exec())

一、解决表格完全适配内容、无滚动条问题

原代码的问题在于未正确触发表格的行列适配逻辑,且未计算表格边框、内边距等额外空间,导致尺寸计算不准确。修改方案如下:

  1. 让行列自动适配内容:在填充完单元格内容后,调用resizeColumnsToContents()和resizeRowsToContents(),让行列尺寸自动匹配内容大小。
  2. 修正尺寸计算:计算总宽高时,要包含表格的边框、内边距、表头宽度/高度等额外空间。
  3. 设置固定尺寸:使用setFixedSize()替代setMinimumSize(),确保表格尺寸刚好容纳所有内容,不会出现滚动条。
  4. 简化ProxyWidget设置:QGraphicsProxyWidget会自动跟随内部Widget的尺寸,无需手动设置minimumSize,还可以让View自动适配场景内容。

修改后的Table类关键代码:

# 先让行列适配内容
self.resizeColumnsToContents()
self.resizeRowsToContents()

# 计算总宽度:列宽总和 + 垂直表头宽度 + 左右边框 + 内边距
total_width = sum([self.columnWidth(i) for i in range(self.columnCount())]) + \
              self.verticalHeader().width() + self.frameWidth() * 2 + \
              self.contentsMargins().left() + self.contentsMargins().right()
# 计算总高度:行高总和 + 水平表头高度 + 上下边框 + 内边距
total_height = sum([self.rowHeight(i) for i in range(self.rowCount())]) + \
               self.horizontalHeader().height() + self.frameWidth() * 2 + \
               self.contentsMargins().top() + self.contentsMargins().bottom()

# 设置固定尺寸,确保表格刚好容纳所有内容
self.setFixedSize(total_width, total_height)

主函数修改:

table = Table(10, 10)
proxy = QGraphicsProxyWidget()
proxy.setWidget(table)
scene.addItem(proxy)

view = QGraphicsView()
view.setScene(scene)
# 让View自动适配场景内容,无需手动设置超大sceneRect
view.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)
view.show()

二、图片添加机制优化与画质改善

当前的图片添加机制是可行的,但画质损失源于每次paint都重复缩放图片,多次缩放会累积画质损耗。优化方案如下:

1. 减少缩放次数,提前预处理图片

在设置QTableWidgetItem时,先将图片缩放到预期的单元格尺寸,避免Delegate每次paint时重复缩放:

if i == 0 and j == 0:
    item = QTableWidgetItem()
    pixmap = QPixmap('D:\\User\\AaCePbBf.png')
    if not pixmap.isNull():
        # 提前缩放到合适尺寸,比如单元格预期大小
        target_size = QSize(100, 100)  # 根据需求调整
        scaled_pixmap = pixmap.scaled(target_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        item.setData(Qt.DecorationRole, scaled_pixmap)
    self.setItem(i, j, item)

2. 让单元格适配图片尺寸(推荐)

在Delegate中重写sizeHint方法,让单元格尺寸自动适配图片大小,从根源上避免图片缩放:

class ImageDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super(ImageDelegate, self).__init__(parent)

    def paint(self, painter, option, index):
        pixmap = index.data(Qt.DecorationRole)
        if pixmap:
            rect = option.rect
            # 此时单元格尺寸已适配图片,只需居中绘制即可,无需缩放
            x = rect.x() + (rect.width() - pixmap.width()) / 2
            y = rect.y() + (rect.height() - pixmap.height()) / 2
            painter.drawPixmap(x, y, pixmap)
        else:
            super().paint(painter, option, index)
    
    def sizeHint(self, option, index):
        pixmap = index.data(Qt.DecorationRole)
        if pixmap:
            # 让单元格尺寸适配图片,加上少量内边距
            return pixmap.size() + QSize(10, 10)
        return super().sizeHint(option, index)

这样表格的行列会自动根据图片大小调整,图片无需缩放就能完整显示,画质自然不会损失。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:34:53