抱歉,你查看的文章不存在

告别会议无趣,也许就差这么一个Python工具

本文由伊洛投稿,州的先生编辑

零、前言

工作以后,小编发现开会时间要占用工作大部分时间,但是每次开会的效率却收效甚微,那么有没有什么方法可以增加开会的活跃力度,从而提高会议效率。这让小编想到在读书的时候,老师为了提高学生的注意力和警惕性,采用随机点名的方式进行回答问题,答对有奖励,答错有对应的惩罚。因此决定做一个会议随机点名系统。

本文涉及以下知识点:

  • python模块time的使用;
  • python文件读写;
  • python图形化程序开发库PyQt的使用;
  • PyQt布局管理和QTime计数器的使用;
  • PyQt界面美化qss样式使用

一、关于PyQt5

PyQt5简介

Python中提供了多种模块来支持编写桌面应用程序,其中包括内置的 tkinter 模块、第三方的 wxPython、PyQt、Kivy 等。这个模块各有优缺点,在此我们选择 PyQt5 来编写会议随机点名系统。

PyQt5是一组来自Digia的Qt5应用程序框架的Python绑定。它适用于Python2和Python3。这是一个跨平台的工具包,它可以运行在所有主要的操作系统,包括UNIX,Windows,Mac OS。

PyQt5的功能实现存在于以下子类当中:

  • QtCore
  • QtGui
  • QtWidgets
  • QtMultimedia
  • QtBluetooth
  • QtNetwork
  • QtPositioning
  • Enginio
  • QtWebSockets
  • QtWebKit
  • QtWebKitWidgets
  • QtXml
  • QtSvg
  • QtSql
  • QtTest

本篇文章只涉及QtCore 和QtWidhets两个类。

QtCore

模块涵盖了包的核心的非GUI功能,此模块被用于处理程序中涉及到的 time、文件、目录、数据类型、文本流、链接、mime、线程或进程等对象。

QtWidgets

模块包含了一整套UI元素组件,用于建立符合系统风格的classic界面,非常方便,可以在安装时选择是否使用此功能。

这里给两个官方的参看指南:

python模式: http://pyqt.sourceforge.net/Docs/PyQt5/

C++模式 http://doc.qt.io/qt-5/classes.html

PyQt的安装

PyQt5在Windows系统可以使用pip工具进行安装,其命令如下所示:

pip install PyQt5

PyQt安装测试

进行Python Shell中,输入如下代码:

import PyQt5

如果不报错,那么表示PyQt5安装成功,其如下图所示:

二、使用PyQt5实现点名系统

程序演示

本文最后实现的会议点名系统效果如下所示:

从上图动画可以看到,当点击开始按钮,名字和福利开始滚动显示;当点击停止按钮,结束点名,保留选中人和对应的福利。

设计UI界面

在开始创建 UI 界面之前,我们先为随机点名系统设计一个原型图,其如下图所示:

可以发现界面主要有三部分组成:

  • 上面的QLabel用来是显示系统名字
  • 中间的窗体Widget分为两部分:
    • QLabel用来是显示被点到人的名字和福利
    • QPushButton按钮实现开始和停止
  • 下面的QLabel用来显示图片

创建图形界面

打开LiClipse.exe开发工具,新建一个文件夹名称为:随机点名工具,然后在该文件夹下面新建一个python module 名字称:Ui_Main.py

首先引入所需要的模块,代码如下所示:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

通过继承 QMainWindow,创建一个主窗口的类和创建一个构造函数,代码如下图所示:

class Ui_MainWindow(QtWidgets.QMainWindow):

    def __init__(self, parent=None):
        """
          构造函数初始化界面
        """
        super(Ui_MainWindow, self).__init__(parent)

下面是本小节的重点,手写UI界面布局,代码如下所示:

