数码相框-主界面MainPage输入功能

本文介绍了如何在C语言中定义输入管理模块,包括输入类型、事件结构体和操作结构体,以及详细展示了如何初始化和处理触摸屏设备,如TouchScreenDevInit和TouchScreenGetInputEvent函数。
摘要由CSDN通过智能技术生成

定义输入管理的头文件

#ifndef _INPUT_MANAGER_H
#define _INPUT_MANAGER_H
#include <sys/time.h>
#include <pthread.h>

/* 输入类型定义 */
#define INPUT_TYPE_STDIN        0  /* 标准输入 */
#define INPUT_TYPE_TOUCHSCREEN  1  /* 触摸屏 */

/* 输入事件值定义 */
#define INPUT_VALUE_UP          0  /* 上 */
#define INPUT_VALUE_DOWN        1  /* 下 */
#define INPUT_VALUE_EXIT        2  /* 退出 */
#define INPUT_VALUE_UNKNOWN     -1 /* 未知 */

/* 输入事件结构体定义,包含事件的时间、类型、坐标、键值和压力等信息 */
typedef struct InputEvent {
	struct timeval tTime;
	int iType;  /* 输入设备类型 */
	int iX;
	int iY;
	int iKey;
	int iPressure;
}T_InputEvent, *PT_InputEvent;

/* 输入操作结构体定义,包含设备名称、线程ID、设备初始化与退出函数指针、获取输入事件函数指针和下一个输入操作结构体指针 */
typedef struct InputOpr {
	char *name;
	pthread_t tTreadID;
	int (*DeviceInit)(void);    /* 设备初始化函数 */
	int (*DeviceExit)(void);   /* 设备退出函数 */
	int (*GetInputEvent)(PT_InputEvent ptInputEvent); /* 获取输入事件函数 */
	struct InputOpr *ptNext;                            /* 下一个输入操作结构体指针 */
}T_InputOpr, *PT_InputOpr;

/* 输入系统初始化 */
int InputInit(void);

/* 注册输入操作 */
int RegisterInputOpr(PT_InputOpr ptInputOpr);

/* 展示已注册的输入操作 */
void ShowInputOpr(void);

/* 初始化所有输入设备 */
int AllInputDevicesInit(void);

/* 获取输入事件 */
int GetInputEvent(PT_InputEvent ptInputEvent);

/* 标准输入设备初始化 */
int StdinInit(void);

/* 触摸屏设备初始化 */
int TouchScreenInit(void);

#endif /* _INPUT_MANAGER_H */

修改touchscreen.c

/*
 * TouchScreenDevInit - 初始化触摸屏设备
 * 
 * 此函数用于初始化触摸屏设备,它会尝试从环境变量获取触摸屏设备节点,
 * 如果未设置,则使用默认设备节点。需要在SelectAndInitDisplay函数调用之后调用此函数,
 * 因为它依赖于LCD的分辨率。
 * 
 * 返回值:
 *      0 - 初始化成功
 *     -1 - 初始化失败
 */
static int TouchScreenDevInit(void)
{
    char *pcTSName = NULL;
    int iBpp;

    // 尝试从环境变量获取触摸屏设备节点
    if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL ) 
    {
        g_tTSDev = ts_open(pcTSName, 0);  /* 以阻塞方式打开 */
    }
    else
    {
        g_tTSDev = ts_open("/dev/event0", 1);
    }

    // 检查设备打开是否成功
    if (!g_tTSDev) {
        DBG_PRINTF(APP_ERR"ts_open error!\n");
        return -1;
    }

    // 配置触摸屏设备
    if (ts_config(g_tTSDev)) {
        DBG_PRINTF("ts_config error!\n");
        return -1;
    }

    // 获取显示分辨率
    if (GetDispResolution(&giXres, &giYres, &iBpp))
    {
        return -1;
    }

    return 0;
}

/*
 * TouchScreenDevExit - 退出触摸屏设备
 * 
 * 此函数用于清理触摸屏设备初始化过程中的资源。
 * 
 * 返回值:
 *      0 - 退出成功
 */
static int TouchScreenDevExit(void)
{
    return 0;
}

/*
 * TouchScreenGetInputEvent - 获取触摸屏输入事件
 * 
 * 从触摸屏设备读取一个输入事件,并将其填充到提供的输入事件结构体中。
 * 
 * 参数:
 *      ptInputEvent - 指向接收输入事件的结构体的指针。
 * 
 * 返回值:
 *      0 - 读取事件成功
 *     -1 - 读取事件失败
 */
