Меня попросили (для некоммерческой организации) написать приложение, которое будет работать на Pi и отображать на экране список гонщиков, разделенных на 3 вертикальные секции (на трассе (1), у ворот (1) и В очереди(до 50)). Ожидается, что в разделе «В очереди» будут показаны не все записи, а только следующие 10.
Сначала список будет получен из файла CSV на USB-накопителе. Список на экране должен прокручиваться на основе внешнего ввода, когда гонщики проходят через стартовые ворота, с механизмом блокировки (экранные кнопки, аппаратные кнопки и т. д.) вверх или вниз в случае возникновения проблем. Каждая строка списка будет состоять примерно из 3 записей - например, стартовый номер, имя и предыдущее время выполнения.
Прокрутка должна быть такой, как если бы три раздела списка были одним разделом. то есть должно измениться одно действие прокрутки: гонщик «На трассе» прокручивается за пределы верхней части экрана, гонщик «В воротах» становится гонщиком «На трассе», а гонщик, находящийся сверху в очереди, становится следующим гонщиком «В воротах».
Меня попросили дать еще какое-то объяснение того, как будет работать прокрутка, пытаться что-то смоделировать здесь сложно, но помогает ли это:
Начальный экран:
Racer on Course:
[blank]
Racer in Gate:
10, Jo Blogs, 13.3
Racers in Queue:
11, John Harrow, 13.4
12, Lynne Graham, 13.5
13, Lindsey Vonn, 14.5
Экран после первого действия «прокрутки»:
Racer on Course:
10 Jo Blogs 13.3
Racer in Gate:
11, John Harrow, 13.4
Racers in Queue:
12, Lynne Graham, 13.5
13, Lindsey Vonn, 14.5
Экран после второго действия «прокрутки»:
Racer on Course:
11,John Harrow,13.4
Racer in Gate:
12,Lynne Graham,13.5
Racers in Queue:
13,Lindsey Vonn,14.5
Нет необходимости редактировать или сохранять какие-либо данные — просто отображайте их в формате CSV.
Я решил использовать Python 3 и PyQt5, так как они кроссплатформенные и широко используются, много примеров, руководств и т. д.
Я использовал Python несколько раз за последние 15 лет, но мои навыки объектно-ориентированного программирования слабы, и я никогда раньше не использовал Qt.
Пример CSV может выглядеть так:
10,Jo Blogs,13.3
11,John Harrow,13.4
12,Lynne Graham,13.5
13,Lindsey Vonn,14.5
Приложение (без загруженных данных) может выглядеть так:

