告別會議無趣,也許就差這麼一個工具(二)
上篇文章我們講述了系統的佈局,這次就來看看功能是怎麼實現的。
3.3 功能函式實現
在隨機點名資料夾下面新建一個python module 名字稱:RandomCall.py,用來實現隨機點名系統的具體功能。
3.3.1 核心技術介紹
隨機功能的核心是:利用時間產生隨機數,作為下標更新名字。
涉及到的python模組為time,PyQt的模組為QTimer
-
time
本篇文章只用到一個函式time.time()來返回當前時間的時間戳;
-
QTimer
QTimer是PyQt的QtCore的一個模組,QTimer類提供重複性和單次定時器。QTimer類為定時器提供高階程式設計介面。要使用它,請建立一個QTimer,將其timeout()訊號連線到相應的插槽,然後呼叫start()。從此以後,它將以固定的時間間隔發出timeout()訊號。示例程式碼如下:
# 例項化QTimer定時器類 time = QTimer(self) # 設定計時間隔並啟動(1000ms == 1s) time.start(1000) # 1S 計時結束,觸發槽函式 ime.timeout.connect(self.showTime)
首先引入所需要的模組,實現介面展示
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一致,證明程式無問題。
3.3.2 python讀取檔案
隨機點名系統產生的名字和福利是通過分別讀取【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讀取檔案網上有很多例項,這裡不再重複造輪子。
3.3.3 開始點名實現
- 將開始按鈕和槽函式在初始化函式 init ()進行繫結,程式碼如下
#開始按鈕繫結槽函式 self.start_button.clicked.connect(self.on_start_button_clicked)
- 開始槽函式的實現,程式碼如下:
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()
- 在建構函式 init ()初始化計數器,程式碼如下:
#初始化定時器 self.p_timer = QTimer(self) #計數結束,觸發函式 self.p_timer.timeout.connect(self.update)
- 介面重新整理函式實現,程式碼如下:
def update(self): """ 更新顯示內容 """ #計算結束時間 self.end_time = time.time() - self.start_time #傳參呼叫顯示姓名和獎勵函式 self.set_name(self.end_time) #每隔50ms呼叫一次函式,更新介面顯示 self.p_timer.start(50)
- 選中名字和獎勵實現,程式碼如下:
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] #控制元件QLabel顯示名字+獎勵 self.select_label.setText(_str)
3.3.4 停止點名實現
停止點名,主要是停止計數,將開始按鈕置為啟用,停止按鈕置為不啟用,程式碼如下:
- 將停止按鈕和槽函式在初始化函式 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()
8.執行RandomCall.py,可以看到本篇文章開始的系統演示,

隨機點名系統.gif
好了,本次文章就講到這,接下來一篇文章會介紹 隨機點名系統 美化的方式
3.3 QSS樣式講解
3.3.1 QSS的概念
QSS全稱Qt Style Sheets,即Qt樣式表。它是Qt提供的一種用來自定義控制元件外觀的機制。QSS大量參考了CSS的內容,只不過QSS的功能比CSS要弱很多,體現在選擇器要少,可以使用的QSS屬性也要少很多,並且並不是所有的屬性都可以用在Qt的所有控制元件上。
3.3.1 QSS語法講解
QSS的語法規則幾乎與CSS相同。一條QSS的樣式是由兩部分組成的,一部分是選擇器指定了哪些控制元件會受到影響,另一部分是指定了屬性的值,表示這些控制元件的哪些屬性會受到影響。例如:
QPushButton { color: red }
-
QPushButton
表示選擇器,指定了所有的QPushButton或者是QPushButton的子類會受到影響,注意凡是繼承自QPushButton的子類也會受到影響,這是與CSS中不同的地方,因為CSS應用的都是一些標籤,沒有類的層次結構,更加沒有子類的概念。
-
{color:red}
規則的定義,表明指定前景顏色是紅色。
整個語法意思就是設定QPushButton類以及其子類的所有控制元件的前景色是紅色。
- 選擇器
選擇特定的類,如示例中的QPushButton,選擇器的選擇方式有七種,如下表:
選中物件 | 示例 | 描述 |
---|---|---|
所有控制元件 | * | 選擇所有當前控制元件和其下的所有視窗部件 |
所有某類的控制元件物件,被其子控制元件物件繼承 | QPushButton | 選擇該類的所有例項,以及該類的子控制元件例項(允許該型別) |
所有某類的控制元件物件,不被其子控制元件物件繼承 | .QPushButton | 選擇該類的所有例項,不包括子控制元件例項 |
ID選擇器 | QPushButton #objectname | 選擇該類例項中物件名為objectName的例項 |
選擇匹配某屬性的控制元件物件 | QPushButton[y=”0”] | 選擇該類滿足該屬性條件的所有例項 |
某類控制元件的子控制元件物件 | QWidget > QPushButton | 選擇指定該類下的直接子控制元件例項 |
某類控制元件的子孫控制元件物件 | QWidget QPushButton | 選擇指定該類下的所有子孫控制元件例項 |
QSS樣式示例
- QPushButton背景色置為紅色,程式碼如下:
QPushButton{background-color:red;}

sparkles
- 物件名為start_button和pause_button的QPushButton背景色置為綠色,程式碼如下:
#start_button,#pause_button{background-color:rrgb(0,255,0)}

