跳转到主要内容

一个简单且基础的Pygame库,用于快速开发菜单界面

项目描述

KezMenu

一个基于Pygame的简单且基础的模块,用于快速开发菜单界面。

简介

此模块基于Pygame社区中PyMike的原始工作(有关更多信息,请参阅EzMeNu项目)。由于在使用Mike的版本库时发现了一些问题,我发布了这个版本,修复了一些问题,并添加了新功能。

您可以使用此模块做什么?

您可以轻松地绘制菜单界面,并使用鼠标或箭头键选择选项。

示例和用法

以下是一个使用此库的完整示例。即使我们使用Python doctest格式,这也不是一个政治上正确的自动化测试,因为我们将在等待用户输入时进行测试,并且没有对结果进行实际测试(不,这不是真的,但没有主要功能在这里真正测试)。

也许有一天我会用更好的Python测试来完善它!

然而... 此页面的代码是一个工作示例。如果您对doctests一无所知,只知道您可以通过下载源代码,进入kezmenu目录并输入以下命令来运行此代码:

python tests.py

如果您已在系统上安装了库,您可以使用Python解释器运行示例程序。

import kezmenu

kezmenu.runTests()

初始化所有Pygame组件

首先,我们需要启用Pygame环境

>>> import pygame
>>> from pygame.locals import *
>>> import pygame.font
>>> pygame.font.init()
>>> screen = pygame.display.set_mode((640,480), 0, 32)

KezMenu通过在pygame.Surface实例上绘制菜单来工作;更好的(更简单的)选择是在屏幕上绘制菜单(使用pygame.display模块的方法获得的另一个Surface实例,如pygame.display.set_mode),因为在Pygame中无法知道从屏幕左上角到blitten表面的偏移量。

如果您不打算在菜单上使用鼠标,仅依赖上下键,这并不重要。要禁用鼠标,只需将KezMEnu实例的mouse_enabled属性设置为False。

在下面的第一个示例中,我们将使用屏幕内部的Surface来绘制菜单。所以,我们首先创建这个Surface

>>> surface = pygame.Surface( (400,400), flags=SRCALPHA, depth=32 )
>>> surface.fill( (150,150,150,255) )
<rect(0, 0, 400, 400)>

现在我们可以在屏幕上绘制Surface。我们将重复这个步骤几次,所以最好创建我们的第一个虚拟函数(这些函数在这个测试环境中并不真正有用)

>>> def blitSurface():
...     screen.blit(surface, (50,50) )
...     pygame.display.update()

因此,我们可以第一次调用它

>>> blitSurface()

这是一个图形测试,所以我们需要延迟自动操作,并使用户能够查看结果,然后再进行操作。我们在继续之前等待用户输入。

为此,我们创建了一个第二个愚蠢的函数,我们稍后会经常调用它

>>> click_count = 0
>>> def waitForUserAction(msg='???'):
...     global click_count
...     click_count+=1
...     pygame.display.set_caption("Example %s - %s" % (click_count, msg))
...     while True:
...         for event in pygame.event.get():
...             if event.type==KEYDOWN:
...                 return

好吧,让我们第一次调用它

>>> waitForUserAction("An empty, dark surface")

我们仅在屏幕上显示了一个填充深色的Surface。

KezMenu

现在是时候创建我们的KezMenu实例了

>>> from kezmenu import KezMenu
>>> menu = KezMenu()

为了绘制我们之前创建的菜单,我们还需要为测试创建另一个虚拟函数

>>> def drawMenu():
...     surface.fill( (150,150,150,255) )
...     menu.draw(surface)
...     blitSurface()
...     pygame.display.flip()

这是创建菜单的有效方法,但我们只能获得一个空菜单(因此对用户不可见)。

>>> drawMenu()
>>> waitForUserAction("You see no difference")

您没有看到示例1中的变化,不是吗?如果我们以这种方式创建菜单,我们需要在运行时填充我们的选项。您可以通过修改options属性来执行此操作。