static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{
    struct ts_sample tSamp;
    struct ts_sample tSampPressed;
    struct ts_sample tSampReleased;
    int iRet;
    int bStart = 0;
    int iDelta;

    static struct timeval tPreTime;
  
    // 循环读取触摸屏事件
    while (1)
    {
        iRet = ts_read(g_tTSDev, &tSamp, 1); /* 如果无数据则休眠 */
        if (iRet == 1)
        {
            // 读取成功,将事件信息填充到结构体中
            ptInputEvent->tTime     = tSamp.tv;
            ptInputEvent->iType     = INPUT_TYPE_TOUCHSCREEN;
            ptInputEvent->iX        = tSamp.x;
            ptInputEvent->iY        = tSamp.y;
            ptInputEvent->iPressure = tSamp.pressure;
            return 0;
        }
        else
        {
            // 读取失败
            return -1;
        }
    }

    return 0;
}


/*
 * g_tTouchScreenOpr - 触摸屏操作结构体
 * 
 * 定义了触摸屏操作的相关函数指针和设备名称。
 */
static T_InputOpr g_tTouchScreenOpr = {
    .name          = "touchscreen",
    .DeviceInit    = TouchScreenDevInit,
    .DeviceExit    = TouchScreenDevExit,
    .GetInputEvent = TouchScreenGetInputEvent,
};

/*
 * TouchScreenInit - 注册触摸屏输入操作
 * 
 * 此函数用于注册触摸屏的输入操作处理函数。
 * 
 * 返回值:
 *      0 - 注册成功
 *     -1 - 注册失败
 */
int TouchScreenInit(void)
{
    return RegisterInputOpr(&g_tTouchScreenOpr);
}
  • TouchScreenDevInit​函数用于初始化触摸屏设备。它首先尝试从环境变量获取触摸屏设备节点,如果未设置,则使用默认设备节点。然后打开触摸屏设备,配置设备,获取显示分辨率,并返回初始化结果(0表示成功,-1表示失败)。
  • TouchScreenDevExit​函数用于清理触摸屏设备初始化过程中的资源。该函数目前没有实现具体的功能,始终返回0表示退出成功。
  • TouchScreenGetInputEvent​函数用于从触摸屏设备读取一个输入事件,并将其填充到提供的输入事件结构体中。函数通过循环读取触摸屏事件,读取成功则将事件信息填充到结构体中并返回0,读取失败则返回-1。
  • g_tTouchScreenOpr​是一个静态结构体,定义了触摸屏操作的相关函数指针和设备名称。
  • TouchScreenInit​函数用于注册触摸屏的输入操作处理函数。它调用RegisterInputOpr​函数,并传入g_tTouchScreenOpr​结构体作为参数,以将触摸屏的操作函数注册到系统中。函数返回注册结果(0表示成功,-1表示失败)。

修改输入事件

修改PageAction结构体:

typedef struct PageAction {
	char *name;
	int (*Run)(void);
	int (*GetInputEvent)(PT_Layout atLayout, PT_InputEvent ptInputEvent);
	int (*Prepare)(void);
	struct PageAction *ptNext;
}T_PageAction, *PT_PageAction;

写主页面的输入捕获事件函数:

/**
 * 获取主页面的输入事件
 * 
 * 此函数用于处理主页面上的触摸输入事件,它会分析触摸点是否落在某个按钮上,
 * 如果落在按钮上,则返回对应按钮的索引;否则,返回-1。
 * 
 * @param atLayout 指向布局结构体数组的指针,用于描述页面上的按钮布局。
 * @param ptInputEvent 指向输入事件结构体的指针,用于存储获取的输入事件。
 * @return 如果成功获取到输入事件且事件类型为触摸屏类型,则返回触点所在的按钮索引;
 *         如果事件类型不是触摸屏类型或触点没有落在任何按钮上,返回-1。
 */