До сих пор я прошел через несколько руководств, в том числе Zetcode: http://zetcode.com/gui/pyqt5 и создал себе (также известный как объединенные примеры вместе) некоторый начальный код, который поможет мне начать работу, но я застрял на нескольких фундаментальных вопросах, для ответа на которые у меня нет знаний. принимать правильные решения сейчас, чтобы они не доставляли мне серьезных проблем позже.
Является ли QTreeWidget/QTreeView правильным виджетом Qt для использования на дисплее?
QTreeWidget и QtreeView. Я понимаю, что разница заключается в том, что данные хранятся в виджете и в модели данных, а виджет просто отображает эти данные, но я не знаю, как правильно поступить для меня и этого приложения.
Прокрутка строк через 3 виджета как единое целое. Какой самый простой/лучший/правильный способ настроить это?
У меня есть несколько указаний относительно того, куда я могу пойти дальше:
Настройка древовидных представлений — https://pythonspot.com/pyqt5-treeview/
Загрузка данных CSV в виджет — pyqt — заполнение QTableWidget данными csv
Любая положительная помощь, указатели, архитектурное направление приветствуются.
Большое спасибо
Мой код пока для справки...
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import (QMainWindow, QTextEdit, QWidget, QLabel, QGridLayout, QLineEdit, QPlainTextEdit,
QTreeView, QAction, QFileDialog, QApplication, qApp)
from PyQt5.QtGui import QIcon
import sys
class Start(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# Build Status Bar
self.statusBar()
# File Menu File > Open Action
openFile = QAction(QIcon('open.png'), 'Open', self)
openFile.setShortcut('Ctrl+O')
openFile.setStatusTip('Open new File')
openFile.triggered.connect(self.showOpenDialog)
# File Menu File > Exit Action
exitAct = QAction(QIcon('exit.png'), '&Exit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('Exit application')
exitAct.triggered.connect(qApp.quit)
# Build Menu Bar
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(openFile)
fileMenu.addAction(exitAct)
self.widget = QWidget()
self.setCentralWidget(self.widget)
# Build Central Widget
lblOnCourse = QLabel('Racer On Course:', self)
lblInGate = QLabel('Racer In gate:', self)
lblInQueue = QLabel('Racers In Queue:', self)
grid = QGridLayout()
grid.setSpacing(10)
OnCourse = QTreeView()
InGate = QTreeView()
InQueue = QTreeView()
InQueue.setRootIsDecorated(False)
#InQueue.dataView.setAlternatingRowColors(True)
grid.addWidget(lblOnCourse, 1, 0)
grid.addWidget(OnCourse, 1, 1)
grid.addWidget(lblInGate, 2, 0)
grid.addWidget(InGate, 2, 1)
grid.addWidget(lblInQueue, 3, 0)
grid.addWidget(InQueue, 3, 1, 5, 1)
self.widget.setLayout(grid)
# Show QMainWindow
self.showMaximized()
#self.showFullScreen()
#self.show()
def showOpenDialog(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/')
if fname[0]:
f = open(fname[0], 'r')
with f:
data = f.readlines()
#self.textEdit.setText(data)
self.statusBar().showMessage('Loaded: ' + str(len(data)) + '. ')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Start()
sys.exit(app.exec_())
Спасибо @eyllanesc. Я обновил свой пост, добавив пример csv и изображение. Таким образом, в начале, когда CSV загружается, «В курсе» будет пустым, «В воротах» будет строка 1 CSV, а «В очереди» будут все остальные строки CSV. в нем (хотя не обязательно показывать их все из-за размера экрана). После того, как 1-й гонщик прошел через ворота (т.е. после первого действия «прокрутки»), «В пути» будет ряд 1, «В воротах» ряд 2, «В очереди» ряд 3 и далее. После того, как 2-й гонщик прошел через ворота, «В пути» будет ряд 2, «В воротах» — ряд 3 и т. д.
Мне уже более понятно, что вы хотите, 1) но у меня есть сомнения по поводу следующего предложения: После того, как 1-й гонщик прошел через ворота (т.е. после первого действия «прокрутки»), Что именно это означает? Означает ли это, что вертикальная полоса прокрутки виджета перемещается или что-то еще? 2) Кроме того, где CSV?
Привет, Пример csv находится в сообщении: 10, Джо Блоги, 13,3 11, Джон Блоги, 13,4 12, Линн Грэм, 13,5 13, Л Вонн, 14,5. До 50 строк, как указано выше. Позвольте мне смоделировать что-нибудь, чтобы показать «прокрутку».
Когда следует выполнить действие «прокрутить»?
Действие «Прокрутка» должно выполняться при получении внешнего импульса через GPIO от стартовых ворот. На экране также должно быть 2 кнопки, одна из которых реализует «прокрутку» в 1 строку, как если бы были запущены стартовые ворота, а вторая кнопка реализует «обратную прокрутку».
Т.к. доступа к GPIO у меня нет, учитывать не буду. Итак, я буду считать, что есть 2 кнопки: «прокрутка» и «обратная прокрутка», первая делает то, что вы указываете в вопросе, а вторая - наоборот. Я не ошибаюсь?
Извините, если это окажется трудным, позвольте мне попробовать другой способ. У нас есть 50 гонщиков, стоящих в очереди в порядке, указанном в CSV. Первый гонщик находится в стартовых воротах, остальные в очереди. Первый гонщик проходит через стартовые ворота (запуская импульс) на трассу, а второй гонщик входит в стартовые ворота. Таким образом, в этот момент первый гонщик в CSV-файле находится «в гонке», второй гонщик — «в стартовых воротах», а остальные гонщики все еще находятся в порядке «в очереди». Гонщики переходят из очереди к воротам и далее к трассе, каждый из которых проходит дистанцию на свое время.
"2 кнопки: "прокрутка" и "обратная прокрутка", первая делает то, что вы указываете в вопросе, а вторая делает противоположное." - Абсолютно. Я могу добавить GPIO для запуска действия «Прокрутка» за пределами исходного кода.
Не усложняйте себе слишком много, я не хочу, чтобы это произошло в реальной жизни (датчики и т.д.). Меня интересует только то, какое поведение вы хотите получить в графическом интерфейсе. Лучше разделить каждую часть, учитывая, что другой не существует, так как создается меньшая сложность.






Итак, с помощью Fiverr у меня появился рабочий код. Заполнение данных в QTree решается следующим образом:
# Create some data:
data = ['XXX' for _ in range(8)]
# Create instance of QTreeView
IG = QTreeView()
# Create a View Model
IGM = self.prepModel(IG)
# Populate View Model
fillModel(IGM, data[1:2])
def prepModel(self, widget):
# initialize a model
model = QStandardItemModel()
# remove indentation and headers
widget.setIndentation(0)
widget.setHeaderHidden(1)
# add (data) model to widget
widget.setModel(model)
return model
def fillModel(self, model, data):
for i, d in enumerate(data):
model.setItem(i, QStandardItem(d))
return
Различное (количество) строк в разных QTreeView выполняется путем заполнения QTreeViewModel различными (количествами) данных:
def display(self):
# show the first
self.fillModel(self.OCM, self.data[0:1])
# show the second
self.fillModel(self.IGM, self.data[1:2])
# show the first (n) of the rest
#self.fillModel(self.IQM, self.data[2:self.displayMaxIQRows + 2])
# show the full queue (-1 doesn't show last?)
self.fillModel(self.IQM, self.data[2:len(self.data)])
Прокрутка выполняется путем перемещения данных между двумя массивами перед повторным запуском display для заполнения QTreeViewModel.
def scroll(self):
# add first element to past data
self.pastData = self.pastData + self.data[0:1]
# remove the first element from data
self.data.pop(0)
# refresh the racers list
self.displayRacers()
return
Надеюсь, это поможет кому-то еще в будущем.
Ваше здоровье Кев
вы могли бы лучше объяснить, может быть, на реальном примере, вы могли бы показать пример csv. Насколько я понял ваш виджет должен иметь 3 раздела: Курс, Ворота и Очередь, и Очередь показывать часть CSV, Курс строку CSV но я не знаю какую строку, и то же самое для Ворот. Не помещайте ненужные тексты, потому что часто они приводят к тому, что никто не читает ваш вопрос.