如何在 table 单元格中显示具有原始大小比例的图像 - pyqt?
How to show images with original size ratio in table cells - pyqt?
我制作了一个 table,其中有一个包含图像的特定列,并使用代码段代码使单元格拉伸到其内容大小:
headerh.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
所以单元格的宽度和高度都根据单元格的内容进行了调整我在这里面临的问题是所有单元格的宽度和高度都调整为最大宽度和高度而不是我想要的这是根据自己的内容调整每个单元格,以便所有图像都能正确显示,不会过度拉伸,从而破坏图像的大小比例,这是我所面对的图像显示:
我希望有一种方法可以使第一个单元格不会像那样拉伸其内容图像!
这是我在没有数据库的情况下编写的完整代码!:
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout)
import sqlite3
import random
class Main(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Arabic Math Project')
self.setContentsMargins(20,20,20,20)
# create table:
self.setStyleSheet("""QTableView::item { border: 0px; padding: 10px;}QTableView{font-size:20px;}QPushButton{width:200px;height:30px}QLineEdit {width:200px;height:50px;}""")
layout = QVBoxLayout()
self.btn = QtWidgets.QPushButton("click it")
self.searchBar = QtWidgets.QLineEdit()
self.searchBar.setAlignment(QtCore.Qt.AlignCenter)
self.searchBar.setStyleSheet("font-size:35px;")
self.searchBar.setPlaceholderText("search")
self.searchBar.textChanged.connect(self.startSearchThreading) #editingFinished()
self.table = QtWidgets.QTableWidget()
#cells auto-resizing
headerh = self.table.horizontalHeader()
headerh.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
headerv = self.table.verticalHeader()
headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
conn = sqlite3.connect("math.db")
conn.text_factory = bytes
self.cur = conn.cursor()
data = self.cur.execute("select * from problems;").fetchall();conn.close()
self.dims = (lambda x: (len(x), len(x[0])))(data) #(rows number, col number)
[self.table.insertRow(i) for i in [i for i in range(self.dims[0])]]
[self.table.insertColumn(i) for i in [i for i in range(self.dims[1]+1)]]
#changing h-header names .
self.table.setHorizontalHeaderLabels(["Unique", "Image", "Test", "Year", "Lesson", "Comment", "Options", "Options-advanced"])
for c in range(self.dims[1]):
for r in range(self.dims[0]):
if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(data[r][c].decode("utf-8")))
else:self.table.setCellWidget(r, c, self.getImage(data[r][c]))
for r in range(self.dims[0]):self.table.setCellWidget(r, self.dims[1], Options(ops=[data[r][self.dims[1]-1].decode("utf-8")]))
# connect table signals:
#self.table.cellChanged.connect(self.cell_changed)
#self.table.itemChanged.connect(self.item_changed)
layout.addWidget(self.searchBar)
layout.addWidget(self.btn)
layout.addWidget(self.table)
self.setLayout(layout)
def getImage(self, image):
imageLabel = QLabel()
imageLabel.setText('')
imageLabel.setScaledContents(True)
pixmap = QtGui.QPixmap()
pixmap.loadFromData(image, "jpg")
imageLabel.setPixmap(pixmap)
return imageLabel
def startSearchThreading(self):
self.table.setRowCount(0)
self.update = updateTable(data= self.searchBar.text())
self.update.new_signal.connect(self.Search)
self.update.start()
def create(self):
self.createFormGroupBox()
return self.formGroupBox
@QtCore.pyqtSlot(int, int, bytes, bool, bytes)
def Search(self, r, c, d, newRowOrder, ops):
#print(r, c, d.decode("utf-8"))
if newRowOrder:self.table.insertRow(self.table.rowCount()) # create new row.
if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(d.decode("utf-8")))
else:self.table.setCellWidget(r, c, self.getImage(d))
for r in range(self.dims[1]):self.table.setCellWidget(r, self.dims[1], Options(ops=[ops]))
class updateTable(QtCore.QThread):
def __init__(self, parent=None, data=True):
super(QtCore.QThread, self).__init__()
self.data = data
new_signal = QtCore.pyqtSignal(int, int, bytes, bool, bytes)
def run(self):
currRow = 0
conn = sqlite3.connect("math.db")
conn.text_factory = bytes
self.cur = conn.cursor()
searched = self.cur.execute(" SELECT * FROM problems WHERE text LIKE ('%' || ? || '%') ", (self.data,)).fetchall()
dims = (lambda x: (len(x), len(x[0])))(searched) if searched!=[] else (0, 0)
print(dims)
for r in range(dims[0]):
for c in range(dims[1]):
self.new_signal.emit(r, c, searched[r][c], True if c==0 else False, searched[r][dims[1]-1])
#if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(searched[r][c].decode("utf-8")))
#else:self.table.setCellWidget(r, c, self.getImage(searched[r][c]))
#self.new_signal.emit(1, 2, searched)
class Options(QtWidgets.QWidget):
def __init__(self, parent=None, ops=[]):
super(Options, self).__init__(parent)
self.setStyleSheet("""QTableView::item { border: 0px; padding: 10px;}QTableView{font-size:20px;}QPushButton{width:200px;height:30px}QLineEdit {width:200px;height:50px;}""")
self.i = random.randint(1, 100)
layout = QFormLayout()
layout.addRow(QLabel("Name:"), QLineEdit())
layout.addRow(QLabel("Country:"), QComboBox())
layout.addRow(QLabel("Age:"), QSpinBox())
self.btn = QtWidgets.QPushButton("click")
self.btn.clicked.connect(self.do)
layout.addWidget(self.btn)
self.setLayout(layout)
print(ops)
def do(self):
print(f"clicked {self.i}")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.resize(600,600)
main.show()
app.exec_()
如果您使用带有 setScaledContents
的 QLabel,它将始终尝试缩放内容,同时 忽略 纵横比。
您可以使用 QLabel 的子类,只要 QPixmap 存在且当前大小比率与像素图的大小比率不同,它就会覆盖默认绘制行为。
class ScaledPixmapLabel(QtWidgets.QLabel):
def __init__(self):
super().__init__()
self.setScaledContents(True)
def paintEvent(self, event):
if self.pixmap():
pm = self.pixmap()
originalRatio = pm.width() / pm.height()
currentRatio = self.width() / self.height()
if originalRatio != currentRatio:
qp = QtGui.QPainter(self)
pm = self.pixmap().scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
rect = QtCore.QRect(0, 0, pm.width(), pm.height())
rect.moveCenter(self.rect().center())
qp.drawPixmap(rect, pm)
return
super().paintEvent(event)
class Main(QtWidgets.QWidget):
# ...
def getImage(self, image):
imageLabel = ScaledPixmapLabel()
pixmap = QtGui.QPixmap()
pixmap.loadFromData(image, "jpg")
imageLabel.setPixmap(pixmap)
return imageLabel
PS: 你不需要在一个新的QLabel上使用setText('')
,它已经没有文本了。
我制作了一个 table,其中有一个包含图像的特定列,并使用代码段代码使单元格拉伸到其内容大小:
headerh.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
所以单元格的宽度和高度都根据单元格的内容进行了调整我在这里面临的问题是所有单元格的宽度和高度都调整为最大宽度和高度而不是我想要的这是根据自己的内容调整每个单元格,以便所有图像都能正确显示,不会过度拉伸,从而破坏图像的大小比例,这是我所面对的图像显示:
我希望有一种方法可以使第一个单元格不会像那样拉伸其内容图像! 这是我在没有数据库的情况下编写的完整代码!:
from PyQt5.QtWidgets import (QApplication, QComboBox, QDialog,
QDialogButtonBox, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout,
QLabel, QLineEdit, QMenu, QMenuBar, QPushButton, QSpinBox, QTextEdit,
QVBoxLayout)
import sqlite3
import random
class Main(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Arabic Math Project')
self.setContentsMargins(20,20,20,20)
# create table:
self.setStyleSheet("""QTableView::item { border: 0px; padding: 10px;}QTableView{font-size:20px;}QPushButton{width:200px;height:30px}QLineEdit {width:200px;height:50px;}""")
layout = QVBoxLayout()
self.btn = QtWidgets.QPushButton("click it")
self.searchBar = QtWidgets.QLineEdit()
self.searchBar.setAlignment(QtCore.Qt.AlignCenter)
self.searchBar.setStyleSheet("font-size:35px;")
self.searchBar.setPlaceholderText("search")
self.searchBar.textChanged.connect(self.startSearchThreading) #editingFinished()
self.table = QtWidgets.QTableWidget()
#cells auto-resizing
headerh = self.table.horizontalHeader()
headerh.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
headerv = self.table.verticalHeader()
headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
conn = sqlite3.connect("math.db")
conn.text_factory = bytes
self.cur = conn.cursor()
data = self.cur.execute("select * from problems;").fetchall();conn.close()
self.dims = (lambda x: (len(x), len(x[0])))(data) #(rows number, col number)
[self.table.insertRow(i) for i in [i for i in range(self.dims[0])]]
[self.table.insertColumn(i) for i in [i for i in range(self.dims[1]+1)]]
#changing h-header names .
self.table.setHorizontalHeaderLabels(["Unique", "Image", "Test", "Year", "Lesson", "Comment", "Options", "Options-advanced"])
for c in range(self.dims[1]):
for r in range(self.dims[0]):
if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(data[r][c].decode("utf-8")))
else:self.table.setCellWidget(r, c, self.getImage(data[r][c]))
for r in range(self.dims[0]):self.table.setCellWidget(r, self.dims[1], Options(ops=[data[r][self.dims[1]-1].decode("utf-8")]))
# connect table signals:
#self.table.cellChanged.connect(self.cell_changed)
#self.table.itemChanged.connect(self.item_changed)
layout.addWidget(self.searchBar)
layout.addWidget(self.btn)
layout.addWidget(self.table)
self.setLayout(layout)
def getImage(self, image):
imageLabel = QLabel()
imageLabel.setText('')
imageLabel.setScaledContents(True)
pixmap = QtGui.QPixmap()
pixmap.loadFromData(image, "jpg")
imageLabel.setPixmap(pixmap)
return imageLabel
def startSearchThreading(self):
self.table.setRowCount(0)
self.update = updateTable(data= self.searchBar.text())
self.update.new_signal.connect(self.Search)
self.update.start()
def create(self):
self.createFormGroupBox()
return self.formGroupBox
@QtCore.pyqtSlot(int, int, bytes, bool, bytes)
def Search(self, r, c, d, newRowOrder, ops):
#print(r, c, d.decode("utf-8"))
if newRowOrder:self.table.insertRow(self.table.rowCount()) # create new row.
if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(d.decode("utf-8")))
else:self.table.setCellWidget(r, c, self.getImage(d))
for r in range(self.dims[1]):self.table.setCellWidget(r, self.dims[1], Options(ops=[ops]))
class updateTable(QtCore.QThread):
def __init__(self, parent=None, data=True):
super(QtCore.QThread, self).__init__()
self.data = data
new_signal = QtCore.pyqtSignal(int, int, bytes, bool, bytes)
def run(self):
currRow = 0
conn = sqlite3.connect("math.db")
conn.text_factory = bytes
self.cur = conn.cursor()
searched = self.cur.execute(" SELECT * FROM problems WHERE text LIKE ('%' || ? || '%') ", (self.data,)).fetchall()
dims = (lambda x: (len(x), len(x[0])))(searched) if searched!=[] else (0, 0)
print(dims)
for r in range(dims[0]):
for c in range(dims[1]):
self.new_signal.emit(r, c, searched[r][c], True if c==0 else False, searched[r][dims[1]-1])
#if c!=1:self.table.setItem(r, c, QtWidgets.QTableWidgetItem(searched[r][c].decode("utf-8")))
#else:self.table.setCellWidget(r, c, self.getImage(searched[r][c]))
#self.new_signal.emit(1, 2, searched)
class Options(QtWidgets.QWidget):
def __init__(self, parent=None, ops=[]):
super(Options, self).__init__(parent)
self.setStyleSheet("""QTableView::item { border: 0px; padding: 10px;}QTableView{font-size:20px;}QPushButton{width:200px;height:30px}QLineEdit {width:200px;height:50px;}""")
self.i = random.randint(1, 100)
layout = QFormLayout()
layout.addRow(QLabel("Name:"), QLineEdit())
layout.addRow(QLabel("Country:"), QComboBox())
layout.addRow(QLabel("Age:"), QSpinBox())
self.btn = QtWidgets.QPushButton("click")
self.btn.clicked.connect(self.do)
layout.addWidget(self.btn)
self.setLayout(layout)
print(ops)
def do(self):
print(f"clicked {self.i}")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.resize(600,600)
main.show()
app.exec_()
如果您使用带有 setScaledContents
的 QLabel,它将始终尝试缩放内容,同时 忽略 纵横比。
您可以使用 QLabel 的子类,只要 QPixmap 存在且当前大小比率与像素图的大小比率不同,它就会覆盖默认绘制行为。
class ScaledPixmapLabel(QtWidgets.QLabel):
def __init__(self):
super().__init__()
self.setScaledContents(True)
def paintEvent(self, event):
if self.pixmap():
pm = self.pixmap()
originalRatio = pm.width() / pm.height()
currentRatio = self.width() / self.height()
if originalRatio != currentRatio:
qp = QtGui.QPainter(self)
pm = self.pixmap().scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
rect = QtCore.QRect(0, 0, pm.width(), pm.height())
rect.moveCenter(self.rect().center())
qp.drawPixmap(rect, pm)
return
super().paintEvent(event)
class Main(QtWidgets.QWidget):
# ...
def getImage(self, image):
imageLabel = ScaledPixmapLabel()
pixmap = QtGui.QPixmap()
pixmap.loadFromData(image, "jpg")
imageLabel.setPixmap(pixmap)
return imageLabel
PS: 你不需要在一个新的QLabel上使用setText('')
,它已经没有文本了。