MaixPy / MaixCAM Touchscreen Usage Guide

Introduction

MaixCAM comes equipped with a touchscreen, which, when used in conjunction with applications, can facilitate numerous engaging functionalities. We can utilize APIs to detect touch interactions on the touchscreen.

Reading Touch Input with MaixPy

MaixPy offers a straightforward maix.touchscreen.TouchScreen class for reading touch inputs. Here's an example:

from maix import touchscreen, app, time

ts = touchscreen.TouchScreen()

pressed_already = False
last_x = 0
last_y = 0
last_pressed = False
while not app.need_exit():
    x, y, pressed = ts.read()
    if x != last_x or y != last_y or pressed != last_pressed:
        print(x, y, pressed)
        last_x = x
        last_y = y
        last_pressed = pressed
    if pressed:
        pressed_already = True
    else:
        if pressed_already:
            print(f"clicked, x: {x}, y: {y}")
            pressed_already = False
    time.sleep_ms(1)  # sleep some time to free some CPU usage

Interactivity with the Screen

Integrating the screen can enable various interactive user experiences. More examples can be found in the MaixPy/examples/vision/touchscreen directory.

As previously described, to display content on the screen, typically, a maix.image.Image object is created and displayed using disp.show(img). Implementing a button is as simple as drawing one on the image and then detecting touches within its area, ensuring that the image's dimensions match those of the screen:

from maix import touchscreen, app, time, display, image

ts = touchscreen.TouchScreen()
disp = display.Display()

img = image.Image(disp.width(), disp.height())

# draw exit button
exit_label = "< Exit"
size = image.string_size(exit_label)
exit_btn_pos = [0, 0, 8*2 + size.width(), 12 * 2 + size.height()]
img.draw_string(8, 12, exit_label, image.COLOR_WHITE)
img.draw_rect(exit_btn_pos[0], exit_btn_pos[1], exit_btn_pos[2], exit_btn_pos[3], image.COLOR_WHITE, 2)

def is_in_button(x, y, btn_pos):
    return x > btn_pos[0] and x < btn_pos[0] + btn_pos[2] and y > btn_pos[1] and y < btn_pos[1] + btn_pos[3]

while not app.need_exit():
    x, y, pressed = ts.read()
    if is_in_button(x, y, exit_btn_pos):
        app.set_exit_flag(True)
    img.draw_circle(x, y, 1, image.Color.from_rgb(255, 255, 255), 2)
    disp.show(img)

Handling Different Screen and Image Sizes

In the example above, the img matches the screen size. If your img and screen sizes differ (e.g., using img = image.Image(240, 240) on a 640x480 screen), the default behavior of disp.show(img) is image.Fit.FIT_CONTAIN, which scales the image to 480x480 and fills the sides with black. If a button is drawn on the 240x240 image, such as at coordinates (0, 0, 60, 40), the button will also be scaled up. Thus, the coordinates for touch detection should be adjusted to ((640 - 480) / 2, 0, 480/240*60, 480/240*40), which translates to (80, 0, 120, 80).

For convenience in scaling images and quickly calculating the positions and sizes of points or rectangles in the scaled image, the image.resize_map_pos function is provided:

from maix import touchscreen, app, time, display, image

ts = touchscreen.TouchScreen()
disp = display.Display()

img = image.Image(240, 240)
img.draw_rect(0, 0, img.width(), img.height(), image.COLOR_WHITE)

# draw exit button
exit_label = "< Exit"
size = image.string_size(exit_label)
exit_btn_pos = [0, 0, 8*2 + size.width(), 12 * 2 + size.height()]
img.draw_string(8, 12, exit_label, image.COLOR_WHITE)
img.draw_rect(exit_btn_pos[0], exit_btn_pos[1], exit_btn_pos[2], exit_btn_pos[3],  image.COLOR_WHITE, 2)
# 图像按键坐标映射到屏幕上的坐标
exit_btn_disp_pos = image.resize_map_pos(img.width(), img.height(), disp.width(), disp.height(), image.Fit.FIT_CONTAIN, exit_btn_pos[0], exit_btn_pos[1], exit_btn_pos[2], exit_btn_pos[3])

def is_in_button(x, y, btn_pos):
    return x > btn_pos[0] and x < btn_pos[0] + btn_pos[2] and y > btn_pos[1] and y < btn_pos[1] + btn_pos[3]

while not app.need_exit():
    x, y, pressed = ts.read()
    if is_in_button(x, y, exit_btn_disp_pos):
        app.set_exit_flag(True)
    # 屏幕的坐标映射回图像上对应的坐标,然后在图像上画点
    x, y = image.resize_map_pos_reverse(img.width(), img.height(), disp.width(), disp.height(), image.Fit.FIT_CONTAIN, x, y)
    img.draw_circle(x, y, 1, image.Color.from_rgb(255, 255, 255), 2)
    disp.show(img, fit=image.Fit.FIT_CONTAIN)