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())
一、解决表格完全适配内容、无滚动条问题
原代码的问题在于未正确触发表格的行列适配逻辑,且未计算表格边框、内边距等额外空间,导致尺寸计算不准确。修改方案如下:
- 让行列自动适配内容:在填充完单元格内容后,调用
resizeColumnsToContents()和resizeRowsToContents(),让行列尺寸自动匹配内容大小。 - 修正尺寸计算:计算总宽高时,要包含表格的边框、内边距、表头宽度/高度等额外空间。
- 设置固定尺寸:使用
setFixedSize()替代setMinimumSize(),确保表格尺寸刚好容纳所有内容,不会出现滚动条。 - 简化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
相关产品推荐
相关产品推荐

