相信很多小伙伴都曾在抖音、快手以及 B 站等平台刷到过表白程序,不论是各种的程序制作爱心或者是程序制作心动符号等,在各个平台很受欢迎。但是其中大多数形式都已经被公众所知晓,且缺乏流动性。故今天我们将自行设计一个表白浪漫程序,具有动态开关宠物、照片墙、弹窗提示以及 turtle 画图等功能。其中具体效果图如下:
本浪漫程序的技术路线分为以下几个部分:
- 通过 Pyqt5 模块构建透明窗口,并设置聊天窗等功能,设置右键功能,使其功能启动“浪漫程序“;
- 开始宠物系统再通过多线程启动其他程序,包含弹窗程序,海龟画图程序等;
- 生成爱心照片墙:通过 2.py 程序生成爱心照片墙,并缩放至1000×806;
- 海龟画图:运行 1.py 程序实现海龟画图,绘制玫瑰花和爱心;
其中的程序操作流程:
首先运行 2.py 生成照片墙,并缩放至 1000×806;然后运行 biu.py 启动宠物系统,通过邮件宠物运行整个程序,最终程序会慢慢完成,形成动态程序效果。
具体功能的形成分为以下几个部分介绍,最终代码也会免费放置文末的百度网盘中,供大家学习参考。
照片墙生成程序
其中程序运行基本步骤为:首先需要将需要生成的照片放置 photo 文件夹中,然后直接运行 2.py 程序即可。
其中的照片墙素材如下:
代码思路如下:
首先自定义二维 list,其中 1 表示填充空白块,0 表示填充读取到的照片;然后读取照片路径,并通过 random 实现随机化,避免相近图片排在一起;接着通过 Image 库读入图片,对读取到得图像集遍历绘制至其中。其中具体部分代码如下所示:
random.shuffle(imgs)
img_h = img_w = 250
rows = len(map)
columns = len(map[0])
figure = Image.new("RGB", (img_w * columns, img_h * rows), "white")
count = 0
for i in range(len(map)):
for j in range(len(map[i])):
if map[i][j] == 1:
continue
else:
try:
image = Image.open(os.path.join(img_dir, imgs[count]))
except:
continue
image = image.resize((img_w, img_h))
figure.paste(image, (img_w * j, img_h * i))
count += 1
这里用游戏中的图片作为生成素材,最终生成的照片墙如下:
启动宠物程序
启动宠物程序基本流程为:首先建立表白语料库作为聊天窗口展示;然后自行选择一些具有表白意义的 gif 动态图作为宠物动作;最后通过 Pyqt5 构建透明窗口程序,通过多线程实现动作交替以及右键鼠标功能等。
1、其中构建的语料库文件如下,存储到“data.txt“中,并通过换行实现语句分割,其中“data.txt”直接放置和程序同一目录即可,可参照文末提供的原始程序放置位置:
2、构建的宠物动作动态图素材,将找到的素材放置biu文件夹下,如下图所示:
3、程序实现。程序实现主要分为初始化透明窗口、设置托盘选项、右键菜单功能、设置聊天对话框功能以及动作时间交替等部分,整体程序的实现有 pyqt5 构成。
其中具体知识点分为以下几个部分:
1、Pyqt5 基本流程
1.1 类的定义和初始化
为了使程序更加规范,我们定义整体的类变量,方便调用。
其中分为下面几步:
1、时间变量初始化
2、调用随时间图案变化函数
3、窗口位置和边框初始化
4、计时器初始化。
5、鼠标跟踪定义
1.2 透明窗口的定义
初始化中加入 self.setAttribute(Qt.WA_TranslucentBackground) 实现背景透明效果。
1.3 不规则窗口函数的建立
主要使用 Qt.AvoidDither|Qt.ThresholdAlphaDither|Qt.ThresholdDither 参数实现不规则窗口。同时还需要规定不规则窗口尺寸等等,主要定义函数 mypix 进行调用
1.4 鼠标设置
可通过初始化 self.setMouseTracking(False) 设置鼠标移动跟踪是否有效。设置为 True 时,只要鼠标在窗口内移动时 mouseMoveEvent 事件就能捕获
设置为 False 时(默认),只有鼠标键按下并在窗口内移动时 mouseMoveEvent 事件才能捕获
注意只能是 QWidget,如果是 QMainwindow,则无效
self.hasMouseTracking()返回设置的状态
1.5 创建多线程时间变化
定义时间变化函数,一个线程用来更新动画,另一个用来更新对话框。
1.6 对话框函数定义
如果鼠标触碰到宠物的话就弹出对话。
其中部分代码如下:
def __init__(self):
super(DemoWin, self).__init__()
self.initUI()
# 初始化,不规则窗口
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow)
self.setAutoFillBackground(False)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.repaint()
# 是否跟随鼠标
self.is_follow_mouse = False
self.move(1650,20)
with open("data.txt", "r") as f:
text = f.read()
self.sentence = text.split("\n")
2、鼠标控制
2.1 鼠标点击事件
鼠标点击 icon 传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键。
2.2 鼠标按下调用
通过 n = event.button() 用来判断是哪个鼠标健触发了事件【返回值:0 1 2 4】。
其中:
- QtCore.Qt.NoButton - 0 - 没有按下鼠标键
- QtCore.Qt.LeftButton -1 -按下鼠标左键
- QtCore.Qt.RightButton -2 -按下鼠标右键
- QtCore.Qt.Mion 或 QtCore.Qt.MiddleButton -4 -按下鼠标中键
通过 nn = event.buttons() 返回前面所列枚举值的组合,用于判断同时按下了哪些键
2.3 鼠标松开
定义函数 mouseReleaseEvent,鼠标键释放时调用参数1:鼠标的作用对象;参数2:鼠标事件对象,用来保存鼠标数据。
2.4 鼠标拖动事件
定义函数 mouseMoveEvent 通过 self.hasMouseTracking() 获取移动值。然后获得鼠标坐标。控制窗口随之移动
2.5 鼠标移出和滚轮事件
鼠标移出定义函数 leaveEvent,滚轮 wheelEvent。
2.6 鼠标右键事件
鼠标移出定义函数contextMenuEvent,在右键菜单里通过cmenu.addAction加入标签。action = cmenu.exec_(self.mapToGlobal(e.pos())) 获取鼠标点击标签,用来判断用户点击了哪一个标签。
其中部分代码如下:
# 当按右键的时候,这个event会被触发
def contextMenuEvent(self, event):
menu = QMenu(self)
video = menu.addAction("浪漫程序")
quitAction = menu.addAction("退出")
action = menu.exec_(self.mapToGlobal(event.pos()))
if action == quitAction:
qApp.quit()
if action == video:
import threading
def t2():
os.system("python 1.py")
t22=threading.Thread(target=t2)
t22.start()
3、动态宠物控制
3.1 根据事件的动作判定
这里定义点击等动作自动回馈等等。
3.2 宠物图片更换
定义列表用来存储素材关系。
3.3 程序退出事件
通过quit函数控制退出
def quit(self):
self.close()
sys.exit()
3.4 整体执行
从main入口开始执行整体类
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("1.jpg"))
# 创建一个主窗口
mainWin = DemoWin()
# 显示
mainWin.show()
# 主循环
sys.exit(app.exec_())
最终实现效果如下如所示:
turtle 画图
这里通过海龟画图绘制爱心和玫瑰,实现动态绘图效果。通过 pensize 函数定义画笔大小;speed 定义速度;Color 定义颜色;等等
其中部分代码如下:
wn = turtle.Screen()
wn.screensize()
wn.setup(width=1.0, height=1.0)
wn.register_shape('1.gif')
rocket = turtle.Turtle()
rocket.shape('1.gif')
color('red', 'pink')
getscreen().tracer(1, 0)
heart(100, 0, 0.7)
go_to(80, 70)
write("小明", font=("楷体", 18, "normal"))
setheading(0)
heart(-80, -100, 1)
go_to(-110, 15)
write("小红", font=("宋体", 20, "normal"))
go_to(40, -80)
write("三生三世皆是你!", move=True, align="left", font=("arial", 22, "italic"))
time.sleep(2)
wn.clear()
弹窗程序
弹窗程序非常简单,通过 tkinter 构建弹窗即可,再定义窗口和字体大小颜色等等即可。然后循环多线程实现。
其中部分代码如下:
def dow():
window = tk.Tk()
width = window.winfo_screenwidth()
height = window.winfo_screenheight()
a = random.randrange(0, width)
b = random.randrange(0, height)
window.title('小明表白小红') # 弹窗的名字
window.geometry("200x50" + "+" + str(a) + "+" + str(b)) # 弹窗大小 tk.Label(window,
text='小明表白小红!', # 标签的文字
bg='Red', # 背景颜色
font=('楷体', 17), # 字体和字体大小
width=15, height=2 # 标签长宽
).pack() # 固定窗口位置
window.mainloop()
threads = []
for i in range(100):
t = threading.Thread(target=dow)
threads.append(t)
time.sleep(0.1)
threads[i].start()
效果如下: