2017-12-6-python-second-step

77 阅读9分钟
  • content {:toc}

本文

afra55.github.io/2017/12/06/…

pip

如果没有 pip 则通过下面的链接下载 get-pip.py 到本地并运行

bootstrap.pypa.io/get-pip.py

或者通过如下链接安装

pip.pypa.io

sudo python3 get-pip.py

Pygame

www.pygame.org

安装 Pygame 依赖的库 brew install hg sdl sdl_image sdl_mixer sdl_ttf

安装 Pygame pip3 install --user hg+http://bitbucket.org/pygame/pygame

或者在 bitbucket.org/pygame/pyga… 下载Pygame对应文件进行安装

.whl 安装方法 python -m pip install --user xx.whl

创建

import pygame

要使用 pygame 则要先初始化: pygame.init()

接下来需要创建一个显示窗口,并持有这个窗口: screen = pygame.display.set_mode((1200, 800))

pygame.display.set_mode((1200, 800)) 创建显示窗口并返回一个 surface 对象,所有图形绘制都在这个窗口内, 实参是一个元组用于指定尺寸

(0, 0) 原点在屏幕左上角,向下向右增大

surface 代表屏幕的一部分,用于显示游戏元素

设置窗口标题: pygame.display.set_caption("Afra55 game")

开始游戏的主要循环:while True:  不断循环来处理所有发生的事物,比如监听按键,绘制图形等

while True:

    # 监视键盘和鼠标事件
    for event in pygame.event.get():
    if event.type == pygame.QUIT:       # 退出, type 指类型
            sys.exit() 
        elif event.type == pygame.KEYDOWN:  # 按键
            if event.key == pygame.K_RIGHT: # 向右箭头 key 指具体的键

    screen.fill(bg_color)
    pygame.display.flip()   # 让绘制的屏幕显示出来, 即更新屏幕显示

pygame.event.get() 来监听事件,按键或者鼠标移动,可以用 循环来捕捉事件

pygame 的颜色以 RGB(0-255)值指定,红(255, 0, 0), 绿(0, 255, 0), 蓝(0, 0, 255)

surface 的 fill() 方法接受一个颜色实参,来设置背景的填充颜色: screen.fill(bg_color)

def fill(self, color, rect=None, special_flags=0) 如果传入 rect 则在 rect 位置区域上绘制背景 color

surface 的 blit(surface, rect) 方法根据指定的位置 rect 绘制实参 surfcae 到调用这个方法的 surface 上

图片

创建一个图片 surface : pygame.image.load_basic('images/view.bmp')

获取 surface 的 rect 属性: image.get_rect(), rect 包含 x, y, center, centerx, centery, top, bottom, left, right, height, width

rect.collidepoint(x, y) 返回一个 布尔类型,用于判断 (x, y) 这个点是否在 rect 区域内

显示所有的绘制:pygame.display.flip()

from pygame.sprite import Sprite Sprite 俗称精灵,可以将相关元素编组,就可以同时操作编组中的所有元素

from pygame.sprite import Group Group 编组,用于存储 Sprite 类似列表,并提供来额外的功能, 调用 update() 方法,则编组中所有的 Sprite 的 update 方法就被调用

sprite = Sprite()   # 创建精灵
group.add(sprite)   # 把精灵加入到编组中
for sprite in group.sprites():    # 遍历编组
    print(sprite)

group.draw(screen)

注: 当使用 for 循环删除列表时,遍历的应该是列表的副本即 调用列表的 copy() 方法或使用切片来获取副本

pygame.draw.rect(self.screen, self.color, self.rect) draw.rect() 用于绘制 一个 rect 大小的背景是 color 的方块

group.draw(screen) 对编组使用 draw(surface) 时,pygame 会自动绘制编组的每个元素到实参 surface 中,绘制的位置由元素的 rect 属性决定

for sprite in group.sprites(): 便利编组的所有元素

pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb)
获取 groupa 和 groupb 两个编组中元素位置有重叠的元素,返回字典,key 是 groupa 中的元素,value 是 groupb 中的元素 是个列表, dokilla 和 dokillb 布尔类型, True 指删除编组中的该元素

