Skip to content

Instantly share code, notes, and snippets.

@minimalefforttech
Created April 6, 2025 21:10
Show Gist options
  • Save minimalefforttech/8bfa6fefed5e209c25bbdb1cab32b2ea to your computer and use it in GitHub Desktop.
Save minimalefforttech/8bfa6fefed5e209c25bbdb1cab32b2ea to your computer and use it in GitHub Desktop.
Styled Qt Delegate with complex data
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