QStyledItemDelegate in QTableView ist falsch ausgerichtetPython

Python-Programme
Anonymous
 QStyledItemDelegate in QTableView ist falsch ausgerichtet

Post by Anonymous »

Ich möchte eine Liste von Dateien mit Sternebewertung in einer QTableView anzeigen. Dazu verwende ich den folgenden Delegaten:

Code: Select all

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

def paint(self, painter, option, index):
file: File = index.data(Qt.UserRole)
star_rating_widget = StarRatingWidget(10, self.parent())
star_rating_widget.set_rating(file.rating)
star_rating_widget.render(painter, option.rect.topLeft())

Code: Select all

StarRatingWidget
Ist ein einfaches QWidget, das 5 QLables in einem QHBoxLayout enthält.
Das funktioniert bisher alles, aber alle StarRatingWidgets werden nach links oben verschoben:
Image

In der ersten Spalte wird die Bewertung als Zahl angezeigt. Sie können sehen, dass alle Sterne leicht nach links und etwas mehr als eine Zeilenhöhe nach oben verschoben sind.
Tests haben ergeben, dass option.rect die Koordinaten mit zurückgibt (0, 0) ist die obere linke Ecke der ersten Zelle, aber star_rating_widget.render behandelt die Koordinaten so, dass (0, 0) die obere linke Ecke des Fensters ist. Die Widgets werden also um den Abstand zwischen Tabelle und Fensterrand und zusätzlich um die Höhe des Tabellenkopfes verschoben.
Bevor jemand fragt, hier der vollständige Code. Zum Ausführen ist pyside6 erforderlich.

Code: Select all

#!/usr/bon/env python

from PySide6.QtCore import Qt, Signal, QAbstractItemModel, QModelIndex, QEvent
from PySide6.QtGui import QMouseEvent
from PySide6.QtWidgets import QApplication, QLabel, QTableView, QMainWindow, QSizePolicy, QHBoxLayout, QWidget, QStyledItemDelegate

class MainWindow(QMainWindow):
def __init__(self):
super().__init__()

self.setGeometry(100, 100, 250, 600)

self.central_widget = QWidget()
self.main_layout = QHBoxLayout()
self.central_widget.setLayout(self.main_layout)
self.setCentralWidget(self.central_widget)

self.list = QTableView()
self.list.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows)
self.list.setSelectionMode(QTableView.SelectionMode.SingleSelection)
self.list.horizontalHeader().setStretchLastSection = True
self.list.verticalHeader().hide()
self.list.show_grid = False
self.list.setItemDelegateForColumn(1, StarRatingDelegate(self.list))
self.list.setModel(ListModel())
self.main_layout.addWidget(self.list)

class ListModel(QAbstractItemModel):
def __init__(self):
super().__init__()
self.horizontal_header_labels = ['Number', 'Stars']

def rowCount(self, parent=QModelIndex()):
return 50

def columnCount(self, parent=QModelIndex()):
return len(self.horizontal_header_labels)

def data(self, index, role):
if not index.isValid():
return None
if role == Qt.DisplayRole:
rating = (index.row() - 2) % 7
return None if rating >= 5 else rating + 1
return None

def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.horizontal_header_labels[section]
return None

def index(self, row, column, parent=QModelIndex()):
if self.hasIndex(row, column, parent):
return self.createIndex(row, column)
return QModelIndex()

def parent(self, index):
return QModelIndex()

class StarRatingWidget(QWidget):
rating_changed = Signal(int)

def __init__(self, font_size, parent=None):
super().__init__(parent)
self.rating = 0
self.hovered_star: int|None = None
self.stars: List[QLabel] = []
self.font_size: int = font_size
self.init_ui()

def star_mouse_event(self, i: int):
def event(event: QMouseEvent):
if event.type() == QEvent.Enter:
self.hovered_star = i
self.update()
elif event.type() == QEvent.Leave:
self.hovered_star = None
self.update()
return event

def init_ui(self):
layout = QHBoxLayout()
for i in range(5):
star = QLabel()
star.mousePressEvent = lambda _, i=i: self.set_rating(i + 1)
star.enterEvent = self.star_mouse_event(i)
star.leaveEvent = self.star_mouse_event(i)
star.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
layout.addWidget(star)
self.stars.append(star)
self.setLayout(layout)
self.update()

def set_rating(self, rating: int|None):
if rating != self.rating:
self.rating = rating
self.update()
self.rating_changed.emit(rating)

def update(self):
for i, star in enumerate(self.stars):
rating = self.rating if self.rating is not None else 0
if i < rating:
star.setText('★')
else:
star.setText('☆')

if self.rating is None:
color = 'gray'
weight = 'normal'
elif i == self.hovered_star:
color = 'blue'
weight = 'bold'
else:
color = 'yellow'
weight = 'normal'

star.setStyleSheet(f'font-size: {self.font_size}px; color: {color};  font-weight: {weight}')

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

def paint(self, painter, option, index):
rating = index.data()
star_rating_widget = StarRatingWidget(10, self.parent())
star_rating_widget.set_rating(rating)
star_rating_widget.render(painter, option.rect.topLeft())

def main():
app = QApplication([])
main_window = MainWindow()
main_window.show()
QApplication.exec()

if __name__ == '__main__':
main()

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post