键盘与鼠标

在程序进行过程中,我们经常需要获取用户的输入来控制程序的行为。Easygraphics提供了获取用户鼠标和键盘输入的基本方法。

暂停等待

Easygraphics中,最常见的用户输入函数就是pause()。这个函数暂停程序,等待用户在图形窗口中点击鼠标或者按下键盘按键来继续程序运行。

鼠标点击

我们可以使用get_click()函数来暂停程序,等待鼠标点击。该函数会返回被点击位置的x,y坐标,和点击时按下了哪些鼠标键。

from easygraphics import *

def main():
    init_graph(800, 600)
    set_render_mode(RenderMode.RENDER_MANUAL)

    while is_run():
        msg = get_click()
        str = "clicked on %d,%d ." % (msg.x, msg.y)
        clear_device()
        draw_text(0, 600, str)

    close_graph()

easy_run(main)

光标位置

get_cursor_pos()函数返回光标所在的位置。

下面的程序持续在绘图窗口中更新光标的位置。

from easygraphics import *

def main():
    init_graph(800, 600)
    set_render_mode(RenderMode.RENDER_MANUAL)

    while is_run():
        x, y = get_cursor_pos()
        clear_device()
        draw_text(0, 600, "%d,%d" % (x, y))
        delay_fps(30)

    close_graph()

easy_run(main)

按下和松开鼠标

可以使用get_mouse_msg()来获取鼠标按钮按下和松开的信息。

非阻塞(Non-Blocking)鼠标处理

如果在之前的100毫秒内没有鼠标操作,get_click()/get_mouse_msg()函数会阻塞程序(暂停程序执行),等待鼠标操作。如果你希望程序能够在检查鼠标操作后不要等待立即继续执行,那么可以先使用非阻塞函数has_mouse_msg()来检查是否有待处理的鼠标操作,然后再使用get_mouse_msg()来获取鼠标信息。

下面的程序持续检查并更新鼠标的位置和鼠标按钮的按下和松开。

from easygraphics import *

def main():
    init_graph(800, 600)
    set_render_mode(RenderMode.RENDER_MANUAL)

    set_fill_color("white")
    while is_run():
        x, y = get_cursor_pos()
        fill_rect(0, 580, 390, 600)
        draw_text(0, 600, "%d,%d" % (x, y))
        if has_mouse_msg():
            msg = get_mouse_msg()
            if msg.type == MouseMessageType.PRESS_MESSAGE:
                typestr = "pressed"
            elif msg.type == MouseMessageType.RELEASE_MESSAGE:
                typestr = "released"
            fill_rect(400, 580, 800, 600)
            draw_text(400, 600, "button %s at %d,%d" % (typestr, x, y))
        delay_fps(30)

    close_graph()

easy_run(main)

鼠标消息示例

下面的程序演示了如何通过处理鼠标操作来交互式的绘制一条贝塞尔曲线。

首先,在绘图窗口中点击,设置曲线第一个控制点的位置;然后,在窗口中再次点击,设置第四个控制点的位置;然后,从这两个点中任意一个开始使用鼠标的拖拽操作(在控制点上按下鼠标左键,不放开,拖动鼠标光标到想要的位置上再松开)设置第二和第三个控制点。程序会实时动态显示生成的贝塞尔曲线。

from easygraphics import *
from PyQt5 import QtCore

