我的第一个minigui程序

来源:互联网 发布:算法设计的基本要素 编辑:程序博客网 时间:2024/04/28 05:12
   第一次在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中所有内建控件的接口定义

 

/*程序入口*/

intMiniGUIMain (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 intHelloWinProc(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;             // controlposition 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 GUIAPIRegisterKeyMsgHook (void* context, MSGHOOK hook);

MSGHOOK GUIAPIRegisterMouseMsgHook (void* context, MSGHOOK hook);

调用这两个函数时,只需传入上下文信息以及钩子回调函数的指针即可。成功时会返回先前注册的钩子函数指针。如果想注销先前注册的钩子函数,只需为 hook 参数传入 NULL RegisterKeyMsgHook (0, old_hook);

 

 

窗口重绘

一般来说,在以下情况下,MiniGUI程序的窗口过程会接收到一个MSG_PAINT消息:

1、用户移动窗口或显示窗口时,MiniGUI向先前被隐藏的窗口发送MSG_PAINT消息;

2、程序使用InvalidateRect函数来更新窗口的无效区域,这将产生一个MSG_PAINT消息;

3、程序调用UpdateWindow函数来重绘窗口;

4、覆盖程序窗口的对话框或消息框被消除;

5、下拉或弹出菜单被消除。

 

基本绘图函数

void GUIAPI SetPixel (HDC hdc, int x, int y, gal_pixel c);

void GUIAPI SetPixelRGB (HDC hdc, int x, int y, int r, int g, int b);

gal_pixel GUIAPI GetPixel (HDC hdc, int x, int y);

void GUIAPI GetPixelRGB (HDC hdc, int x, int y, int* r, int* g, int* b);

gal_pixel GUIAPI RGB2Pixel (HDC hdc, int r, int g, int b);

void GUIAPILineTo (HDC hdc, int x, int y);

void GUIAPIMoveTo (HDC hdc, int x, int y);

void GUIAPI Circle (HDC hdc, int x, int y, int r);

void GUIAPI Rectangle (HDC hdc, int x0, int y0, int x1, int y1);

菜单

定时器

 

MiniGUI 中,应用程序可以调用SetTimer 函数创建定时器。SetTimer 的第三个参数用来指定定时器的间隔,默认以10 毫秒为单位。

 

当创建的定时器到期时,创建定时器时指定的窗口就会收到MSG_TIMER 消息,并传递到期的定时器标识号。

在不需要定时器时,应用程序可以调用KillTimer 函数删除定时器。

应用程序还可以调用ResetTimer函数重新设定定时器的间隔。

IsTimerInstalled函数用于检查一个定时器是否被安装到指定的窗口上。

HaveFreeTimer用于检测系统中是否还有可用的定时器资源。

 

 

其他一些说明

1、设备字体

2、文本输出

3、颜色

4、输入框限制

SetWindowCallbackProc(hwndedit, RestrictedEditBox); 

原创粉丝点击