精华内容
下载资源
问答
  • 【项目源码】风力发电机PMSG模型设计,simulink仿真文件mdl.rar
  • 3.2 设计目标分析 3.3 安全保密需求分析 3.4 开发与运行环境 3.5 系统可行性分析 3.5.1 技术可行性 3.5.2 经济可行性 3.5.3 管理可行性 3.5.4 法律可行性 4. 系统设计 4.1 概要设计 4.1.1 主控端规划 ...

    课题

    C++基于MFC实验室机房管理系统

    目   录

    1. 引言

    2. 开发技术简介

    2.1 VC++ 6.0开发平台介绍

    2.2 数据库系统介绍

    3. 系统需求分析

    3.1 需求分析

    3.2 设计目标分析

    3.3 安全保密需求分析

    3.4 开发与运行环境

    3.5 系统可行性分析

    3.5.1 技术可行性

    3.5.2 经济可行性

    3.5.3 管理可行性

    3.5.4 法律可行性

    4. 系统设计

    4.1 概要设计

    4.1.1 主控端规划

    4.1.2 学生端规划

    4.2 功能模块结构的设计

    4.3 系统操作流程图

    4.4 系统数据库设计

    4.4.1 数据表设计

    4.4.2 视图设计

    4.4.3 触发器设计

    5. 系统实现

    5.1 HOOK 消息钩子设计

    5.1.1 概述

    5.1.2 程序相关代码分析

    5.2 学生端全屏透明登陆窗体设计

    5.2.1 概述

    5.2.2 程序相关代码分析

    5.3 系统托盘设计

    5.3.1 概述

    5.3.2 程序相关代码分析

    5.4 学生端监听服务端后台线程设计

    5.4.1 概述

    5.4.2 程序相关代码分析

    5.5 系统还原失效检测

    5.5.1 概述

    5.5.2 程序相关代码分析

    5.6 多线程主控端设计

    5.6.1 概述

    5.6.2 程序相关代码分析

    5.7 Excel表格导入和导出的实现

    5.7.1 概述

    5.7.2 程序相关代码分析

    5.8 单程序实例的实现

    5.8.1 概述

    5.7.2 程序相关代码分析

    5.9 主机列表的实现.

    5.9.1 概述

    5.9.2 主要代码分析

    5.10 远程桌面的实现

    5.10.1 概述

    5.10.2 主要代码分析.

    5.11  配置信息注册表存储的实现

    5.11.1 概述

    5.11.2 相关代码分析

    5.12 状态栏下实现进度条

    6. 系统测试与性能分析

    7. 总结

    参考文献

    致谢


    此处省略几千字


     

    概要设计

    实验室机房管理系统是一个典型的C/S模式应用程序,包括学生端和主控端两部分。

    主控端规划

    主控端负责学生端上机登陆的验证、学生端的远程控制等,具体的功能模块如下:

    (1) 系统设置模块

    1) 通讯设置:主控端与被控端的通讯端口设置。

    2) 密码修改:修改主控端解锁密码。

    (2) 账号管理:

    1) 添加账号:需要的字段有:学号、姓名、班级、密码。

    2) 账号修改:对指定的账号进行修改,如学生忘记密码,可以让管理 员修改密码。

    3) 批量导入:可以把包含账号信息Excel表格数据导入到数据库。

    4) 批量删除:可以对查询出来的账号批量删除。

    (3) 日常维护:

    1) 上机日志:记录学生的每次登陆和注销的日志。

    2) 异常日志:记录学生端异常日志,如还原卡失效。

    3) 数据库备份:管理员可以定期对进行数据备份

    (4) 学生端列表:

    1) 列表动态维护:管理学生端连接,并在列表上动态更新。

    2) 消息发送:对选中的学生端发送消息。

    3) 远程桌面:对单个学生端进行远程桌面控制。

    4) 远程关机:对选中的学生端发出关机命令。

    5) 远程重启:对选中的学生端发出关机命令。

    学生端规划

    学生端负责学生机屏幕锁定、执行主控端的命令等,具体的功能模块如下:

    (1) 登陆模块:

    1) 热键屏蔽:系统启动时屏蔽掉相关热键,并锁定屏幕,显示登录框。

    2) 登陆验证:发送学号与密码到服务端,若验证成功,会自动解锁。

    3) 管理员解锁:管理员可以利用解锁密码解除学生端的锁定。

    (2) 与服务端通信模块:

    1) 接收消息:接收服务端发过来的消息并自动在桌面提示。

    2) 接收远程控制:对服务端要求的各种控制进行响应。

    3) 异常监控:把学生端出现的异常发送给服务端。

    4) 修改密码:学生修改登陆密码。

    (3) 学生端设置:需要在管理模式才能使用,设置通讯方式和解锁密码。

     

    功能模块结构设计

     

    系统操作流程图

     

     

    系统数据库设计

    数据表设计(部分)

    对于实验室机房管理系统,主要的功能是来控制学生端的上机,数据库设计比较简单。本系统采用SQL 2000 数据库,系统数据库名称为db_LabMS,数据库db_LabMS中包括3个数据表。下面分别给出数据库概要说明、数据表的结构。

    (1)用户数据表

    用户保存系统用户的账户信息,数据表命名为“student”,结构见表:4-1。

    表:4-1 用户表(student)

    序号

    列名

    数据类型

    长度

    标识

    主键

    允许空

    默认值

    说明

    1

    s_id

    int

    4

     

     

    自动编号ID

    2

    s_xh

    nvarchar

    12

     

     

    学号

    3

    s_name

    nvarchar

    8

     

     

     

    名字

    4

    s_pwd

    nvarchar

    12

     

     

     

    密码

    5

    s_class

    nvarchar

    30

     

     

     

    班级

     

    (2)上机记录数据表

        用于保存学生上机记录数据,数据表命名为“log”,结构见表:4-2。

    表:4-2 上机记录数据表(log)

    序号

    列名

    数据类型

    长度

    标识

    主键

    允许空

    默认值

    说明

    1

    l_id

    int

    4

     

    自动编号ID

    2

    s_xh

    nvarchar

    12

     

     

     

    学号

    3

    l_type

    nvarchar

    8

     

     

     

    类型

    4

    l_time

    datetime

    8

     

     

    (getdate())

    时间

    5

    l_pc

    nvarchar

    20

     

     

     

    Pc名

     

    (3)异常数据表

    用于保存学生机出现异常信息,数据表命名为“exception”,结构见表:4-3。

    表:4-3 异常数据表(exception)

    序号

    列名

    数据类型

    长度

    标识

    主键

    允许空

    默认值

    说明

    1

    e_id

    int

    4

     

    自动编号ID

    2

    e_type

    nvarchar

    50

     

     

     

    异常类型

    3

    e_state

    nvarchar

    8

     

     

    (N'未处理')

    状态

    4

    e_pc

    nvarchar

    20

     

     

     

    Pc名

    5

    e_time

    datetime

    8

     

     

    (getdate())

    异常出现时间

    (4)主机列表数据表

    用于保存当前登陆的学生机列表,数据表命名为“list”,结构见表4-4。

    表:4-4 主机列表数据表(list)

     

    序号

    列名

    数据类型

    长度

    标识

    主键

    允许空

    默认值

    说明

    1

    l_xh

    nvarchar

    12

     

     

     

    学号

    2

    l_mac

    nvarchar

    12

     

     

     

    MAC地址

    3

    l_pc

    nvarchar

    20

     

     

     

    PC名

    4

    l_time

    datetime

    8

     

     

    (getdate())

    登陆时间

     视图设计(部分)

    从用户角度来看,一个视图是从一个特定的角度来查看数据库中的数据。从数据库系统内部来看,视图是由一张或多张表中的数据组成的,从数据库系统外部来看,视图就如同一张表一样,对表能够进行的一般操作都可以应用于视图,例如查询,插入,修改,删除操作等。[3]

    系统的logview视图创建语句如下:

    CREATE VIEW dbo.logview
    
    AS
    
    SELECT dbo.[log].l_time, dbo.[log].s_xh, dbo.student.s_name, dbo.[log].l_type,
    
          dbo.[log].l_pc, dbo.student.s_class
    
    FROM dbo.[log] INNER JOIN
    
          dbo.student ON dbo.[log].s_xh = dbo.student.s_xh

     触发器设计(部分)

    触发器(trigger)是个特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。[4]当对log表进进行插入操作,会触发更新list表,list表保存这当前主机列表。

    触发器trig_updatelist创建语句如下:

    CREATE TRIGGER trig_updatelist ON dbo.[log]
    
    FOR insert
    
    AS
    
    if exists(select l_mac from inserted where l_mac not in (select l_mac from [list]))
    
    begin
    
    insert into [list](l_pc,l_mac,l_xh) select l_pc,l_mac,s_xh from inserted
    
    end
    
    else
    
    begin
    
    delete [list] where l_mac=(select l_mac from inserted)
    
    end
    
    

     

    系统实现(部分)

    HOOK 消息钩子设计

    概述

    学生端开机是要进行锁屏,屏蔽系统热键,保护锁屏程序不被关闭。屏蔽系统热键需要利用到HOOK技术,钩子(Hook)是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。[5]当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理Window消息或特定事件。通过HOOK技术可以屏蔽掉一些热键如ALT+F4、 ALT+ESC等,可以有效保护锁屏程序。

    程序相关代码分析

    一般来讲,系统级钩子必须是一个DLL。下面提供的一个键盘钩子DLL的代码片断(TaskKeyHook.dll):

    //头文件
    
    
    
    //TaskKeyHook.h
    
    //
    
    #define DLLIMPORT __declspec(dllimport)
    
    
    
    DLLIMPORT BOOL DisableTaskKeys(BOOL bEnable, BOOL bBeep);
    
    DLLIMPORT BOOL AreTaskKeysDisabled();
    
    
    
    //实现文件
    
    
    
    // TaskKeyHook.cpp
    
    //
    
    #define _WIN32_WINNT 0x0500 // for KBDLLHOOKSTRUCT
    
    #include <afxwin.h>         // MFC core and standard components
    
    
    
    #define DLLEXPORT __declspec(dllexport)
    
    
    
    //
    
    // App (DLL) object
    
    //
    
    class CTaskKeyHookDll : public CWinApp {
    
    public:
    
         CTaskKeyHookDll()  { }
    
         ~CTaskKeyHookDll() { }
    
    } MyDll;
    
    
    
    
    
    // 下面的代码表示这一部分在此DLL所有实例之间共享
    
    // 低级键盘钩子一定是系统级的钩子
    
    //
    
    #pragma data_seg (".mydata")
    
    HHOOK g_hHookKbdLL = NULL; // 钩子句柄
    
    BOOL  g_bBeep = FALSE;     // 按下非法键时蜂鸣响铃
    
    #pragma data_seg ()
    
    #pragma comment(linker, "/SECTION:.mydata,RWS") // 告诉链接器:建立数据共享段
    
    
    
    //
    
    // 低级键盘钩子
    
    // 截获任务转换键:不传递直接返回
    
    //
    
    LRESULT CALLBACK MyTaskKeyHookLL(int nCode, WPARAM wp, LPARAM lp)
    
    {
    
         KBDLLHOOKSTRUCT *pkh = (KBDLLHOOKSTRUCT *) lp;
    
    
    
         if (nCode==HC_ACTION) {
    
             BOOL bCtrlKeyDown =
    
                  GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT) * 8) - 1);
    
    
    
             if ((pkh->vkCode==VK_ESCAPE && bCtrlKeyDown) || // Ctrl+Esc
    
                  // Alt+TAB
    
                  (pkh->vkCode==VK_TAB && pkh->flags & LLKHF_ALTDOWN) ||  
    
                  // Alt+Esc
    
                  (pkh->vkCode==VK_ESCAPE && pkh->flags & LLKHF_ALTDOWN)||
    
                  (pkh->vkCode==VK_LWIN || pkh->vkCode==VK_RWIN)) { // 开始菜单
    
                       if (g_bBeep && (wp==WM_SYSKEYDOWN||wp==WM_KEYDOWN))
    
                           MessageBeep(0); // 蜂鸣
    
                       return 1; // 不再往CallNextHookEx传递,直接返回
    
             }
    
         }
    
         return CallNextHookEx(g_hHookKbdLL, nCode, wp, lp);
    
    }
    
    
    
    
    
    // 是否屏蔽任务键序列——也就是说键盘钩子是否安装?
    
    // 注:这里假设没有其它钩子做同样的事情
    
    //
    
    DLLEXPORT BOOL AreTaskKeysDisabled()
    
    {
    
         return g_hHookKbdLL != NULL;
    
    }
    
    
    
    
    
    // 屏蔽任务键:安装低级键盘构
    
    // 返回当前是否屏蔽标志(TRUE/FALSE)
    
    //
    
    DLLEXPORT BOOL DisableTaskKeys(BOOL bDisable, BOOL bBeep)
    
    {
    
         if (bDisable) {
    
             if (!g_hHookKbdLL) {
    
                  g_hHookKbdLL = SetWindowsHookEx(WH_KEYBOARD_LL,
    
                       MyTaskKeyHookLL, MyDll.m_hInstance, 0);
    
             }
    
    
    
         } else if (g_hHookKbdLL != NULL) {
    
             UnhookWindowsHookEx(g_hHookKbdLL);
    
             g_hHookKbdLL = NULL;
    
         }
    
         g_bBeep = bBeep;
    
    
    
         return AreTaskKeysDisabled();
    
    }  

    TaskKeyHook 输出两个函数:DisableTaskKeys 和 AreTaskKeysDisabled。前者安装WH_KEYBOARD_LL 钩子;后者判断这个钩子是否安装。此键盘钩子的处理思路是截获Alt+Tab,Ctrl+Esc,Alt+Esc以及Windows 键等热键。

    学生端全屏透明登陆窗体设计

    概述

    学生端一启动就会自动对学生机进行全屏锁定。学生端锁屏登陆界面图:5-1所示。其实现原理是通过两个对话框实现,父对话框实现全屏透明窗体,然后弹出子对话框(登陆框),登陆框隐藏了边框,并且用笔刷填充了背景。

     

    图:5-1 实验室机房管理系统主窗体

     

    程序相关代码分析

    全屏透明登陆窗体主要代码片段:

    // ClientDlg.cpp : implementation file
    
    
    
    void CClientDlg::OnFullScreen()
    
    {
    
    
    
         LONG style = GetWindowLong(m_hWnd, GWL_STYLE);    //得到窗口风格
    
         ::ShowWindow(m_hWnd, SW_MAXIMIZE);
    
         style = GetWindowLong(m_hWnd, GWL_STYLE);
    
         style &= ~(WS_DLGFRAME | WS_THICKFRAME);
    
         SetWindowLong(m_hWnd, GWL_STYLE, style);          //设置窗口风格
    
         int cx = GetSystemMetrics(SM_CXSCREEN);
    
         int cy = GetSystemMetrics(SM_CYSCREEN);
    
         ::SetWindowPos(m_hWnd, HWND_TOPMOST, -1, -1, cx+3, cy+3, SWP_FRAMECHANGED);//实现全屏显示
    
    
    
         ::InvalidateRect(m_hWnd,NULL,TRUE);               //窗口背景要被擦除
    
    
    
         SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
    
             GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);    //窗口加入WS_EX_LAYERED扩展属性
    
         HINSTANCE hInst = LoadLibrary("User32.DLL");
    
         if (hInst)
    
         {
    
             typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
    
             MYFUNC fun = NULL;
    
             fun = (MYFUNC)GetProcAddress(hInst,"SetLayeredWindowAttributes");    //取得SetLayeredWindowAttributes函数指针
    
             if (fun)
    
                  fun(this->GetSafeHwnd(),0,125,2);    //设置窗口为半透明
    
             FreeLibrary(hInst);
    
         }
    
    
    
         CTaskKeyMgr::Disable(CTaskKeyMgr::ALL, TRUE); //利用Hook工具类实现热键屏蔽
    
    
    
         CLoginDlg dlg=new CLoginDlg();
    
         dlg.DoModal();                   //弹出模式对话框等待用户输出
    
    
    
         CTaskKeyMgr::Disable(CTaskKeyMgr::ALL, FALSE); //恢复所有禁止的东西
    
    }

    登陆框主要代码片段:

    // LoginDlg.cpp : implementation file
    //
    //填充背景
    void CLoginDlg::OnPaint() 
    {
    	CPaintDC dc(this); // device context for painting
    	CRect   rect;   
    	GetClientRect(&rect);   
    	CDC   dcMem;   
    	dcMem.CreateCompatibleDC(&dc);   
    	CBitmap   bmpBackground;   
    	bmpBackground.LoadBitmap(IDB_BITMAP1);  
    	BITMAP   bitmap;   
    	bmpBackground.GetBitmap(&bitmap);   
    	CBitmap   *pbmpOld=dcMem.SelectObject(&bmpBackground);   
    	dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,   
    		bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  
    }
    void CLoginDlg::OnLogin() 
    {
    	// TODO: Add your control notification handler code here
    	UpdateData(true);
    
    	if ((m_uid == "")||(m_pwd == ""))         //如果用户名为空
    	{		
    		MessageBoxA("用户名或密码不能为空");
    		GetDlgItem(IDC_UID)->SetFocus();
    		return;
    	}
    	else
    	{
    		if (m_uid.Find(" ")!=-1)
    		{
    			MessageBoxA("用户名不能包含空格");
    			GetDlgItem(IDC_UID)->SetFocus();
    			return;
    		}else
    			if (m_pwd.Find(" ")!=-1)
    			{
    				MessageBoxA("密码不能包含空格");
    				GetDlgItem(IDC_PWD)->SetFocus();
    				return;
    			}
    
    	}
    	//发送用户名和密码到服务端验证
    	if (CScoketMgr::SendLogin(m_uid,m_pwd))
    	{
    		CDialog::OnCancel();
    	}
    
    }
    
    BOOL CLoginDlg::PreTranslateMessage(MSG* pMsg) 
    {
    	// 屏蔽掉RETURN、PAUSE、ESCAPE键,防止登陆框被关闭
    	if   (pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_RETURN) 
    	{       
    		return TRUE;   
    	}
    	if   (pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_PAUSE) 
    	{       
    		return TRUE;   
    	}
    	if (pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_ESCAPE)
    	{
    		return TRUE;
    	}
    
    	return CDialog::PreTranslateMessage(pMsg);
    }
    void CLoginDlg::OnClose() 
    {
    	// 防止登陆框被关闭
    
    	return;
    
    }
    
    void CLoginDlg::OnUnlock() 
    {
    	// 解锁
    	UpdateData(true);
    	CMD5 md5T;
    	if (md5T.MD5(m_pwd)==theApp.unlockpwd)       //验证解锁密码
    		OnCancel();
    }
    

    此处省略几千字


     

    资源下载

    完整源程序+数据库+论文+使用说明下载:https://download.csdn.net/download/frank2102/19414729

     

     

    展开全文
  • VC++课程设计常见问题解答

    千次阅读 2017-12-11 15:12:43
    作者做完了自己的课程设计,其中遇到了不少问题,估计其他同学也会遇到,所以在此写一篇博客,希望有问题的同学能到此处速查,方便大家,这样就不需要去百度了,百度上很多人说的不清楚,而且各种答案,根本不知道...

    新博客地址wmathor

    1. 前言

      作者做完了自己的课程设计,其中遇到了不少问题,估计其他同学也会遇到,所以在此写一篇博客,希望有问题的同学能到此处速查,方便大家,这样就不需要去百度了,百度上很多人说的不清楚,而且各种答案,根本不知道哪个是对的

    2. 问题详解

      方便读者查询,我在下面放上我所讲内容的小标题,

    • 新建对话框
    • 多个对话框的调用问题
    • 美化界面——给对话框添加背景图
    • 美化界面——自定义按钮样式
    • VC++中常见问题的解决方法

    新建对话框

      课程设计当中不论是信息管理系统还是计算器,都需要大家做一个登录界面,那么做完登录界面之后,如何跳转到下一个对话框呢?下面我附上操作步骤

      首先新建一个对话框,右键单击“Dialog”—>“插入Dialog”
    这里写图片描述

      这时,新的对话框就建好了,你也可以修改他的名字,这里我就不改了
    这里写图片描述

      然后我们给新的对话框建立一个类向导,右键单击对话框的任意位置—>“建立类向导”
    这里写图片描述

      按照图上步骤选择,有可能你默认不是"create a new class",那就要选这一项,然后选"OK"
    这里写图片描述

      要给新建的类起个名字,这里注意不能重复取之前已有的类的名字,这里我取名“test2”,然后点"OK",接下来点右下角出现的“确定”即可
    这里写图片描述

      成功之后,在类视图里能看到多了一个你刚才取名字的类,到此为止,新的对话框就建立完成
    这里写图片描述



    **多个对话框调用问题**   这里所讲的是如果想在一个对话框上点击一个按钮跳转到另一对话框应该如何实现,我同时也会讲一下如何在运行时首先运行你所想要的对话框

      我首先在第一个对话框上设置一个按钮
    这里写图片描述

      现在我在第一个对话框中添加一个按钮,它的功能是跳转到第二个对话框
    这里写图片描述

      给按钮添加函数
    这里写图片描述

      但是在这里还没完,微软给我们提供的mfc肯定有自带的函数,能够实现打开对话框,但是要想打开对话框,肯定需要用类创建一个对象,然后用对象点的方式调用函数(方法),但是两个对话框属于不同的类,如何能够在一个对话框里使用另一个对话框的类呢?只要在这个对话框类里加上另一个需要被打开对话框的头文件就行了
    这里写图片描述

      然后就可以使用另一个对话框的类来创建对象了,这里用到的函数是DoModal()
    这里写图片描述

      这里在补充一点,因为可能在特定情况下我们需要打开第二个对话框,同时关闭第一个对话框,如何实现呢?只要在中间加上一句**CDialog::OnOK();**即可
    这里写图片描述

      问题总是接踵而至,如果按照我的方法做到了这里,细心的读者一定会发现,当点击按钮跳转到第二个对话框的时候,第一个对话框确实关闭了,第二个对话框确实打开了,但是,最严重的问题来了,**任务栏的图标也不见了!**按钮点击后,任务栏的图标随着第一个对话框的关闭也消失了,这可不是我们想要的,不要急,下面我就说说解决办法,很简单

      因为是第二个对话框的任务栏图标没了,所以我们操作的类肯定是第二个对话框,这个读者要搞清楚,首先给对话框新建一个函数
      这里读者要注意因为我这个对话框里没有任何控件,所以还好,但是如果读者做的对话框里有控件,记得一定要选跟Class name相同的Object IDs,选别的都找不到这个函数,切记!切记!切记!然后选择WM_InitDialog这个函数
    这里写图片描述

      在函数里加上一句话就ok
    ModifyStyleEx(WS_EX_TOOLWINDOW, WS_EX_APPWINDOW);
      这里读者没必要搞懂这是什么意思,作者自己也不懂,但是这并不是课程设计中最重要的地方,读者只需要做到不求甚解就好
    这里写图片描述

      现在任务栏图标就出来了
    这里写图片描述

      至此,最基本的创建对话框以及多个对话框的调用问题已经解决了,掌握这些已经可以完成课程设计了,下面我会在讲一些如何对界面进行优化,包括给对话框添加背景图,还有使用设计者自己设计的图替换按钮,有兴趣的读者可以看下去


    美化界面——给对话框添加背景图
      先放上效果图
    这里写图片描述

      其实并不难,这里我一步一步说,首先一开始上来并不是写代码,也不是准备资源图,而是去下载我们需要的库,GDI+库如果没有这个库,就无法使用各种与图像有关的功能,下载地址我会放在这篇文章的最末尾,下载GDI+库之后还不够,要使用库,肯定要导入,下面我就先讲讲如何导入库

      首先选择"Tools"—>“选项”
    这里写图片描述

      然后选择"目录"—>“include files”,接着按照图上的步骤做,找到下载好的GDI+库的路径里的"INCLUDE"文件夹包含进来
    这里写图片描述

      接下来的操作就和上面差不多,“目录”—>“Libray files”,找到下载好的GDI+库的路径里的"LIB"文件夹包含进来,目前准备工作已经做了一半了
    这里写图片描述

      库包含进来了,下面要做的就是找到你需要的资源图,把他转换成bmp格式,然后导入到资源中去就行了,vc6.0对bmp图是有严格要求的,这里我说一个bmp图片转换的简单方法,只需要win10自带的画图工具即可

      把jpg或png格式的图,拖到"画图工具"中打开,如果需要调整大小,可以直接在里面调整,之后点击"文件"—>“另存为”—>“bmp图片”,就转换成功了,亲测有效,比网上很多在线转换工具方便多了
    这里写图片描述

      这里有点要注意,转换的时候默认是24色位图,要改成256色位图,不要问我为什么,自己试试就知道了,除了256以外,其他的vc6.0无法使用
    这里写图片描述

      图有了,现在打开vc6.0的资源视图,把刚才转好格式的资源图引入进来
    这里写图片描述
    这里写图片描述

      接下来开始写代码,先附上代码,再附图

    	CPaintDC dc(this);
    		CRect rc;
            GetClientRect(&rc);
            CDC dcMem;
            dcMem.CreateCompatibleDC(&dc);
            CBitmap bmpBackground;
            bmpBackground.LoadBitmap(IDB_BITMAP1);//这是资源图的编号,如果想换成别的背景图,把资源图导入之后,改编号就行
    
            BITMAP bitmap;
            bmpBackground.GetBitmap(&bitmap);
            CBitmap* pbmpPri = dcMem.SelectObject(&bmpBackground);
            dc.StretchBlt(0,0,rc.Width(), rc.Height(), &dcMem,0,0,bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
    

      在OnPaint函数里,不论else里面有什么,把上面那段代码复制进去,替换掉else里面的所有东西即可
    这里写图片描述

      这里我啰嗦一句,主对话框才有Paint函数,新建的一开始都是没有的,所以得去自己添加,下面附图,还是一样,记得选择和Class name一样的IDs
    这里写图片描述

      现在看一下变成了什么样子,读者肯定发现了,静态文本的背景色没有去掉,在这里很丑,下面我告诉大家如何将静态文本背景变成透明
    这里写图片描述

      首先给对话框类添加一个函数CTLCOLOR
    这里写图片描述

      然后在函数中写上这段代码

    if(pWnd->GetDlgCtrlID( ) == (IDC_1))//IDC_1是控件对应的ID,切记,不能使用默认的ID,也就是IDC_STATIC,必须改一下
    	{
    		pDC->SetBkMode(TRANSPARENT);
    		pDC->SetTextColor(RGB(50,50,50));
    		return HBRUSH(GetStockObject(HOLLOW_BRUSH));
    	}
    

      这里if的作用是控制到底修改哪一个控件的样式,如果不加if,直接写if里面的内容,会将对话框内的所有的控件全部变为这种样式,如果需要将多个控件修改样式,只需要多加几个if,在if里面写上修改样式的代码即可
    这里写图片描述

      至此,整个界面皮肤美化工作就结束了


    **美化界面——自定义按钮样式**   用自己的图片修改替换默认的按钮样式,操作并不难,先看一下效果图,在这里我将按钮换成了我找的一张“手”的素材图 ![这里写图片描述](https://img-blog.csdn.net/20171221160420142?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzcyMzY3NDU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/0/gravity/SouthEast)

      首先需要修改按钮的属性样式,鼠标右键按钮—>“属性”—>“样式”—>“所有者绘制”
    这里写图片描述

      然后再类中定义一个公有的成员变量,不需要初始化

    CBitmapButton m_btnX1;
    

    这里写图片描述

      然后在**OnInitDialog()函数中加上三行代码,代码里的参数我也有注释解释了,读者看懂以后非常容易运用,然后编译运行即可成功修改按钮的样式,这里还是一样,如果不是主对话框,没有OnInitDialog()**这个函数,读者按照上面的方法添加函数即可,这里实在没必要多讲

    	m_btnX1.LoadBitmaps(IDB_BITMAP2);//这里可以添加两幅位图,用逗号隔开,分别表示鼠标按下和弹起的图片
    	m_btnX1.SubclassDlgItem(IDC_BUTTON1,this);//这里的第一个参数是你想替换掉的按钮的ID
    	m_btnX1.SizeToContent();
    

    这里写图片描述

      至此,按钮美化工作就结束了


      **VC++中一些常见问题的解决方法**   (1)为什么某个类突然在工作区间里面突然看不见了?

      只是类隐藏了,打开FILEVIEW,找到隐藏类的头文件,随便敲一下键盘的空格键,类就会在CLASSVIEW中显示了

      (2)在基于对话框的程序中,一按回车键,对话框就没了

      在对话框中建立类向导,选择和类名一样的IDs,在右边选择一个叫PreTranslateMessage的函数
      添加函数之后编辑代码,在里面加上下面的代码,之后无论是摁回车还是ESC键,都不会关闭对话框了

    if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_RETURN)    
            return TRUE; 
    if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_ESCAPE)    
            return TRUE; 
    

    这里写图片描述

      (3)怎样改变VC++编辑器默认的颜色?
      工具—>选项—>格式,选中注释的颜色即可改变



    3.总结

      到此为止,我在做课程设计当中遇到的所有问题全部解决了,我把我的课程设计作品——手机销售管理系统放到了csdn上,有需要的同学可以下载参考,不过需要积分,如果没有积分,可以加我qq私聊我直接发给你,QQ:739616037

    我的课程设计(有源码):http://download.csdn.net/download/qq_37236745/10162962
    GDI+库:https://pan.baidu.com/s/1dFfJfH3 密码:njze

    展开全文
  • static PMSG pmsg ; static RECT rectScroll ; static TCHAR szTop[] = TEXT ("Message Key Char ") TEXT ("Repeat Scan Ext ALT Prev Tran") ; static TCHAR szUnd[] = TEXT ("_______ ___ ____ ") TEXT ("__...
  • 初学者对单片机的按键设计,往往是只作简单的I/O检测或A/D检测,并未考虑到防抖及其它问题,同时也带来可移植性差的问题。 一般按键设计为模块化,并具有按键码与功能码之分,除防抖设计外,同时需要考虑功能码输出...


    前言

      本人从事单片机软件设计工作多年,既从事过裸机系统的设计,也在小型嵌入式实时操作系统下进行过设计。因在工作当中发现好多人对单片机软件的设计非常随意,尤其是在驱动方面,其考虑问题过于单一,并且应用层与底层驱动之间耦合度较大。基于此,本人整理工作当中做过常用的最基本设计分享到这里,希望对需要的人有所帮助或参考。当然,可能我的设计方法并不是很好,所以也算是一种学习交流。
      在整理的过程中,可能会缺乏统一规划,仅先整理一部分常用的驱动设计。至于其它部分的内容,待今后跟进需要再逐一补充。

    《驱动设计–按键驱动》

      好多人对单片机的按键设计,往往是只作简单的I/O检测或A/D检测,并未考虑到防抖及其它问题,同时也带来可移植性差的问题。一般应该将按键驱动进行分层设计,并具有扫描码与功能码之分,除防抖设计外,同时需要考虑功能码输出时具有按键状态(包括按键按下、长按及长按时间、按键释放等)。甚至,必要的按键处理也应该一并考虑,只是这部分具体应该如何处理,则需要留给上层决定。

    一、按键扫描方式

      按键一般有2种扫描方式,I/O电平检测与AD电压检测,按键的扫描函数应该由具体的应用去处理(根据具体的硬件电路进行设计)。

    1.I/O电平检测

      I/O电平检测又分为2种。
      1)一个按键的一端连接到一个普通I/O口上,另外一端接地。这种方式仅适用于按键较少的情况;
      2)一个按键的一端连接到一个行扫描I/O上,另外一端连接到列扫描I/O口上,这样I/O口将分为行扫描组与列扫描组。这种方式适用于按键较多的情况;

    2.AD电压检测

      这种方式实际上是将一个电压通过多个电阻进行均等分压,每个分压点接入一个按钮的一端,按钮的另一端接地。这种方式在一个AD口不适合连接太多的按钮,因为其受分压间距的影响,如果间距太小,则会出现检测误差或错误,甚至这种方式本身就依赖于电压的稳定性;

    二、按键驱动数据结构

      按键驱动数据结构设计,包括扫描码、功能码,驱动数据结构设计,以下分别描述各个部分内容;

    1.扫描码

      扫描码的设计至少可以使用两种方式。一种是设计为1个bit对应1个按键,这样一个字节可以对应独立的8个按键,同时还可以表示众多的组合按键;另一种是设计为枚举类型,每一个按键或组合按键对应一个枚举值;扫描码的生成由扫描函数完成;
      这里以第一种方式设计扫描码,如有5个按键:上(bit0)、下(bit1)、左(bit2)、右(bit3)、确定(bit4)。具体定义如下(实际可设计为1–4个字节<这里以两个字节举例>);
      扫描码应该由具体的应用去设计。

    #define	BitShift(key)		(0x0001<<(key))		//bit表示方法扫描码生成宏定义
    #define	KEY_SERIAL_UP		0
    #define	KEY_SERIAL_DN		1
    #define	KEY_SERIAL_LF		2
    #define	KEY_SERIAL_RT		3
    #define	KEY_SERIAL_EN		4
    //
    #define	KEY_SCAN_NO			0x00//扫描码-无按键
    #define	KEY_SCAN_UP   		BitShift(KEY_SERIAL_UP)//扫描码-按键上
    #define	KEY_SCAN_DN			BitShift(KEY_SERIAL_DN)//扫描码-按键下
    #define	KEY_SCAN_UPDN  		(BitShift(KEY_SERIAL_UP)|BitShift(KEY_SERIAL_DN))//扫描码-按键上+按键下(组合键)
    #define	KEY_SCAN_LF			BitShift(KEY_SERIAL_LF)//扫描码-按键左
    #define	KEY_SCAN_RT			BitShift(KEY_SERIAL_RT)//扫描码-按键右
    #define	KEY_SCAN_EN			BitShift(KEY_SERIAL_EN)//扫描码-按键确认
    #define	KEY_SCAN_MAX		KEY_SCAN_EN
    //注:以上还可以定义更多组合按键扫描码,此处不再列出
    

    2.功能码

      功能码可以表示4种状态,按键按下、短按键释放、按键长按、长按键释放,之所以设计多种状态的功能码,是考虑到软件可能会使用不同的按键状态来做处理。以上4种状态的功能码将以基本功能码为基础,使用宏定义生成。基本功能码完全可以使用自然数来定义,如有5个按键如上描述,使用4个字节表示功能码。
      功能码应该由具体的应用去设计。

    1)定义基本功能码分别为

    #define	KEY_NO				0x00
    #define	KEY_UP				0x01//基本功能码-上按键按下
    #define	KEY_DN				0x02//基本功能码-下按键按下
    #define	KEY_LF				0x03//基本功能码-左按键按下
    #define	KEY_RT				0x04//基本功能码-右按键按下
    #define	KEY_EN				0x05//基本功能码-确认键按下
    #define	KEY_UPDN			0x06//基本功能码-上按键+下按键同时按下(组合键)
    #define	KEY_MAX				KEY_UPDN
    

    2)功能码的宏定义

      使用功能码的高8位来表示状态,低16位为基本功能码。

    #define	SHORT_PRESS 		0x00
    #define	SHORT_BREAK 		0x01
    #define	LONG_PRESS	    	0x02
    #define	LONG_BREAK 	    	0x03
    #define	SHPKEY(key)			((key)+(SHORT_PRESS<<24))//按键按下
    #define	SHBKEY(key)			((key)+(SHORT_BREAK<<24))//短按键释放
    #define LGKEY(key)			((key)+(LONG_PRESS<<24))//按键长按
    #define LGBKEY(key)			((key)+(LONG_BREAK<<24))//长按键释放
    

    3)功能码定义

      功能码的定义在一个应用中应该是可以统一的。

    #define	KEY_NO_KEY			0x00//无功能码
    //按键按下
    #define	KEY_UP_PRESS		SHPKEY(KEY_UP)
    #define	KEY_DN_PRESS		SHPKEY(KEY_DN)
    #define	KEY_LF_PRESS		SHPKEY(KEY_LF)
    #define	KEY_RT_PRESS		SHPKEY(KEY_RT)
    #define	KEY_EN_PRESS		SHPKEY(KEY_EN)
    #define	KEY_UPDN_PRESS  	SHPKEY(KEY_UPDN)
    //短按键释放
    #define	KEY_UP_BREAK		SHBKEY(KEY_UP)
    #define	KEY_DN_BREAK		SHBKEY(KEY_DN)
    #define	KEY_LF_BREAK		SHBKEY(KEY_LF)
    #define	KEY_RT_BREAK		SHBKEY(KEY_RT)
    #define	KEY_EN_BREAK		SHBKEY(KEY_EN)
    #define	KEY_UPDN_BREAK  	SHBKEY(KEY_UPDN)
    //按键长按
    #define	KEY_UP_LONG			LGKEY(KEY_UP)
    #define	KEY_DN_LONG			LGKEY(KEY_DN)
    #define	KEY_LF_LONG			LGKEY(KEY_LF)
    #define	KEY_RT_LONG			LGKEY(KEY_RT)
    #define	KEY_EN_LONG			LGKEY(KEY_EN)
    #define	KEY_UPDN_LONG  		LGKEY(KEY_UPDN)
    //长按键释放
    #define	KEY_UP_LONG_BREAK	LGBKEY(KEY_UP)
    #define	KEY_DN_LONG_BREAK	LGBKEY(KEY_DN)
    #define	KEY_LF_LONG_BREAK	LGBKEY(KEY_LF)
    #define	KEY_RT_LONG_BREAK	LGBKEY(KEY_RT)
    #define	KEY_EN_LONG_BREAK	LGBKEY(KEY_EN)
    #define	KEY_UPDN_LONG_BREAK	LGBKEY(KEY_UPDN)
    //注:以上还可以定义更多组合按键功能码,此处不再列出
    

    4)扫描码与基本功能码默认映射

    const uint32_t FunCode[KEY_SCAN_MAX+1]=
    {
    	KEY_NO_KEY,KEY_UP,KEY_DN,//0x00,0x01,0x02,
    	KEY_NO_KEY,KEY_LF,//0x03,0x04,
    	KEY_NO_KEY,KEY_NO_KEY,KEY_NO_KEY,KEY_RT,//0x05,0x06,0x07,0x08,
    	KEY_NO_KEY,KEY_NO_KEY,KEY_NO_KEY,KEY_NO_KEY,//0x09,0x0a,0x0b,0x0c,
    	KEY_NO_KEY,KEY_NO_KEY,KEY_NO_KEY,KEY_EN,//0x0d,0x0e,0x0f,0x10,
    };
    //定义默认的扫描码映射函数
    uint32_t KeyMapDef(uint16_t scanCode)
    {
    	return	FunCode[scanCode];
    }
    

    3.按键驱动数据结构

    1)按键值

      按键值包括扫描码与功能码,其定义如下:

    typedef struct
    {
    	uint16_t	 	scan;	//扫描码
    	uint32_t 		func;	//功能码
    }tKeyValue;//按键值
    

    2)按键消息

      按键消息包括按键长按时间与按键值,其定义如下:

    typedef struct
    {
    	uint16_t		time;	//长按键按下时间
    	tKeyValue		value;
    }tKeyMsg;//按键信息
    

    3)扫描状态

      按键扫描分有几个状态:按键按下、抖动检测、确认按下、长按键、等待释放、按键释放;
    按键按下:在按键释放状态,检测到有任意按键按下时进入此状态;
    抖动处理:在按键按下或释放时检测到相反状况,进入此状态进行抖动处理;
    确认按下:按键按下并持续一定时间后,则进入此状态,产生基本功能码;
    长按键:确认按键已经按下,并在一定时间之后,检测到按键仍然按下,则进入此状态,并产生长按功能码;
    等待释放:在检测到按键弹起并执行抖动处理成功后,进入此状态,并在结束此状态时产生短按键释放或长按键释放功能码;
    按键释放:按键按下时抖动处理失败,或等待释放成功,设置到此状态,并可重新开始检测新的按键按下检测;
      各个扫描状态的定义如下

    #define	SKEY_STATE_RELEASE			0		//按键释放
    #define	SKEY_STATE_PUSH				1		//按键按下
    #define	SKEY_STATE_PRESS			2		//确认按下
    #define	SKEY_STATE_PRESS_LONG		3		//长按键
    #define	SKEY_STATE_JITTER			0x40	//抖动处理
    #define	SKEY_STATE_WAITRELEASE		0x80	//等待释放
    #define	SKEY_STATE_MASK				0x0f	//互斥的状态屏蔽字
    

    4)按键扫描

      按键扫描含多个要素,扫描状态、按键按下计时器、按下抖动计时器、释放抖动计时器、当前扫描码、上次扫描码、扫描参数等。其定义如下:

    //设计扫描参数的意义在于,可以使得各个独立的按键驱动有不同的参数数据
    typedef struct
    {
    	uint16_t	scanUnit;				//按键扫描时间单位
    	uint16_t	jitterPressCntMax;		//按键按下抖动时间
    	uint16_t	jitterReleaseCntMax;	//按键弹起抖动时间
    	uint16_t	keepCntEnsure;			//按键按下首次持续时间
    	uint16_t	keepCntLongStart;		//按键按下首次判断长按时间
    	uint16_t	keepCntLongKeep;		//按键按下持续长按时间间隔
    }tScanParam;//扫描参数
    
    typedef struct 
    {
    	uint8_t			state;				//扫描状态	
    	uint8_t 		pressCnt;			//扫描到同时按键个数
    	uint8_t 		keepCnt;			//按键按下计时器,向下计数,单位为扫描时间,如10ms
    	uint8_t			jitterPressCnt;		//按下抖动计时器,向上计数
    	uint8_t 		jitterReleaseCnt;	//释放抖动计时器,向上计数
    	uint16_t 		curKey;				//当前扫描码
    	uint16_t 		prevKey;			//上次扫描码
    }tScan;//按键扫描
    

    5)按键驱动数据结构

      按键驱动包括所有参数、状态、安装的驱动处理函数等,其定义如下:

      以下驱动函数由初始化时外部提供,用以安装

    typedef uint8_t(tKeyScanFunc)(uint32_t*);
    /*
    按键扫描函数原型:uint8_t(tKeyScanFunc)(uint32_t*);
    输入:按键扫描码结果存储数据指针;
    输出:扫描按键按下个数;
    */
    
    typedef void(tKeyExportFunc)(tKeyMsg*);
    /*
    按键输出函数原型:void(tKeyExportFunc)(tKeyMsg*);
    输入:按键信息指针;
    输出:无;
    说明:用户应用层需要获取按键时,在安装驱动时需要传递输出函数,且此功能函数在运行于操作系统的情况更合适,只需要设计一个发送队列或邮箱的函数将按键推送到应用层即可;当然,裸机运行情况下也可以设计一个函数完成推送功能;
    */
    
    typedef void(tKeyParseFunc)(tKeyMsg*);
    /*
    按键解析函数原型:void(tKeyParseFunc)(tKeyMsg*);
    输入:按键信息指针;
    输出:无;
    说明:用户应用层希望扫描到按键时直接解析,则在安装驱动时需要传递解析函数;此功能函数适用于运行于裸机情况,反之可设置为NULL;另外,如无特殊需求,此函数实际可以不使用,仅exportF也可以完成相应功能;
    */
    
    typedef uint32_t(tKeyMapFunc)(uint16_t);
    /*
    按键扫描码映射函数原型:uint32_t(tKeyMapFunc)(uint16_t);
    输入:按键扫描码;
    输出:基本功能码;
    说明:用户可以指定扫描码与基本功能码的映射函数,也可以不指定,此时驱动将使用默认的方法;
    */
    
    typedef void(tKeyLLInitFunc)(void);
    /*
    按键低级初始化函数原型:void(tKeyLLInitFunc)(void);
    输入:无;
    输出:无;
    说明:用户指定的低级初始化函数,完成底层硬件初始化;这里没有将其设计为要求直接挂载(因为直接挂载会限制应用程序的设计),是为了进一步降低耦合度与增强灵活性。
    */
    
    typedef void(tKeyLLUnInitFunc)(void);
    /*
    按键低级去初始化函数原型:void(tKeyLLUnInitFunc)(void);
    输入:无;
    输出:无;
    说明:用户指定的低级去初始化函数,完成底层硬件去初始化;
    */
    
    typedef struct
    {
    	tKeyScanFunc 	*pScan,			//安装的按键扫描函数
    	tKeyExportFunc 	*pExport,		//安装的按键输出处理函数(可以设置为空)
    	tKeyParseFunc 	*pParse,		//安装的按键解析处理函数(可以设置为空)
    	tKeyMapFunc   	*pMap,			//安装的扫描码映射处理函数(可以设置为空)
    	tKeyLLInitFunc	*pInit,			//安装的底层初始化函数(可以设置为空)
    	tKeyLLUnInitFunc *pUnInit;		//安装的底层去初始化函数(可以设置为空)
    }tKeyDrvFunc;//按键驱动函数
    
    typedef struct
    {
    	bool			valid;			//驱动安装有效性<TRUE,驱动有效>
    	bool			running;		//按键处理正在运行标志<TRUE正在运行>
    	tScanParam		param;			//扫描参数
    	tScan			scan;			//扫描结构
    	tKeyMsg			keyMsg;			//按键消息
    	tKeyDrvFunc		func;			//外部安装的驱动函数
    }tKeyDriver;//按键驱动数据结构
    

    三、按键驱动代码设计

    1.参数及变量定义

    //以下定义默认参数值,时间单位定义为ms
    #define	KEYSCAN_UINT_DEF		10		//按键扫描时间单位
    #define	JITTERPRESSCNTMAX_DEF	30		//按键按下抖动时间
    #define	JITTERRELEASECNTMAX_DEF	30		//按键弹起抖动时间
    #define	KEEPCNT_ENSURE_DEF		30		//按键按下首次持续时间
    #define	KEEPCNT_LONG_START_DEF	1000	//按键按下首次判断长按时间
    #define	KEEPCNT_LONG_KEEP_DEF	100		//按键按下持续长按时间间隔
    //宏定义
    #define	ScanKeyCnt(time)		((time)/pPkeyDrv->param.scanUnit)//扫描按键时间计数值
    #define	FuncLKeyCnt(time)		((time)/pPkeyDrv->param.keepCntLongKeep)//功能码长按键保持时间计数值
    #define	MALLOC_MEM(memSize)		malloc(memSize)//内存申请宏
    #define	FREE_MEM(pMem)			free(pMem)//内存释放宏
    

    2.驱动处理

    //按键驱动轮询函数,包括以下所有被分拆的部分(各个子模块已经被展开)
    void Key_Poll(tKeyDriver *pKeyDrv)
    

    1)按键按下检测

      按键在释放状态,则首先检测按键按下

    if	(pKeyDrv==NULL||pKeyDrv->valid==FALSE)
    return;//驱动安装失败,拒绝执行
    pKeyDrv->running=TRUE;//处理开始运行
    pKeyDrv->scan.pressCnt=pKeyDrv->func.pScan(&pKeyDrv->scan.curKey);//按键扫描
    if	(pKeyDrv->scan.state==SKEY_STATE_RELEASE)//扫描状态为按键释放时,执行按下检测
    {
    	Key_PushProcess(pKeyDrv);// 按键按下模块
    	/*
    	void Key_PushProcess(tKeyDriver *pKeyDrv)// 按键按下模块
    	{
    		if	(pKeyDrv->scan.pressCnt>0)
    		{//有按键按下,进入按键按下确认状态
    			pKeyDrv->scan.prevKey=pKeyDrv->scan.curKey;
    			pKeyDrv->scan.state=SKEY_STATE_PUSH;
    			pKeyDrv->scan.keepCnt=pKeyDrv->param.keepCntEnsure;
    			pKeyDrv->scan.jitterPressCnt=0;
    			pKeyDrv->scan.jitterReleaseCnt=0;
    		}
    	}
    	*/
    }
    

    2)抖动处理

      进入抖动处理的条件(按键按下后):
      A 检测到按键释放;
      B 检测按键值发生变化;

    else if  (pKeyDrv->scan.state&SKEY_STATE_JITTER)//抖动处理状态可以与其它状态同时存在
    {
    	Key_JitterProcess(pKeyDrv);// 抖动处理模块
    	/*
    	void Key_JitterProcess(tKeyDriver *pKeyDrv)// 抖动处理模块
    	{
    		if	(pKeyDrv->scan.pressCnt>0)
    		{//抖动处理时,有按键按下且稳定则直接退出
    			pKeyDrv->scan.jitterReleaseCnt=0;
    			if	(pKeyDrv->scan.curKey==pKeyDrv->scan.prevKey)
    			{
    				//抖动时按键没有变化,维持原按键扫描码
    				pKeyDrv->scan.state-=SKEY_STATE_JITTER;
    			}
    			else
    			{
    				pKeyDrv->scan.jitterPressCnt++;
    				if	(pKeyDrv->scan.jitterPressCnt>=ScanKeyCnt(pKeyDrv->param.jitterPressCntMax))
    				{//抖动处理超时(按键在发生变化),重新设置为按键确认检测
    					pKeyDrv->scan.prevKey=pKeyDrv->scan.curKey;
    					pKeyDrv->scan.state=SKEY_STATE_PUSH;
    					pKeyDrv->scan.keepCnt=pKeyDrv->param.keepCntEnsure;
    					pKeyDrv->scan.jitterPressCnt=0;
    				}
    			}
    		}
    		else
    		{//抖动处理时,无按键按下
    			pKeyDrv->scan.jitterPressCnt=0;
    			pKeyDrv->scan.jitterReleaseCnt++;
    			if	(pKeyDrv->scan.jitterReleaseCnt>=ScanKeyCnt(pKeyDrv->param.jitterReleaseCntMax))
    			{//按键弹起抖动处理时间到
    				pKeyDrv->scan.jitterReleaseCnt=0;
    				if	((pKeyDrv->scan.state&SKEY_STATE_MASK)==SKEY_STATE_PUSH)
    				{
    					//按键按下未被确认时,认为按键无效
    					pKeyDrv->scan.state=SKEY_STATE_RELEASE;
    				}
    				else
    				{
    					//按键被确认,进一步确定是短按键还是长按键释放(同时增加一倍延时检测)
    					pKeyDrv->scan.state=(pKeyDrv->scan.state&SKEY_STATE_MASK)+SKEY_STATE_WAITRELEASE;
    				}
    			}
    		}
    	}
    	*/
    }
    

    3)等待释放

      按键释放时,抖动处理完毕后进入此状态

    else if  (pKeyDrv->scan.state&SKEY_STATE_WAITRELEASE)
    {
    	Key_ReleaseProcess(pKeyDrv);// 释放处理模块
    	/*
    	void Key_ReleaseProcess(tKeyDriver *pKeyDrv)// 释放处理模块
    	{
    		if	(pKeyDrv->scan.pressCnt>0)
    		{//等待释放时,检测到有按键按下,回到抖动处理
    			pKeyDrv->scan.state-=SKEY_STATE_WAITRELEASE;
    			pKeyDrv->scan.state|=SKEY_STATE_JITTER; 
    			pKeyDrv->scan.jitterReleaseCnt=0;
    			pKeyDrv->scan.jitterPressCnt=0;
    		}
    		else
    		{//等待释放(延时)
    			pKeyDrv->scan.jitterReleaseCnt++;
    			if	(pKeyDrv->scan.jitterReleaseCnt>=ScanKeyCnt(pKeyDrv->param.jitterReleaseCntMax)))
    			{//按键弹起检测再次超时
    				pKeyDrv->scan.state&=SKEY_STATE_MASK;
    				pKeyDrv->keyMsg.value.scan=pKeyDrv->scan.prevKey;
    				if	(pKeyDrv->scan.state==SKEY_STATE_PRESS)
    				{
    					//产生短按键释放功能码
    					pKeyDrv->keyMsg.value.func=SHBKEY(pKeyDrv->func.pMap(pKeyDrv->scan.prevKey));
    				}
    				else// if (pKeyDrv->scan.state==SKEY_STATE_PRESS_LONG)
    				{
    					//产生长按键释放功能码
    					pKeyDrv->keyMsg.value.func=LGBKEY(pKeyDrv->func.pMap(pKeyDrv->scan.prevKey));
    				}
    				//执行按键驱动中安装的按键输出或按键解析功能
    				pKeyDrv->scan.state=SKEY_STATE_RELEASE;
    				if	(pKeyDrv->func.pExport!=NULL)
    				pKeyDrv->func.pExport(&pKeyDrv->keyMsg);//执行按键输出
    				if	(pKeyDrv->func.pParse!=NULL)
    				pKeyDrv->func.pParse(&pKeyDrv->keyMsg);//执行按键解析
    			}
    		}
    	}
    	*/
    }
    

    4)按键释放或抖动

      按键按下后,出现按键弹起或按键扫描值变化,将设置进入抖动检测

    else if (pKeyDrv->scan.pressCnt==0||pKeyDrv->scan.curKey!=pKeyDrv->scan.prevKey)
    {	
    	Key_Jitter(pKeyDrv);// 抖动检测模块
    	/*
    	void Key_Jitter(tKeyDriver *pKeyDrv) 抖动检测模块
    	{
    		//pressCnt==0,检测到按键释放,则需要进入抖动检测;
    		//scan.curKey!=scan.prevKey,检测按键值发生变化,则需要进入抖动检测
    		pKeyDrv->scan.state|=SKEY_STATE_JITTER;
    		pKeyDrv->scan.jitterReleaseCnt=0;
    		pKeyDrv->scan.jitterPressCnt=0;
    	}
    	*/
    }
    

    5)按键确认及产生功能码

      按键按下且未出现抖动情况,则检测并产生功能码

    else
    {
    	Key_FunCodeProcess(pKeyDrv);// 功能码产生模块
    	/*
    	void Key_FunCodeProcess(tKeyDriver *pKeyDrv)// 功能码产生模块
    	{
    		if	(pKeyDrv->scan.keepCnt)
    			pKeyDrv->scan.keepCnt--;
    		if	(pKeyDrv->scan.keepCnt==0)
    		{//保持pKeyDrv->scan.keepCnt设置值的时间计数到0时,进行按键功能码产生处理
    			if (pKeyDrv->scan.state==SKEY_STATE_PUSH)
    			{//按键按下确认
    				pKeyDrv->scan.state=SKEY_STATE_PRESS;//设置扫描状态为按下
    				//设置按键信息
    				pKeyDrv->keyMsg.time=0;
    				pKeyDrv->keyMsg.value.scan=pKeyDrv->scan.prevKey;
    				pKeyDrv->keyMsg.value.func=SHPKEY(pKeyDrv->func.pMap(pKeyDrv->scan.prevKey));
    				//设置下次检测时间(长按检测)
    				pKeyDrv->scan.keepCnt=ScanKeyCnt(pKeyDrv->param.keepCntLongStart);
    			}
    			else
    			{//长按键处理
    				pKeyDrv->keyMsg.value.scan=pKeyDrv->scan.prevKey;
    				pKeyDrv->keyMsg.value.func=LGKEY(pKeyDrv->func.pMap(pKeyDrv->scan.prevKey));
    				//设置下次检测时间(长按间隔)
    				pKeyDrv->scan.keepCnt=ScanKeyCnt(pKeyDrv->param.keepCntLongKeep);
    				if	(pPkeyDrv->scan.state==SKEY_STATE_PRESS)
    				{//首次长按键
    					pKeyDrv->scan.state=SKEY_STATE_PRESS_LONG;
    					pKeyDrv->keyMsg.time=FuncLKeyCnt(pKeyDrv->param.keepCntLongStart);
    				}
    				else
    				{//重复的长按键
    					if	(pKeyDrv->keyMsg.time<0xffffffffff)
    					pKeyDrv->keyMsg.time++;
    				}
    			}
    			//执行按键驱动中安装的按键输出或按键解析功能
    			if	(pKeyDrv->func.pExport!=NULL)
    			pKeyDrv->func.pExport(&pKeyDrv->keyMsg);//执行按键输出
    			if	(pKeyDrv->func.pParse!=NULL)
    			pKeyDrv->func.pParse(&pKeyDrv->keyMsg);//执行按键解析
    		}
    	}
    	*/
    }
    pKeyDrv->running=FALSE;//处理运行结束
    

    3.按键驱动安装

      按键驱动安装主要完成驱动内存申请(参数传递了接收申请内存的指针),驱动函数安装及扫描参数设置等操作。返回tKeyPollFunc类型的按键驱动轮询处理指针,用于应用程序定时调用(其参数为:pKeyDrv),若返回为NULL,则安装失败。
      扫描参数可以为每一个需要独立分开的按键驱动设置不同的参数,也可以使用驱动默认参数值;

    typdef void (tKeyPollFunc)(tKeyDriver*);
    typedef struct
    {
    	tKeyDrvFunc		func;			//按键驱动函数
    	tScanParam		param;			//扫描参数
    }tKeyInitParam;//按键驱动安装参数
    
    tKeyPollFunc* Key_Initial(tKeyInitParam *pInitParam,tKeyDriver	 *pKeyDrv)
    {//pKeyDrv 接收驱动内存申请的指针
    	if	(pInitParam==NULL)
    	return	NULL;
    	pKeyDrv=MALLOC_MEM(sizeof(tKeyDriver));
    	if	(pInitParam->func.pScan!=NULL)//必须提供扫描函数,否则安装失败
    	{
    		pKeyDrv->valid=TRUE;
    		pKeyDrv->running=FALSE;
    		//扫描寄存器初始化
    		pKeyDrv->scan.state=SKEY_STATE_RELEASE;
    		pKeyDrv->scan.keepCnt=0;
    		pKeyDrv->scan.jitterPressCnt=0;
    		pKeyDrv->scan.jitterReleaseCnt=0;
    		pKeyDrv->scan.curKey=KEY_NO;
    		pKeyDrv->scan.prevKey=KEY_NO;
    		//安装驱动处理函数及设置扫描参数
    		pKeyDrv->func=pInitParam->func;
    		pKeyDrv->param=pInitParam->param;
    		//检测映射函数
    		if	(pKeyDrv->func.pMap==NULL)//未指定映射函数,则使用默认映射函数
    		pKeyDrv->func.pMap=KeyMapDef;
    		//依次检测扫描参数是否需要使用默认值
    		if	(pKeyDrv->param.scanUnit==0)//扫描时间单位
    		pKeyDrv->param.scanUnit=KEYSCAN_UINT_DEF;
    		if	(pKeyDrv->param.jitterPressCntMax==0)//按下抖动检测时间
    		pKeyDrv->param.jitterPressCntMax=JITTERPRESSCNTMAX_DEF	;
    		if	(pKeyDrv->param.jitterReleaseCntMax==0)//释放抖动检测时间
    		pKeyDrv->param.jitterReleaseCntMax=JITTERRELEASECNTMAX_DEF;
    		if	(pKeyDrv->param.keepCntEnsure==0)//按下确认保持时间
    		pKeyDrv->param.keepCntEnsure=KEEPCNT_ENSURE_DEF;
    		if	(pKeyDrv->param.keepCntLongStart==0)//检测首次长按时间
    		pKeyDrv->param.keepCntLongStart=KEEPCNT_LONG_START_DEF;
    		if	(pKeyDrv->param.keepCntLongKeep==0)//长按保持时间间隔
    		pKeyDrv->param.keepCntLongKeep=KEEPCNT_LONG_KEEP_DEF;
    		//执行低级初始化操作
    		if	(pKeyDrv->func.pInit!=NULL)
    		pKeyDrv->func.pInit();
    		return	Key_Poll;
    	}
    	else
    	{
    		FREE_MEM(pKeyDrv);
    		pKeyDrv=NULL;
    		return	NULL;
    	}
    }
    

    4.按键驱动卸载

      按键驱动的卸载调用前,必须手动停止按键驱动轮询的定时调用,此处不对其进行检查,仅对驱动轮询是否正在运行进行检查。

    bool Key_UnInitial(tKeyDriver *pKeyDrv)
    {
    	if	(pKeyDrv!=NULL&&pKeyDrv->running==FALSE)
    	{
    		//执行低级去初始化操作
    		if	(pKeyDrv->func.pUnInit!=NULL)
    		pKeyDrv->func.pUnInit();
    		FREE_MEM(pKeyDrv);
    		pKeyDrv=NULL;
    		return	TRUE;
    	}
    	else
    	return	FALSE;
    }
    

    四、总结

    1.使用说明

    1)必要的移植修改设计说明

      A,需要设计扫描码与功能码及映射函数(pMap),扫描参数可以根据需要是否使用默认值或者进行单独定义;
      B,至少需要设计按键扫描函数(pScan);
      C,选择按键输出函数(pExport)或按键分析函数(pParse)根据需要进行设计;
      D,不管是裸机运行还是在操作系统下运行,均需要进行按键驱动安装;
      E,设计中将轮询函数提供给上层去决定如何执行,这样可以进一步降低耦合度以及对增按键强驱动使用的灵活性。对于裸机运行可将轮询函数放在硬件定时器产生的POLLING中执行;对于运行在操作系统(如FreeRTOS)下可以将轮询函数放在某个软件定时器的回调函数中执行(或发送事件到某个任务执行);

    2)外部调用接口

      驱动安装函数Key_Initial是唯一直接提供给应用层必须调用的接口;
      驱动卸载函数Key_UnInitial是接提供给应用层可选调用的接口;
      驱动轮询函数是间接提供给应用层周期性调用的接口;

    3)按键驱动使用示例

    /*其它头文件包含*/
    //#include ......
    
    //按键驱动头文件包含
    #include "KeyDriver.h"
    
    /*扫描码与功能码等内容定义*/
    //#define ......
    
    //底层初始化及去初始化函数声明
    void KeyLLInit(void);
    void KeyLLUnInit(void);
    
    //按键扫描函数声明
    uint8_t ScanFunc(uint32_t scan);
    //按键分析处理函数设计声明
    void ParseFunc(tKeyMsg* pMsg);
    //主函数设计
    void main(void)
    {
    	//变量定义
    	tKeyDriver 		*pKeyDrv;
    	tKeyPollFunc	*pKeyPollFunc;
    	tKeyInitParam 	init;
    	
    	LLed_InitParamSetup(&init);
    	/*
    	void LLed_InitParamSetup(tKeyInitParam *pInit)
    	{
    		pInit->func.pScan=&ScanFunc;
    		pInit->func.pParse=&ParseFunc;
    		pInit->func.pInit=KeyLLInit;
    		pInit->func.pUnInit=KeyLLUnInit;
    		pInit->func.pExport=NULL;
    		pInit->param.scanUnit=0;
    		pInit->param.jitterPressCntMax=0;
    		pInit->param.jitterReleaseCntMax=0;
    		pInit->param.keepCntEnsure=0;
    		pInit->param.keepCntLongStart=0;
    		pInit->param.keepCntLongKeep=0;
    	}
    	*/
    	pKeyPollFunc=Key_Initial(&init,pKeyDrv);
    	for	(;;)
    	{
    		delayMs(10);
    		pKeyPollFunc(pKeyDrv);
    		/*其它处理*/
    		//......
    	}
    }
    

    2.其它说明

      以上按键驱动设计,表面上看似乎较为复杂,但实际上是因为两个原因才如此进行设计。
      1)首先,按键驱动的设计考虑到一个应用里面可能存在多个不同的扫描处理方法,可以同时安装多个独立的按键驱动。甚至,设计遥控器驱动也基本可以不做修改而直接使用;
      2)其次,这里已经将按键驱动与应用层尽量做到了较低的耦合度,在移植时仅需要提供一些必要的辅助设计即可,甚至,参数数据均可以使用默认值;

    五、后续内容

      下个分享内容:单片机软件常用设计分享(二)驱动设计之LED灯显示设计

    说明

      以上设计方法基本为本人在工作中所用,但为了分享,做了一定的整理并进行扩充(扩充后未进行编译运行<抱歉>)。如有错误或BUG,欢迎指正。

    展开全文
  • ucgui界面设计示例2

    千次阅读 2014-10-29 11:32:29
    环境:主机:WIN8开发环境:MDK4.72ucgui版本:3.90mcu: stm32f103VE说明:本程序基于ucgui对话框机制设计了一个界面,并用6个实体按键对界面进行控制,并增加了进度条显示效果图: 源码:gui_match.h/***************...
     ucgui界面设计示例2


    本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.


    环境:

    主机:WIN8

    开发环境:MDK4.72

    ucgui版本:3.90

    mcu: stm32f103VE


    说明:

    本程序基于ucgui对话框机制设计了一个界面,并用6个实体按键对界面进行控制,并增加了进度条显示


    效果图:

     


    源码:

    gui_match.h

    /*********************************************************************
    *						对码绑定界面模块头文件
    *						(c)copyright 2014,jdh
    *						  All Right Reserved
    *新建时间:2014/10/24 by jdh
    **********************************************************************/
    
    #ifndef _GUI_MATCH_H_
    #define _GUI_MATCH_H_
    
    /*********************************************************************
    *							头文件
    **********************************************************************/
    
    #include "world.h"
    
    /*********************************************************************
    *							宏定义
    **********************************************************************/
    
    /*********************************************************************
    *							工作间隔
    *单位:ms
    **********************************************************************/
    
    #define INTERVAL_GUI_MATCH			100  
    
    /*********************************************************************
    *							进度条显示时间
    *单位:ms
    **********************************************************************/
    
    #define TIME_PROGBAR_GUI_MATCH		3000 
    
    /*********************************************************************
    *							函数
    **********************************************************************/
    
    /*********************************************************************
    *							模块载入
    **********************************************************************/
    
    void gui_match_load(void);
    
    /*********************************************************************
    *							模块运行
    **********************************************************************/
    
    void gui_match_run(void);
    
    /*********************************************************************
    *							设置显示状态
    *参数:enable:0:关闭显示,1:打开显示
    **********************************************************************/
    
    void gui_match_show(uint8_t enable);
    
    /*********************************************************************
    *							得到当前的显示状态
    *返回:0:关闭显示,1:打开显示
    **********************************************************************/
    
    uint8_t gui_match_get_show(void);
    
    /*********************************************************************
    *							得到绑定的脚镣id
    *返回:0:未绑定,其他:脚镣id
    **********************************************************************/
    
    uint16_t gui_match_get_fetter_id_bind(void);
    
    #endif
    
    


    gui_match.c

    /*********************************************************************
    *						对码绑定界面模块主文件
    *						(c)copyright 2014,jdh
    *						  All Right Reserved
    *新建时间:2014/10/24 by jdh
    *修改时间:2014/10/29 by jdh
    **********************************************************************/
    
    /*********************************************************************
    *							头文件
    **********************************************************************/
    
    #include "gui_match.h"
    #include "cc1100.h"
    #include "gui_main.h"
    
    /*********************************************************************
    *							宏定义
    **********************************************************************/
    
    #define ID_FRAMEWIN            		(GUI_ID_USER + 0x10)
    #define ID_BUTTON_OK            	(GUI_ID_USER + 0x11)
    #define ID_BUTTON_CANCEL            (GUI_ID_USER + 0x12)
    #define ID_BUTTON_UP            	(GUI_ID_USER + 0x13)
    #define ID_BUTTON_DOWN            	(GUI_ID_USER + 0x14)
    #define ID_BUTTON_LEFT            	(GUI_ID_USER + 0x15)
    #define ID_BUTTON_RIGHT            	(GUI_ID_USER + 0x16)
    #define ID_TEXT_MATCH           	(GUI_ID_USER + 0x17)
    #define ID_TEXT_ID           		(GUI_ID_USER + 0x18)
    #define ID_TEXT_PROGBAR           	(GUI_ID_USER + 0x19)
    #define ID_LISTBOX           		(GUI_ID_USER + 0x1A)
    #define ID_PROGBAR           		(GUI_ID_USER + 0x1B)
    
    /*********************************************************************
    *							列表框存储的数据数量
    **********************************************************************/
    
    #define LIST_LEN					20
    
    /*********************************************************************
    *							数据结构
    **********************************************************************/
    
    /*********************************************************************
    *							按键状态
    **********************************************************************/
    
    struct _Key_State
    {
    	uint8_t ok;
    	uint8_t cancel;
    	uint8_t up;
    	uint8_t down;
    	uint8_t left;
    	uint8_t right;
    };
    
    /*********************************************************************
    *							列表框缓存
    **********************************************************************/
    
    struct _List
    {
    	uint8_t len;
    	uint16_t buf[LIST_LEN];
    };
    
    /*********************************************************************
    *							静态变量
    **********************************************************************/
    
    /*********************************************************************
    *							界面句柄
    **********************************************************************/
    
    static WM_HWIN Handle_Gui;
    
    /*********************************************************************
    *							资源表
    **********************************************************************/
    
    static const GUI_WIDGET_CREATE_INFO _aDialogCreate[] = 
    {
      { FRAMEWIN_CreateIndirect, 	"Frame3", 	ID_FRAMEWIN, 			0, 0, 240, 320, 0, 0x0},
      { BUTTON_CreateIndirect, 		"OK", 		ID_BUTTON_OK, 		5, 255, 40, 20, 0, 0x0},
      { BUTTON_CreateIndirect, 		"Button", 	ID_BUTTON_DOWN, 	95, 280, 40, 20, 0, 0x0},
      { BUTTON_CreateIndirect, 		"UP", 		ID_BUTTON_UP, 		95, 255, 40, 20, 0, 0x0},
      { BUTTON_CreateIndirect, 		"CANCEL", 	ID_BUTTON_CANCEL, 	185, 255, 40, 20, 0, 0x0},
      { BUTTON_CreateIndirect, 		"RIGHT", 	ID_BUTTON_RIGHT, 	140, 270, 40, 20, 0, 0x0},
      { BUTTON_CreateIndirect, 		"LEFT", 	ID_BUTTON_LEFT, 	50, 270, 40, 20, 0, 0x0},
      { TEXT_CreateIndirect, 		"Match", 	ID_TEXT_MATCH, 		140, 15, 80, 20, 0, 0x0},
      { TEXT_CreateIndirect, 		"ID", 		ID_TEXT_ID, 		140, 40, 80, 20, 0, 0x0},
      { TEXT_CreateIndirect, 		"", 		ID_TEXT_PROGBAR, 	140, 65, 80, 20, 0, 0x0},
      { LISTBOX_CreateIndirect, 	"Listbox", 	ID_LISTBOX, 		5, 10, 120, 220, 0, 0x0},
      { PROGBAR_CreateIndirect, 	"Progbar", 	ID_PROGBAR, 		140, 85, 80, 20, 0, 0x0},
      // USER START (Optionally insert additional widgets)
      // USER END
    };
    
    /*********************************************************************
    *							上次工作时间
    **********************************************************************/
    
    static struct _Time Time_Last = 
    {
        .s = 0,
        .ms = 0,
        .us = 0
    };
    
    /*********************************************************************
    *							进度条开始的时间
    **********************************************************************/
    
    static struct _Time Time_Progbar = 
    {
        .s = 0,
        .ms = 0,
        .us = 0
    };
    
    /*********************************************************************
    *							接收CC1100的时间
    **********************************************************************/
    
    static struct _Time Time_Recv_CC1100 = 
    {
        .s = 0,
        .ms = 0,
        .us = 0
    };
    
    /*********************************************************************
    *							按键状态
    **********************************************************************/
    
    static struct _Key_State Key_State = 
    {
    	.ok = 0,
    	.cancel = 0,
    	.up = 0,
    	.down = 0,
    	.left = 0,
    	.right = 0
    };
    
    /*********************************************************************
    *							当前显示状态
    *0:未显示,1显示
    **********************************************************************/
    
    static uint8_t State_Show = 0;
    
    /*********************************************************************
    *							进度条动画开始标志
    *0:终止,1:扫描,2:绑定
    **********************************************************************/
    
    static uint8_t Flag_Progbar = 0;
    
    /*********************************************************************
    *							列表框存储器
    **********************************************************************/
    
    static struct _List List = 
    {
    	.len = 0
    };
    
    /*********************************************************************
    *							已绑定脚镣ID
    *0:未绑定,其他:ID
    **********************************************************************/
    
    static uint16_t Fetter_Id_Bind = 0;
    
    /*********************************************************************
    *							静态函数
    **********************************************************************/
    
    /*********************************************************************
    *							回调函数
    **********************************************************************/
    
    static void _cbDialog(WM_MESSAGE * pMsg);
    
    /*********************************************************************
    *							定时工作
    **********************************************************************/
    
    static void slot_tick(void);
    
    /*********************************************************************
    *							按键处理
    **********************************************************************/
    
    static void deal_key(void);
    
    /*********************************************************************
    *							进度条动画
    *参数:percent:百分比
    **********************************************************************/
    
    static void progbar_show(uint8_t percent);
    
    /*********************************************************************
    *							发送125k绑定信号
    **********************************************************************/
    
    static void emit_125k_bind(void);
    
    /*********************************************************************
    *							处理cc1100接收数据
    *参数:task:0:扫描,1:绑定
    **********************************************************************/
    
    static void deal_cc1100(uint8_t task);
    
    /*********************************************************************
    *							产生激发数据
    *参数:cmd:功能码
    *     data:产生的2字节激发数据
    **********************************************************************/
    
    static void generate_exciter_data(uint8_t cmd,uint8_t *data);
    
    /*********************************************************************
    *							函数
    **********************************************************************/
    
    /*********************************************************************
    *							模块载入
    **********************************************************************/
    
    void gui_match_load(void)
    {
    	//新建界面
    	Handle_Gui = GUI_CreateDialogBox(_aDialogCreate, GUI_COUNTOF(_aDialogCreate), 
    									 _cbDialog, WM_HBKWIN, 0, 0);
    	gui_match_show(OFF);
    }
    
    /*********************************************************************
    *							模块运行
    **********************************************************************/
    
    void gui_match_run(void)
    {
    	struct _Time time;
    	
    	//判断当前是否显示
    	if (State_Show == 0)
    	{
    		return;
    	}
    	
    	//判断当前是否处于扫描状态
    	if (Flag_Progbar == 1)
    	{
    		deal_cc1100(0);
    	}
    	else
    	{
    		//判断当前是否处于绑定状态
    		if (Flag_Progbar == 2)
    		{
    			deal_cc1100(1);
    		}
    	}
    	
        //得到当前时间
        get_time(&time);
    
        //判断是否到工作时间
    	if (sub_time(time,Time_Last) >= INTERVAL_GUI_MATCH * 1000)
        {
            //更新时间
            Time_Last = time;
            
            //定时工作
            slot_tick();
        }
    }
    
    /*********************************************************************
    *							设置显示状态
    *参数:enable:0:关闭显示,1:打开显示
    **********************************************************************/
    
    void gui_match_show(uint8_t enable)
    {
    	WM_HWIN hItem;
    	
    	State_Show = enable;
    	if (enable)
    	{
    		//设置列表框为焦点
    		hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    		WM_SetFocus(hItem);
    		
    		WM_ShowWindow(Handle_Gui);
    	}
    	else
    	{
    		WM_HideWindow(Handle_Gui);
    	}
    }
    
    /*********************************************************************
    *							得到当前的显示状态
    *返回:0:关闭显示,1:打开显示
    **********************************************************************/
    
    uint8_t gui_match_get_show(void)
    {
    	return State_Show;
    }
    
    /*********************************************************************
    *							得到绑定的脚镣id
    *返回:0:未绑定,其他:脚镣id
    **********************************************************************/
    
    uint16_t gui_match_get_fetter_id_bind(void)
    {
    	//return Fetter_Id_Bind;
    	return 0x100;
    }
    
    /*********************************************************************
    *							定时工作
    **********************************************************************/
    
    static void slot_tick(void)
    {
    	uint32_t ms = 0;
    	uint8_t percent = 0;
    	WM_HWIN hItem;
    	
    	//按键处理
    	deal_key();
    	
    	//判断当前进度条是否需要显示
    	if (Flag_Progbar)
    	{
    		//判断是否是扫描
    		if (Flag_Progbar == 1)
    		{
    			//判断激发信号是否结束
    			if (inf_exciter_get_busy() == 0)
    			{
    				//关闭激发模块电源
    				inf_exciter_power(OFF);
    			}
    		}
    		
    		//判断是否到工作时间
    		ms = sub_time(Time_Last,Time_Progbar) / 1000;
    		if (ms < TIME_PROGBAR_GUI_MATCH)
    		{
    			percent = ms * 100 / TIME_PROGBAR_GUI_MATCH;
    			progbar_show(percent);
    		}
    		else
    		{
    			//结束进度条动画
    			Flag_Progbar = 0;
    			progbar_show(100);
    			
    			//文本:结束
    			hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_PROGBAR);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"结束");
    		}
    	}
    }
    
    /*********************************************************************
    *							按键处理
    **********************************************************************/
    
    static void deal_key(void)
    {
    	WM_HWIN hItem;
    	uint8_t index = 0;
    	uint16_t id = 0;
    	uint8_t data[3] = {0};
    	
    	//判断下键是否按下
    	if (inf_key_detect_hold(KEY_DOWN))
    	{
    		if (Key_State.down == 0)
    		{
    			Key_State.down = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_DOWN);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    			
    			//发送按键信号
    			GUI_SendKeyMsg(GUI_KEY_DOWN, 1);
    		}
    	}
    	else
    	{
    		if (Key_State.down == 1)
    		{
    			Key_State.down = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_DOWN);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    		}
    	}
    	
    	//判断上键是否按下
    	if (inf_key_detect_hold(KEY_UP))
    	{
    		if (Key_State.up == 0)
    		{
    			Key_State.up = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_UP);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    			
    			//发送按键信号
    			GUI_SendKeyMsg(GUI_KEY_UP, 1);
    		}
    	}
    	else
    	{
    		if (Key_State.up == 1)
    		{
    			Key_State.up = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_UP);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    		}
    	}
    	
    	//判断扫描键是否按下
    	if (inf_key_detect_hold(KEY_OK) && (Flag_Progbar == 0))
    	{
    		if (Key_State.ok == 0)
    		{
    			Key_State.ok = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_OK);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    			
    			//文本:开始扫描
    			hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_PROGBAR);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"开始扫描");
    			
    			//开始扫描
    			Flag_Progbar = 1;
    			//保存当前时间
    			get_time(&Time_Progbar);
    			
    			//打开125k电源
    			inf_exciter_power(ON);
    			//发送125k绑定信号
    			emit_125k_bind();
    			
    			//清空列表框
    			List.len = 0;
    			hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    			listbox_clear(hItem);
    		}
    	}
    	else
    	{
    		if (Key_State.ok == 1)
    		{
    			Key_State.ok = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_OK);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    		}
    	}
    	
    	//判断清除键是否按下
    	if (inf_key_detect_hold(KEY_LEFT))
    	{
    		if (Key_State.left == 0)
    		{
    			Key_State.left = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_LEFT);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    			
    			//清空列表框
    			List.len = 0;
    			hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    			listbox_clear(hItem);
    		}
    	}
    	else
    	{
    		if (Key_State.left == 1)
    		{
    			Key_State.left = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_LEFT);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    		}
    	}
    	
    	//判断绑定键是否按下
    	if (inf_key_detect_hold(KEY_RIGHT) && (Flag_Progbar == 0))
    	{
    		if (Key_State.right == 0)
    		{
    			Key_State.right = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_RIGHT);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    			
    			//判断当前是否有项
    			if (List.len == 0)
    			{
    				return;
    			}
    			//得到脚镣id
    			hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    			index = LISTBOX_GetSel(hItem);
    			if (index >= List.len)
    			{
    				//清空列表框
    				List.len = 0;
    				hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    				listbox_clear(hItem);
    				return;
    			}
    			id = List.buf[index];
    			//数据
    			data[0] = 0;
    			data[1] = 0;
    			data[2] = 0;
    			//等待可以发送
    			while (cc1100_judge_tx() == 0);
    			//发送对码绑定帧
    			cc1100_tx(CMD_RF_BIND,id,data);
    			
    			//开始绑定
    			Flag_Progbar = 2;
    			//保存当前时间
    			get_time(&Time_Progbar);
    			
    			//更新绑定的脚镣ID
    			Fetter_Id_Bind = 0;
    			//更新文本
    			hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_MATCH);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"未绑定脚镣");
    			
    			hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_ID);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"ID:0");
    			
    			//更新文本
    			hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_PROGBAR);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"正在绑定");
    		}
    	}
    	else
    	{
    		if (Key_State.right == 1)
    		{
    			Key_State.right = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_RIGHT);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    		}
    	}
    	
    	//判断返回键是否按下
    	if (inf_key_detect_hold(KEY_CANCEL) && (Flag_Progbar == 0))
    	{
    		if (Key_State.cancel== 0)
    		{
    			Key_State.cancel = 1;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_CANCEL);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS | BUTTON_STATE_PRESSED);
    		}
    	}
    	else
    	{
    		if (Key_State.cancel == 1)
    		{
    			Key_State.cancel = 0;
    			
    			//按键状态改变
    			hItem = WM_GetDialogItem(Handle_Gui, ID_BUTTON_CANCEL);
    			BUTTON_SetState(hItem,BUTTON_STATE_HASFOCUS);
    			
    			//返回主界面
    			gui_match_show(OFF);
    			gui_main_show(ON);
    		}
    	}
    }
    
    /*********************************************************************
    *							进度条动画
    *参数:percent:百分比
    **********************************************************************/
    
    static void progbar_show(uint8_t percent)
    {
    	WM_HWIN hItem;
    	
    	//进度条显示
    	hItem = WM_GetDialogItem(Handle_Gui, ID_PROGBAR);
    	PROGBAR_SetValue(hItem,percent);
    }
    
    /*********************************************************************
    *							发送125k绑定信号
    **********************************************************************/
    
    static void emit_125k_bind(void) 
    {
    	uint8_t data[2] = {0};
    	
    	//生成激活数据
    	generate_exciter_data(CMD_125K_BIND,data);
    	//生成新的激发序列
    	inf_exciter_generate_frame(data,2);
    
    	//等待空闲
    	while (inf_exciter_get_busy());
    	//发送
    	inf_exciter_start();
    }
    
    /*********************************************************************
    *							处理cc1100接收数据
    *参数:task:0:扫描,1:绑定
    **********************************************************************/
    
    static void deal_cc1100(uint8_t task)
    {
    	struct _Rx_Buf_CC1100 buf;
    	WM_HWIN hItem;
    	char str[20] = {0};
    	
    	buf = cc1100_get_rx_buf();
    	//判断是否是最新帧
    	if (compare_time(buf.time,Time_Recv_CC1100) != 2)
    	{
    		return;
    	}
    	
    	//保存时间
    	Time_Recv_CC1100 = buf.time;
    	
    	if (task == 0)
    	{
    		//判断功能码是否是上传脚镣ID帧
    		if (buf.cmd != CMD_RF_UP_FETTER_ID)
    		{
    			return;
    		}
    		
    		//判断是否还有存储空间
    		if (List.len >= LIST_LEN)
    		{
    			return;
    		}
    		
    		//更新数据
    		List.buf[List.len++] = buf.src_id;
    		sprintf(str,"%d",List.buf[List.len - 1]);
    		//更新列表框
    		hItem = WM_GetDialogItem(Handle_Gui, ID_LISTBOX);
    		LISTBOX_AddString(hItem, str);
    		
    		return;
    	}
    	
    	if (task == 1)
    	{
    		//判断功能码是否是确认对码绑定
    		if (buf.cmd != CMD_RF_ACK_BIND)
    		{
    			return;
    		}
    		
    		//更新绑定的脚镣ID
    		Fetter_Id_Bind = buf.src_id;
    		//更新文本
    		hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_MATCH);
    		TEXT_SetFont(hItem, &GUI_FontHZ12);
    		TEXT_SetText(hItem,"已绑定脚镣");
    		
    		hItem = WM_GetDialogItem(Handle_Gui, ID_TEXT_ID);
    		TEXT_SetFont(hItem, &GUI_FontHZ12);
    		sprintf(str,"ID:0x%x",Fetter_Id_Bind);
    		TEXT_SetText(hItem,str);
    		
    		return;
    	}
    }
    
    /*********************************************************************
    *							产生激发数据
    *参数:cmd:功能码
    *     data:产生的2字节激发数据
    **********************************************************************/
    
    static void generate_exciter_data(uint8_t cmd,uint8_t *data)
    {
    	uint8_t temp = 0;
    	uint8_t check = 0;
    	
    	temp = cmd << 6;
    	temp |= LOCAL_ID >> 4;
    	data[0] = temp;
    	temp = LOCAL_ID << 4;
    	
    	check = checksum4(data,2);
    	temp |= check;
    	data[1] = temp;
    }
    
    /*********************************************************************
    *							回调函数
    **********************************************************************/
    
    static void _cbDialog(WM_MESSAGE * pMsg) 
    {
    	WM_HWIN hItem;
    
    	switch (pMsg->MsgId) 
    	{
    	case WM_INIT_DIALOG:
    		{
    			//初始化窗体
    			//增加小按键
    			FRAMEWIN_AddCloseButton(pMsg->hWin, FRAMEWIN_BUTTON_RIGHT, 0);
    			FRAMEWIN_AddMaxButton(pMsg->hWin, FRAMEWIN_BUTTON_RIGHT, 1);
    			FRAMEWIN_AddMinButton(pMsg->hWin, FRAMEWIN_BUTTON_RIGHT, 2);
    			FRAMEWIN_SetFont(pMsg->hWin, &GUI_FontHZ12);
    			FRAMEWIN_SetText(pMsg->hWin,"对码绑定");
    			
    			//初始化列表框
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_LISTBOX);
    //			//设置内容
    //			LISTBOX_SetFont(hItem, &GUI_FontHZ12);
    //			LISTBOX_AddString(hItem, "0x10");
    //			LISTBOX_AddString(hItem, "0x11");
    //			LISTBOX_AddString(hItem, "0x12");
    //			LISTBOX_AddString(hItem, "0x13");
    //			LISTBOX_AddString(hItem, "0x14");
    //			List.buf[0] = 0x10;
    //			List.buf[1] = 0x11;
    //			List.buf[2] = 0x12;
    //			List.buf[3] = 0x13;
    //			List.buf[4] = 0x14;
    //			List.len = 5;
    			
    			//设置为焦点
    			WM_SetFocus(hItem);
    			SCROLLBAR_CreateAttached(hItem, SCROLLBAR_CF_VERTICAL);
    			
    			//初始化按键
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_OK);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"扫描");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_CANCEL);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"返回");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_UP);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"上");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_DOWN);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"下");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_LEFT);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"清除");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_BUTTON_RIGHT);
    			BUTTON_SetFont(hItem, &GUI_FontHZ12);
    			BUTTON_SetText(hItem,"绑定");
    			
    			//初始化文本
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_MATCH);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"未绑定脚镣");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_ID);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"ID:0");
    			
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_TEXT_PROGBAR);
    			TEXT_SetFont(hItem, &GUI_FontHZ12);
    			TEXT_SetText(hItem,"结束");
    			
    			//初始化进度条
    			hItem = WM_GetDialogItem(pMsg->hWin, ID_PROGBAR);
    			PROGBAR_SetBarColor(hItem,0,GUI_RED);
    			PROGBAR_SetBarColor(hItem,1,GUI_GREEN);
    			
    			break;
    		}
    	default:
    		{
    			WM_DefaultProc(pMsg);
    			break;
    		}
    	}
    }
    
    


    展开全文
  • ucgui界面设计&实体按键驱动

    万次阅读 2014-10-24 09:22:25
    环境:主机:WIN8开发环境:MDK4.72ucgui版本:3.90mcu: stm32f103VE说明:本程序基于ucgui对话框机制设计了一个界面,并用6个实体按键对界面进行控制效果图:源码:gui_main.h/**************************
  • 用builder创立一个界面...hItem = pMsg->hWin; FRAMEWIN_SetFont(hItem, &GBK_16m16); FRAMEWIN_SetText(hItem, “自助取款机”); FRAMEWIN_SetTextAlign(hItem, GUI_TA_HCENTER | GUI_TA_VCENTER); 插入WM_PAIN
  • C++ 高性能服务器网络框架设计细节

    万次阅读 多人点赞 2017-10-12 15:48:59
    C++ 高性能服务器网络框架设计细节 关注微信公众号:「GitChat 技术杂谈」 一本正经的讲技术 【不要错过文末彩蛋】 前言 这篇文章我们将介绍服务器的开发,并从多个方面探究如何开发一款高性能高...
  • 《Windows程序设计》复习题

    万次阅读 多人点赞 2016-05-24 13:37:35
    《Windows程序设计》复习题,包含windows程序设计和MFC程序设计的众多知识点。
  • Windows程序设计--窗口与消息

    千次阅读 2015-09-09 14:43:04
    进行Windows程序设计时,其实就是在进行一种面向对象的编程。在面向对象中,对象是代码和数据的组合,一个窗口也是一个对象。在用户眼中,窗口是屏幕上的对象,并可借助键盘或鼠标直接与之进行交互。用户对窗口的...
  • 设计应用层协议

    2020-01-01 18:27:09
    1.简述 ... 实现自己的应用功能时,已知的知名协议(http,smtp,ftp等)在安全性、可扩展性等方面不能满足需求,从而需要设计并实现自己的应用层协议。 2.协议分类 2.1按编码方式 二进制协议...
  • VCL之设计模式简析

    2018-09-05 23:21:54
    说到设计模式,这个是我一直有种冲动想要写点什么的,但不知如何下笔,其实今天写这篇文章也是硬着头皮写的,因为我说要写的,不能再耽搁了。 为什么拖了这么长时间,是因为不知道从设计模式,还是从具体的代码开始...
  • MFC 进行界面设计与编程

    千次阅读 2017-10-02 23:28:10
    由UI设计界面背景图片、相关按钮图片等,然后在代码中创建关联控件变量。对于无需变化的背景、按钮,可以不设控件变量关联。一般有以下几个步骤: 1.UI设计界面; 2.创建需要变动的控件变量与之关联,并设置...
  • } MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG; WM_QUIT消息将导致GetMessage传回0 大写标识符 句柄是一个(通常为32位的)整数,它代表一个对象。 标识符 含义 HINSTANCE 执行...
  • } MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG; 我们来解释一下MSG结构体成员的功能和含义: 1)HWND hwnd;  发生消息的窗口句柄。  windows图形界面应用程序是靠消息来驱动的。我们点击鼠标,按下键盘、...
  •  pMsg,  int  nTarget);   static  CLog *  GetInstance();   //  摧毁singleton的入口   static   void  DestroyInstance(); }; __inline  void  DEBUG_MSG(LPSTR filename,  ...
  • 这一章的代码有点小问题,下面贴出KEYVIEW2中的部分代码。 if(pmsg) free(pmsg);... cLinesMax=cyClientMax/... pmsg=(PMSG)malloc(cLinesMax*sizeof(MSG)); cLines=0; 上面是我更改后的代码,原书中的代码如
  • 设计模式之美笔记12

    2020-08-23 15:36:39
    记录学习王争的设计模式之美 课程 笔记和练习代码,以便回顾复习,共同进步 文章目录观察者模式原理及应用场景剖析基于不同应用场景的不同实现方式异步非阻塞观察者模式的简单实现EventBus框架功能需求guava ...
  • 基于区块链的传感器数据保护系统的设计与实现
  • 基于区块链的传感器数据保护系统的设计与实现
  • main.c /************************************************************************* > File Name: main.c > Author: HuangShixin >... > Created Time: 2020年09月05日 星期六 13时48分17秒 ...
  • Linux的suspend机制的设计原理

    千次阅读 2010-02-09 20:36:00
    error = device_suspend(PMSG_FREEZE); //设备暂时停止,因为以下要设置很多状态,这样可以保证状态稳定 ... if ((error = swsusp_suspend())) //机器准备进入suspend goto Done; if (in_suspend) { ...
  • Windows程序设计:第一个窗口

    千次阅读 2009-10-22 21:53:00
    .dml {border:2px solid green;width:200px;background-color:#eeeeee;margin:0 0 0 0}.ddm {background-color:#cccccc;margin-left:0mm} 目录: 1.窗口程序 2.分析 注册窗口类别
  • 界面设计技巧

    2011-12-30 16:09:28
    BOOL CBApp::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class CBDevice* pDevice = m_pSetting->getCurrentDevice(); if(pDevice !=
  • 深入浅出Win32多线程设计之MFC的多线程作者:宋宝华出处:天极开发责任编辑: 方舟 [ 2006-01-19 13:42 ]在MFC程序中创建一个线程,宜调用AfxBeginThread函数1、创建和终止线程 在MFC程序中创建一个线程,宜调用...
  • 跟踪发现是下面函数的问题:void CSubject::OnMsg(CSMSG *pMsg){ for(list::iterator it = m_lstMsgListener.begin(); it != m_lstMsgListener.end(); it ++) { ASSERT( NULL != (*it) ); 
  • 设计模式------中介者模式(Mediator Pattern)   一、引子  中介在现实生活中并不陌生,满大街的房屋中介、良莠不齐的出国中介……。它们的存在是因为它们能给我们的生活带来一些便利:租房、买房...
  • 前几天,刚写的一个...跟踪发现是下面函数的问题:void CSubject::OnMsg(CSMSG *pMsg){ for(list::iterator it = m_lstMsgListener.begin(); it != m_lstMsgListener.end(); it ++) { ASSERT( NULL != (*it) ); 

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,010
精华内容 1,204
关键字:

pmsg设计