self.setObjectName("MainWindow") # 设置主窗口名字
        self.setWindowTitle("随机点名系统") # 设置系统名字
        self.resize(673, 381) # 设置主窗口大小
        self.setMinimumSize(673, 381) # 设置主窗口最小值
        self.setMaximumSize(674, 441) # 设置主窗口最大值
        self.centralwidget = QtWidgets.QWidget(self) # 创建核心窗口
        self.centralwidget.setObjectName("<u>centralwidget</u>") # 设置核心窗口名字
        self.top_label = QtWidgets.QLabel(self.centralwidget)  # 创建QLabel显示上层图片
        self.top_label.setGeometry(0, 0, 673, 85) # 设置上层QLabel的大小和位置
        self.top_label.setPixmap(QtGui.QPixmap("top.png"))  # 为上层QLabel显示图片
        self.top_label.setObjectName("top_label") # 设置上层QLabel的名字
        self.bottom_label = QtWidgets.QLabel(self.centralwidget) # 创建QLabel显示下层图片
        self.bottom_label.setGeometry(0, 300, 673, 85) # 设置下层QLabel的大小和位置
        self.bottom_label.setMinimumSize(673, 85) # 设置下层QLabel的最小值
        self.bottom_label.setMaximumSize(673, 85) # 设置下层QLabel的最大值
        self.bottom_label.setPixmap(QtGui.QPixmap("bottom.png")) ## 为下层QLabel显示图片
        self.bottom_label.setObjectName("bottom_label") # 设置下层QLabel的名字
        self.mid_widget = QtWidgets.QWidget(self.centralwidget) # 为中间创建一个窗体
        self.mid_widget.setGeometry(6, 91, 660, 206) # 设置中间窗体的位置和大小
        self.mid_widget.setObjectName("mid_widget") # 设置中间窗体的名字
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.mid_widget) # 为中间窗体设置一个水平布局
        self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) # 调整中间窗体的位置(将左、上、右、下的外边距设置为不同的值)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2") # 设置中间窗体布局的名字
        #为水平布局设置水平、垂直方向的大小调整策略
        spacerItem = QtWidgets.QSpacerItem(209, 20,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem)

        self.verticalLayout = QtWidgets.QVBoxLayout() # 创建一个垂直布局
        self.verticalLayout.setObjectName("verticalLayout") # 设置垂直布局名字
        self.select_label = QtWidgets.QLabel("王天安-组长发10元红包", self.mid_widget) # 创建一个QLable显示被抽中的人和福利
        self.select_label.setMinimumSize(204, 63) # 设置最小值
        self.select_label.setMaximumSize(209, 63) # 设置最大值

        # 设置QLabel显示格式
        self.select_label.setFrameShape(QtWidgets.QFrame.Panel)
        self.select_label.setFrameShadow(QtWidgets.QFrame.Plain)
        self.select_label.setAlignment(QtCore.Qt.AlignCenter) # 设置文字位置居中
        self.select_label.setWordWrap(True) # 设置可以自动换行
        self.select_label.setObjectName("select_label") # 设置QLabel显示名字
        self.verticalLayout.addWidget(self.select_label) # 为垂直布局选中人的QLabel控件
        self.horizontalLayout = QtWidgets.QHBoxLayout() # 创建水平布局
        self.horizontalLayout.setObjectName("horizontalLayout") # 设置水平布局名字
        self.start_button = QtWidgets.QPushButton("开始", self.mid_widget) # 创建开始按钮
        self.start_button.setObjectName("start_button") # 设置开始按钮名字
        self.horizontalLayout.addWidget(self.start_button) # 为垂直布局增加开始按钮
        # 为水平布局设置水平、垂直方向的大小调整策略
        spacerItem1 = QtWidgets.QSpacerItem(24, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem1)

        self.pause_button = QtWidgets.QPushButton("停止", self.mid_widget) # 创建停止按钮
        self.pause_button.setObjectName("pause_button") # 设置停止按钮名字
        self.horizontalLayout.addWidget(self.pause_button) # 为水平布局怎加停止按钮控件

        # 布局嵌套
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.horizontalLayout_2.addLayout(self.verticalLayout)

        # 为水平布局设置水平、垂直方向的大小调整策略
        spacerItem2 = QtWidgets.QSpacerItem(209, 20,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem2)
        self.setCentralWidget(self.centralwidget) # 核心窗体初始化
        self.menubar = QtWidgets.QMenuBar(self) # 创建菜单栏
        self.menubar.setGeometry(0, 0, 673, 23)  # 设置菜单栏的大小和位置
        self.menubar.setObjectName("<u>menubar</u>") # 设置菜单栏的名字
        self.setMenuBar(self.menubar) # 添加菜单栏