在定义选项之前,我们需要知道菜单动作必须执行什么

>>> option_selected = None
>>> def option1():
...     global option_selected
...     option_selected = 1
>>> menu.options = ( {'label': 'First option!', 'callable': option1}, )

如您所见,选项成员必须是一个字典的元组。这些字典必须包含(至少)labelcallable参数;其他参数可以指定用于高级使用(见EFFECTS.txt)。

label是要为菜单选项绘制的字符串,而callable是要在选择时调用的函数、对象、方法等。

由于我们将菜单绘制在不在(0,0)屏幕位置的Surface中,如果我们想以后使用鼠标控制,我们需要指定screen_topleft_offset属性

>>> menu.screen_topleft_offset = (50,50)
>>> drawMenu()
>>> waitForUserAction("Our first option!")

这样我们就告诉菜单,所有坐标都必须从屏幕左上角开始计算偏移量。

直接将屏幕对象传递给menu.draw方法更为常见,所以在我们所有的其他示例中,我们将放弃使用Surface对象。

>>> surface = None

自定义菜单GUI:颜色、字体等

最后一个例子中显示的菜单有点丑。离屏幕边界太近,非选中元素使用的颜色也很丑。你也可以为已经创建的菜单修改这些属性

>>> menu.position
(0, 0)
>>> menu.position = (30,50)
>>> menu.position
(30, 50)
>>> drawMenu()
>>> waitForUserAction("Not soo near to border now...")

现在菜单在屏幕上的位置更合适了。

让我们修改一些字体属性,但首先让我谈谈菜单的尺寸。菜单尺寸的数据始终可以通过使用widthheight属性来获取

>>> menu.width
126
>>> menu.height
115

这些值与菜单中的标签显示有关,也受字体使用(及其尺寸)的影响

>>> new_font = pygame.font.Font(None, 38)
>>> menu.font = new_font
>>> drawMenu()
>>> waitForUserAction("Bigger font")

这个更大的字体有不同的尺寸,所以整个菜单的尺寸也增加了

>>> menu.width
154
>>> menu.height
135

现在来谈谈颜色

>>> menu.color = (255,255,255,100)
>>> menu.focus_color = (255,255,0)
>>> drawMenu()
>>> waitForUserAction("...and better colors")

正如你所见,我们可以轻松地操作字体颜色和选中项的字体。

用我们的KezMenu做些有用的事情

你注意到我们之前的例子都是静态截图,没有可能的交互。

要使用我们的菜单进行一些真正的示例,我们需要使用KezMEnu.update方法,并传递pygame捕获的pygame.Event实例。因为菜单通常是一种等待用户决策的方式,所以不再需要waitForUserAction虚拟函数。

>>> click_count+=1
>>> pygame.display.set_caption("Example %s - %s" % (click_count, "Use the KezMenu freely"))
>>> while True:
...     events = pygame.event.get()
...     menu.update(events)
...     drawMenu()
...     if option_selected:
...         break
>>> option_selected is not None
True

现在,option_selected变量包含与所选选项相关的可调用对象的返回值。

注意:如果你在运行此测试时选择退出选项,你将得到一个假测试失败。这不是KezMenu的错误,但在Python测试中这是正常的:sys.exit调用会引发一个SystemExit异常,在测试中会被以不同的方式处理。

好了,例子就到这里了!

但KezMenu还有一些效果!你可以在EFFECTS.txt文件中找到有关菜单效果的示例。

再见!

>>> pygame.quit()

玩转KezMenu的效果

简介

从版本0.3.0开始,KezMenu的内部结构变化很大。其中之一是每行都有自己的pygame.font.Font来使用。

这将给我们提供大量关于菜单条目显示效果的自由。

