mirror of
https://github.com/HChaZZY/Random-Picker.git
synced 2025-12-06 10:33:50 +08:00
260 lines
9.5 KiB
Python
260 lines
9.5 KiB
Python
'''
|
||
Random_Picker 用Python实现的随机点名器
|
||
Copyright (C) 2022 海Cha
|
||
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
'''
|
||
|
||
import xlrd as excel
|
||
from tkinter import *
|
||
import tkinter.messagebox as msgbox
|
||
import random
|
||
import sys
|
||
import winsound
|
||
import webbrowser
|
||
|
||
version = "v1.2.2"
|
||
|
||
filename = "./data/names.xls"
|
||
configname = "./data/config.data"
|
||
selname = "./assets/sel.wav"
|
||
procname = "./assets/proc.wav"
|
||
iconname = "./assets/点名器.ico"
|
||
gui_size = "650x200"
|
||
|
||
protection_override = False
|
||
up_percent = 30
|
||
down_persent = 40
|
||
elim_rows = 1
|
||
percent_override = True
|
||
|
||
elim_id = []
|
||
up_id = []
|
||
down_id = []
|
||
|
||
sound = True
|
||
|
||
students = []
|
||
classes = []
|
||
subjects = []
|
||
filter = []
|
||
|
||
last_choice = ""
|
||
|
||
gui = Tk()
|
||
|
||
gui.withdraw()
|
||
gui.title("点名器")
|
||
gui.geometry(gui_size)
|
||
gui.resizable(0,0)
|
||
gui.configure(bg = "white")
|
||
|
||
try:
|
||
if len(sys.argv) > 1:
|
||
for arg in sys.argv[1:]:
|
||
if arg == "--licence":
|
||
if msgbox.askokcancel('许可证信息', '点名器 ' + version + ' Copyright (C) 2022 海Cha\n本程序是开源程序,受开源协议 GNU General Public Licence v3.0 (GPL v3) 保护\n基于GPL v3协议,本程序没有任何质量保证。\n这是一个自由软件,欢迎再次分发。\n点击「确认」将会由系统默认浏览器打开LICENCE文件\n出现此对话框的原因是由于您在运行本软件时传入了 --licence 参数,欲启动主程序,请移除该参数。'):
|
||
webbrowser.open_new_tab('https://www.gnu.org/licenses/gpl-3.0.html')
|
||
assert False
|
||
if arg == "--version":
|
||
msgbox.showinfo('版本信息', '点名器 ' + version + ' Copyright (C) 2022 海Cha\n出现此对话框的原因是由于您在运行本软件时传入了 --version 参数,欲启动主程序,请移除该参数。')
|
||
assert False
|
||
if arg == "--help":
|
||
msgbox.showinfo('帮助信息','----- 点名器 ' + version + ' -----\n--licence 显示许可证信息\n--version 显示版本信息\n--path 显示程序运行路径\n--help 显示此信息\n欲打开主程序GUI,则无需传参\n出现此对话框的原因是由于您在运行本软件时传入了 --help 参数,欲启动主程序,请移除该参数。')
|
||
assert False
|
||
if arg == "--path":
|
||
msgbox.showinfo('路径信息','点名器 ' + version + ' Copyright (C) 2022 海Cha\n当前程序运行在 ' + sys.argv[0] + ' 路径上\n出现此对话框的原因是由于您在运行本软件时传入了 --path 参数,欲启动主程序,请移除该参数。')
|
||
assert False
|
||
if arg.find("--") != -1:
|
||
msgbox.showerror('传参错误','无法识别参数 ' + arg + ' 请调整您的启动参数\n传入 --help以查看帮助信息\n出现此对话框的原因是由于您在运行本软件时传入了 ' + arg + ' 参数,欲启动主程序,请移除该参数。')
|
||
assert False
|
||
except AssertionError:
|
||
sys.exit()
|
||
|
||
try:
|
||
file = open(iconname)
|
||
file.close()
|
||
gui.iconbitmap(iconname)
|
||
except IOError:
|
||
if not msgbox.askokcancel('资源文件错误', '在 ./assets目录下未能找到 点名器.ico 文件,点击「确定」将加载默认图标,点击「取消」以关闭程序'):
|
||
sys.exit()
|
||
|
||
try:
|
||
file = open(selname)
|
||
file.close()
|
||
file = open(procname)
|
||
file.close()
|
||
except IOError:
|
||
if msgbox.askokcancel('资源文件错误', '在 ./assets目录下未能找到音频文件,点击「确定」将关闭声音,点击「取消」以关闭程序'):
|
||
sound = False
|
||
else:
|
||
sys.exit()
|
||
|
||
class Student(object):
|
||
name = ""
|
||
subject = ""
|
||
id = ""
|
||
class_name = ""
|
||
|
||
def __init__(self,id,class_name,subject,name):
|
||
self.id = id
|
||
self.class_name = class_name
|
||
self.subject = subject
|
||
self.name = name
|
||
|
||
try:
|
||
with excel.open_workbook(filename) as excel_data:
|
||
table = excel_data.sheets()[0]
|
||
# win32api.SetFileAttributes(filename,win32con.FILE_ATTRIBUTE_HIDDEN)
|
||
except FileNotFoundError:
|
||
msgbox.showerror('找不到数据库文件', '在 ./data下未能找到 names.xls 文件,请确认您的文件存在')
|
||
sys.exit()
|
||
|
||
try:
|
||
cols = table.ncols
|
||
rows = table.nrows
|
||
assert cols == 4
|
||
assert rows > 1
|
||
except AssertionError:
|
||
msgbox.showerror('数据库文件格式不正确', '数据库文件内行/列数不合法,请确认数据库文件拥有超过1的行数和等于4的列数,当前行数:' + str(rows) + ' 当前列数:' + str(cols))
|
||
sys.exit()
|
||
|
||
try:
|
||
with open(configname,'r') as file:
|
||
# win32api.SetFileAttributes(configname,win32con.FILE_ATTRIBUTE_HIDDEN)
|
||
config = file.read().splitlines()
|
||
for unit in config:
|
||
temp = unit.split(",")
|
||
if temp[1] == '0':
|
||
elim_id.append(int(temp[0]))
|
||
elif temp[1] == '+':
|
||
up_id.append(int(temp[0]))
|
||
elif temp[1] == "-":
|
||
down_id.append(int(temp[0]))
|
||
else:
|
||
pass
|
||
except:
|
||
percent_override = False
|
||
|
||
up_percent = len(up_id) * 5 if len(up_id) <= 6 else 30
|
||
down_percent = len(down_id) * 8 if len(down_id) <= 5 else 40
|
||
|
||
gui.deiconify()
|
||
|
||
for i in range(elim_rows,rows):
|
||
tmp_list = [str(table.cell_value(i,j)) for j in range(0,cols)]
|
||
if (int(float(tmp_list[0])) not in elim_id):
|
||
student = Student(tmp_list[0],tmp_list[1],tmp_list[2],tmp_list[3])
|
||
students.append(student)
|
||
|
||
cur_stu = students[:]
|
||
|
||
for student in students:
|
||
if student.class_name not in classes:
|
||
classes.append(student.class_name)
|
||
if student.subject not in subjects:
|
||
subjects.append(student.subject)
|
||
|
||
cur_name = StringVar()
|
||
|
||
def upd_name(name):
|
||
cur_name.set(name)
|
||
|
||
upd_name("")
|
||
|
||
listbox = Listbox(gui, selectmode = MULTIPLE, height = 5)
|
||
|
||
for tmp_class in classes:
|
||
listbox.insert("end",tmp_class)
|
||
|
||
def sel_class(flag = 1):
|
||
global filter, listbox, classes, cur_stu, students, percent_override
|
||
filter.clear()
|
||
for selection in listbox.curselection():
|
||
# print(selection)
|
||
filter.append(classes[selection])
|
||
# print(filter)
|
||
if filter:
|
||
if flag:
|
||
msgbox.showinfo('班级选择已应用', '已应用当前班级选择', parent=gui)
|
||
percent_override = False
|
||
cur_stu.clear()
|
||
for student in students:
|
||
if student.class_name in filter:
|
||
# print(student.name)
|
||
cur_stu.append(student)
|
||
else:
|
||
if flag:
|
||
msgbox.showwarning('班级选择已应用', '当前设置会选择所有班级的名单,这样对吗?', parent=gui)
|
||
percent_override = False
|
||
filter = classes[:]
|
||
cur_stu = students[:]
|
||
|
||
def choose():
|
||
global last_choice, cur_stu
|
||
sel_class(0)
|
||
# 触发30%概率,从up中挑选
|
||
if (random.randint(1,100) < up_percent and percent_override):
|
||
protection_override = True;
|
||
temp = []
|
||
for student in cur_stu:
|
||
if int(float(student.id)) in up_id:
|
||
temp.append(student)
|
||
cur_stu = temp[:]
|
||
elif (random.randint(1,100) < down_persent and percent_override):
|
||
protection_override = True;
|
||
temp = [];
|
||
for student in cur_stu:
|
||
if int(float(student.id)) not in down_id:
|
||
temp.append(student)
|
||
cur_stu = temp[:]
|
||
else:
|
||
protection_override = False
|
||
if not cur_stu:
|
||
protection_override = False
|
||
sel_class(0)
|
||
choice = random.choice(cur_stu)
|
||
# print(choice.name)
|
||
counter = 0;
|
||
while (last_choice == choice.name and (not protection_override) and (len(cur_stu) > 1)) or choice.id in elim_id:
|
||
choice = random.choice(cur_stu)
|
||
counter = counter + 1
|
||
if counter >= 100:
|
||
break
|
||
# print(choice.name)
|
||
upd_name(choice.name)
|
||
class_label.config(text = choice.class_name)
|
||
subject_label.config(text = choice.subject)
|
||
last_choice = choice.name
|
||
if sound:
|
||
winsound.PlaySound(selname, winsound.SND_ASYNC | winsound.SND_FILENAME)
|
||
|
||
startrandom = Button(gui, text = "立刻摇人!", font = ("宋体", 17, "bold"), height = 2, fg = "red", command = choose, bg = "white")
|
||
setclass = Button(gui, text = "应用班级选用", font = ("宋体", 17), height = 2, command = sel_class, bg = "white")
|
||
scrool = Scrollbar(gui, command = listbox.yview)
|
||
listbox.config(yscrollcommand=scrool.set)
|
||
|
||
name_label = Label(gui, textvariable = cur_name, font = ("宋体", 30, "bold"), width = 20, bg = "white", fg = "blue")
|
||
class_label = Label(gui, text = "", font = ("宋体", 15), width = 20, bg = "white")
|
||
subject_label = Label(gui, text = "", font = ("宋体", 15), width = 20, bg = "white")
|
||
|
||
class_label.grid(row = 2, column = 1, sticky = N+S+E+W)
|
||
subject_label.grid(row = 2, column = 2, sticky = N+S+E+W)
|
||
name_label.grid(row = 1, column = 1, sticky = N+S)
|
||
listbox.grid(row = 1, column = 2, sticky = N+S)
|
||
startrandom.grid(row = 3, column = 1, sticky = N+S+E+W)
|
||
setclass.grid(row = 3, column = 2, sticky = N+S+E+W)
|
||
scrool.grid(row = 1, column = 3, sticky = N+S)
|
||
|
||
gui.mainloop() |