在这个 UI 界面中,我们:

  • 使用 QWidget() 来创建空的窗口部件;
  • 使用 QVBoxLayout() 来创建垂直盒子布局层;
  • 使用 QHBoxLayout() 来创建水平盒子布局层;
  • 使用 QPushButton() 来创建按钮,实现功能函数;
  • 使用 QLabel() 来创建文本标签,用来显示图片和文字;

继续在代码中增加python主函数,调用界面初始化类,代码如下所示:

if __name__ == "__main__":

    """
     主函数,实例化界面类并显示
    """
    app = QtWidgets.QApplication(sys.argv)
    ui = Ui_MainWindow()
    ui.show()
    sys.exit(app.exec_())

运行程序文件,即可以显示随机点名系统主界面,如下图所示:

功能函数实现

在随机点名文件夹下面新建一个python module 名字称:RandomCall.py,用来实现随机点名系统的具体功能。

随机点名功能的核心是:利用时间产生随机数,作为下标更新名字。

涉及到的python模块为time,PyQt的模块为QTimer

  • time: 本篇文章只用到一个函数time.time()来返回当前时间的时间戳;
  • QTimer: QTimer是PyQt的QtCore的一个模块,QTimer类提供重复性和单次定时器。QTimer类为定时器提供高级编程接口。要使用它,请创建一个QTimer,将其timeout()信号连接到相应的插槽,然后调用start()。从此以后,它将以固定的时间间隔发出timeout()信号。示例代码如下:
time = QTimer(self) # 实例化QTimer定时器类
time.start(1000) # 设置计时间隔并启动(1000ms == 1s)
ime.timeout.connect(self.showTime) # 1S 计时结束,触发槽函数

首先引入所需要的模块,实现界面展示,代码如下所示:

import sys,time
from PyQt5.QtCore import Qt, QFile, QIODevice, QTextStream, QTextCodec
from PyQt5.QtCore import pyqtSlot, QTimer
from PyQt5.QtWidgets import QMainWindow, QApplication
# 主窗体设计界面
from Ui_Main import Ui_MainWindow

创建实现功能类,且定义构造函数,代码如下所示:

class RandomCallMain(QMainWindow, Ui_MainWindow):

    """
    构造函数
    """
    def __init__(self, parent=None):
    super(RandomCallMain, self).__init__(parent)

添加python主函数,调用实现功能类,显示主界面,代码如下所示:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = RandomCallMain()
    w.show()
    sys.exit(app.exec_())

运行RandomCall.py文件,主界面显示和运行Ui_Main.py一致,证明程序无问题。

读取信息文件

随机点名系统产生的名字和福利是通过分别读取【name.txt】和【reward.txt】两个文件存储到列表实现的,代码如下所示:

  • 读取名字文件
def getNameFile(self):

        """
        读取名字文件
        """
        with open('name.txt', 'r', encoding='UTF-8') as f:
            self.name_list = f.readlines()
        f.close()
        return self.name_list

通过 with open()读取名字文件,然后将结果保存在self.name_list列表,最后返回列表,供其他函数调用。

  • 读取奖励文件
def getRewardFile(self):

        """
        读取奖励文件
        """
        with open('reward.txt', 'r', encoding='UTF-8') as f:
            self.reward_list = f.readlines()
        f.close()
        return self.reward_list

通过 with open()读取奖励文件,然后将结果保存在self.reward_list列表,最后返回列表,供其他函数调用。

TIPS:关于python读取文件网上有很多实例,这里不再重复造轮子。

开始点名的实现

1.将开始按钮和槽函数在初始化函数init()进行绑定,代码如下

# 开始按钮绑定槽函数
self.start_button.clicked.connect(self.on_start_button_clicked)

2.开始槽函数的实现,代码如下:

def on_start_button_clicked(self):
        """
        开始点名
        """
        self.start_button.setEnabled(False) # 按开始钮置为不可用
        self.pause_button.setEnabled(True) # 设置停止按钮为可用
        self.start_time = time.time() - self.end_time # 记录开始时间
        self.update() # 调用界面刷新函数