>>> import pygame
>>> from pygame.locals import *
>>> import pygame.font
>>> pygame.font.init()
>>> screen = pygame.display.set_mode((640,480), 0, 32)
>>> screen.fill( (50,50,50,255) )
<rect(0, 0, 640, 480)>
>>> click_count = 0
>>> def waitForUserAction(msg='???'):
...     global click_count
...     click_count+=1
...     pygame.display.set_caption("Example %s - %s" % (click_count, msg))
...     while True:
...         for event in pygame.event.get():
...             if event.type==KEYDOWN:
...                 return
>>> def updateCaption(msg='???'):
...     global click_count
...     click_count+=1
...     pygame.display.set_caption("Example %s - %s" % (click_count, msg))
>>> from kezmenu import KezMenu
>>> def drawMenu():
...     screen.fill( (50,50,50,255) )
...     menu.draw(screen)
...     pygame.display.flip()
>>> option_selected = 0
>>> def optSelected():
...     global option_selected
...     option_selected=1
>>> menu = KezMenu(
...            ["First option!", optSelected],
...            ["sEcond", optSelected],
...            ["Again!", optSelected],
...            ["Lambda", optSelected],
...            ["Quit", optSelected],
...        )
>>> menu.font = pygame.font.Font(None, 20)
>>> menu.color = (255,255,255)
>>> menu.position = (10,10)

让我们显示当前菜单的高度

>>> menu.height
70

这里又是一个标准菜单。

>>> drawMenu()
>>> waitForUserAction("The same boring menu")

现在我们想为'sEcond'条目使用更大的字体

>>> menu.options[1]['font'] = pygame.font.Font(None, 26)
>>> drawMenu()
>>> waitForUserAction("Bigger entry 2")

让我们知道,手动修改菜单选项可能会导致菜单本身的某些错误,因为KezMenu实例没有注意到参数的变化

>>> menu.height
70

所以即使我们显示了一个新绘制的菜单,保存的尺寸也没有改变。这是不好的。我们可以简单地调用一个内部KezMenu方法来修复这个问题,通常KezMenu对象会为我们调用这个方法

>>> menu._fixSize()
>>> menu.height
74

这篇介绍只是KezMenu效果内部实现方式的冰山一角。

KezMenu可用的效果

这里有一个可用效果的列表和用法示例。使用enableEffect方法启用效果,并且必须用于现有效果,否则会引发KeyError。

>>> menu.enableEffect('not-existing-effect-just-for-raise-error')
Traceback (most recent call last):
...
KeyError: "KezMenu don't know an effect of type not-existing-effect-just-for-raise-error"

在所有下面的例子中,我们需要一个计时器,所以可以使用pygame.time.Clock

>>> clock = pygame.time.Clock()

要启用效果,我们必须使用enableEffect方法,并将效果名称传递给它,可选地传递一些关键字参数。

重要事项:效果可以(有时)组合使用!

raise-line-padding-on-focus

此效果会在时间流逝的过程中提高聚焦元素的上下填充。最后一个元素的填充只会提高顶部填充。第一个元素的填充只会提高底部填充。

填充

默认:10px。将被添加到所选菜单条目上下方的像素数。

enlarge_time

默认:500毫秒。达到最大填充所需的时间(以秒为单位)。

>>> updateCaption('raise-line-padding-on-focus')
>>> option_selected = 0
>>> menu.enableEffect('raise-line-padding-on-focus')
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break

我们可以用新的自定义值调用此效果

>>> updateCaption('raise-line-padding-on-focus (custom)')
>>> option_selected = 0
>>> menu.enableEffect('raise-line-padding-on-focus', padding=30, enlarge_time=1.)
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break
>>> menu.disableEffect('raise-line-padding-on-focus')

raise-col-padding-on-focus

此效果会在时间流逝的过程中提高聚焦元素左侧的填充。

填充

默认:10px。将被添加到所选菜单条目左侧的像素数。

enlarge_time

默认:500毫秒。达到最大填充所需的时间(以秒为单位)。

>>> updateCaption('raise-col-padding-on-focus')
>>> option_selected = 0
>>> menu.enableEffect('raise-col-padding-on-focus')
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break

我们可以用新的自定义值调用此效果

