利用PyCharm设计简单的不重复单词抽取器

由于一人听写单词需要,想设计一个不重复单词抽取器。看了小破站的各种视频,加上对于相关包信息的搜集,制作了一个简易版的小程序。写篇小文章来记录一下过程。
相关源码、最终效果图和相关资源网址放在本文的最后。
目录
1.预备操作
2.背景的导入
3.按钮与显示界面设计
4.源码、效果图和参考网址
预备操作:
导入相关模块和包,代码如下:
import tkinter as tk#导入绘制界面库
import random#导入随机函数使用
from PIL import ImageTk,Image#绘背景图使用
from tkinter import filedialog#导入文件使用
import copy#重新开始功能使用
import pygame as py#导入音乐使用背景的导入:
(1)在导入背景之前,需要初始化一个窗口实例,对窗口实例进行初始化操作:添加标题文字(title()函数)、窗体大小(geometry()函数)。注意若要调整窗口为600*600的,参数应该使用“600x600”而不能使用“600*600”(x为英文字母x).
代码如下:
root=tk.Tk()#初始化一个窗口实例,名字为root
root.title("随机抽取")#添加标题文字
root.geometry('600x600')#设置窗体大小(2)导入背景前先将背景图片保存到本地的某个地方。使用Image中的open()函数打开背景图片(使用绝对路径),使用resize()函数调整图片的大小。然后使用PhotoImage()函数提取图片像素建立新图片。注意这里不能使用tk中的PhotoImage()函数而要使用ImageTk中的PhotoImage()函数,前者支持gif形式的图片,本文采用jpg图片,使用后者。
然后使用tk中的label()函数对图像进行绘制。
具体代码如下:
#导入背景图片
img=Image.open(r"C:\Users\86157\Desktop\随机单词抽取\1.jpg")
img=img.resize((600,600))
photo = ImageTk.PhotoImage(img)
tk.Label(master=root,image=photo).grid(row=0, column=0)效果图如下:

3.按钮与显示界面设计
(1)显示界面设计
抽取的结果要显示在屏幕上,使用tk中的StringVar()实现,先进行初始化,使用set()函数设置未抽取时的内容。然后对字体(本文使用黑体)进行调整,并使用place()函数将其放置在画布的某个位置。
代码如下:
num = tk.StringVar()
num.set('目前还未抽取')
label = tk.Label(root, textvariable=num, font=("SimHei", 40))
label.place(x=50, y=120)
同理设计显示已经抽出的单词的个数。
代码如下:
num2 = tk.StringVar()
num2.set("已抽取个数:"+str(age))
label = tk.Label(root, textvariable=num2, font=("SimHei", 40))
label.place(x=50, y=30)
效果图如下:

