对于使用过计算机的人,应该对图形用户界面(GUI)应该都不会太陌生,这里就不在赘述。那么对于python这样的动态语言有没有GUI相关的库呢?答案是肯定有的,那么常见的有哪些呢?主要有tkinter、wxPython、PyQt、PyGTK等模块,而tkinter是python默认的模块,没有功能特别强大的GUI控件,所以真的要在python中进行GUI开发,推荐使用wxPython、PyQt、PyGTK等模块。Pyhton还提供了Pygame游戏开发模块。下面主要介绍tkinter、wxPython、Pygame的使用,废话不多说直接开始吧,哈哈哈哈哈~
tkinter是基于Tk工具包的一个模块,而Tk为控件的摆放提供了三种布局管理器,通过布局管理器可以对控件进行定位,这三种布局管理器分别是:
Placer:开发者提供控件的大小和摆放位置
Packer:自动将控件填充到合适的位置
Grid:基于网格坐标来摆放控件
讲了这些还是不知道tkinter怎么使用,那么我们直接介绍使用tkinter来开发GUI的基本步骤:
导入tkinter模块中我们需要的东西
创建一个顶层窗口对象并用它来承载整个GUI应用
在顶层窗口对象上添加GUI组件
通过代码将这些GUI组件的功能组织起来
进入主事件循环(main loop)
wxPython是一个Python包装wxWidgets(c++编写)的一个流行的跨平台的GUI工具包,可以作为Python的一个扩展模块。wxObject类是wxPython API的核心模块,它是所有类的基础类,包括所有GUI应用程序使用的部件。如wx.Button,wx.StaicText等。
Pygame是一个开源的Python模块,专门用于多媒体应用(如电子游戏)的开发,其中包含对图像、声音、视频、事件、碰撞等的支持。Pygame的使用基本步骤:
导入Pygame模块
先初始化
构建一个窗口
设置标题
让其保持运行状态,直到用户手动关闭
先检测事件,如果检测到关闭按钮那么就退出
下面从五方面来介绍Pygame的使用:
我们可以通过Pygame中的draw模块在游戏窗口中绘制各种图形,主要包括:线条、矩形、多边形、圆、椭圆、圆弧等。但最重要想说的不是这个,而是“屏幕坐标系”。什么是屏幕坐标系,它就是指将屏幕左上角设置为坐标原点‘(0, 0)’,向右是x轴的正向,向下是y轴的正向,在表示位置或者设置尺寸的时候,我们默认的单位都是像素(像素概念)。说了那么多我们举个例子更实际一些:
import pygame # 导入pygame模块
def main():
# 初始化pygame模块
pygame.init()
# 初始化显示窗口并设置窗口尺寸
screen = pygame.display.set_mode((888, 666))
# 设置当前窗口的标题
pygame.display.set_caption('888666')
# 设置窗口背景色
screen.fill((200, 102, 22))
# 绘制一个圆(参数分别是: 屏幕, 颜色, 圆心位置, 半径, 0表示填充圆)
pygame.draw.circle(screen, (255, 0, 0,), (100, 100), 30, 0)
# 刷新当前窗口(渲染窗口将绘制的图像呈现出来)
pygame.display.flip()
running = True
# 开启一个事件循环处理发生的事件
while running:
# 从消息队列中获取事件并对事件进行处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if __name__ == '__main__':
main()
如果需要直接加载图像到窗口上,可以使用pygame中image模块的函数来加载图像,再通过之前获得的窗口对象的`blit`方法渲染图像,代码如下:
import pygame
WIN_WIDTH = 800
WIN_HEIGHT = 800
#初始化
pygame.init()
#构建游戏窗口
chuangkou = pygame.display.set_mode((WIN_WIDTH,WIN_HEIGHT))
#设置游戏标题
pygame.display.set_caption('图片')
# 填充背景
chuangkou.fill((255,255,255))
pygame.display.flip()
image = pygame.image.load('./res/ball.png')
# 在窗口上渲染图像
chuangkou.blit(image, (50, 50))
pygame.display.update() #再次刷新
# 开启一个事件循环处理发生的事件
while True:
for x in pygame.event.get():
if x .type==pygame.QUIT:
exit()
动画效果其实就是把不连续的图片连续的播放,只要每秒钟达到了一定的帧数,那么就可以做出比较流畅的动画效果,代码如下:
import pygame
WIN_WIDTH = 800
WIN_HEIGHT = 800
#初始化
pygame.init()
#构建游戏窗口
chuangkou = pygame.display.set_mode((WIN_WIDTH,WIN_HEIGHT))
#设置游戏标题
pygame.display.set_caption('图片')
# 填充背景
chuangkou.fill((255,255,255))
pygame.display.flip()
image = pygame.image.load('./res/ball.png')
# 在窗口上渲染图像
chuangkou.blit(image, (50, 50))
pygame.display.update() #再次刷新
num =1
d = 0 #初始化旋转的角度
# 开启一个事件循环处理发生的事件
while True:
num += 1
if num % 20 == 0:
d+=2
newimage = pygame.transform.rotozoom(image, d, 0.2)
chuangkou.blit(newimage, (0, 0))
pygame.display.update()
for x in pygame.event.get():
if x .type==pygame.QUIT:
exit()
在游戏中会有很多对象出现,而这些对象之间的“碰撞”在所难免,比如炮弹击中了飞机、箱子撞到了地面等。碰撞检测在绝大多数的游戏中都是一个必须得处理的至关重要的问题,pygame的sprite(动画精灵)模块就提供了对碰撞检测的支持。通常情况下,我们使用该模块的基类 Sprite 来创建一个子类,从而达到处理精灵的目的。当我们需要管理大量的精灵时,操作它们将变得复杂,此时通过构建精灵容器(group 类)也就是精灵组来统一管理这些精灵。构建方法如下:
group = pygame.sprite.Group() # 创建精灵组
group.add(sprite_one) # 向组内添加一个精灵
此同时pygame.sprite模块也提供了多种检测精灵是否碰撞的方法,如下所示:
方法 | 说明 |
---|---|
pygame.sprite.collide_rect() | 两个精灵之间的矩形检测,即矩形区域是否有交汇,返回一个布尔值 |
pygame.sprite.collide_circle() | 两个精灵之间的圆形检测,即圆形区域是否有交汇,返回一个布尔值 |
pygame.sprite.collide_mask() | 两个精灵之间的像素蒙版检测,更为精准的一种检测方式 |
pygame.sprite.spritecollide() | 精灵和精灵组之间的矩形碰撞检测,一个组内的所有精灵会逐一地对另外一个单个精灵进行碰撞检测,返回值是一个列表,包含了发生碰撞的所有精灵 |
pygame.sprite.spritecollideany() | 精灵和精灵组之间的矩形碰撞检测,上述函数的变体,当发生碰撞时,返回组内的一个精灵,无碰撞发生时,返回 None |
pygame.sprite.groupcollide() | 检测在两个组之间发生碰撞的所有精灵,它返回值是一个字典,将第一组中发生碰撞的精灵作为键,第二个组中发生碰撞的精灵作为值 |
说了那么多关于pygame.sprite碰撞检测的函数,下面我们举个例子来得更直观一点:
import sys, pygame
from random import *
class MyClass(pygame.sprite.Sprite):
def __init__(self, image_file, location, speed):
pygame.sprite.Sprite.__init__(self) #初始化动画精灵
self.image = pygame.image.load(image_file) #加载图片
self.rect = self.image.get_rect() #得到定义图像边界矩形
self.rect.left, self.rect.top = location #设置球的初始位置
self.speed = speed #创建一个速度
def move(self):
self.rect = self.rect.move(self.speed)
if self.rect.left < 0 or self.rect.right > width:
self.speed[0] = -self.speed[0]
if self.rect.top < 0 or self.rect.bottom > height:
self.speed[1] = -self.speed[1]
def animate(group):
screen.fill([255, 255, 255])
for ball in group:
ball.move()
for ball in group:
group.remove(ball) #从组删除精灵
#检查精灵与组的碰撞
if pygame.sprite.spritecollide(ball, group, False):
ball.speed[0] = -ball.speed[0]
ball.speed[1] = -ball.speed[1]
group.add(ball)
screen.blit(ball.image, ball.rect)
pygame.display.flip()
pygame.time.delay(20)
#设置窗口大小和颜色
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
screen.fill([255, 255, 255])
img_file = "beach_ball.png"
clock = pygame.time.Clock()
group = pygame.sprite.Group() #创建精灵组
#将球增加到列表
for row in range(0, 2):
for column in range(0, 2):
location = [column * 180 + 10, row * 180 + 10]
speed = [choice([-4, 4]), choice([-4, 4])] #让每个球变得随机性
ball = MyClass(img_file, location, speed)
group.add(ball)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
frame_rate = clock.get_fps()
print( "frame rate = ", frame_rate)
animate(group)
clock.tick(30)
pygame.quit()
其实通过上面的代码例子中,细心的人应该注意到有一个pygame.event.get()方法,它就是获取鼠标事件,而且通过事件对象的`type`属性可以判定事件类型,再通过`pos`属性就可以获得鼠标点击的位置。
这里只是简单的介绍pygame的使用,要想了解更多pygame知识,推荐pygame的官方网站,但要求要有一定的英文基础哈哈哈哈哈~。其实我们学习这些模块,不但要了解怎么使用他们,更重要的是要掌握面向对象程序设计和事件驱动的思想去解决现实中的问题。