【问题标题】:PyQt5 - CSV Import, Display and Scroll advice - Views vs Widgets, QTreeView vs OthersPyQt5 - CSV 导入、显示和滚动建议 - 视图与小部件、QTreeView 与其他
【发布时间】:2019-08-29 14:59:27
【问题描述】:

我被要求(为非商业组织)编写一个应用程序,该应用程序将在 Pi 上运行并在屏幕上显示赛车手列表,分为 3 个垂直部分(在球场 (1)、在门内 ( 1) 和队列中(最多 50 个))。 “队列中”部分预计不会显示所有条目 - 仅显示接下来的 10 个条目。

列表最初来自 U 盘上的 CSV 文件。当赛车手通过起跑门时,屏幕上的列表应根据外部输入滚动,并在出现问题时向上或向下滚动覆盖机制(屏幕按钮、硬件按钮等)。列表的每一行将包含 3 个左右的条目 - 例如书目号、姓名和之前的运行时间。

滚动应该就像列表的三个部分是一个部分一样。即单个滚动动作应该改变:On Course 赛车手滚动离开屏幕顶部,In Gate 赛车手变成 On Course 赛车手,而顶部 In Queue 赛车手变成下一个 In Gate 赛车手。

有人要求我提供更多关于滚动如何工作的解释,试图在这里模拟一些东西很难,但这有帮助吗:

开始屏幕:

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,因为它们是跨平台的并且被广泛使用,有很多示例、教程等。

在过去的 15 年中,我曾多次使用 Python,但我的面向对象技能较弱,之前没有使用过 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 并自己构建了一些初始代码(也就是将示例组合在一起),这些代码让我开始学习,但我被一些我不知道的基本问题所困扰'没有知识现在就做出正确的决定,以免以后给我造成重大问题。

  1. QTreeWidget / QTreeView 是用于显示的正确 Qt Widget 吗?

  2. QTreeWidget 与 QtreeView - 我了解不同之处在于存储在小部件与数据模型中的数据和小部件仅显示该数据 - 但我不知道适合我的正确方法和这个应用程序。

  3. 作为一个实体在 3 个小部件中滚动行 - 设置它的最简单/最好/正确的方法是什么?

我有一些关于我下一步可能去哪里的指示:

设置树视图 - https://pythonspot.com/pyqt5-treeview/

将 CSV 数据加载到小部件中 - pyqt - populating QTableWidget with csv data

感谢任何积极的帮助、指点和架构方向。

非常感谢

到目前为止我的代码供参考...

#!/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 个部分:Course、Gate 和 Queue,并且 Queue 显示 CSV 的一部分,Course 是 CSV 的一行,但我不知道是哪一行,Gate 也是如此。不要放不必要的文字,因为很多时候它们会导致没有人阅读您的问题。
  • 谢谢@eyllanesc 我已经用示例 csv 和图像更新了我的帖子。总之,在开始加载 CSV 时,“In Course”将为空,“In Gate”将包含 CSV 的第 1 行,而“In Queue”将包含 CSV 的所有其余行在其中(尽管由于屏幕大小不一定会全部显示)。在第一个赛车手通过大门后(即在第一个“滚动”动作之后),然后“在赛道上”将有第 1 行、“在大门内”第 2 行、“在队列中”第 3 行。在第二名赛车手通过大门后,“In Course”将有第 2 排、“In Gate”第 3 排等。
  • 我已经更清楚你想要什么了,1) 但我对以下句子有疑问:在第一个赛车手穿过大门之后(即在第一个“滚动”动作之后),这到底是什么意思?这是否意味着小部件的垂直滚动条被移动了或者是别的什么? 2) 此外,CSV 在哪里?
  • 嗨,示例 csv 在帖子中:10,Jo Blogs,13.3 11,John Blogs,13.4 12,Lynne Graham,13.5 13,L Vonn,14.5。最多 50 行,如上。让我模拟一些东西来显示“滚动”。
  • 应该什么时候执行'scroll'动作?

标签: python python-3.x csv pyqt pyqt5


【解决方案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

不同QTreeViews中的不同(数量)行是通过用不同(数量)数据填充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)])

滚动是通过在两个数组之间移动数据来完成的,然后重新运行“显示”以重新填充 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

希望将来能对其他人有所帮助。

干杯 凯夫

【讨论】:

    猜你喜欢
    • 2018-11-20
    • 2018-11-27
    • 2019-10-25
    • 1970-01-01
    • 2015-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    相关资源
    最近更新 更多