Issue
i made a table with a certain column that holds images and made cells stretch to its content size with the snippet code:
headerh.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
headerv.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
so both width and height of cells are adjusted to the content of the cells the problems i'm facing here is that the width and height of all cells are adjusted to the maximum width and height not wut i want which is adjusting every cell to its own content so all images shows correctly with no over stretching that ruins the size ratio of the image and here is an image shows wut i'm facing:
i wish there is a way to make the first cell not stretch its content image like that ! and here is the complete code i'm writing without the database !:
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_()
Solution
If you're using a QLabel with setScaledContents
, it will always try to scale the contents while ignoring the aspect ratio.
You can use a subclass of QLabel that overrides the default painting behavior whenever a QPixmap exists and the current size ratio is different from that of the pixmap.
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: You don't need to use setText('')
on a new QLabel, it already has no text.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.