python中的pygame库,并没有传统菜单功能,正好手边有一自己想做的小项目,需要在pygame中实现菜单功能。现将其中实现菜单功能的约400行代码摘取出来,供大家参考。
该菜单完全依托pygame实现,没有借用任何其它库。实现效果如下:
菜单中定义了主题,可以按空格键改变,为简化,只定义了2个主题,即深色主题(见上图)和浅色主题(见下图):
点选菜单后,程序会执行相应代码,下图为点“圆”后在屏幕输出的一个随机绘制圆的小程序,点其它菜单项其它均用print()提示:
下面提交代码,并进行简要说明。程序用到的库有:
from sys import exit
import pygame
from pygame.locals import *
from random import randint
from math import floor
定义一个class:
class mymenu(object): # 在pygame中定义菜单,支持鼠标和键盘操作
主程序定义了几个全局变量,是对一些可调整的基本量进行定义,比如菜单栏的高度、状态栏的高度、颜色等,方便使用者修改,一些变量使用了中文,我觉得用中文做变量或过程名称,可以少写许多中文注释,所以有些地方就直接用中文了。
# 主程序 ===========================
def main(NoWelcom=False):
global screen_w,screen_h,底部状态栏高度 , 菜单栏高度 , screen,菜单 ,字体,背景颜色
pygame.init()
pygame.display.set_caption('Pygame菜单演示')
字体='simsun'
底部状态栏高度 = 22
菜单栏高度 = 22
背景颜色 = (255,255,255)
改变窗口大小((1000, 800),RESIZABLE)
菜单=mymenu() # 初始化顶部菜单
菜单项全部定义成了变量,当然,如果需要的话,可以自己改为传递参数也行。
菜单分隔条,用 '-'号表示
菜单项的宽度会根据字体大小和文字多少自动调整。演示中定义的变量如下:
def __init__(self):
self.menu_height=菜单栏高度
self.sub_top_height=12 # 子菜单第一行上边保留空间
self.default_fontsize=16 # 菜单初始字体大小
self.mainfontsize=self.default_fontsize # 主菜单字体大小
self.subfontsize =self.default_fontsize # 子菜单字体大小 当菜单高度大于窗口高度时,字体会自动缩小,以适应窗口
self.menus =[ '文件(F)','直角坐标函数展示(R)','极坐标函数展示(P)','功能(S)','趣味(Q)','帮助(H)'] # 第一级菜单 即主菜单
self.submenus =[['新建... Ctrl+N','修改...','-','打开文件... Ctrl+O','保存到文件... Ctrl+S','保存图片... ','-','打开内置函数...','-','退出 Alt+F4'],
['圆','椭圆','抛物线','正弦曲线','正切曲线','两个方程求共解','-','锯齿波','方波','-','笑脸','美之心(纹)','五星红旗'],
['阿基米德螺线','伯努利双扭线','笛卡尔心形线','-','回旋','绳结','花心','-','模拟表盘','扫描','绚丽图形','头结','蝴蝶曲线'],
['改变菜单主题 空格','-','坐标系... F9','-','绘图方式... 1234','画笔颜色... F10','-','切换背景图片 F6','图例设置...','-','屏幕大小... F12','-','更多设置...'],
['天体运行模拟系统','导弹模拟系统','宇宙大爆炸模拟系统','-','三体游戏','魂斗罗游戏','-','屏幕爬虫','彩虹漩涡','飘雪'],
['操作说明 F1','软件说明','视频介绍','-','注册...','-','关于']] # 第二级菜单 其中的 '-' 为划一条分隔线 add_separator
self.subcommand=[['新建.showTK("新建")','修改.showTK()','-','打开文件()','保存文件()','屏幕截图()','-','从内置函数挑选()','-','退出系统()'],
['画圆()','椭圆','抛物线','正弦曲线','正切曲线','两个方程求共解','-','锯齿波','方波','-','笑脸','美之心(纹)','五星红旗'],
['阿基米德螺线','伯努利双扭线','笛卡尔心形线','-','回旋','绳结','花心','-','模拟表盘','扫描','绚丽图形','头结','蝴蝶曲线'],
['改变菜单主题()','-','选择坐标系()','-','绘图方式()','画笔颜色设置()','-','背景图片集.切换()','图例.图例设置()','-','调整屏幕大小()','-','调整相关变量()'],
['天体运行模拟系统()','导弹轨迹()','宇宙大爆炸()','-','三体()','魂斗罗()','-','屏幕爬虫()','彩虹漩涡()','飘雪()'],
['操作说明(1)','软件说明()','播放视频()','-','注册()','-','关于()']] # 点选后需要执行的命令
程序中主题的实现,实际就是一些颜色的定义,本演示只简单用了两种主题:
def menu_colors(self):
if 背景颜色==(255,255,255):
self.fgcolor=(232,232,232) # 前景色
self.bgcolor=(33,34,35) # 背景色
self.activefgcolor=(68,68,68) # 鼠标在其上时字体显示的颜色
self.activebgcolor=(132,188,230) # 鼠标在其上时背景显示的颜色
self.submenu_bg_color=(70,70,70) # 二级菜单的背景颜色
self.submenu_border_color=(2,2,2) # 二级菜单边沿处颜色
else:
self.fgcolor=(68,68,68) # 字体颜色
self.bgcolor=(251,252,253) # 主菜单背景颜色
self.activefgcolor=(68,68,68) # 鼠标在其上时字体颜色
self.activebgcolor=(168,210,253) # 鼠标在其上时背景颜色
self.submenu_bg_color=(251,252,253) # 二级菜单的背景颜色
self.submenu_border_color=(220,221,222) # 二级菜单边沿处颜色
鼠标和键盘,用 pygame.event.get() 获取相关事件来实现。当鼠标移动到屏幕上端达到菜单高度范围内时,执行命令:mouse_over_menu() ,激活菜单。
elif event.type==MOUSEMOTION : # 鼠标移动事件 pos, rel, buttons 三个参数说明:当前鼠标坐标,相对移动距离,按键 ,数据格式分别为:(1619, 7) (0, 0, 0) (3, -6)
if 0<=event.pos[1]<=菜单栏高度 : # 菜单位置
菜单.mouse_over_menu(posx=event.pos[0])
显示鼠标处数值(event.pos,'提示:请您在菜单栏中选择')
elif 菜单.get_sub_is_active(): # 有二级菜单激活状态
subrect=菜单.get_subrect()
if (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]):
菜单.mouse_over_submenu(posy=event.pos[1])
显示鼠标处数值(event.pos,'提示:可以用鼠标或键盘上下左右键选择相应菜单')
def mouse_over_menu(self,posx): # 鼠标经过
self.pos_to_i(posx)
if self.i is not None:
self.menu_chose()
else:
self.menu_root()
if self.sub_is_active : # 如果二级菜单已经打开
self.submenu()
如果有点击鼠标事件发生,则执行:menu_click(),如果在打开的菜单上点击,执行 submenu_click()
elif event.type==MOUSEBUTTONDOWN : # 有鼠标被按下的事件发生
if event.button==1 : # 鼠标左键按下
if 0<=event.pos[1]<=菜单栏高度 :# 菜单位置
菜单.menu_click(posx=event.pos[0],posy=event.pos[1])
elif 菜单.get_sub_is_active(): # 有二级菜单激活状态
subrect=菜单.get_subrect()
if (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]):
菜单.submenu_click(posx=event.pos[0],posy=event.pos[1])
else:
菜单.lost_focus()
else:
菜单.lost_focus()
定义键盘快捷键操作:按alt+定义按键,执行 menu_alt()
elif mods & pygame.KMOD_ALT and event.key<256:
if chr(event.key).upper() in 'FRPSQH': # 主菜单项
菜单.menu_alt(key=event.key)
菜单打开状态下,鼠标和键盘上、下、左、右、回车键均可选择命令,用 menu_key() 选择命令,
if key==K_ESCAPE:
菜单.lost_focus()
elif key==K_LEFT:
if self.i>0:
self.i -= 1
self.open_submenu(self.i,0)
elif key==K_RIGHT:
if self.i<len(self.menus)-1:
self.i += 1
self.open_submenu(self.i,0)
elif key==K_DOWN:
if self.j is None:
self.j=0
elif self.j<=len(self.submenus[self.i])-1:
self.j += 1
if self.j<len(self.submenus[self.i])-1 and self.submenus[self.i][self.j][0]=='-':
self.j += 1
if self.j>=len(self.submenus[self.i]):
self.j=0
self.open_submenu(self.i,self.j)
elif key==K_UP:
if self.j is None:
self.j=len(self.submenus[self.i])-1
if self.j>=0:
self.j -= 1
if self.submenus[self.i][self.j][0]=='-':
self.j -= 1
if self.j<0:
self.j=len(self.submenus[self.i])-1
self.open_submenu(self.i,self.j)
elif key==K_RETURN or key==K_KP_ENTER:
self.submenu_click()
elif key<256 and chr(key).upper() in 'FRPSQH': # 主菜单项
self.menu_alt(key)
然后,根据点选内容,执行相应命令。相应命令存在变量 self.subcommand 中,是str格式,可以用exec() 或 evel() 执行。
当鼠标或键盘焦点不在菜单上时,要执行 lost_focus() ,取消菜单激活状态。
程序中通过保存屏幕和显示保存的屏幕,实现菜单的快速切换,如果程序很小,可以直接刷新,这需要开发者另外来改写了。
程序中还有一些其它技巧,读取代码参考吧,好了,现在上完整代码:
# encoding:utf-8
# Copyright (C) 2021-2022 Liu Qinghao
__author__ = 'Liu Qinghao' # 作者
'''
# Tel: 13837335336
# 微信: yikehongxin6666
# Email: 11220200@QQ.com
'''
from sys import exit
import pygame
from pygame.locals import *
from random import randint
from math import floor
class mymenu(object): # 在pygame中定义菜单,支持鼠标和键盘操作
def __init__(self):
self.menu_height=菜单栏高度
self.sub_top_height=12 # 子菜单第一行上边保留空间
self.default_fontsize=16 # 菜单初始字体大小
self.mainfontsize=self.default_fontsize # 主菜单字体大小
self.subfontsize =self.default_fontsize # 子菜单字体大小 当菜单高度大于窗口高度时,字体会自动缩小,以适应窗口
self.menus =[ '文件(F)','直角坐标函数展示(R)','极坐标函数展示(P)','功能(S)','趣味(Q)','帮助(H)'] # 第一级菜单 即主菜单
self.submenus =[['新建... Ctrl+N','修改...','-','打开文件... Ctrl+O','保存到文件... Ctrl+S','保存图片... ','-','打开内置函数...','-','退出 Alt+F4'],
['圆','椭圆','抛物线','正弦曲线','正切曲线','两个方程求共解','-','锯齿波','方波','-','笑脸','美之心(纹)','五星红旗'],
['阿基米德螺线','伯努利双扭线','笛卡尔心形线','-','回旋','绳结','花心','-','模拟表盘','扫描','绚丽图形','头结','蝴蝶曲线'],
['改变菜单主题 空格','-','坐标系... F9','-','绘图方式... 1234','画笔颜色... F10','-','切换背景图片 F6','图例设置...','-','屏幕大小... F12','-','更多设置...'],
['天体运行模拟系统','导弹模拟系统','宇宙大爆炸模拟系统','-','三体游戏','魂斗罗游戏','-','屏幕爬虫','彩虹漩涡','飘雪'],
['操作说明 F1','软件说明','视频介绍','-','注册...','-','关于']] # 第二级菜单 其中的 '-' 为划一条分隔线 add_separator
self.subcommand=[['新建.showTK("新建")','修改.showTK()','-','打开文件()','保存文件()','屏幕截图()','-','从内置函数挑选()','-','退出系统()'],
['画圆()','椭圆','抛物线','正弦曲线','正切曲线','两个方程求共解','-','锯齿波','方波','-','笑脸','美之心(纹)','五星红旗'],
['阿基米德螺线','伯努利双扭线','笛卡尔心形线','-','回旋','绳结','花心','-','模拟表盘','扫描','绚丽图形','头结','蝴蝶曲线'],
['改变菜单主题()','-','选择坐标系()','-','绘图方式()','画笔颜色设置()','-','背景图片集.切换()','图例.图例设置()','-','调整屏幕大小()','-','调整相关变量()'],
['天体运行模拟系统()','导弹轨迹()','宇宙大爆炸()','-','三体()','魂斗罗()','-','屏幕爬虫()','彩虹漩涡()','飘雪()'],
['操作说明(1)','软件说明()','播放视频()','-','注册()','-','关于()']] # 点选后需要执行的命令
self.subsize = []
for i in range(len(self.submenus)): # 二级菜单大小 w h ,根据内容自动算出其宽和高度
self.subsize.append([len(max(self.submenus[i],key=lencc).encode('GBK'))*self.subfontsize/2+30 ,
len(self.submenus[i])*self.subfontsize*2 +self.sub_top_height])
topline=int((self.menu_height-self.subfontsize)/2) # 子菜单第一行上面留空
self.xy= [(12,topline),(84,topline),(252,topline),(403,topline),(475,topline),(547,topline),(622,topline)] # 定义每个菜单的起始位置,数量应比self.menus多一个数,最后一个数是最后一个菜单的最后坐标
# 以上几个数据必须完全对应才行,否则会出错!!! 注意数据排列方式!!!
self.i = None # 记忆一级菜单位置 (一级菜单也叫主菜单)
self.j = None # 记忆二级菜单位置
self.subrect=None # 二级菜单感应鼠标范围
self.sub_is_active=False # 二级菜单是否已经打开
self.menu_root()
def menu_colors(self):
if 背景颜色==(255,255,255):
self.fgcolor=(232,232,232) # 前景色
self.bgcolor=(33,34,35) # 背景色
self.activefgcolor=(68,68,68) # 鼠标在其上时字体显示的颜色
self.activebgcolor=(132,188,230) # 鼠标在其上时背景显示的颜色
self.submenu_bg_color=(70,70,70) # 二级菜单的背景颜色
self.submenu_border_color=(2,2,2) # 二级菜单边沿处颜色
else:
self.fgcolor=(68,68,68) # 字体颜色
self.bgcolor=(251,252,253) # 主菜单背景颜色
self.activefgcolor=(68,68,68) # 鼠标在其上时字体颜色
self.activebgcolor=(168,210,253) # 鼠标在其上时背景颜色
self.submenu_bg_color=(251,252,253) # 二级菜单的背景颜色
self.submenu_border_color=(220,221,222) # 二级菜单边沿处颜色
def menu_root(self): # 菜单的基础
self.menu_colors()
pygame.draw.rect(screen,self.bgcolor,(0,0,screen_w,self.menu_height))
for i in range(len(self.menus)):
str_to_screen(' '+self.menus[i]+' ',self.xy[i][0],self.xy[i][1],self.mainfontsize,self.fgcolor,bgcolor=self.bgcolor,bold=True)
def mouse_over_menu(self,posx): # 鼠标经过
self.pos_to_i(posx)
if self.i is not None:
self.menu_chose()
else:
self.menu_root()
if self.sub_is_active : # 如果二级菜单已经打开
self.submenu()
def menu_chose(self): # 画主菜单被选择部分
pygame.draw.rect(screen,self.activebgcolor,(self.xy[self.i][0],0,self.xy[self.i+1][0]-self.xy[self.i][0],self.menu_height))
str_to_screen(' '+self.menus[self.i]+' ',self.xy[self.i][0],self.xy[self.i][1],self.mainfontsize,self.activefgcolor,bgcolor=self.activebgcolor)
def submenu_chose(self):
pygame.draw.rect(screen,self.activebgcolor,(self.子菜单坐标x[self.j]-10,self.子菜单坐标y[self.j]-self.subfontsize/2,self.subsize[self.i][0]*(self.subfontsize/self.default_fontsize)+10,self.subfontsize*2))
str_to_screen(' '+self.submenus[self.i][self.j]+' ',self.子菜单坐标x[self.j],self.子菜单坐标y[self.j],self.subfontsize,self.activefgcolor,bgcolor=self.activebgcolor)
def mouse_over_submenu(self,posy): # 鼠标经过二级菜单
self.submenu()
self.pos_to_j(posy)
if self.j is not None:
self.submenu_chose()
def pos_to_j(self,posy): # 确定鼠标在哪个二级菜单上
j2=floor((posy-12-self.menu_height)/self.subfontsize) # 向下取整
j=floor(j2/2)
if j2%2==0 and (self.i is not None) and self.submenus[self.i][j][0] != '-':
self.j=j
else:
self.j=None
def pos_to_i(self,posx): # 确定鼠标在哪个主菜单上
self.i=None
self.j=None
for i in range(len(self.menus)):
if self.xy[i][0] <= posx < self.xy[i+1][0]:
self.menu_root()
self.i=i
break
def save_screen(self):
self.sub = screen.subsurface((0,self.menu_height,screen_w,screen_h-self.menu_height-底部状态栏高度)).copy() # 保存屏幕
def recovery_screen(self):
self.j=None
screen.blit(self.sub, (0,self.menu_height)) # 从保存的屏幕中恢复屏幕
def lost_focus(self): # 失去焦点时
self.recovery_screen()
self.sub_is_active=False
self.i=None
self.menu_root()
# pygame.display.update()
def menu_click(self,posx,posy): # 主菜单点击事件
self.mouse_over_menu(posx)
self.submenu()
def menu_alt(self,key): # 键盘 alt+菜单字母 被按下
# FRPSQH self.menus=[ '文件(F)','直角坐标系函数(R)','极坐标函数(P)','设置(S)','趣味(Q)','帮助(H)']
for i in range(len(self.menus)):
if chr(key).upper() in self.menus[i]:
self.open_submenu(i,0)
return
def menu_key(self,key): # 在菜单被激活时处理传过来的按键
if key==K_ESCAPE:
菜单.lost_focus()
elif key==K_LEFT:
if self.i>0:
self.i -= 1
self.open_submenu(self.i,0)
elif key==K_RIGHT:
if self.i<len(self.menus)-1:
self.i += 1
self.open_submenu(self.i,0)
elif key==K_DOWN:
if self.j is None:
self.j=0
elif self.j<=len(self.submenus[self.i])-1:
self.j += 1
if self.j<len(self.submenus[self.i])-1 and self.submenus[self.i][self.j][0]=='-':
self.j += 1
if self.j>=len(self.submenus[self.i]):
self.j=0
self.open_submenu(self.i,self.j)
elif key==K_UP:
if self.j is None:
self.j=len(self.submenus[self.i])-1
if self.j>=0:
self.j -= 1
if self.submenus[self.i][self.j][0]=='-':
self.j -= 1
if self.j<0:
self.j=len(self.submenus[self.i])-1
self.open_submenu(self.i,self.j)
elif key==K_RETURN or key==K_KP_ENTER:
self.submenu_click()
elif key<256 and chr(key).upper() in 'FRPSQH': # 主菜单项
self.menu_alt(key)
def open_submenu(self,i,j): # 把焦点定位到一个子菜单上
self.i=i
self.menu_root()
self.menu_chose()
self.submenu()
self.j=j
self.submenu_chose()
def submenu_click(self,posx=0,posy=0): # 二级菜单点击事件 后两个参数感觉没用,经长时间运行后如果没有问题可以删除
if self.i is not None and self.j is not None:
command=self.subcommand[self.i][self.j]
self.lost_focus()
pygame.display.update()
print(f'您选择要执行的命令是 {command} ,你可以用 eval() 或 exec() 的方式执行该命令')
if '退出' in command or '主题' in command or '画圆' in command:
exec(command)
def submenu(self): # 创建二级菜单
self.recovery_screen()
# pr('self.i=',self.i)
if self.i is None:
return
self.sub_is_active=True # 二级菜单是否已经打开
self.子菜单坐标x=[] # self.xy[self.i][0]+10
self.子菜单坐标y=[] # self.menu_height+12
起点x=self.xy[self.i][0]+10
起点y=self.menu_height+12
self.subfontsize=self.default_fontsize
self.subrect=[起点x-10,起点y,self.subsize[self.i][0]*(self.subfontsize/self.default_fontsize)+10]
子菜单高度=len(self.submenus[self.i])*self.subfontsize*2 +12
pygame.draw.rect(screen,self.submenu_bg_color ,(self.xy[self.i][0],self.menu_height,self.subsize[self.i][0]*(self.subfontsize/self.default_fontsize)+10,子菜单高度)) # 二级菜单 的 背景
pygame.draw.rect(screen,self.submenu_border_color,(self.xy[self.i][0],self.menu_height,self.subsize[self.i][0]*(self.subfontsize/self.default_fontsize)+10,子菜单高度),1) # 二级菜单 的 边框
for i in range(len(self.submenus[self.i])):
self.子菜单坐标x.append(起点x)
self.子菜单坐标y.append(起点y)
if self.submenus[self.i][i][0]=='-':
pygame.draw.rect(screen,self.fgcolor,(self.子菜单坐标x[i],int(self.子菜单坐标y[i]+self.subfontsize/2),self.subsize[self.i][0]*(self.subfontsize/self.default_fontsize)+10-20,1))
起点y += self.subfontsize *2
else:
str_to_screen(' '+self.submenus[self.i][i]+' ',self.子菜单坐标x[i],self.子菜单坐标y[i],self.subfontsize,self.fgcolor)
起点y += self.subfontsize *2
self.subrect.append(起点y-self.subrect[1])
def get_sub_is_active(self): # 获取二级菜单是否已经打开的状态
return self.sub_is_active
def get_subrect(self): # 获取菜单感应鼠标坐标范围 (x,y,w,h)
return self.subrect
def get_i(self): # 获取当前主菜单位置
return self.i
def get_j(self): # 获取当前二级菜单位置
return self.j
def str_to_screen(string,x,y,fontsize,color,bgcolor=None,bold=False): # 参数说明:(显示的内容,左上角坐标x y,字体大小,字颜色) 显示的内容:可以接收数字(int ,float)和字符类型(str)
if isinstance(string,(int,float)): # 判断数据类型
string=str(string) # 把数据转换成字符串
cur_font = pygame.font.SysFont(字体, int(fontsize))
textSurf = cur_font.render(string, True, color,bgcolor)
cur_font.set_bold(bold)
TextRect = (x,y)
screen.blit(textSurf,TextRect)
def 显示鼠标处数值(屏幕坐标,鼠标处数值):
pygame.draw.rect(screen,(0,0,255), (0,screen_h-底部状态栏高度,screen_w,底部状态栏高度),width=0) # 清空状态栏
if 屏幕坐标==(-1,-1):
pygame.draw.rect(screen,(0,0,255), (0,screen_h-底部状态栏高度,screen_w,底部状态栏高度),width=0) # 清空状态栏
str_to_screen(鼠标处数值,3,screen_h-底部状态栏高度+3,14,(255,255,255),(0,0,255))
return
str_to_screen(f' 屏幕坐标:{int(屏幕坐标[0])},{int(屏幕坐标[1])}',\
0,screen_h-底部状态栏高度+3,14,(255,255,255),(0,0,255))
str_to_screen(f'{鼠标处数值}',270,screen_h-底部状态栏高度+3,14,(255,255,255),(0,0,255))
def 改变窗口大小(screen_w_h=(700,600),状态=RESIZABLE):
global screen,screen_w,screen_h
screen_w,screen_h=screen_w_h
if screen_w <700: # 限止最小宽度
screen_w = 700
if screen_h <600: # 限止最小高度
screen_h = 600
screen = pygame.display.set_mode((screen_w,screen_h),状态)
pygame.draw.rect(screen,(0,0,255),(0,screen_h-底部状态栏高度,screen_w,底部状态栏高度)) # 绘制底部状态栏背景
def lencc(string): # 返回真实占用字节数(注:1个汉字占用2个字节)
return len(string.encode('GBK'))
def 改变菜单主题():
global 背景颜色
if 背景颜色 == (255,255,255):
背景颜色 = (0,0,0)
else:
背景颜色 = (255,255,255)
清空背景()
菜单.lost_focus()
def 清空背景():
screen.fill(背景颜色)
def 画圆(): # 随机画几个圆,用于演示
清空背景()
for i in range(20):
xy = (randint(0,screen_w),randint(0,screen_h))
color = (randint(0,255),randint(0,255),randint(0,255))
r = randint(10,300)
w = randint(0,5)
pygame.draw.circle(screen,color,xy,r,w)
菜单.menu_root()
菜单.save_screen()
def 退出系统():
exit()
# 主程序 ===========================
def main(NoWelcom=False):
global screen_w,screen_h,底部状态栏高度 , 菜单栏高度 , screen,菜单 ,字体,背景颜色
pygame.init()
pygame.display.set_caption('Pygame菜单演示')
字体='simsun'
底部状态栏高度 = 22
菜单栏高度 = 22
背景颜色 = (255,255,255)
改变窗口大小((1000, 800),RESIZABLE)
菜单=mymenu() # 初始化顶部菜单
菜单.save_screen()
while 1:
for event in pygame.event.get():
mods=pygame.key.get_mods() # 返回组合键的掩码
pygame.event.clear() # 从队列中清除所有的事件
if event.type == pygame.QUIT:
退出系统()
elif event.type==KEYDOWN : # 有键盘输入的事件发生
if 菜单.get_sub_is_active(): # 有二级菜单激活状态
菜单.menu_key(event.key)
elif event.key==K_ESCAPE:
退出系统()
elif event.key==K_SPACE:
改变菜单主题()
elif mods & pygame.KMOD_ALT and event.key<256:
if chr(event.key).upper() in 'FRPSQH': # 主菜单项
菜单.menu_alt(key=event.key)
elif event.type==MOUSEBUTTONDOWN : # 有鼠标被按下的事件发生
if event.button==1 : # 鼠标左键按下
if 0<=event.pos[1]<=菜单栏高度 :# 菜单位置
菜单.menu_click(posx=event.pos[0],posy=event.pos[1])
elif 菜单.get_sub_is_active(): # 有二级菜单激活状态
subrect=菜单.get_subrect()
if (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]):
菜单.submenu_click(posx=event.pos[0],posy=event.pos[1])
else:
菜单.lost_focus()
else:
菜单.lost_focus()
elif event.button==2 : # 鼠标中键按下
if 菜单.get_sub_is_active(): # 有二级菜单激活状态
菜单.lost_focus()
elif event.button==3 : # 鼠标右键按下
if 菜单.get_sub_is_active(): # 有二级菜单激活状态
if (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]): # 鼠标在二级菜单内点击
菜单.submenu_click(posx=event.pos[0],posy=event.pos[1])
else: # 鼠标在二级菜单以外点击
菜单.lost_focus()
elif event.button==4 : # 鼠标中键向前滚轮
subrect=菜单.get_subrect()
if 菜单.get_sub_is_active() and (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]): # 有二级菜单激活状态
... # 在二级菜单内滚轮
else:
菜单.lost_focus()
elif event.button==5 : # 鼠标中键向后滚轮
subrect=菜单.get_subrect()
if 菜单.get_sub_is_active() and (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]): # 有二级菜单激活状态
... # 在二级菜单内滚轮
else:
菜单.lost_focus()
elif event.type==VIDEORESIZE : # 窗口缩放事件
改变窗口大小(event.size)
elif event.type==MOUSEMOTION : # 鼠标移动事件 pos, rel, buttons 三个参数说明:当前鼠标坐标,相对移动距离,按键 ,数据格式分别为:(1619, 7) (0, 0, 0) (3, -6)
if 0<=event.pos[1]<=菜单栏高度 : # 菜单位置
菜单.mouse_over_menu(posx=event.pos[0])
显示鼠标处数值(event.pos,'提示:请您在菜单栏中选择')
elif 菜单.get_sub_is_active(): # 有二级菜单激活状态
subrect=菜单.get_subrect()
if (subrect[0] < event.pos[0] < subrect[0] +subrect[2]) and (subrect[1] < event.pos[1] < subrect[1] +subrect[3]):
菜单.mouse_over_submenu(posy=event.pos[1])
显示鼠标处数值(event.pos,'提示:可以用鼠标或键盘上下左右键选择相应菜单')
else:
菜单.lost_focus()
显示鼠标处数值(event.pos,'')
elif event.type==WINDOWLEAVE : # 鼠标离开窗口事件
菜单.lost_focus()
pygame.display.update()
if __name__ == '__main__':
main()
复制粘贴可以直接执行哦 :)