group.empty() 清空编组中的所有元素

pygame.sprite.spritecollideany(sprite, group) spritecollideany 方法第一个实参是精灵,第二个是编组,用于检测精灵是否和编组的元素位置有重叠, 如果没有重叠 返回 None,有重叠 则返回 group 中的这个元素

位置重叠,由元素的 rect 判断

from time import sleep


sleep(0.5)

sleep(seconds) 让程序睡眠 seconds 秒

文本

import pygame.ftfont pygame.ftfont 能够再屏幕上渲染文本

font = pygame.ftfont.SysFont(None, 48) 返回一个 FontType 指用什么字体来渲染文本, 实参None指使用默认字体, 48指文本等字号,详细配置看文档

msg_image = font.render(msg, True, self.text_color, self.button_color)

def render(self, text, antialias, color, background=None) 将 text 文本转换为图像,并返回图像 surface,antialias 布尔类型是否开启反锯齿功能, color 指文本颜色, background 指背景色(默认是透明色)

not Flast == True

not True == False

not 类似 java 中的 !

def round(number, ndigits=None) round() 让小数精确到小数点后 ndigits 位,如果 ndigits 为负数, round() 将圆整到最近的 10,100,100 等多整数倍

"{:,}".format(rounded_score) 将数值转化为字符串时,在其中插入逗号,例如 1,000,000

小结

Python编程 从入门到实践 里面的打飞机游戏很有意思,做完后有了更深一层的认识

github.com/Afra55/alie…

GUI 编程

图形用户界面编程

python 默认的 UI 工具包 tkinter ,它基于 Tk 工具包(最初为工具命令语言 Tcl 设计的)

1. 导入 Tkinter 模块
2. 创建 一个 顶层 窗口 对象, 用于 容纳 整个 GUI 应用
3. 在 顶层 窗口 对象 之上( 或者“ 其中”) 构建 所有 的 GUI 组件( 及其 功能)
4. 通过 底层 的 应用 代码 将 这些 GUI 组件 连接 起来
5. 进入 主事 件 循环

创建顶层窗口,可以创建多个顶层窗口,但是只能有一个根窗口

tkinter.Tk()

顶层 的 根 窗口 对象 包含 组成 GUI 应用 的 所有 小窗 口 对象。 它们 可能 是 文字 标签、 按钮、 列表 框 等。 这些 独立 的 GUI 组件 称为 控 件。 所以 当 我们 说 创建 一个 顶层 窗口 时, 只是 表示 需要 一个 地方 来 摆放 所 有的 控 件

事件 可以 包括 按钮 按下( 及 释放)、 鼠标 移动、 敲击 回车 键 等。 一个 GUI 应用 从 开始 到 结束 就是 通过 整套 事件 体系 来 驱动 的。 这种 方式 称为 事件 驱动 处理

布局管理器有三种:Placer(设置控件的大小和位置来配置摆放控件),Packer(填充控件到父控件中),Grid(网格)

摆放完控件后进入主循环:tkinter.mainloop()

常用控件描述
Button用于包含文本或图像,并提供额外事件,例如 鼠标悬浮、按下、释放、键盘事件
Canvas提供绘制图像到功能(线段,椭圆,多边形,矩形),可以包含图像或位图
CheckButton多选框
Entry单行文本框,用于收集键盘输入
Frame包含其他控件到纯容器
Label包含文本或图像 
LabelFrame一个 Frame 可以包含文本或图像
Listbox选项列表
Menu按下 Menubutton 后弹出的选项列表,用户可以从中选择
Menubutton用于包含 Menu
Message消息,多行文本框
PanedWindow容器控件,可以控制其他控件在其中摆放
Radiobutton单选框
Scale线性'滑块'控件,根据起始和结束值,来返回当前值
Scrollbar为 Text、Canvas、Listbox、Entry 提供滑动功能
SpinboxEntry 和 Button 的组合,可以对值进行调整
Text多行文本框,用于收集或显示用户输入的文本
Toplevel于 Frame 类似,并提供一个单独的窗口 