sparkles
- 子控制元件(sub-control)
子控制元件(同輔助選擇器),對於複雜的控制元件有必要對其子控制元件視窗進行控制,不同的控制元件類包含不同的子控制元件,如QCheckBox中包含indicator子控制元件。
QSS示例
QCheckBox的前面的選擇框背景色設定為紅色,程式碼如下:
QCheckBox#checkBox::indicator{ width:10px; height:10px; background-color: red; }

sparkles
3.狀態選擇器(pseudo-states)
狀態選擇器,可根據不同控制元件的不同狀態對視窗進行控制,如”hover”表示滑鼠放上時的狀態,”pressed”表示滑鼠保持按下時的狀態,可根據狀態設定不同的外觀.
QSS示例
滑鼠放在QPushButton上面時背景色設定為紅色,程式碼如下:
QPushButton:hover{background-color:red;}

sparkles
4.QSS樣式其他方式
- 屬性(property)
屬性,是一個視窗部件所固有的特徵,每一個型別的視窗控制元件都會有屬於他們自己的屬性,如width,height(輔助選擇器才有),color等等,定製控制元件的不同外觀。注意:屬性是使用邏輯否(!)操作符,如!hover,是滑鼠未放在上面的其他狀態。
- 屬性值(value)
屬性值,跟在每一個屬性後面有一個值,可以是bool,int,10px,red,rgb(0,0,0)等等,根據屬性的不同,屬性值的型別不同,通過修改指定控制元件的指定屬性的屬性值來實現不同的效果,如示例:background-color、width、height等。
-
盒模型(box model)
包含了4個影響佈局的矩形
sparkles
- 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.html3.3.1 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的小夥伴起到拋磚引玉的作用,如果想深入研究的可以繼續學習。
附錄:
- Ui_Main.py完整程式碼如下:
#!/user/bin/env python # -*- coding: utf-8 -*- """ Created on 2019年1月17日pa @author: <u>yiluo</u> @site: https://github.com/bingshilei @email: 786129166<u>@qq.com</u> @file: Ui_Main.py @description: 隨機點名程式,主窗體 """ import sys from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): """ 建構函式初始化介面 """ super(Ui_MainWindow, self).__init__(parent) #設定主視窗名字 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>") #建立QLabel顯示上層圖片 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") #為中間建立一個窗體 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") #建立一個QLable顯示被抽中的人和福利 self.select_label = QtWidgets.QLabel("王天安-組長髮10元紅包", self.mid_widget) #設定最小值 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) #設定QLabel顯示名字 self.select_label.setObjectName("select_label") #為垂直佈局選中人的QLabel控制元件 self.verticalLayout.addWidget(self.select_label) #建立水平佈局 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) if __name__ == "__main__": """ 主函式,例項化介面類並顯示 """ app = QtWidgets.QApplication(sys.argv) ui = Ui_MainWindow() ui.show() sys.exit(app.exec_())
- RandomCall.py完整程式碼如下:
#!/user/bin/env python # -*- coding: <u>utf</u>-8 -*- """ Created on 2019年1月17日 @author: <u>yiluo</u> @site: https://github.com/bingshilei @email: 786129166<u>@qq.com</u> @file: RandomCallMain.py @description: 隨機點名程式,功能函式實現 """ import sys, time from PyQt5.QtCore import Qt from PyQt5.QtCore importQTimer from PyQt5.QtWidgets import QMainWindow, QApplicatio #匯入主介面函式 from Ui_main import Ui_MainWindow class RandomCallMain(QMainWindow, Ui_MainWindow): """ 隨機點名系統功能類. """ def __init__(self, parent=None): """ 建構函式 """ super(RandomCallMain, self).__init__(parent) #窗體透明 self.setAttribute(Qt.WA_TranslucentBackground, True) self.setupUi(self) #初始化顯示資訊 self.select_label.setText('開始點名') #初始化開始時間 self.start_time = 0.0 #初始化結束時間 self.end_time = 0.0 #初始化定時器 self.p_timer = QTimer(self) #計數結束,觸發函式 self.p_timer.timeout.connect(self.update) #開始按鈕繫結槽函式 self.start_button.clicked.connect(self.on_start_button_clicked) #停止按鈕繫結槽函式 self.pause_button.clicked.connect(self.on_pause_button_clicked) def keyPressEvent(self, e): """ 重寫滑鼠退出事件,ESC鍵退 """ if e.key() == Qt.Key_Escape: self.close() 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() def update(self): """ 更新顯示內容 """ try: self.end_time = time.time() - self.start_time self.set_name(self.end_time) #每隔50ms呼叫一次函式,更新介面顯示 self.p_timer.start(50) except Exception as e: print(e) def getNameFile(self): """ 讀取名字檔案 """ with open('name.txt', 'r', encoding='UTF-8') as f: self.name_list = f.readlines() f.close() return 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 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) def on_pause_button_clicked(self): """ 停止點名 """ self.start_button.setEnabled(True) self.pause_button.setEnabled(False) self.p_timer.stop() def readqss(): with open('style.qss',encoding='UTF-8') as f : data = f.read() f.close() return data if __name__ == '__main__': app = QApplication(sys.argv) #載入qss檔案 app.setStyleSheet(readQss()) w = RandomCallMain() w.show() sys.exit(app.exec_())