#python #qt #pyqt #pyside
Вопрос:
Пользовательская модель данных, которую я представлю ниже на основе QAbstractListModel, будет представлена в двух представлениях: интерфейс управления на основе QWidget и «панель мониторинга» на основе QML. Сторона управления на основе QWidget должна отображать элементы модели (строки модели) в пользовательском делегате с каждой точкой данных с указанными пользовательскими ролями в модели, описанной ниже, а также, по крайней мере, предоставлять кнопку для вызова виджета редактора для изменения точек данных, предоставляемых ролями (т. е. дата или начальный час для определенных элементов).
class ScheduleModel(QAbstractListModel):
SfiRole = Qt.UserRole 1
NameRole = Qt.UserRole 2
ClsRole = Qt.UserRole 3
FlagRole = Qt.UserRole 4
OwnrRole = Qt.UserRole 5
RecordRole = Qt.UserRole 6
DeptRole = Qt.UserRole 7
DateStrRole = Qt.UserRole 8
HourRole = Qt.UserRole 9
EstTimeRole = Qt.UserRole 10
StatusRole = Qt.UserRole 11
def __init__(self, parent=None):
super().__init__(parent)
self._data = []
def rowCount(self, parent=QModelIndex()):
return len(self._data)
@Slot()
def updateSchedule(self, schedule_items: list):
self.beginResetModel()
self._data = schedule_items
self.endResetModel()
def data(self, index=QModelIndex(), role: int = Qt.DisplayRole):
if 0 <= index.row() < self.rowCount() and index.isValid():
item = self._data[index.row()]
if role == self.SfiRole:
return item.sfi
elif role == self.NameRole:
return item.item_name
elif role == self.ClsRole:
return item.class_attendance
elif role == self.FlagRole:
return item.flag_attendance
elif role == self.OwnrRole:
return item.owner_attendance
elif role == self.RecordRole:
return item.record_status
elif role == self.DeptRole:
return item.responsible_dept
elif role == self.DateStrRole:
return item.date
elif role == self.HourRole:
return item.start_hour
elif role == self.EstTimeRole:
return item.est
elif role == self.StatusRole:
return "Passive"
else:
return None
def roleNames(self):
roles = dict()
roles[self.SfiRole] = b'sfiRole'
roles[self.NameRole] = b'nameRole'
roles[self.ClsRole] = b'clsRole'
roles[self.FlagRole] = b'flagRole'
roles[self.OwnrRole] = b'ownrRole'
roles[self.RecordRole] = b'recordRole'
roles[self.DeptRole] = b'deptRole'
roles[self.DateStrRole] = b'dateStrRole'
roles[self.HourRole] = b'hourRole'
roles[self.EstTimeRole] = b'estTimeRole'
roles[self.StatusRole] = b'statusRole'
return roles
Модель, описанная выше, работает для сохранения данных и вызова по именам индексов и ролей. Я предпочитаю использовать QListView и QStyledItemDelegate для отображения данных в представлении на основе Qt. Насколько я сейчас понимаю, я должен разработать метод рисования для целей отображения, а для базовых моделей Qt использует DisplayRole для чтения строк из моделей данных. Но, как вы можете видеть из модели, я не облегчил роль dispplay, и у меня есть несколько пользовательских ролей для отображения точек данных для каждого элемента в модели.
Я пытаюсь создать метод рисования для делегата, который наследуется от QStyledItemDelegate, чтобы нарисовать что-то подобное этому. Например, я отметил роли на картинке.
Короче говоря, вопрос в следующем: можно ли переопределить метод рисования QStyledItemDelegate для отображения строк, предоставляемых пользовательскими ролями данных, а также отобразить, можно ли рисовать кнопки для вызова виджета редактора в пользовательском делегате?
Комментарии:
1. Представление элемента на основе виджета Qt по умолчанию отображает данные на основе ролей:
DisplayRole
возвращает печатаемое значение (строку или число),BackgroundRole
иForegroundRole
используются для цвета фона и текста элемента соответственно и т. Д. Каждая запись должна содержать только одно поле и возвращать данные только об этом поле, но, видя ваши пользовательские имена ролей, кажется, что в вашей модели данных для каждой записи много полей, поэтому вам, вероятно, следует вместо этого выбрать табличную модель.2. Я тоже рассматривал это в течение очень короткого периода. Но мне показалось, что это неправильно, потому что «расписание», с которым я работаю, также поставляется в виде электронной таблицы Excel. Таким образом, я хочу представить данные в более «округленном» виде на стороне управления на основе QWidget. По этой причине я ищу метод «по книге» для использования пользовательских ролей в QListView. Надеюсь, я смогу объясниться. Я все еще относительно новичок в программировании пользовательского интерфейса.
3. Если вы имеете в виду, что хотите изменить способ отображения записей пользователю, это не проблема: делегаты также используются именно по этой причине. Если вы уточните, что должно отображаться в представлении списка, мы сможем лучше понять, что вы пытаетесь сделать, а затем дадим вам более подходящие ответы.
4. Отредактировал мой вопрос, чтобы немного прояснить проблему. @musicamante спасибо, что терпишь меня.
5. @PerturbedMachinist ваш вопрос неясен
Ответ №1:
Я попытался создать решение на основе QWidget и потерпел неудачу. После этого попробуйте создать и раскрасить метод, чтобы добиться того вида, который я хотел. Я оставляю свой класс делегата и метод рисования ниже в качестве примера сложного делегата.
class TestItemDelegate(QStyledItemDelegate):
"""A delegate to show test items in listview in qt side"""
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.model = self.parent().model()
def paint(self, painter: QPainter,
option: QStyleOptionViewItem, index: QModelIndex):
model_ind = index.model()
canvas = option.rect.getRect()
painter.setRenderHint(QPainter.Antialiasing, on=True)
# Supplying data from model
sfi = index.data(model_ind.SfiRole)
name = index.data(model_ind.NameRole)
cls_att = index.data(model_ind.ClsRole)
flg_att = index.data(model_ind.FlagRole)
ownr_att = index.data(model_ind.OwnrRole)
# rec_stat = index.data(model_ind.RecordRole)
resp_dept = index.data(model_ind.DeptRole)
date_str = index.data(model_ind.DateStrRole)
hour_str = index.data(model_ind.HourRole)
est_duration = index.data(model_ind.EstTimeRole)
# status = model_ind.data(index, model_ind.StatusRole)
# Frame and Background(s)
pen = QPen()
pen.setColor("Black")
pen.setWidth(2)
painter.setPen(pen)
painter.drawRoundedRect(option.rect, 10, 10)
painter.setPen(Qt.blue)
# Coordinates for delegate background
x, y, w, h = canvas
# Drawing of the texts
painter.drawText(
QRect(x 50, y, w-200, h//2),
Qt.AlignVCenter, name)
painter.drawText(
QRect(x, y, h, h),
Qt.AlignCenter, sfi)
painter.drawText(
QRect(x w-150, y, 50, h//3),
Qt.AlignVCenter,
"C:{}".format('-' if cls_att == '' else cls_att))
painter.drawText(
QRect(x w-150, y h//3, 50, h//3),
Qt.AlignVCenter,
"F:{}".format('-' if flg_att == '' else flg_att))
painter.drawText(
QRect(x w-150, y 2*h//3, 50, h//3),
Qt.AlignVCenter,
"O:{}".format('-' if ownr_att == '' else ownr_att))
painter.drawText(
QRect(x 50, y h//2, w//3, h//2),
Qt.AlignVCenter, resp_dept)
painter.drawText(
QRect(x w-100, y, 100, h//2),
Qt.AlignCenter, date_str.strftime('%d-%m-%Y')
)
painter.drawText(
QRect(x w-100, y h//2, 50, h//2),
Qt.AlignCenter, hour_str.strftime('%H:%M')
)
painter.drawText(
QRect(x w-50, y h//2, 50, h//2),
Qt.AlignCenter, est_duration
)
def createEditor(self, parent, option, index):
print(type(parent))
def sizeHint(self, option, index):
size = QSize(300, 50)
return size
Я установил модель как выбираемую и редактируемую с помощью метода флагов модели.
def flags(self, index):
if index.isValid():
return (Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable)
return super().flags(index)
Прямо сейчас я создаю виджет редактора и относительные методы. Возможно, обновите этот ответ, чтобы оставить исчерпывающий ответ после того, как я найду приемлемое решение.