def main():
    init_graph(800, 600)
    set_render_mode(RenderMode.RENDER_MANUAL)

    msg = get_click()
    x1=msg.x
    y1=msg.y
    circle(x1, y1, 3)
    msg = get_click()
    x2=msg.x
    y2=msg.y
    circle(x2, y2, 3)
    line(x1, y1, x2, y2)

    x3, y3 = x1, y1
    x4, y4 = x2, y2
    reg1 = QtCore.QRect(x1 - 2, y1 - 2, 5, 5)
    reg2 = QtCore.QRect(x2 - 2, y2 - 2, 5, 5)
    draging_which_point = 0
    while is_run():
        if draging_which_point == 1:
            draw_line(x1, y1, x, y)
            draw_bezier(x1, y1, x, y, x4, y4, x2, y2)
        elif draging_which_point == 2:
            draw_line(x2, y2, x, y)
            draw_bezier(x1, y1, x3, y3, x, y, x2, y2)

        if has_mouse_msg():
            # x, y, type, buttons, modifiers = get_mouse_msg()
            msg = get_mouse_msg()
            if msg.type == MouseMessageType.PRESS_MESSAGE:
                if reg1.contains(msg.x, msg.y):
                    draging_which_point = 1
                    set_color(Color.WHITE)
                    set_composition_mode(CompositionMode.SRC_XOR_DEST)
                    x, y = x3, y3
                elif reg2.contains(msg.x, msg.y):
                    draging_which_point = 2
                    set_color(Color.WHITE)
                    set_composition_mode(CompositionMode.SRC_XOR_DEST)
                    x, y = x4, y4
                else:
                    draging_which_point = 0
            elif msg.type == MouseMessageType.RELEASE_MESSAGE:
                if draging_which_point == 1:
                    x3, y3 = msg.x, msg.y
                elif draging_which_point == 2:
                    x4, y4 = msg.x, msg.y
                draging_which_point = 0

                set_color(Color.BLACK)
                set_composition_mode(CompositionMode.SOURCE)
                clear_device()
                draw_line(x1, y1, x3, y3)
                draw_line(x2, y2, x4, y4)
                circle(x1, y1, 3)
                circle(x2, y2, 3)
                draw_bezier(x1, y1, x3, y3, x4, y4, x2, y2)
        else:
            if draging_which_point == 1:
                x, y = get_cursor_pos()
                draw_line(x1, y1, x, y)
                draw_bezier(x1, y1, x, y, x4, y4, x2, y2)
            elif draging_which_point == 2:
                x, y = get_cursor_pos()
                draw_line(x2, y2, x, y)
                draw_bezier(x1, y1, x3, y3, x, y, x2, y2)
        delay_fps(60)

    close_graph()

easy_run(main)

字符输入

我们可以使用has_kb_hit()函数(非阻塞)来检查是否有任意的ascii可见字符被输入,然后使用get_char()函数(阻塞)来读取输入的字符。

下面的程序是一个简单的打字游戏

from easygraphics import *
import random


def show_welcome():
    clear_device()
    set_color("yellow")
    set_font_size(64)
    draw_text(160, 110, "Print Game");
    set_color("white");
    c = 0
    set_font_size(20)
    while is_run():
        if has_kb_hit():
            break
        set_color(color_rgb(c, c, c))
        draw_text(180, 400, "Press any key to continue")
        c = (c + 8) % 255;
        delay_fps(30)
    ch = get_char()
    clear_device()


def show_goodbye():
    clear_device();
    set_color("yellow");
    set_font_size(48);
    draw_text(104, 180, "Bye!!!");
    pause()


def main():
    init_graph(640, 480)
    set_render_mode(RenderMode.RENDER_MANUAL)
    set_background_color("black")

    show_welcome()
    random.seed()
    set_font_size(20)
    set_fill_color("black")

    while is_run():
        target = chr(65 + random.randint(0, 25))
        x = random.randint(0, 620)
        for y in range(16, 460):
            set_color("white")
            draw_text(x, y, target)
            if has_kb_hit():
                key = get_char()
                if key.upper() == target:
                    fill_rect(x - 2, y - 22, x + 22, y + 2)  # clear the char and generate next char
                    break
                if key == " ":
                    show_goodbye()
                    close_graph()
                    exit()
            delay_fps(60)
            fill_rect(x - 2, y - 22, x + 22, y + 2)  # clear the char

    close_graph()

easy_run(main)

按键消息

可以使用has_kb_msg()函数(非阻塞)来检查是否有任意键被按下,然后使用get_key()函数来读取按下的键。