为了520能够博得女友欢心,我设计了一个用来表白的程序,主要用到了tkinter的画布和各种鼠标事件,今天就来分享给大家。(借鉴要谨慎,可不要只用它来糊弄女盆友哦)
程序的设计是用tkinter模拟手机操作,实现手机桌面的展示、滑动和下拉,然后点击指定位置,可以弹出新的内容。其原理是用canvas显示图片,所谓的滑动和点击等等,其实就是图片的更换;下拉则是利用鼠标事件来移动图片,实现和手机下拉相同的效果(不到半屏自动回位,超过半屏自动落下,落下后拖动底端回位)。
桌面是犯罪嫌疑人——偷心贼
下拉的效果:
部分效果如上所示,点击信息、拨号和相册,可以分别弹出新的图片(把表白的内容放在这里);点击home键则是返回(home键是一个显示了图片的button按钮);桌面还可以滑动,滑动后切换成另一张背景图(我本人),然后对应绑定了不同的鼠标事件,点击后会显示与之前不同的图片。(所有图片都是我用自己的手机截图的)
程序逻辑里,最重要的部分就是几个模式的区分,我用flag来定义,具体如下:flag=0是初始状态、点击屏幕其他位置和下拉未到半屏回位后的状态;flag=1是点击屏幕顶端下拉;flag=2是下拉超过半屏后自动落下,和此时再点击其他位置;flag=3是落下后点击屏幕底端回位;flag=5是切换屏幕。
程序中创建了两个canvas,一个用来显示外壳(固定不动),另一个用来显示屏幕(触发各种事件)。在这两个画布中,获取鼠标位置event.x和event.y是分开计的,所以我们只需要用到显示屏幕的画布中的位置。根据信息、拨号和相册的位置,在点击时设置对应的flag值,触发各自的事件(其实就是显示新的图片)。
另外,所有屏幕图片的大小都是400*700,所以桌面的初始位置在(200,350)附近,而下拉图片的初始位置是(200,-350),此时是在画布外的,不会显示出来。触发下拉事件时,它就会跟随鼠标移动。(这也是创建两个canvas的原因,如果只用一个,由于屏幕不是在画布的顶端,因此下拉图片不会被隐藏起来;而如果它属于其中一个画布,但初始位置在画布外,那么就会隐藏)
下面是完整代码和简单注释:
from tkinter import * import tkinter as tk from PIL import Image, ImageTk import time import cv2 flag=0 #状态标志 root = Tk() root.title("手机") root.geometry("450x840+500+0") root.overrideredirect(True) canvas2 = Canvas(root,width=450, height=840,bg='white',highlightthickness=0) canvas = Canvas(root,width=400, height=700,bg='black',highlightthickness=0) f=0 #记录之前的flag,当前事件结束后返回前一个状态 canvas2.place(x=0,y=0) #手机壳 canvas.place(x=24,y=80) #屏幕 #左键点击home键,清除刚才显示的图片(即返回桌面),同时开始计时 def onLeftButton(event): global start start=time.time() canvas.delete('c') #鼠标左键抬起home键,结束计时,超过3秒则退出程序(关机),否则退回之前的flag def ButtonUp(event): global end,start,flag end=time.time() flag=f if end-start>=3: root.destroy() #获得鼠标位置,并设置相应的flag def callback(event): global x,y,flag x = event.x y = event.y if flag!=2 and 0<y<10: flag=1 if flag==2 and y>680: flag=3 #双击“信息”、“拨号”或“相册”的位置,显示新的图片 #两个桌面对应不同的图片,用flag来区分 def DoubleButton(event): if flag==5: if 30<x<90 and 30<y<90: canvas.create_image(200,350,image=var7,tags="c") elif 120<x<180 and 600<y<660: canvas.create_image(200,350,image=var8,tags="c") else: if 30<x<90 and 30<y<90: canvas.create_image(200,350,image=var3,tags="c") elif 120<x<180 and 600<y<660: canvas.create_image(200,350,image=var4,tags="c") elif 220<x<270 and 600<y<660: canvas.create_image(200,350,image=var5,tags="c") #按住左键并拖动鼠标,显示下拉图片 def onLeftButtonMove(event): global a,flag,f if flag==2: return if flag==0: f=5-flag #这里要么是0,要么是5 return if flag==5: f=5-flag return #下拉栏落下后,拖动底端回位 if flag==3: if event.y<=702: canvas.delete('a') canvas.create_image(200,event.y-350,image=var1,tags="a") return #跟随鼠标下拉 if flag==1 and event.y<=702: canvas.delete('a') canvas.create_image(200,event.y-350,image=var1,tags="a") return #释放左键,触发下拉的动态效果(自动下落或回位)以及两个桌面的切换 def onLeftButtonUp(event): global a,flag if flag==0: if abs(event.x-x)>10: canvas.create_image((200,350), image=var6,tags='b') flag=5 return else: return if flag==5: if abs(event.x-x)>10: canvas.create_image((200,350), image=var2,tags='b') flag=0 return else: return if flag==2: return yy=event.y i=0 if flag==3: #不到半屏自动回位 while yy-i>=-350: canvas.delete('a') canvas.create_image(200,yy-i-350,image=var1,tags="a") i+=1 root.update_idletasks() #刷新 root.update() flag=f return #超过半屏自动落下 if yy>350: while yy+i<=702: canvas.delete('a') canvas.create_image(200,yy+i-350,image=var1,tags="a") i+=1 root.update_idletasks() #刷新 root.update() flag=2 return #点击底端,自动回位 while yy-i>=-350: canvas.delete('a') canvas.create_image(200,yy-i-350,image=var1,tags="a") i+=1 root.update_idletasks() #刷新 root.update() flag=f #存储初始图 load = Image.open("res/0.jpg") #手机壳图片 var= ImageTk.PhotoImage(load) load = Image.open("res/1.png") var1= ImageTk.PhotoImage(load) load = Image.open("res/2.jpg") var2= ImageTk.PhotoImage(load) load = Image.open("res/3.jpg") var3= ImageTk.PhotoImage(load) load = Image.open("res/4.jpg") var4= ImageTk.PhotoImage(load) load = Image.open("res/5.jpg") var5= ImageTk.PhotoImage(load) load = Image.open("res/6.jpg") var6= ImageTk.PhotoImage(load) load = Image.open("res/7.png") var7= ImageTk.PhotoImage(load) load = Image.open("res/8.jpg") var8= ImageTk.PhotoImage(load) load = Image.open("res/bt.png") bt= ImageTk.PhotoImage(load) canvas.create_image((200,-350), image=var1,tags='a') #下拉图片的初始位置,此时未进入画布当中 canvas2.create_image((225,430), image=var) #手机壳 canvas.create_image((200,352), image=var2,tags='b') #初始桌面 b = Button(root, image = bt, bg='black',activebackground='black') b.place(x=165,y=800) b.bind('<Button-1>', onLeftButton) b.bind('<ButtonRelease-1>', ButtonUp) canvas.bind('<B1-Motion>', onLeftButtonMove) #按住并移动左键 canvas.bind('<ButtonRelease-1>', onLeftButtonUp) #释放左键 canvas.bind('<Double-Button-1>', DoubleButton) #双击左键 root.bind("<Button-1>",callback) root.mainloop()
P.S.代码中用到的各种位置都经过了微调,达到最佳效果。
在这篇文章里,我们演示了如何用tkinter实现复杂的鼠标事件,将不同组件的鼠标事件结合起来。赶紧学会这一手,回去哄女朋友吧!