3.在构造函数init()初始化计数器,代码如下:

self.p_timer = QTimer(self) # 初始化定时器
self.p_timer.timeout.connect(self.update) # 计数结束,触发函数

4.界面刷新函数实现,代码如下:

def update(self):
        """
        更新显示内容
        """
        self.end_time = time.time() - self.start_time # 计算结束时间
        self.set_name(self.end_time) # 传参调用显示姓名和奖励函数
        self.p_timer.start(50) # 每隔50ms调用一次函数,更新界面显示

5.选中名字和奖励实现,代码如下:

def set_name(self, end_time):
        """
        取选中的名字
        """
        cur = int(end_time * 100 % 30) # 计算数组下标
        self.getNameFile() # 调用读取名字文件函数
        self.getRewardFile() # 调用读取奖励文件函数
        _str = self.name_list[cur].strip('\n') + ':' + self.reward_list[cur] # 名字和奖励字符串拼接
        self.select_label.setText(_str) # 控件QLabel显示名字+奖励

停止点名的实现

停止点名,主要是停止计数,将开始按钮置为启用,停止按钮置为不启用,代码如下:

1.将停止按钮和槽函数在初始化函数init()进行绑定,代码如下

# 开始按钮绑定槽函数
self.pause_button.clicked.connect(self.on_pause_button_clicked)

2.停止槽函数的实现,代码如下:

def on_pause_button_clicked(self):
        """
        停止点名
        """
        self.start_button.setEnabled(True) # 开始按钮置为启用
        self.pause_button.setEnabled(False) # 停止按钮置为不启用
        self.p_timer.stop() # 停止计数

3.运行RandomCall.py,可以看到本篇文章开始的系统演示,这里不再展示。

三、QSS样式介绍

QSS的概念

QSS全称Qt Style Sheets,即Qt样式表。它是Qt提供的一种用来自定义控件外观的机制。QSS大量参考了CSS的内容,只不过QSS的功能比CSS要弱很多,体现在选择器要少,可以使用的QSS属性也要少很多,并且并不是所有的属性都可以用在Qt的所有控件上。

QSS语法

QSS的语法规则几乎与CSS相同。一条QSS的样式是由两部分组成的,一部分是选择器指定了哪些控件会受到影响,另一部分是指定了属性的值,表示这些控件的哪些属性会受到影响。例如:

QPushButton { color: red }
  • QPushButton 表示选择器,指定了所有的QPushButton或者是QPushButton的子类会受到影响,注意凡是继承自QPushButton的子类也会受到影响,这是与CSS中不同的地方,因为CSS应用的都是一些标签,没有类的层次结构,更加没有子类的概念。
  • {color:red} 规则的定义,表明指定前景颜色是红色。

整个语法意思就是设置QPushButton类以及其子类的所有控件的前景色是红色。

1.选择器

选择特定的类,如示例中的QPushButton,选择器的选择方式有七种,如下表所示:

选中对象

示例

描述

所有控件

*

选择所有当前控件和其下的所有窗口部件

所有某类的控件对象,被其子控件对象继承

QPushButton

选择该类的所有实例,以及该类的子控件实例(允许该类型)

所有某类的控件对象,不被其子控件对象继承

.QPushButton

选择该类的所有实例,不包括子控件实例

ID选择器

QPushButton #objectname

选择该类实例中对象名为objectName的实例

选择匹配某属性的控件对象

QPushButton[y=”0”]

选择该类满足该属性条件的所有实例

某类控件的子控件对象

QWidget > QPushButton

选择指定该类下的直接子控件实例

某类控件的子孙控件对象

QWidget QPushButton

选择指定该类下的所有子孙控件实例

QSS样式示例:

  • QPushButton背景色置为红色,代码如下所示:
QPushButton{background-color:red;}

得到的图形样式如下所示:

  • 对象名为startbutton和pausebutton的QPushButton背景色置为绿色,代码如下所示:
#start_button,#pause_button{background-color:rrgb(0,255,0)}

得到的图形样式如下图所示:

2.子控件(sub-control)

子控件(同辅助选择器),对于复杂的控件有必要对其子控件窗口进行控制,不同的控件类包含不同的子控件,如QCheckBox中包含indicator子控件。