Label 示例

import tkinter


if __name__ == '__main__':
    top = tkinter.Tk()
    label = tkinter.Label(top, text='Hello World!')
    label.pack()
    tkinter.mainloop()

Button 示例

import tkinter


if __name__ == '__main__':
    top = tkinter.Tk()
    quit_btn = tkinter.Button(top, text='Hello World!', command=top.quit)   # command 用于绑定点击的回调函数
    quit_btn.pack()
    tkinter.mainloop()

Packer 默认垂直排列

import tkinter


if __name__ == '__main__':
    top = tkinter.Tk()

    hello = tkinter.Label(top, text='Hello Afra55!')
    hello.pack()

    quit_btn = tkinter.Button(top, text='QUIT!', command=top.quit, bg='red', fg='white')
    quit_btn.pack(fill=tkinter.X, expand=1)
    
    tkinter.mainloop()

Scale 示例

import tkinter


def resize(ev=None):
    hello.config(font='华康少女字体 -%d bold' % scale.get())


if __name__ == '__main__':
    top = tkinter.Tk()
    top.geometry('400x400')

    hello = tkinter.Label(top, text='床前明月光!', font='华康少女字体 -12 bold')
    hello.pack(fill=tkinter.Y, expand=1)

    scale = tkinter.Scale(top, from_=10, to=40, orient=tkinter.HORIZONTAL, command=resize)
    scale.set(12)
    scale.pack(fill=tkinter.X, expand=1)

    quit_btn = tkinter.Button(top, text='QUIT!', command=top.quit, activeforeground='white', activebackground='red')
    quit_btn.pack()

    tkinter.mainloop()

偏函数

使用 偏 函数, 可以 通过 有效地“ 冻结” 那些 预先 确定 的 参数 来 缓存 函数 参数, 然后 在 运行时, 当获 得 需要 的 剩余 参数 后, 可以 将它 们 解冻, 传递 到 最终 的 参数 中, 从而 使用 最终 确定 的 所有 参数 去 调用 函数

from functools import partial
from tkinter import Tk, Button, X
from tkinter.messagebox import showinfo, showwarning, showerror  # tk 对话框

warn = 'warn'
error = 'error'
info = 'info'

SIGNS = {
    'error one': error,
    'warn one': warn,
    'info one': info,
    'error two': error,
    'warn two': warn,
    'info two': info,
}

error_cb = lambda: showerror('Error', 'Error Button Pressed!')
warn_cb = lambda: showwarning('Warning', 'Warning Button Pressed!')
info_cb = lambda: showinfo('Info', 'Info Button Pressed!')

top = Tk()
top.geometry('400x400')
top.title('偏函数示例')
Button(top, text='退出', command=top.quit, bg='red', fg='white').pack()

# 这里使用了两阶偏函数
my_button = partial(Button, top)    # 第一阶模版化两 Button 和 top,即每次调用 my_button 就会调用 Button类 并把 top 作为第一个参数
ErrorButton = partial(my_button, command=error_cb, bg='white', fg='red')    # 第二阶偏函数,使用第一阶并模版化,创建按钮类型
WarnButton = partial(my_button, command=warn_cb, bg='goldenrod1')
InfoButton = partial(my_button, command=info_cb, bg='white')

for each_sign in SIGNS:
    sign_type = SIGNS[each_sign]
    cmd = '%sButton(text=%r%s).pack(fill=X, expand=True)' % (
        sign_type.title(), each_sign,
        '.upper()' if sign_type == error else '.title()')
    eval(cmd)   # 每个按钮通过 eval() 函数实例化

top.mainloop()

文件列表示例

import os
from time import sleep
from tkinter import *


