目录
上才艺。
最近需要编写一个抽奖的小玩意,但是查了一下网上使用wxpython的方法似乎不是很多,遂自己研究了一下。
杂话(解释)
以下是需要用到的一些库
import images #存放图片编码的py文件
import wx,time,random,copy,sys,os
import wx.lib.buttons as buttons
from wx.lib.embeddedimage import PyEmbeddedImage
import threading
首先是界面,原本想使用布局,但是一来对布局不是很熟,二来一开始时我的界面设想应该是没有布局那么规则的。
class xiuli(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, '第一代抽奖系统', size=(550, 350),
style=wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX | wx.SYSTEM_MENU)
image = PyEmbeddedImage(images.head0).GetBitmap()
icon=wx.Icon()
icon.CopyFromBitmap(image)
self.SetIcon(icon)
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
global bitmap0
panel = wx.Panel(self)
bitmap0 = wx.StaticBitmap(panel, -1, PyEmbeddedImage(images.backg).GetBitmap(), (0, 0))
# sizer = wx.GridBagSizer(5,5)
path = r"\xxxxx\xx\name.txt"
if not os.path.exists(path):
wx.MessageBox('未找到目标文件')
sys.exit()
f = open(path, 'r', encoding='utf-8')
b = f.readlines()
f.close()
self.names=[i.replace('\n','') for i in b]
print(self.names)
self.name1 = copy.copy(self.names)
# self.name0='\n'.join(self.names)
b = ''.join(b)
input1 = wx.TextCtrl(bitmap0,-1,'候选人名单:\n'+b,size=(-1,300),pos=(5,5),style=wx.TE_READONLY|wx.TE_MULTILINE)
input1.SetBackgroundColour((255,255,240))
self.output0 = wx.TextCtrl(bitmap0,-1,'',size=(100,-1),pos = (175,50),style=wx.TE_READONLY)
self.output0.SetBackgroundColour((211, 211, 211))
# output0.Disable()
self.input2 = wx.TextCtrl(bitmap0,-1,'预选人数',size=(60,-1),pos=(300,50))
self.input3 = wx.TextCtrl(bitmap0,-1,'抽选结果...\n------',size=(150,300),pos=(370,5),style=wx.TE_READONLY|wx.TE_MULTILINE)
self.input3.SetBackgroundColour((255,228,181))
self.button1 = buttons.GenBitmapTextButton(bitmap0, -1,PyEmbeddedImage(images.pic1).GetBitmap(), " 复位抽取 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 100),size=(185,35),name = '0')
self.button2 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic2).GetBitmap(), " 清除结果 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 150), size=(185, 35),name='1')
self.button3 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic3).GetBitmap(), " 不复位抽取",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 200), size=(185, 35),name='2')
self.button4 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic4).GetBitmap(), " 停下来 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 250), size=(185, 35),name='3')
self.input2.Bind(wx.EVT_LEFT_DOWN, self.text0)
self.button1.Bind(wx.EVT_BUTTON, self.start1)
self.button2.Bind(wx.EVT_BUTTON, self.start1)
self.button3.Bind(wx.EVT_BUTTON, self.start1)
self.button4.Bind(wx.EVT_BUTTON, self.end1)
self.button4.Disable()
为了体现差异,唯一一块可以并需要用户填数的文本框并没有设定背景颜色。同时因为我们设定了默认文本,所以需要在鼠标点击的时候清除掉默认文本。
def text0(self,event):
if "预选人数" in self.input2.GetValue():
self.input2.ChangeValue("")
self.input2.SetFocus()
if self.input2.GetValue() != "":
self.input2.Unbind(wx.EVT_LEFT_DOWN)
每个按键都绑定一个按下-不可按-可按的事件,增强使用感。于是我将按键都绑定到同一个事件下,在事件中再用name判断按下的是哪一个键。
def start1(self,event):
btn = event.GetEventObject()
btn.Disable()
btnname = btn.GetName()
# print(btnname)
if btnname == '1':
self.reclear()
btn.Enable()
return
numb = self.input2.GetValue()
try:
numb = int(numb)
except:
wx.MessageBox('请填入正确人数')
btn.Enable()
return
self.btn = btn
if btnname=='0':
self.button4.Enable()
self.numb = numb
self.name1 = copy.copy(self.names)
self.refresh_fun()
elif btnname=='2':
if numb not in range(1, len(self.name1)+1):
wx.MessageBox('人数过多')
btn.Enable()
return
self.button4.Enable()
self.numb = numb
self.refresh_fun()
else:
pass
btn.Enable()
然后就是具体的事件处理,我初始的设想是一号位一直切换名字,同时二号位一个个的输出名字,给用户更强的体验感,但在具体的操作后我发现这个方法似乎十分麻烦。在我直接修改界面内容时,我期望的效果是一个个名字输出,但事实上内容会一次全部输出,哪怕我中间加了sleep等待依然如此,只不过是反应的时间变得更长了。
于是我上网搜索了一下似乎在同一线程中,wxpython无法同时响应事件与更改界面,他会在处理完全部逻辑后再更改界面。
这时就需要另外引入一个线程来对界面进行更改了。
def refresh_fun(self):
self.op = True
self.testThread = MyThread(self.output0,self.name1)
self.testThread.setDaemon(True) # 设为保护线程,主进程结束会关闭线程
self.testThread.getParm() # 获得线程内部值
self.testThread.setParm(1) # 修改线程内部值
self.testThread.start() # 开始线程
class MyThread(threading.Thread):
def __init__(self, aaa,names):
threading.Thread.__init__(self)
self.Flag = True # 停止标志位
self.Parm = 0 # 用来被外部访问的
# 自行添加参数
self.aaa = aaa
self.names=names
def run(self):
while (True):
if (not self.Flag):
self.aaa.SetLabel('抽选完毕')
break
else:
self.aaa.SetLabel(random.choice(self.names))
# print("1")
time.sleep(0.1)
def setFlag(self, parm): # 外部停止线程的操作函数
self.Flag = parm # boolean
def setParm(self, parm): # 外部修改内部信息函数
self.Parm = parm
def getParm(self): # 外部获得内部信息函数
return self.Parm
可以看到,当我们按下按钮时,一号位就会开始不停地切换名字,当然我们可以在此时同时对二号位进行修改。
我这里因为找了四个图案,想要凑齐四个按键,所以没有对二号位进行修改,而且如果二号位与一号位写在同一线程中,用户的体验感会很差,因为没法保证一号位一直切换,而二号位是隔一段时间输出一个名字。(我懒得再写一个线程修改二号位,反正我第四个按钮都要修改二号位的)
按照此时的代码,我们按下按钮后一号位会一直切换名字,而停不下来,于是我们设置一个终止按钮,在按下时更改标记值,使线程终止。
同时需要注意,因为所有线程是用的是同一个对象,终止键只会暂停最新的一个线程,所以当我们按下两次按键或者更多次时,终止位只能发生一次作用。因此当我们按下一个键后我们需要将其他按键锁定。
def end1(self,event):
self.testThread.setFlag(False)
if self.btn.GetName() =='2':
self.continuego()
elif self.btn.GetName()=='0':
self.justgo()
self.button4.Disable()
def reclear(self):
self.input3.SetValue('抽选结果...')
def continuego(self):
# print()
for i in range(self.numb):
b = random.choice(self.name1)
self.input3.SetValue(self.input3.GetValue() + '\n' + b)
self.name1.remove(b)
self.input3.SetValue(self.input3.GetValue() + '\n' + '------')
def justgo(self): #重置抽取
self.name1 = copy.copy(self.names)
for i in range(self.numb):
b = random.choice(self.name1)
self.input3.SetValue(self.input3.GetValue() + '\n' + b)
self.name1.remove(b)
self.input3.SetValue(self.input3.GetValue() + '\n' + '------')
self.name1 = copy.copy(self.names)
此处用到了python的copy,因为在测试时我发现,哪怕我将self.names赋值给self.name1,但实际上我修改self.name1时依然会影响到self.names。
在按下第四个按钮时终止一号位名字的切换同时判断按下的是哪一个键,然后进行具体的操作。
另外不得不一提的是,我原本希望令图片能够自适应我的组件大小,但是似乎并不可行。于是我先将图片尺寸设置好,再换成64位编码,比较常用的尺寸是32x32。
全代码
# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File : price.py
# Time :2022/9/23 17:54
# Author :Ray Zhong
# version :python 3.7
# Description:
"""
import images
import wx,time,random,copy,sys,os
import wx.lib.buttons as buttons
from wx.lib.embeddedimage import PyEmbeddedImage
import threading
class xiuli(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, '第一代抽奖系统', size=(550, 350),
style=wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX | wx.SYSTEM_MENU)
image = PyEmbeddedImage(images.head0).GetBitmap()
icon=wx.Icon()
icon.CopyFromBitmap(image)
self.SetIcon(icon)
self.InitUI()
self.Centre()
self.Show()
def InitUI(self):
global bitmap0
panel = wx.Panel(self)
bitmap0 = wx.StaticBitmap(panel, -1, PyEmbeddedImage(images.backg).GetBitmap(), (0, 0))
# sizer = wx.GridBagSizer(5,5)
path = r"\\itgzfs01\GZAccounts\Maxim's H.K\AP\Users\Ray Zhong\开发代码\others\name.txt"
if not os.path.exists(path):
wx.MessageBox('未找到目标文件')
sys.exit()
f = open(path, 'r', encoding='utf-8')
b = f.readlines()
f.close()
self.names=[i.replace('\n','') for i in b]
# print(self.names)
self.name1 = copy.copy(self.names)
# self.name0='\n'.join(self.names)
b = ''.join(b)
input1 = wx.TextCtrl(bitmap0,-1,'候选人名单:\n'+b,size=(-1,300),pos=(5,5),style=wx.TE_READONLY|wx.TE_MULTILINE)
input1.SetBackgroundColour((255,255,240))
self.output0 = wx.TextCtrl(bitmap0,-1,'',size=(100,-1),pos = (175,50),style=wx.TE_READONLY)
self.output0.SetBackgroundColour((211, 211, 211))
# output0.Disable()
self.input2 = wx.TextCtrl(bitmap0,-1,'预选人数',size=(60,-1),pos=(300,50))
self.input3 = wx.TextCtrl(bitmap0,-1,'抽选结果...\n------',size=(150,300),pos=(370,5),style=wx.TE_READONLY|wx.TE_MULTILINE)
self.input3.SetBackgroundColour((255,228,181))
self.button1 = buttons.GenBitmapTextButton(bitmap0, -1,PyEmbeddedImage(images.pic1).GetBitmap(), " 复位抽取 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 100),size=(185,35),name = '0')
self.button2 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic2).GetBitmap(), " 清除结果 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 150), size=(185, 35),name='1')
self.button3 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic3).GetBitmap(), " 不复位抽取",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 200), size=(185, 35),name='2')
self.button4 = buttons.GenBitmapTextButton(bitmap0, -1, PyEmbeddedImage(images.pic4).GetBitmap(), " 停下来 ",
style=wx.IMAGE_ALPHA_THRESHOLD | wx.BORDER, pos=(175, 250), size=(185, 35),name='3')
self.input2.Bind(wx.EVT_LEFT_DOWN, self.text0)
self.button1.Bind(wx.EVT_BUTTON, self.start1)
self.button2.Bind(wx.EVT_BUTTON, self.start1)
self.button3.Bind(wx.EVT_BUTTON, self.start1)
self.button4.Bind(wx.EVT_BUTTON, self.end1)
self.button4.Disable()
def text0(self,event):
if "预选人数" in self.input2.GetValue():
self.input2.ChangeValue("")
self.input2.SetFocus()
if self.input2.GetValue() != "":
self.input2.Unbind(wx.EVT_LEFT_DOWN)
def start1(self,event):
btn = event.GetEventObject()
btn.Disable()
btnname = btn.GetName()
# print(btnname)
if btnname == '1':
self.reclear()
btn.Enable()
return
numb = self.input2.GetValue()
try:
numb = int(numb)
except:
wx.MessageBox('请填入正确人数')
btn.Enable()
return
self.btn = btn
if btnname=='0':
self.button4.Enable()
self.numb = numb
self.name1 = copy.copy(self.names)
self.refresh_fun()
elif btnname=='2':
if numb not in range(1, len(self.name1)+1):
wx.MessageBox('人数过多')
btn.Enable()
return
self.button4.Enable()
self.numb = numb
self.refresh_fun()
else:
pass
btn.Enable()
def end1(self,event):
self.testThread.setFlag(False)
if self.btn.GetName() =='2':
self.continuego()
elif self.btn.GetName()=='0':
self.justgo()
self.button4.Disable()
def refresh_fun(self):
self.op = True
self.testThread = MyThread(self.output0,self.name1)
self.testThread.setDaemon(True) # 设为保护线程,主进程结束会关闭线程
self.testThread.getParm() # 获得线程内部值
self.testThread.setParm(1) # 修改线程内部值
self.testThread.start() # 开始线程
def reclear(self):
self.input3.SetValue('抽选结果...')
def continuego(self):
# print()
for i in range(self.numb):
b = random.choice(self.name1)
self.input3.SetValue(self.input3.GetValue() + '\n' + b)
self.name1.remove(b)
self.input3.SetValue(self.input3.GetValue() + '\n' + '------')
def justgo(self): #重置抽取
self.name1 = copy.copy(self.names)
for i in range(self.numb):
b = random.choice(self.name1)
self.input3.SetValue(self.input3.GetValue() + '\n' + b)
self.name1.remove(b)
self.input3.SetValue(self.input3.GetValue() + '\n' + '------')
self.name1 = copy.copy(self.names)
class MyThread(threading.Thread):
def __init__(self, aaa,names):
threading.Thread.__init__(self)
self.Flag = True # 停止标志位
self.Parm = 0 # 用来被外部访问的
# 自行添加参数
self.aaa = aaa
self.names=names
def run(self):
while (True):
if (not self.Flag):
self.aaa.SetLabel('抽选完毕')
break
else:
self.aaa.SetLabel(random.choice(self.names))
time.sleep(0.1)
def setFlag(self, parm): # 外部停止线程的操作函数
self.Flag = parm # boolean
def setParm(self, parm): # 外部修改内部信息函数
self.Parm = parm
def getParm(self): # 外部获得内部信息函数
return self.Parm
if __name__ == '__main__':
app = wx.App() # 创建应用程序对象
login = xiuli()
app.MainLoop()
ps:吐槽一下为什么代码段也要计入总字数,整得我都怀疑自己了,200行的代码统计超过1W个字
=。=!