Created
April 6, 2025 21:10
-
-
Save minimalefforttech/8bfa6fefed5e209c25bbdb1cab32b2ea to your computer and use it in GitHub Desktop.
Styled Qt Delegate with complex data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from PySide6 import QtWidgets, QtCore, QtGui | |
reference_date = QtCore.QDate(2025, 4, 7) | |
SAMPLE_TICKET_DATA = [ | |
{ | |
"id": "PIPE-101", | |
"summary": "Fix pipeline issue", | |
"assignee": "Alice Tinker", | |
"comments": 2, | |
"updated": reference_date.addDays(-3).toString("yyyy-MM-dd"), | |
"reporter": "Emma Williams" | |
}, | |
{ | |
"id": "IT-202", | |
"summary": "Resolve network problem", | |
"assignee": "Bob Morgan", | |
"comments": 0, | |
"updated": reference_date.addDays(-8).toString("yyyy-MM-dd"), | |
"reporter": "David Chen" | |
}, | |
{ | |
"id": "CREHELP-303", | |
"summary": "Creature animation bug", | |
"assignee": "Charlie Park", | |
"comments": 14, | |
"updated": reference_date.addDays(-1).toString("yyyy-MM-dd"), | |
"reporter": "Sophia Rodriguez" | |
}, | |
{ | |
"id": "PIPE-104", | |
"summary": "Optimize data flow", | |
"assignee": "Alice Tinker", | |
"comments": 0, | |
"updated": reference_date.addDays(-12).toString("yyyy-MM-dd"), | |
"reporter": "Michael Johnson" | |
}, | |
{ | |
"id": "IT-205", | |
"summary": "Install new software", | |
"assignee": "Bob Morgan", | |
"comments": 0, | |
"updated": reference_date.addDays(-6).toString("yyyy-MM-dd"), | |
"reporter": "Olivia Smith" | |
} | |
] | |
class TicketItemDelegate(QtWidgets.QStyledItemDelegate): | |
def sizeHint(self, option, index): | |
# Ideally you would get this from the actual data | |
return QtCore.QSize(option.rect.width(), 60) | |
def paint(self, painter, option, index): | |
painter.save() | |
ticket = index.data(QtCore.Qt.DisplayRole) | |
if option.state & QtWidgets.QStyle.State_Selected: | |
painter.fillRect(option.rect, option.palette.highlight()) | |
rect = option.rect | |
left_margin = 10 | |
initials = "".join([name[0].upper() for name in ticket["reporter"].split() if name]) | |
circle_size = 30 | |
circle_rect = QtCore.QRect( | |
rect.left() + left_margin, | |
rect.top() + (rect.height() - circle_size) // 2, | |
circle_size, | |
circle_size | |
) | |
# This creates a circle color based on the persons name, like we see in many apps | |
painter.setRenderHint(QtGui.QPainter.Antialiasing) | |
name_hash = sum([ord(c) for c in ticket["reporter"]]) | |
hue = (name_hash % 360) / 360.0 | |
color = QtGui.QColor.fromHslF(hue, 0.7, 0.5) | |
painter.setBrush(QtGui.QBrush(color)) | |
painter.setPen(QtCore.Qt.NoPen) | |
painter.drawEllipse(circle_rect) | |
painter.setPen(QtCore.Qt.white) | |
painter.drawText(circle_rect, QtCore.Qt.AlignCenter, initials) | |
text_left = circle_rect.right() + 10 | |
text_width = rect.width() - text_left - 10 | |
id_rect = QtCore.QRect( | |
text_left, | |
rect.top() + 2, | |
text_width - 100, | |
20 | |
) | |
painter.setPen(option.palette.text().color()) | |
painter.drawText(id_rect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop, ticket["id"]) | |
summary_rect = QtCore.QRect( | |
text_left, | |
id_rect.bottom() - 2, | |
text_width - 100, | |
20 | |
) | |
painter.drawText(summary_rect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop, ticket["summary"]) | |
assignee_rect = QtCore.QRect( | |
rect.right() - 150, | |
rect.top() + 2, | |
140, | |
20 | |
) | |
painter.drawText(assignee_rect, QtCore.Qt.AlignRight | QtCore.Qt.AlignTop, ticket["assignee"]) | |
# Remember that you can use unicode characters in strings to reduce the text you need. | |
comments_text = f"{ticket['comments']} 🗩" | |
comments_rect = QtCore.QRect( | |
rect.right() - 150, | |
assignee_rect.bottom() - 2, | |
140, | |
20 | |
) | |
painter.drawText(comments_rect, QtCore.Qt.AlignRight | QtCore.Qt.AlignTop, comments_text) | |
updated_date = QtCore.QDate.fromString(ticket["updated"], "yyyy-MM-dd") | |
current_date = QtCore.QDate.currentDate() | |
days_diff = updated_date.daysTo(current_date) | |
days_text = f"{days_diff} days ago" | |
days_rect = QtCore.QRect( | |
rect.right() - 150, | |
comments_rect.bottom() - 2, | |
140, | |
20 | |
) | |
painter.drawText(days_rect, QtCore.Qt.AlignRight | QtCore.Qt.AlignTop, days_text) | |
painter.restore() | |
class TicketListWidget(QtWidgets.QWidget): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
layout = QtWidgets.QVBoxLayout(self) | |
list_view = QtWidgets.QListView() | |
list_view.setAlternatingRowColors(True) | |
delegate = TicketItemDelegate(self) | |
list_view.setItemDelegate(delegate) | |
model = QtGui.QStandardItemModel() | |
list_view.setModel(model) | |
list_view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) | |
list_view.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) | |
layout.addWidget(list_view) | |
self.setMinimumSize(500, 300) | |
self.setWindowTitle("Ticket List View") | |
# Load the sample data | |
for ticket in SAMPLE_TICKET_DATA: | |
item = QtGui.QStandardItem() | |
item.setData(ticket, QtCore.Qt.DisplayRole) | |
model.appendRow(item) | |
if __name__ == "__main__": | |
import sys | |
app = QtWidgets.QApplication(sys.argv) | |
widget = TicketListWidget() | |
widget.show() | |
sys.exit(app.exec()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment