概述
EasyX实现按钮效果
利用EasyX绘制按钮,实现按钮的鼠标悬浮、按下、弹起效果。
效果展示
实现原理
在EasyX现有基础上,实现了widget窗口元素,并用C语言的方式,从widget派生出button(按钮)、label(文本框)等窗口控件,利用container窗口容器进行管理,并封装了鼠标和键盘按键,实现了简易的消息派发机制,使得程序逻辑只需关心按钮被按下的消息事件,而无需做鼠标坐标和图形区域判断。
- 消息机制的封装(部分代码)
/*********************
* 框架 - 消息派发
**********************/
#define TASK_QUEUE_SIZE 10
typedef struct _tTaskInfo {
int type;
void* data;
} TaskInfo;
typedef struct _tTaskQueue {
TaskInfo* data;
int front;
int rear;
int capacity;
} TaskQueue;
//创建事件
typedef void* (*CallCreate)();
//销毁事件
typedef void (*CallDestroy)(void* context);
//键盘事件
typedef int (*CallKeyBoard)(int key, TaskQueue* queue, void* context);
//鼠标事件
typedef int (*CallMouse)(MOUSEMSG* msg, TaskQueue* queue, void* context);
//任务事件
typedef int (*CallTask)(TaskQueue* queue, void* context);
//空闲事件
typedef int (*CallIdle)(void* context);
//运行环境
typedef struct _tRuntime {
void* context;
CallCreate create;
CallDestroy destroy;
CallKeyBoard keyboard;
CallMouse mouse;
CallTask task;
CallIdle idle;
} Runtime;
TaskQueue* createTaskQueue(int capacity) {
TaskQueue* queue = (TaskQueue*)malloc(sizeof(TaskQueue));
memset(queue, 0, sizeof(TaskQueue));
queue->capacity = capacity;
queue->data = (TaskInfo*)malloc(sizeof(queue->data[0]) * capacity);
memset(queue->data, 0, sizeof(sizeof(queue->data[0]) * capacity));
return queue;
}
void destroyTaskQueue(TaskQueue* queue) {
if (queue) {
free(queue->data);
free(queue);
}
}
int emptyTaskQueue(TaskQueue* queue) {
return (queue && queue->front == queue->rear);
}
int fullTaskQueue(TaskQueue* queue) {
return (queue && queue->front == ((queue->rear + 1) % queue->capacity));
}
void enqueueTaskQueue(TaskQueue* queue, int type, void* data) {
if (queue) {
if (!fullTaskQueue(queue)) {
int pos = queue->rear;
TaskInfo* task = &queue->data[pos];
queue->rear = (pos + 1) % queue->capacity;
task->type = type;
task->data = data;
}
}
}
void dequeueTaskQueue(TaskQueue* queue, TaskInfo* task) {
if (queue) {
if (!emptyTaskQueue(queue)) {
int pos = queue->front;
queue->front = (pos + 1) % queue->capacity;
*task = queue->data[pos];
}
}
}
Runtime createRuntime(CallCreate create, CallDestroy destroy, CallKeyBoard keyboard, CallMouse mouse, CallTask task, CallIdle idle) {
Runtime runtime = { NULL, create, destroy, keyboard, mouse, task, idle };
return runtime;
}
int dispatchMessage(Runtime* runtime) {
void* context = runtime->create();
TaskQueue* queue = createTaskQueue(TASK_QUEUE_SIZE);
int ret = 0;
FlushMouseMsgBuffer();
while (1) {
if (runtime->keyboard && _kbhit()) {
int key = _getch();
ret = runtime->keyboard(key, queue, context);
if (ret != 0) {
break;
}
} else if (runtime->mouse && MouseHit()) {
MOUSEMSG msg = GetMouseMsg();
ret = runtime->mouse(&msg, queue, context);
if (ret != 0) {
break;
}
} else if (runtime->task && !emptyTaskQueue(queue)) {
ret = runtime->task(queue, context);
if (ret != 0) {
break;
}
} else if (runtime->idle) {
ret = runtime->idle(context);
if (ret != 0) {
break;
}
}
}
destroyTaskQueue(queue);
runtime->destroy(context);
return ret;
}
- 窗体控件的封装(部分代码)
/*********************
* 框架 - 窗体控件
**********************/
#define STYLE_BK_COLOR 0xFFFFFF
#define STYLE_WIDGET_BUTTON_COLOR_LINE 0x808080
#define STYLE_WIDGET_BUTTON_COLOR_FILL 0x808080
#define STYLE_WIDGET_BUTTON_COLOR_TEXT 0xFFFFFF
#define STYLE_WIDGET_BUTTON_COLOR_FOCUS 0x404040
#define STYLE_WIDGET_BUTTON_SHADOW_COLOR 0xC0C0C0
#define STYLE_WIDGET_BUTTON_SHADOW_OFFSET_X 3
#define STYLE_WIDGET_BUTTON_SHADOW_OFFSET_Y 3
#define STYLE_WIDGET_BUTTON_FONT_HEIGHT 16
enum {
WIDGET_TYPE_NULL,
WIDGET_TYPE_CONTAINER,
WIDGET_TYPE_BUTTON,
WIDGET_TYPE_LABEL,
};
enum {
WIDGET_LABEL_ALIGN_LEFT,
WIDGET_LABEL_ALIGN_CENTER,
};
enum {
WIDGET_FLAG_NULL = 0,
WIDGET_FLAG_FOCUS = 1 << 0,
WIDGET_FLAG_CLICK = 1 << 1
};
typedef struct _tPoint {
int x;
int y;
} Point;
typedef struct _tRect {
Point point;
int width;
int height;
} Rect;
typedef struct _tWidget {
int type;
int id;
int flag;
Rect rect;
} Widget;
typedef struct _tWidgetList {
Widget** data;
int size;
int capacity;
} WidgetList;
typedef struct _tWidgetContainer {
Widget widget;
WidgetList* list;
} WidgetContainer;
typedef struct _tWidgetButton {
Widget widget;
wchar_t* text;
} WidgetButton;
typedef struct _tWidgetLabel {
Widget widget;
int font_height;
int align;
COLORREF fill_color;
COLORREF line_color;
COLORREF text_color;
COLORREF focus_color;
wchar_t* text;
} WidgetLabel;
wchar_t* convertCharToWchar(const char* input);
WidgetList* createWidgetList(int capacity);
void destroyWidgetList(WidgetList* list);
void appendWidgetList(WidgetList* list, Widget* widget);
WidgetContainer* createWidgetContainer(int id, int x, int y, int width, int height);
void appendWidgetContainer(WidgetContainer* container, Widget* widget);
void destroyWidgetContainer(WidgetContainer* container);
WidgetButton* createWidgetButton(int id, int x, int y, int width, int height, const char* text);
void destroyWidgetButton(WidgetButton* button);
void drawWidgetButton(WidgetButton* button);
WidgetLabel* createWidgetLabel(int id, int x, int y, int width, int height, int font_height, COLORREF fill_color, COLORREF line_color, COLORREF text_color, COLORREF focus_color, int align, const char* text);
void destroyWidgetLabel(WidgetLabel* label);
void drawWidgetLabel(WidgetLabel* label);
void drawWidgetContainer(WidgetContainer* container);
int hitWidget(Widget* widget, MOUSEMSG* msg);
Widget* hitWidgetContainer(WidgetContainer* container, MOUSEMSG* msg);
wchar_t* convertCharToWchar(const char* input) {
int input_len = (int)strlen(input);
int output_len = MultiByteToWideChar(CP_ACP, 0, input, input_len, NULL, 0);
wchar_t* output = new wchar_t[output_len + 1];
MultiByteToWideChar(CP_ACP, 0, input, input_len, output, output_len);
output[output_len] = '