int MainPageGetInputEvent(PT_Layout atLayout, PT_InputEvent ptInputEvent)
{
	T_InputEvent tInputEvent;
	int iRet;
	int i = 0;

	/* 从输入管理器获取原始触摸屏事件 */
	iRet = GetInputEvent(&tInputEvent);
	if (iRet)
	{
		return -1; // 获取输入事件失败
	}

	// 检查事件类型是否为触摸屏类型
	if (tInputEvent.iType != INPUT_TYPE_TOUCHSCREEN)
	{
		return -1; // 事件类型不是触摸屏
	}

	*ptInputEvent = tInputEvent; // 将获取的输入事件赋值给传入的结构体

	/* 处理触摸事件,判断触点是否落在某个按钮的区域中 */
	while (atLayout[i].strIconName)
	{
		// 判断触点是否在当前按钮的边界内
		if ((tInputEvent.iX >= atLayout[i].iTopLeftX) && (tInputEvent.iX <= atLayout[i].iBotRightX) \
			 (tInputEvent.iY >= atLayout[i].iTopLeftY) && (tInputEvent.iY <= atLayout[i].iBotRightY))
		{
			// 找到被触点命中的按钮
			return i;
		}
		else
		{
			i++; // 继续检查下一个按钮
		}		
	}

	/* 触点没有落在任何按钮上 */
	return -1;
}

写处理主页面的输入捕获事件流程处理

/* 3. 调用GetInputEvent获得输入事件,进而处理 */
while (1)
{
	iIndex = MainPageGetInputEvent(g_atMainPageLayout, &tInputEvent);
	if (tInputEvent.iPressure == 0)
	{
		/* 如果是松开 */
		if (bPressed)
		{
			/* 曾经有按钮被按下 */
			ReleaseButton(&g_atMainPageLayout[iIndexPressed]);
			bPressed = 0;
			iIndexPressed = -1;
		}
	}
	else
	{
		/* 按下状态 */
		if (iIndex != -1)
		{
			if (!bPressed)
			{
				/* 未曾按下按钮 */
				bPressed = 1;
				iIndexPressed = iIndex;
				PressButton(&g_atMainPageLayout[iIndexPressed]);
			}
		}
	}	
}

判断输入事件类型

  • 松开事件if (tInputEvent.iPressure == 0)​ 当检测到输入事件的压力值为0时,认为用户已松开(抬起手指)。

    • 释放按钮if (bPressed)​ 如果之前有按钮处于按下状态(由标志变量bPressed​记录),则执行以下操作:

      • 调用ReleaseButton函数释放之前按下(索引为iIndexPressed)的按钮,将其视觉效果恢复至未按下状态。然后将标志变量bPressed置为0,表示当前无按钮被按下,并将iIndexPressed重置为-1。
  • 按下事件else​(即当tInputEvent.iPressure != 0​时,认为用户正在按下)

    • 判断有效索引if (iIndex != -1)​ 如果返回的索引iIndex​不为-1,表示触发事件的是有效的按钮。

    • 处理首次按下if (!bPressed)​ 如果之前没有按钮被按下(bPressed​为0),执行以下操作:

      • 将标志变量bPressed置为1,表示已有按钮被按下;将iIndexPressed设置为当前触发事件的按钮索引iIndex。接着调用PressButton函数处理按钮按下事件,更新按钮的视觉效果以体现被按下的状态。

翻转按钮

/*
 * 函数名称:InvertButton
 * 功能描述:将指定区域内的按钮图像颜色取反,实现按钮按下时的视觉效果。
 * 参数列表:
 *  - ptLayout: 指向一个PT_Layout结构体的指针,该结构体包含了按钮在屏幕上的布局信息。
 * 返回值:无。
 */

static InvertButton(PT_Layout ptLayout)
{
    int iX;
    int iY;
    int i;
    unsigned char *pucVideoMem;
    PT_DispOpr ptDispOpr = GetDefaultDispDev(); // 获取默认显示设备的操作接口

    // 计算按钮图像在Framebuffer中的起始地址
    pucVideoMem = ptDispOpr->pucDispMem;
    pucVideoMem += ptLayout->iTopLeftY * ptDispOpr->iLineWidth + ptLayout->iTopLeftX * ptDispOpr->iBpp / 8;

    // 遍历按钮图像的每个像素,将其颜色取反
    for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)
    {
        for (iX = ptLayout->iTopLeftX, i = 0; iX <= ptLayout->iBotRightX; iX++, i++)
        {
            pucVideoMem[i] = ~pucVideoMem[i];  /* 取反 */
        }
        pucVideoMem += ptDispOpr->iLineWidth; // 根据行宽度移动到下一行的起始位置
    }
  
}