>>> updateCaption('raise-col-padding-on-focus (custom)')
>>> option_selected = 0
>>> menu.enableEffect('raise-col-padding-on-focus', padding=20, enlarge_time=3.)
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break
>>> menu.disableEffect('raise-col-padding-on-focus')

enlarge-font-on-focus

此效果将按给定倍数提高所选菜单元素的字体大小。Pygame的Font类有一个限制(不是一个错误):在字体创建后无法获取字体数据(家族、大小)。

因此,为了使用此效果,需要将所有字体数据传递给init方法,并将创建一个新字体(标准菜单的‘font’属性将被覆盖)。

font

必需。字体名称或路径,与传递给Pygame Font构造函数的方式相同,因此也可以是None。

size

必需。字体大小,与传递给Pygame Font构造函数的方式相同。

enlarge_factor

默认:2。(200%)。最大扩展时字体大小的倍数,作为一个实值。

enlarge_time

默认:500毫秒。达到最大字体大小所需的时间(以秒为单位)。

>>> updateCaption('enlarge-font-on-focus')
>>> option_selected = 0
>>> menu.enableEffect('enlarge-font-on-focus', font=None, size=18)
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break

现在我们可以自定义所有数据

>>> updateCaption('enlarge-font-on-focus (focus)')
>>> option_selected = 0
>>> menu.enableEffect('enlarge-font-on-focus', font=None, size=18, enlarge_factor=5., enlarge_time=2.)
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break
     >>> menu.disableEffect('enlarge-font-on-focus')

组合KezMenu效果

KezMenu效果的主要作用是足够灵活,可以在同一时间激活。随着未来可用的效果的增加,有时可能会出现效果相互冲突的情况,但一般来说,我会尽量将它们整合。

同时激活多个效果非常简单:只需激活即可!

>>> updateCaption('Combined effects example')
>>> option_selected = 0
>>> menu.enableEffect('raise-line-padding-on-focus', padding=30, enlarge_time=1.)
>>> menu.enableEffect('raise-col-padding-on-focus', padding=20, enlarge_time=1.)
>>> menu.enableEffect('enlarge-font-on-focus', font=None, size=16, enlarge_factor=3.)
>>> while True:
...     time_passed = clock.tick() / 1000.
...     events = pygame.event.get()
...     menu.update(events, time_passed)
...     drawMenu()
...     if option_selected:
...         break
>>> menu.disableEffect('raise-line-padding-on-focus')
>>> menu.disableEffect('raise-col-padding-on-focus')
>>> menu.disableEffect('enlarge-font-on-focus')

想编写一个新效果吗?

如果有人对开发新效果感兴趣,我将很高兴将其集成到KezMenu中!

更新日志

0.3.6 (2013-06-07)

  • 修复了打包错误

0.3.5

  • 使用Python 2.6和Pygame 1.9进行测试

  • 对doctest进行了修复

  • 删除了过时的代码

0.3.1

  • 没有新功能,但修复了在py2exe环境中使用模块时中断菜单的问题。

0.3.0

  • 添加了README.txt,格式为doctest。

  • 添加了许多针对不遵循PEP 8命名方法的弃用警告。这些方法将在未来被删除。

  • 如果菜单位置从(0,0)移动,则由于未计算此偏移量,鼠标控制将出现错误。

  • 支持菜单效果

0.2.1

  • 作为egg发布。

  • 添加了一些txt文件。

0.2.0 - 未发布

  • 修复了许多与字体处理相关的问题。

  • 添加了对鼠标使用的支持。

0.1.0

对于0.1.0版本,我的意思是原始EzMeNu 1.0版本。

致谢

  • Pygame社区的PyMike对他的原始工作表示感谢。

待办事项

  • 子菜单?

  • 更多效果(欢迎提出建议)

  • 需要更好地处理透明度

获取代码

源代码库托管在GitHub

项目详情


下载文件

下载适合您平台的文件。如果您不确定要选择哪个,请了解更多关于安装包的信息。

源代码分发

KezMenu-0.3.6.tar.gz (17.3 kB 查看哈希值)

上传时间: 源代码

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面