第一次在Linux环境下编程,使用minigui做个界面显示位置和速度曲线。Windows下写过一些C程序,minigui学习了两个礼拜,研究了点Emacs,边写边学习。
在104系统上运行,与底层FPGA通信,将其采集到的数据读入并显示。FPGA此处不谈,记录下minigui,以helloworld为例。
/**********************************************************************************/
#include <stdio.h>
#include <minigui/common.h> //包括minigui常用的宏以及数据类型的定义
#include <minigui/minigui.h> //包含全局的和通用的接口函数以及某些杂项函数的定义
#include <minigui/gdi.h> //包含minigui绘图函数的接口定义
#include <minigui/window.h> //包含窗口有关的宏、数据类型、数据接口定义以及函数接口声明
//#include <minigui/control.h> //包含libminigui中所有内建控件的接口定义
/*程序入口*/
int
MiniGUIMain (int argc, const char* argv[]) //argc:命令行参数个数 argv参数字符串数组指针
{
MSG Msg; //window.h中
HWND hMainWnd;
MAINWINCREATE CreateInfo; //描述一个主窗口的属性
//const char* old_renderer;
#ifdef _MGRM_PROCESSES
JoinLayer(NAME_DEF_LAYER , "helloworld" , 0 , 0); //MiniGUI-Processes模式下加入层(客户端)
#endif
CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION; //设置主窗口风格:可见|有边框|有标题栏
CreateInfo.dwExStyle = WS_EX_NONE; //扩展风格:无
CreateInfo.spCaption = "HelloWorld"; //标题
CreateInfo.hMenu = 0; //主菜单:无
CreateInfo.hCursor = GetSystemCursor(0); //设置主窗口的光标为系统缺省光标
CreateInfo.hIcon = 0; //图标:无
CreateInfo.MainWindowProc = HelloWinProc; //设置主窗口的窗口函数,所有发往该窗口的消息由该函数处理
CreateInfo.lx = 0; //屏幕上的位置(0,0)、(320,240)
CreateInfo.ty = 0;
CreateInfo.rx = 320;
CreateInfo.by = 240;
CreateInfo.iBkColor = COLOR_lightwhite; //背景色
CreateInfo.dwAddData = 0; //附加数据:无
//在窗口过程中,可以使用GetWindowAdditionalData函数获取该指针,从而获得所需要传递的参数。
CreateInfo.hHosting = HWND_DESKTOP; //设置主窗口的托管窗口为桌面窗口
//MiniGUI-Threads 中每个线程创建的第一个主窗口,其托管窗口必须是桌面,即
HWND_DESKTOP,
//该线程的其他窗口,必须由属于同一线程的已有主窗口作为托管窗口。
//系统在托管窗口为 HWND_DESKTOP
时创建新的消息队列,
//而在指定非桌面的窗口作为托管窗口时,使用该托管窗口的消息队列,
//也就是说,同一线程中的所有主窗口应该使用同一个消息队列。
//在调用 MiniGUIMain
之前,MiniGUI 启动自己的桌面窗口(Desktop)。
//old_renderer = SetDefaultWindowElementRender("classic");
hMainWnd =
CreateMainWindow (&CreateInfo); //创建一个主窗口,返回值为所创建主窗口的句柄
if (hMainWnd == HWND_INVALID)
return -1;
ShowWindow(hMainWnd, SW_SHOWNORMAL); //显示:参数1:所要显示的窗口句柄 参数2:显示窗口的方式(显示/隐藏)
while (GetMessage(&Msg, hMainWnd)) { //参数1:要获取消息的主窗口的句柄 参数2:指向MSG结构的指针
//GetMessage函数将用从消息队列中取出的消息来填充该消息结构的各个域
TranslateMessage(&Msg); //把击键消息转换为MSG_CHAR消息,然后直接发送到窗口过程函数
DispatchMessage(&Msg); //把消息发往该消息的目标窗口的窗口过程,让其处理。
//处理完消息后,应用程序的窗口函数将返回到DispatchMessage函数,再返回到应用程序代码,
//应用程序又从下一个GetMessage函数调用开始消息循环。
}
//SetDefaultWindowElementRenderer(old_renderer);
MainWindowThreadCleanup (hMainWnd); //清除主窗口所使用消息队列系统资源
return 0;
}
/*窗口函数*/
//窗口过程是一个特定类型的函数,用来接收和处理所有发送到该窗口的消息。
//每个控件类有一个窗口过程,属于同一控件类的所有控件共用同一个窗口过程来处理消息。
static int
HelloWinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
//窗口过称函数,参数与MSG结构的前4个域相同 //由minigui调用,是一个回调函数
{
HDC hdc;
switch (message) {
case MSG_PAINT: //屏幕输出
hdc = BeginPaint (hWnd); //获得设备上下文句柄
TextOut (hdc, 60, 60, "Hello world!"); //文本输出
EndPaint (hWnd, hdc); //释放设备上下文句柄
return 0;
case MSG_CLOSE: //点击关闭按钮时
DestroyMainWindow (hWnd); //销毁主窗口
PostQuitMessage (hWnd); //在消息队列中投入一个MSG_QUIT消息,
//当GetMessage函数取出MSG_QUIT消息时将返回0.,最终导致程序退出消息循环
return 0;
}
return DefaultMainWinProc(hWnd, message, wParam, lParam); //默认处理
}
/**********************************************************************************/
以上是完整的helloworld程序,可以直接用。
接下来是对话框,有模态对话框和非模态对话框之分。
模态对话框就是显示之后,用户不能再切换到其他主窗口进行工作的对话框,而只能在关闭之后,才能使用其他的主窗口。MiniGUI
中,使用 DialogBoxIndirectParam
函数建立的对话框就是模态对话框。实际上,该对话框首先根据模板建立对话框,然后禁止其托管主窗口,并在主窗口的 MSG_CREATE
消息中创建控件,之后发送 MSG_INITDIALOG
消息给回调函数,最终建立一个新的消息循环,并进入该消息循环,直到程序调用 EndDialog
函数为止。
非模态对话框在利用对话框模板中的数据建立主窗口之后,会立即返回。使用
CreateMainWindowIndirect函数建立普通的主窗口。
对话框模板
在
MiniGUI 中,用两个结构来表示对话框模板(<minigui/window.h>)
,如下所示:
typedef struct
{
char* class_name;
// control class
DWORD dwStyle;
// control style
int x, y, w, h; // control
position in dialog
int id;
// control identifier
const char* caption; // control caption
DWORD dwAddData;
// additional data
DWORD dwExStyle;
// control extended style
} CTRLDATA;
//用来定义控件
typedef CTRLDATA*
PCTRLDATA;
typedef struct
{
DWORD dwStyle;
// dialog box style
DWORD dwExStyle;
// dialog box extended style
int x, y, w, h;
// dialog box position
const char* caption;
// dialog box caption
HICON hIcon;
// dialog box icon
HMENU hMenu;
// dialog box menu
int controlnr;
// number of controls
PCTRLDATA controls;
// poiter to control array
DWORD dwAddData;
// addtional data, must be zero
} DLGTEMPLATE;
//用来定义对话框本身
typedef DLGTEMPLATE*
PDLGTEMPLATE;
在程序中,应该首先利用 CTRLDATA
定义对话框中所有的控件,并用数组表示。控件在该数组中的顺序,也就是对话框中用户按TAB键时的控件切换顺序。然后定义对话框,指定对话框中的控件数目,并指定 DLGTEMPLATE
结构中的 controls
指针指向定义控件的数组。
例如:
static CTRLDATA ButtonCtrls[BUTTONNUM];
static DLGTEMPLATE ButtonPanel = {
WS_VISIBLE | WS_THINFRAME,
WS_EX_NONE, 0,0,0,0,
"buttonlist",
0,0,
BUTTONNUM, ButtonCtrls,
0
};
ButtonPanel.controls = ButtonCtrls;
定义完对话框模板数据后,需要定义对话框的回调函数。
对话框操作函数
(不一定仅在对话框中可用)
函数名称
用途
备注
DestroyAllControls
销毁所有的子窗口
GetDlgCtrlID
根据控件句柄获取控件标识符
GetDlgItem
根据控件标识符获取控件句柄
GetDlgItemInt
获取控件文本并转换为整数值
SetDlgItemInt
根据整数值设置控件文本
GetDlgItemText
获取子控件文本
功能同 GetWindowText
GetDlgItemText2
获取子控件文本
根据文本长度自动分配内存,应用程序负责释放该内存
SetDlgItemText
设置子控件文本
功能同 SetWindowText
GetNextDlgGroupItem
获取下一个同组子控件
用于遍历同组控件,参阅 WS_GROUP
风格
GetNextDlgTabItem
获取下一个“TAB
键停止”子控件
用于TAB键游历控件,参阅WS_TABSTOP风格
SendDlgItemMessage
向子控件发送消息
功能同 SendMessage
CheckDlgButton
设置检查框子控件的选中状态
CheckRadioButton
设置单选按钮子控件的选中状态
IsDlgButtonChecked
检查子按钮是否选中
GetDlgDefPushButton
获取当前默认子按钮
通用窗口操作函数
函数名称
用途
备注
UpdateWindow
立即更新某个窗口
ShowWindow
显示或隐藏某个窗口
IsWindowVisible
判断某个窗口是否可见
控件和主窗口均可用
EnableWindow
使能或禁止某个窗口
IsWindowEnabled
判断某个窗口是否可用
GetClientRect
获取窗口客户区矩形
GetWindowRect
获取窗口矩形
屏幕坐标系中的窗口尺寸
GetWindowBkColor
获取窗口背景色
SetWindowBkColor
设置窗口背景色
GetWindowFont
获取窗口默认字体
SetWindowFont
设置窗口默认字体
GetWindowCursor
获取窗口光标
SetWindowCursor
设置窗口光标
GetWindowStyle
获取窗口风格
GetWindowExStyle
获取窗口扩展风格
GetFocusChild
获取拥有输入焦点的子窗口
SetFocusChild
设置焦点子窗口
GetWindowCallbackProc
获取窗口过程函数
SetWindowCallbackProc
设置窗口过程函数
GetWindowAdditionalData
获取窗口附加数据一
SetWindowAdditionalData
设置窗口附加数据一
GetWindowAdditionalData2
获取窗口附加数据二
SetWindowAdditionalData2
设置窗口附加数据二
对话框和控件在内部已使用附加数据二,保留附加数据一给应用程序使用
GetWindowCaption
获取窗口标题
通常用于主窗口
SetWindowCaption
设置窗口标题
通常用于主窗口
InvalidateRect
使窗口的给定矩形区域无效
将引发窗口重绘
GetUpdateRect
获取窗口当前的无效区域外包矩形
ClientToScreen
将窗口客户区坐标转换为屏幕坐标
ScreenToClient
将屏幕坐标转换为客户区坐标
WindowToScreen
将窗口坐标转换为屏幕坐标
ScreenToWindow
将屏幕坐标转换为窗口坐标
IsMainWindow
判断给定窗口是否为主窗口
IsControl
判断给定窗口是否为控件
IsDialog
判断给定窗口是否为对话框
GetParent
获取窗口的父窗口句柄
主窗口的父窗口永远为HWND_DESKTOP
GetMainWindowHandle
返回包含某个窗口的主窗口句柄
GetNextChild
获取下一个子窗口
用于遍历某个窗口的所有子窗口
GetNextMainWindow
获取下一个主窗口句柄
用于遍历所有主窗口
GetHosting
获取某个主窗口的托管窗口
GetFirstHosted
获取某个主窗口的第一个被托管窗口
GetNextHosted
获取下一个被托管窗口
用于遍历某个主窗口的所有被托管窗口
GetActiveWindow
获取当前活动主窗口
SetActiveWindow
设置当前活动主窗口
GetCapture
获取当前捕获鼠标的窗口
SetCapture
捕获鼠标
ReleaseCapture
释放鼠标
MoveWindow
移动窗口或改变窗口大小
ScrollWindow
滚动窗口客户区的内容
事件钩子
通常情况下,键盘事件和鼠标事件以其正常的途径从底层设备传递到最终的应用程序窗口过程中进行处理。MiniGUI
提供了一种机制,使得我们可以在这些事件转换成相应的消息并传递到具体的窗口之前截获这些事件,然后有两种选择:让事件继续沿着正常的路径传递;或者打断事件的传递。这种机制就是钩子机制。
钩子其实是一个回调函数,如果应用程序注册有钩子,系统就会在传递消息的中途调用这个回调函数,然后根据该回调函数的返回值来判断是否继续传递消息。
MiniGUI-Threads
和 MiniGUI-Standalone
模式下定义的钩子回调函数的原型如下所示:
typedef int (*
MSGHOOK)(void* context, HWND dst_wnd, int msg, WPARAM wparam, LPARAM lparam);
其中,context
是注册钩子时传入的一个上下文信息,可以是一个指针;dst_wnd
是该消息的目标主窗口;msg 是消息标识符;wparam
和 lparam 是消息的两个参数。钩子函数的返回值决定了系统是否继续传递事件:返回 HOOK_GOON
将继续传递事件;返回 HOOK_STOP
将停止事件的继续传递。
注册键盘和鼠标事件的钩子函数:
MSGHOOK GUIAPI
RegisterKeyMsgHook (void* context, MSGHOOK hook);