QSS样式示例:

QCheckBox的前面的选择框背景色设置为红色,代码如下所示:

QCheckBox#checkBox::indicator{
    width:10px;
    height:10px;
    background-color: red; 
}

得到的图形样式如下图所示:

3.状态选择器(pseudo-states)

状态选择器,可根据不同控件的不同状态对窗口进行控制,如”hover”表示鼠标放上时的状态,”pressed”表示鼠标保持按下时的状态,可根据状态设置不同的外观.

QSS样式示例:

鼠标放在QPushButton上面时背景色设置为红色,代码如下所示:

QPushButton:hover{background-color:red;}

得到的图形样式如下图所示:

QSS样式其他方式

  • 属性(property) 属性,是一个窗口部件所固有的特征,每一个类型的窗口控件都会有属于他们自己的属性,如width,height(辅助选择器才有),color等等,定制控件的不同外观。注意:属性是使用逻辑否(!)操作符,如!hover,是鼠标未放在上面的其他状态。
  • 属性值(value) 属性值,跟在每一个属性后面有一个值,可以是bool,int,10px,red,rgb(0,0,0)等等,根据属性的不同,属性值的类型不同,通过修改指定控件的指定属性的属性值来实现不同的效果,如示例:background-color、width、height等。
  • 盒模型(box model) 包含了4个影响布局的矩形:
  • content rectangle:绘制窗口部件的内容的区域,如文字,图片。
  • padding rectangle:包围content rectangle,由padding属性指定填充操作,主要是窗口部件内容与边缘线(border)之间的空隙,由top,right,bottom和left设置他的大小,缺省为0。
  • border rectangle:包围padding rectangle,为边界预留空间,可认为是窗口的外框线。
  • margin rectangle:最外面的矩形,主要是负责与其他窗口部件间的距离。

QSS样式还有很多设置方式,如圆角弧度,背景色,九宫格等,本篇文章不再做详细解释,这里给个官方网站,有兴趣的小伙伴可以去看: http://doc.qt.io/qt-5/qtwidgets-module.html

QSS样式使用方式

  • 方案一,直接在代码使用,如下代码所示:
# 设置开始按钮的背景色为红色
self.start_button.setStyleSheet(“background-color:red;”)
  • 方案二,将样式设置写在一个后缀名为.qss的文件里面,然后在代码界面加载该文件,实现逻辑功能和样式美化的分离,本文使用的就是这个方式。

首先在随机点名文件夹下面新建一个文件,命名为【style.qss】,代码如下所示:

/*设置主窗口背景*/
#centralwidget{
    background-color:rgb(157, 11, 12);
    border-radius:4px;
    }

/*设置中间窗体显示背景*/
#mid_widget{
    background-color: rgb(244, 216, 215);
    }

/*中间窗体按钮样式*/
#start_button,#pause_button{
    /*定义最小最大宽高*/
    min-width: 36px;
    min-height: 36px;
    color: balck;   /*文字颜色*/
    font-size:18px;
    }

/*中间窗体按钮鼠标浮在上面的样式*/
#start_button:hover,#pause_button:hover{
    background-color: red; /*带透明度白色背景*/
}

/*名字显示样式设置*/
#select_label{
    font-size: 18px "黑体";

然后在RandomCall.py新建一个函数readQss用来读取qss文件,代码如下所示:

def readQss():
"""读取qss文件"""
    with open('style.qss',encoding='UTF-8') as f :
        data = f.read()
        f.close()
    return data

最后在主函数调用readQsss函数实现样式,代码如下所示:

#读取QSS样式
app.setStyleSheet(readQss())

截至到此,本篇文章已经到了尾声,简单总结下,本篇文章介绍了PyQt的布局、控件的使用、QTimer计数器的使用、QSS样式的简单学习,但是对上面的知识点并没有做过深的讲解,本篇只是想为利用python写GUI的小伙伴起到抛砖引玉的作用,如果想深入研究的可以继续学习。

原文发布于微信公众号 - 州的先生(zmister2016)

原文发表时间:2019-01-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

州的先生

4 篇文章54 人订阅

扫码关注云+社区

领取腾讯云代金券