(2)按钮设置
按钮一共分为四个,随机抽取,重新抽取,导入文件,开关音乐。
首先,定义三个列表L,L2,L3三者均为空列表,L用于存放抽取的数据,L2和L3重新抽取中对L中的内容进行修正。
代码如下:
L,L2,L3=[],[],[]
1.导入文件:自定义getfile()函数
使用global将全局变量L,L2,L3调入到函数内部进行使用。然后使用askopenfilename()函数导入文件,将导入的文件的绝对路径返回给一个变量,接着使用路径来打开相应的文件。本文使用文本文件txt,文件中的文本形式类似为:“1.学生\n”,因此需要对每一行取出的字符进行分离操作,使用split()函数分离两次就得到了“学生”,将其存添加到空列表L中,重复这个过程直到没有元素可以添加了,然后将L进行深拷贝,存储在L2中。
代码如下:
def getfile():
global L,L2,L3
L,L2,L3=[],[],[]
file_path=filedialog.askopenfilename()
with open(file_path, encoding="utf-8") as file:
while (1):
result = file.readline()
result1 = result.split("\n")[0]
result2 = result1.split(".")[-1]
if (result):
L.append(result2)
else:
L2 = copy.deepcopy(L)
break
当按下“随机抽取按钮之后”,才会调用上述函数,因此上述函数时点击按钮时发生的事件。按钮采用tk.Button()函数进行调用,command参数使用lambda函数,点击后具体的操作为getfile()函数。然后将按钮放在界面合适的位置即可。
代码如下:
button3=tk.Button(root,text="导入文件",font=("Microsoft SimHei",28),command=lambda:getfile())
button3.place(x=135,y=415)
2.随机抽取
在导入文件之后,列表L中就存放了所有带抽取的单词。在抽取过程中需要不断改变显示的数据以及已经抽取元素的个数。定义一个全局变量age用于存放已经抽取元素个数,将全局变量age(统计抽取个数)和num2(显示内容)在抽取单词的getcharacters()函数内部调用。
每一次进行抽取,显示已经抽取元素的个数会增加,列表中元素会减少,显示内容会改变。因此每次操作需更改三部分,显示内容更改可以在函数体外得到,故不写入该函数中。将列表长度作为条件判断,当列表长度为0时候,抽取完毕返回信息;当列表长度不为0时候,利用random.randint()函数随机抽取一个整数,age自增,然后在num2中显示age的值,接着将数删除并作为函数的返回值。注意不能先删除再返回,删除和返回需要同一个值,可以使用pop()函数或者remove()函数等。
代码如下:
def getcharacters(L):
global age,num2
length=len(L)#列表长度
if(length!=0):
number = random.randint(0, length-1) # 所取得序号
age=age+1
num2.set("已抽取个数:"+str(age))
return L.pop(number)
else:
return "抽取完毕!"
与上述设计按钮同理,这里的getcharacters()只是点击按钮时调用的函数,仍需要设计按钮。仍使用tk.Button()函数,command中调用lambda函数,这里需要将选出来的单词显示在num中,即需要抽取字符并且显示,故使用num.set(str(getcharacters())),在调用gethcharacters后并输出到屏幕上,然后调整按钮位置。(str在这里多余,若要抽取其他类型,如整型数据可以加上)
代码如下:
button=tk.Button(root,text="随机抽取",font=("Microsoft SimHei",28),command=lambda:num.set(str(getcharacters(L))))
button.place(x=135,y=215)
3.开关音乐
由于作者水平受限,开关音乐时只能做到重新播放和关闭。
设置一个flag来实现音乐的开关。当打开程序时,音乐自动播放,使用py中的init()函数进行初始化,然后使用load()函数导入对应的音频文件,然后使用play()函数进行播放,第一个参数设置为-1表示循环播放,第二个参数设置为0,表示从第0秒开始。
点击按钮所调用的函数为stop_openmusic(),当flag=1的时候点击,使用stop()函数停止音乐,同时将flag的值调整为0,;当flag=0的时候点击,模仿开始时播放音乐的步骤即可。
代码如下:
flag=1
py.mixer.init()
py.mixer.music.load(r"C:\Users\86157\Desktop\随机单词抽取\音乐.mp3")
py.mixer.music.play(-1, 0)
def stop_openmusic():
global flag
if(flag==1):
py.mixer.music.stop()
flag=0
else:
py.mixer.init()
py.mixer.music.load(r"C:\Users\86157\Desktop\随机单词抽取\音乐.mp3")
py.mixer.music.play(-1, 0)
flag=1
按钮设置与上述按钮设置同理,直接放代码:
button3=tk.Button(root,text="开关音乐",font=("Microsoft SimHei",28),command=lambda:stop_openmusic())
button3.place(x=135,y=515)
4.重新抽取
重新抽取的过程就是将L的内容变成与初始导入时候一样的内容,并且调整num2中显示已经抽取元素的个数的过程。再抽取过程中L发生改变,L2是L的深拷贝,若使用单纯的赋值操作,则二者会连接在一起,对L中元素进行的删除操作会等同地发生在L2中,故不能仅仅利用L2来修正L。L3作为L2的深拷贝,需要在函数执行的最后进行操作,故这之前需要将L2还原。本文利用L3对L进行修正,当第一次L2和L不相同时,L2中存放了完整的元素,L3为空,用L3深拷贝L2,然后赋值给L;当之后L2和L不相同时,L3中存放了开始时完整的数据,故用L3来修正L,并且将L2进行修正(对L进行深拷贝)为了保证L3不变。然后修改num2中显示的值为0即可。
代码如下:
def restart():
global L,L2,L3,age
if((L2!=L)&(L3!=[])):
L=L3
L2=copy.deepcopy(L)
if((L2!=L)&(L3==[])):
L3=copy.deepcopy(L2)
L=L3
L3=copy.deepcopy(L2)
age = 0
num2.set("已抽取个数:" + str(age))
num.set("目前还未抽取")
按钮设计与上述类似,直接放代码:
button2=tk.Button(root,text="重新抽取",font=("Microsoft SimHei",28),command=lambda:restart())
button2.place(x=135,y=315)
至此小程序设计完毕。
4.源码、效果图和参考网址
源码:
import tkinter as tk#导入库
import random
from PIL import ImageTk,Image
from tkinter import filedialog
import copy
import pygame as py
age=0
#初始化对象
root=tk.Tk()#初始化一个窗口实例,名字为root
root.title("随机抽取")#添加标题文字
root.geometry('600x600')#设置窗体大小
#导入背景图片
img=Image.open(r"C:\Users\86157\Desktop\随机单词抽取\1.jpg")
img=img.resize((600,600))
photo = ImageTk.PhotoImage(img)
tk.Label(master=root,image=photo).grid(row=0, column=0)
#显示抽取出来的界面
num = tk.StringVar()
num.set('目前还未抽取')
label = tk.Label(root, textvariable=num, font=("SimHei", 40))
label.place(x=50, y=120)
num2 = tk.StringVar()
num2.set("已抽取个数:"+str(age))
label = tk.Label(root, textvariable=num2, font=("SimHei", 40))
label.place(x=50, y=30)
L,L2,L3=[],[],[]
def getfile():
global L,L2,L3
L,L2,L3=[],[],[]
file_path=filedialog.askopenfilename()
with open(file_path, encoding="utf-8") as file:
while (1):
result = file.readline()
result1 = result.split("\n")[0]
result2 = result1.split(".")[-1]
if (result):
L.append(result2)
else:
L2 = copy.deepcopy(L)
break
def getcharacters(L):
global age,num2
length=len(L)#列表长度
if(length!=0):
number = random.randint(0, length-1) # 所取得序号
age=age+1
num2.set("已抽取个数:"+str(age))
return L.pop(number)
else:
return "抽取完毕!"
def restart():
global L,L2,L3,age
if((L2!=L)&(L3!=[])):
L=L3
L2=copy.deepcopy(L)
if((L2!=L)&(L3==[])):
L3=copy.deepcopy(L2)
L=L3
L3=copy.deepcopy(L2)
age = 0
num2.set("已抽取个数:" + str(age))
num.set("目前还未抽取")
#导入音乐
flag=1
py.mixer.init()
py.mixer.music.load(r"C:\Users\86157\Desktop\随机单词抽取\音乐.mp3")
py.mixer.music.play(-1, 0)
def stop_openmusic():
global flag
if(flag==1):
py.mixer.music.stop()
flag=0
else:
py.mixer.init()
py.mixer.music.load(r"C:\Users\86157\Desktop\随机单词抽取\音乐.mp3")
py.mixer.music.play(-1, 0)
flag=1
#设置按钮
button=tk.Button(root,text="随机抽取",font=("Microsoft SimHei",28),command=lambda:num.set(str(getcharacters(L))))
button.place(x=135,y=215)
button2=tk.Button(root,text="重新抽取",font=("Microsoft SimHei",28),command=lambda:restart())
button2.place(x=135,y=315)
button3=tk.Button(root,text="导入文件",font=("Microsoft SimHei",28),command=lambda:getfile())
button3.place(x=135,y=415)
button3=tk.Button(root,text="开关音乐",font=("Microsoft SimHei",28),command=lambda:stop_openmusic())
button3.place(x=135,y=515)
root.mainloop()
效果图:

相关包的使用及处理问题参考网站:
(23条消息) Python-Tkinter图形化界面设计(详细教程 )_python tkinter图形_王张飞的博客-CSDN博客
(23条消息) Python之解决tkinter.PhotoImage不显示图片的问题 Python3_tk.photoimage_苏妲己点姜子牙的博客-CSDN博客
(23条消息) pygame导入音频_pygame输入音频_黑脉金的博客-CSDN博客
MyFreeMP3 (liumingye.cn)(下载mp3)
拓展 用Python制作一个随机点名的小程序_哔哩哔哩_bilibili
(23条消息) tkinter导入文件_摇摇晃摇晃的博客-CSDN博客