I have been asked (for a non-commercial organisation) to write an application that will run on a Pi and display on a screen a list of Racers, separated into 3 vertical sections (On Course (1), In Gate (1) and In Queue(up to 50)). The 'In Queue' section is not expected to show all entries - just the next 10 say.
The list will initially come from a CSV file on a USB stick. The list on-screen should scroll based on an external input as the racers go through the start gate, with an override mechanism (on-screen buttons, hardware buttons, etc) up or down in case of issues. Each row of the list will consist of 3 or so entries - bib number, name and previous run time for example.
Scrolling should be as if the three sections of the list were one section. i.e. a single scroll action should change: the On Course racer scrolls off the top of the screen, the In Gate racer becomes the On Course racer, and the top In Queue racer becomes the next In Gate racer.
I have been asked for some more explanation of how the scrolling would work, trying to mock something up here is hard, but does this help:
Starting Screen:
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
Screen after first 'scroll' action:
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
Screen after second 'scroll' action:
Racer on Course:
11,John Harrow,13.4
Racer in Gate:
12,Lynne Graham,13.5
Racers in Queue:
13,Lindsey Vonn,14.5
There is no requirement to edit or save any of the data - just display as per the CSV.
I have decided to use Python 3 and PyQt5 as they are cross-platform and in wide use, lots of examples, tutorials, etc.
I have used Python several times over the past 15 years, but my Object Oriented skills are weak and I have not used Qt before.
An example CSV might look like:
10,Jo Blogs,13.3
11,John Harrow,13.4
12,Lynne Graham,13.5
13,Lindsey Vonn,14.5
The application (without any data loaded) might look like this:
I have been through several tutorials so far, including the Zetcode one: http://zetcode.com/gui/pyqt5 and built myself (aka joined examples together) some initial code that gets me started, but I am stuck over a few fundamental questions that I don't have the knowledge to make the right decisions on now, so that they don't cause me significant issues later.
Is QTreeWidget / QTreeView the right Qt Widget to use for the display?
QTreeWidget vs QtreeView - I understand the difference is around the data being stored within the widget vs in a data model and the widget just displaying that data - but I don't know the right way to go for me and this application.
Scrolling lines through 3 widgets as a single entity - What is the simplest / best / right way to set that up?
I have some pointers as to where I might go next:
Setup TreeViews - https://pythonspot.com/pyqt5-treeview/
Loading a CSV data into a Widget - pyqt - populating QTableWidget with csv data
Any positive help, pointers, architectural direction appreciated.
Thanks very much
My code so far for reference...
#!/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_())