class DirList(object):
    def __init__(self, initdir=None):
        self.top = Tk()
        self.label = Label(self.top, text='文件夹监听器')     # 标题
        self.label.pack()

        self.dirl = Label(self.top, fg='blue', font=('Helvetica', 12, 'bold'))   # 显示当前路径
        self.dirl.pack()

        self.dirfm = Frame(self.top)    # 框
        self.dirsb = Scrollbar(self.dirfm)  # 滑块
        self.dirsb.pack(side=RIGHT, fill=Y)     # 滑块在右侧
        self.dirs = Listbox(self.dirfm, height=15, width=50, yscrollcommand=self.dirsb.set)     # 列表,展示当前目录下的文件
        self.dirs.bind('<Double-1>', self.setdirandgo)  # 双击鼠标左键, 跳转到选择到目标路径
        self.dirsb.config(command=self.dirs.yview)      # 改变垂直方向的位置
        self.dirs.pack(side=LEFT, fill=BOTH)    # 列表在左侧,填充 xy
        self.dirfm.pack()

        self.cwd = StringVar(self.top)
        self.dirn = Entry(self.top, width=50, textvariable=self.cwd)    # 输入框
        self.dirn.bind('<Return>', self.dols)       # 绑定回车键, 跳转到输入框内容的目录下
        self.dirn.pack()

        self.bfm = Frame(self.top)      # 最底下的容器
        self.clr = Button(self.bfm, text='清空',
                          command=self.clrdir,      # 清空输入框内容
                          activeforeground='white',
                          activebackground='blue')
        self.ls = Button(self.bfm,
                         text='跳转到选中目录',
                         command=self.dols,
                         activeforeground='white',
                         activebackground='green')
        self.quit = Button(self.bfm, text='退出',
                           command=self.top.quit,
                           activeforeground='white',
                           activebackground='red')
        self.clr.pack(side=LEFT)
        self.ls.pack(side=LEFT)
        self.quit.pack(side=LEFT)
        self.bfm.pack()

        if initdir:
            self.cwd.set(os.curdir)
            self.dols()

    def clrdir(self, ev=None):
        """
        空输入框内容
        """
        self.cwd.set('')

    def setdirandgo(self, ev=None):
        self.last = self.cwd.get()
        self.dirs.config(selectbackground='red')    # 选择的文件背景变为红色
        check = self.dirs.get(self.dirs.curselection())
        if not check:
            check = os.curdir
        self.cwd.set(check)     # 设置输入框为选择的item文件名
        self.dols()             # 跳转到选择到文件目标

    def dols(self, ev=None):
        """
        跳转到目标目录
        """
        error = ''
        tdir = self.cwd.get()   # 获取输入框的内容
        if not tdir:    # 入股内容为空,则默认为 '.'
            tdir = os.curdir

        if not os.path.exists(tdir):        # 如果文件不存在
            error = tdir + ': 没找到该文件'
        elif not os.path.isdir(tdir):       # 如果不是文件夹
            error = tdir + ': 不是一个文件夹'

        if error:   # 如果出错
            self.cwd.set(error)     # 输入框设置出错信息
            self.top.update()       # 更新绘制
            sleep(2)                # 睡眠2秒
            if not (hasattr(self, 'last') and self.last):
                self.last = os.curdir
            self.cwd.set(self.last)     # 设置输入框为上一个正确的路径
            self.dirs.config(selectbackground='LightSkyBlue')   # 设置选择的item背景是亮蓝色
            self.top.update()       # 更新绘制
            return

        self.cwd.set('抓取文件夹内容...')
        self.top.update()
        dirlist = os.listdir(tdir)  # 获取目标路径下的文件列表
        dirlist.sort()              # 按文件名 排序
        os.chdir(tdir)              # 将活动目录设置为目标路径
        self.dirl.config(text=os.getcwd())      # 显示目标路径
        self.dirs.delete(0, END)    # 清空当前展示的文件列表
        self.dirs.insert(END, os.curdir)    # 插入 '.'
        self.dirs.insert(END, os.pardir)    # 插入 '..'
        for eachFile in dirlist:
            self.dirs.insert(END, eachFile)     # 插入目标路径下的所有文件
        self.cwd.set(os.curdir)     # 输入框内容设置为 '.'
        self.dirs.config(selectbackground='LightSkyBlue')   # # 设置选择的item背景是亮蓝色


def main():
    d = DirList(os.curdir)
    mainloop()


if __name__ == '__main__':
    main()

相关工具

wiki.python.org/moin/GuiPro…