/**
 * 释放按钮的资源或改变按钮状态。
 * @param ptLayout 指向布局结构体的指针,该结构体中包含了按钮的相关信息。
 * 该函数通过调用InvertButton函数来实现按钮状态的反转,用以模拟按钮被释放的效果。
 */
void ReleaseButton(PT_Layout ptLayout)
{
    InvertButton(ptLayout); // 反转按钮状态
}

好的,我来为你解答这个问题。 首先,我们需要安装pymysql和tkinter库。你可以通过以下命令来安装它们: ``` pip install pymysql ``` ``` sudo apt-get install python3-tk ``` 接下来,我们需要创建一个Python窗口,并在窗口中添加登录和注册界面。你可以使用以下代码: ```python import tkinter as tk import pymysql class BusApp: def __init__(self, root): self.root = root self.root.geometry("400x300") self.root.title("Bus App") # 创建登录和注册界面 self.create_login_screen() self.create_register_screen() def create_login_screen(self): # 创建登录界面 self.login_frame = tk.Frame(self.root) self.login_frame.pack() # 添加用户名标签和输入框 tk.Label(self.login_frame, text="用户名").grid(row=0, column=0) self.username = tk.Entry(self.login_frame) self.username.grid(row=0, column=1) # 添加密码标签和输入框 tk.Label(self.login_frame, text="密码").grid(row=1, column=0) self.password = tk.Entry(self.login_frame, show="*") self.password.grid(row=1, column=1) # 添加登录按钮 tk.Button(self.login_frame, text="登录", command=self.login).grid(row=2, column=0) def create_register_screen(self): # 创建注册界面 self.register_frame = tk.Frame(self.root) # 添加用户名标签和输入框 tk.Label(self.register_frame, text="用户名").grid(row=0, column=0) self.new_username = tk.Entry(self.register_frame) self.new_username.grid(row=0, column=1) # 添加密码标签和输入框 tk.Label(self.register_frame, text="密码").grid(row=1, column=0) self.new_password = tk.Entry(self.register_frame, show="*") self.new_password.grid(row=1, column=1) # 添加注册按钮 tk.Button(self.register_frame, text="注册", command=self.register).grid(row=2, column=0) def login(self): # 获取用户名和密码 username = self.username.get() password = self.password.get() # 连接数据库 conn = pymysql.connect(host='localhost', user='root', password='password', database='bus') cursor = conn.cursor() # 查询用户信息 sql = "SELECT * FROM users WHERE username=%s AND password=%s" cursor.execute(sql, (username, password)) result = cursor.fetchone() if result: # 登录成功,打开界面 self.root.withdraw() import MainPage MainPage.MainPage(self.root, username) else: # 登录失败,提示错误信息 tk.messagebox.showerror("错误", "用户名或密码错误!") def register(self): # 获取新用户名和密码 new_username = self.new_username.get() new_password = self.new_password.get() # 连接数据库 conn = pymysql.connect(host='localhost', user='root', password='password', database='bus') cursor = conn.cursor() # 查询用户名是否已存在 sql = "SELECT * FROM users WHERE username=%s" cursor.execute(sql, (new_username,)) result = cursor.fetchone() if result: # 用户名已存在,提示错误信息 tk.messagebox.showerror("错误", "用户名已存在!") else: # 插入新用户信息 sql = "INSERT INTO users (username, password) VALUES (%s, %s)" cursor.execute(sql, (new_username, new_password)) conn.commit() # 注册成功,提示成功信息 tk.messagebox.showinfo("成功", "注册成功!") # 清空输入框 self.new_username.delete(0, tk.END) self.new_password.delete(0, tk.END) if __name__ == "__main__": root = tk.Tk() app = BusApp(root) root.mainloop() ``` 在上面的代码中,我们使用了tkinter库创建了一个名为BusApp的类,该类包含了登录和注册界面的实现。在登录界面中,我们获取用户输入的用户名和密码,然后连接数据库并查询用户信息,如果查询结果非空,则打开界面;否则,提示错误信息。在注册界面中,我们获取用户输入的新用户名和密码,然后连接数据库并查询用户名是否已存在,如果存在则提示错误信息,否则插入新用户信息并提示注册成功信息。 最后,我们需要在登录成功后打开名为MainPage.py的Python文件。你可以在BusApp类的login方法中添加以下代码: ```python import os # 打开MainPage.py文件 os.system("python MainPage.py") ``` 这样,当用户输入正确的用户名和密码时,就会自动打开MainPage.py文件。 希望这个例子对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值