PyQt5 — советы по импорту, отображению и прокрутке CSV — представления и виджеты, QTreeView и другие

Меня попросили (для некоммерческой организации) написать приложение, которое будет работать на 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

Приложение (без загруженных данных) может выглядеть так:

PyQt5 — советы по импорту, отображению и прокрутке CSV — представления и виджеты, QTreeView и другие

До сих пор я прошел через несколько руководств, в том числе Zetcode: http://zetcode.com/gui/pyqt5 и создал себе (также известный как объединенные примеры вместе) некоторый начальный код, который поможет мне начать работу, но я застрял на нескольких фундаментальных вопросах, для ответа на которые у меня нет знаний. принимать правильные решения сейчас, чтобы они не доставляли мне серьезных проблем позже.

  1. Является ли QTreeWidget/QTreeView правильным виджетом Qt для использования на дисплее?

  2. QTreeWidget и QtreeView. Я понимаю, что разница заключается в том, что данные хранятся в виджете и в модели данных, а виджет просто отображает эти данные, но я не знаю, как правильно поступить для меня и этого приложения.

  3. Прокрутка строк через 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_())

вы могли бы лучше объяснить, может быть, на реальном примере, вы могли бы показать пример csv. Насколько я понял ваш виджет должен иметь 3 раздела: Курс, Ворота и Очередь, и Очередь показывать часть CSV, Курс строку CSV но я не знаю какую строку, и то же самое для Ворот. Не помещайте ненужные тексты, потому что часто они приводят к тому, что никто не читает ваш вопрос.

eyllanesc 08.04.2019 14:55

Спасибо @eyllanesc. Я обновил свой пост, добавив пример csv и изображение. Таким образом, в начале, когда CSV загружается, «В курсе» будет пустым, «В воротах» будет строка 1 CSV, а «В очереди» будут все остальные строки CSV. в нем (хотя не обязательно показывать их все из-за размера экрана). После того, как 1-й гонщик прошел через ворота (т.е. после первого действия «прокрутки»), «В пути» будет ряд 1, «В воротах» ряд 2, «В очереди» ряд 3 и далее. После того, как 2-й гонщик прошел через ворота, «В пути» будет ряд 2, «В воротах» — ряд 3 и т. д.

Kevin W 08.04.2019 16:45

Мне уже более понятно, что вы хотите, 1) но у меня есть сомнения по поводу следующего предложения: После того, как 1-й гонщик прошел через ворота (т.е. после первого действия «прокрутки»), Что именно это означает? Означает ли это, что вертикальная полоса прокрутки виджета перемещается или что-то еще? 2) Кроме того, где CSV?

eyllanesc 08.04.2019 16:57

Привет, Пример csv находится в сообщении: 10, Джо Блоги, 13,3 11, Джон Блоги, 13,4 12, Линн Грэм, 13,5 13, Л Вонн, 14,5. До 50 строк, как указано выше. Позвольте мне смоделировать что-нибудь, чтобы показать «прокрутку».

Kevin W 08.04.2019 19:27

Когда следует выполнить действие «прокрутить»?

eyllanesc 08.04.2019 20:28

Действие «Прокрутка» должно выполняться при получении внешнего импульса через GPIO от стартовых ворот. На экране также должно быть 2 кнопки, одна из которых реализует «прокрутку» в 1 строку, как если бы были запущены стартовые ворота, а вторая кнопка реализует «обратную прокрутку».

Kevin W 08.04.2019 21:00

Т.к. доступа к GPIO у меня нет, учитывать не буду. Итак, я буду считать, что есть 2 кнопки: «прокрутка» и «обратная прокрутка», первая делает то, что вы указываете в вопросе, а вторая - наоборот. Я не ошибаюсь?

eyllanesc 08.04.2019 21:03

Извините, если это окажется трудным, позвольте мне попробовать другой способ. У нас есть 50 гонщиков, стоящих в очереди в порядке, указанном в CSV. Первый гонщик находится в стартовых воротах, остальные в очереди. Первый гонщик проходит через стартовые ворота (запуская импульс) на трассу, а второй гонщик входит в стартовые ворота. Таким образом, в этот момент первый гонщик в CSV-файле находится «в гонке», второй гонщик — «в стартовых воротах», а остальные гонщики все еще находятся в порядке «в очереди». Гонщики переходят из очереди к воротам и далее к трассе, каждый из которых проходит дистанцию ​​на свое время.

Kevin W 08.04.2019 21:05

"2 кнопки: "прокрутка" и "обратная прокрутка", первая делает то, что вы указываете в вопросе, а вторая делает противоположное." - Абсолютно. Я могу добавить GPIO для запуска действия «Прокрутка» за пределами исходного кода.

Kevin W 08.04.2019 21:06

Не усложняйте себе слишком много, я не хочу, чтобы это произошло в реальной жизни (датчики и т.д.). Меня интересует только то, какое поведение вы хотите получить в графическом интерфейсе. Лучше разделить каждую часть, учитывая, что другой не существует, так как создается меньшая сложность.

eyllanesc 08.04.2019 21:07
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
10
719
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, с помощью 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

Надеюсь, это поможет кому-то еще в будущем.

Ваше здоровье Кев

Другие вопросы по теме