4.3 配置对话框窗口实现
属性表是一个系统定义的对话框,它管理页及为他们提供一个公共的容器。一个属性表可以包含一页或者多页。一页可以包含设置项目的字体类型风格,大小,颜色等属性的控制。每一页可以有一个标签,用户根据标签来选择每一页。在创建属性表对话框时。过填充一双PROPSHEETPAGE结构定义了页(pages),在PROPSHEETHEADER函数中指定了它的地址,并调用了PropertySheet函数。对话框模板,图标和页的标签(label)被从应用程序的可执行文件中的资源装入。属性表的图标也同样被从应用程序的资源中装入(引用MSDN关于属性表的相关介绍)
typedef struct _PROPSHEETPAGE {
DWORD dwSize;
DWORD dwFlags;
HINSTANCE hInstance;
union {
LPCSTR pszTemplate;
LPCDLGTEMPLATE pResource;
};
union {
HICON hIcon;
LPCSTR pszIcon;
};
LPCSTR pszTitle;
DLGPROC pfnDlgProc;
LPARAM lParam;
LPFNPSPCALLBACK pfnCallback;
UINT FAR* pcRefParent;
} PROPSHEETPAGE, FAR* LPPROPSHEETPAGE;
实现的思想:
为了实现多页有效联系在一起。我们需要填充PROPSHEETPAGE结构的相关数据,
如图标,模板,函数过程,标题栏等。在创建一个属性表,我们必须定义一页或者多页。例如我们想创建四页,那么就需要定义一个数组,每一项就代表一页。
PROPSHEETPAGE psp[2];//创建两个属性页
PROPSHEETHEADER psh;//定义个对象
其次,在PROPSHEETHEADER函数中指定了它的地址,最后并调用了PropertySheet函如:PropertySheet(&psh);
通过获取这个地址,创建一个属性表对话框,并将创建的属性页链接在一起作为一个整体。
属性表可以嵌入多个页面,在规划好的后台设置的布局后,如果想增加几属性页,那么只需要我们再填充PROPSHEETPAGE 这个结构体相关的信息。
图4-3属性表与对话框关系图
PROPSHEETPAGE psp[2];//设置两页属性页
将其改变为我们所需要的页面数,如需要4页就改变其数组。
PROPSHEETPAGE psp[4];//设置四页属性页
其后,我们在创建两页的属性页里面的提示下,
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[0].hInstance =hInst;
psp[0].pszTemplate =MAKEINTRESOURCE(IDD_Setusual);//应用某个模板
psp[0].pszIcon = NULL;//是否使用图标
psp[0].pfnDlgProc = (DLGPROC)Config_setusual;//窗口函数过程
psp[0].pszTitle = "常规";//标签
psp[0].lParam = 0;
psp[0].pfnCallback = NULL;
主要我们所要改变的其中包括模板pszTemplate,标题psTitle,函数过程pfnDlgProc,图标pszIcon等。而主要我们做的事情,就是在资源文件里面新建多几个对话框,然后把这些对话框作为属性页嵌入到属性表里面去。这样就可以完成添加属性页。
配置对话框窗口的实现,当中还有一件事情要我们去完成的事情。我们增加了几个属性页面,这些页面是不具备功能。为此我们需要对每一个属性页面增加一个函数的过程,这些函数过程的作用是帮手我们完成后台设置的功能。在代码实现的过程中,我们应该注意到一个地方如:
psp[1].pfnDlgProc = (DLGPROC)Config_setkey;
Config_setkey这个就是我们所添加的一个函数名称。
下面为我们创建的一个函数过程:
BOOL WINAPI Config_setkey(HWND hWnd,UINT message, WPARAM wParam,LPARAM lParam)
{
//这里就是我们要添加的代码
}
这个就是其中一个属性页的函数过程,当中的代码就是要我们完成的功能。
4.4 后台配置文件
讲到配置文件,应该先知道什么是用户配置文件,以及它的作用。
概念:什么是用户配置文件?
用户配置文件就是在用户登录时定义系统加载所需环境的设置和文件的集合。它包括所有用户专用的配置设置,如程序项目、屏幕颜色、网络连接、打印机连接、鼠标设置及窗口的大小和位置。
问: 用户配置文件的作用?
用户配置文件有利于帮助用户保存一些用户定义系统设置,起到备份的作用。
应用: 输入法的后台配置文件用途?
话说回头,输入法后台配置文件其实和用户配置文件是一样的,只是在说法上不同而已。我们主要利用配置文件所做的事情就是保存用户对输入法程序的一些基本设置,它的用途就是保存用户的设置。
因此,当我们了解了相关的配置文件,我们的后台设置的工具就可以开展了。
后台布局分析和规划完成后,我们要为整个设置的后台建立一个或者多个数据结构体,这些数据结构体作用在于保存用户设置的信息。这个数据结构体起到重要的作用。
其中,下面是在程序中,定义的一个结构体
typedef struct tagSETCONFIG
{
DWORD Set_shift; //设置shift
DWORD Set_ctrl; //设置ctrol键
DWORD Set_IDC_dot; //设置翻页控件(,. 句话与逗号)
DWORD Set_IDC_add; //设置翻页控件(+- 加号与减号)
DWORD Set_IDC_LeftAndRight; //设置翻页控件(左右控制键)
DWORD Set_IDC_Zkuohao; //设置翻页控件([] 中括号)
DWORD Set_ChineseorEnglist; //初始化英语还是中文状态
DWORD Set_QuanjiaoAndbanjiao;//初始化全角和半角
DWORD Set_ChinesedotAndEnglishdot;// 初始化英语和中文标点符号
DWORD Set_IDC_IsMouseFollow; //是否开启光标跟随事件
int Set_IDC_IDC_nCandNum; //设置候选字数
…………………………………
………………………………………
………………………………………
(省略)
} SETCONFIG;
当用户在后台设置了所选的功能,每次应用的时候,都会保存在一份配置文件中,在这份配置文件,主要格式如下:左边为变量名,右边为保存设定的数据
[IME]
LEFTSHIFT=0
CTRL=0
LRkey=0
Zkuohao=0
……………
………………..
……………………
(省略)
将信息写入配置ini的函数有,
1.所用的WINAPI函数原型为:
BOOL WritePrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpString, LPCTSTR lpFileName );
其中各参数的意义
LPCTSTR lpAppName 是ini文件中的一个字段名.
LPCTSTR lpKeyName 是lpAppName下的一个键名,通俗讲就是变量名.
LPCTSTR lpString 是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.
LPCTSTR lpFileName 是完整的ini文件名
其中,第三个参数很多时候是其他类型的时候,可以通过sprintf来格式转换。
在头文件 #include<stdio.h>中 语法: string sprintf(string format, mixed [args]...);传回值: 字串
4.4.4 读取配置文件
问题:读取配置文件主要解决些什么?
配置文件的作用是保存用户的设置,读取配置文件实现是读取用户自己定义的设置。
解决办法:
保存了自定义的配置,同样还需要进行读取文件中的变量值,因为需要为它编写一个函数作为读取配置的函数。
Void Load_config()
{
//读取配置文件
}
为了实现这样的功能,我们只要设计一个读取配置文件的函数,通过利用如GetPrivateProfileString 或者GetPrivateProfileInt 函数实现读取配置文件中的变量值,然后将这个变量值赋值给一个结构体当中一个全局变量,这个变量就会根据值来判断用户对程序上的设置。
、
什么时候调用配置文件?根据我们的程序开始,就需要进行对配置文件进行加载。也就是说,当我们打开程序的时候,我们的程序就要把我们的加载我们的配置文件,这些配置文件,能够开启用户自选定功能,如皮肤切换,鼠标跟随,初始化状态窗口的状态贴图等等。
4.5 右键弹出菜单实现
菜单是属于系统上一种资源。在规划好功能之后,我们需要对其设置一些标识作为区分这些菜单子项目的每一个项目,方便日后调用。下图为主要的设置图。
图4-5 菜单对应变量图
名称说明:
为了方便读懂菜单的标识,菜单设置需要作一些处理。“IDM_”意思是菜单的标识,ID:为标识,M:解析为菜单英语MENU 的M大写开头。
主要变量说明:
菜单子项名称 | 菜单标识 | 功能作用 |
基本设置 | IDM_SETTING | 调用后台设置对话框 |
更换皮肤 | IDM_CHOOSESKIN | 选择皮肤更换 |
软键盘 | IDM_SOFT | 软键盘设置 |
帮助 | IDM_HELP | 关于输入法的帮助文档 |
关于输入法 | IDM_ABOUT | 关于输入法的介绍 |
皮肤一 | IDM_SKIN1 | 选择第一套皮肤 |
通过鼠标的右键可以弹出浮动式的菜单,为了实现这一效果,首先要了解一个函数。
函数原型:BOOL TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT prcRect);
HMENU hMenu; // 菜单句柄
UINT uFlags;//屏幕位置和鼠标键的标志
int x;//屏幕水平坐标
int y;// 屏幕的垂直坐标
int nReserved;//reserved
HWND hWnd;//窗口句柄
CONST RECT prcRect;//矩形结构的地址
下图为鼠标右键弹出的图:
图4-5 菜单
函数功能:该函数在指定位置显示快捷菜单,并跟踪菜单项的选择。快捷菜单可出现在屏幕上的任何位置。
下面为创建浮动菜单的过程:
第一步:创建一个Menu资源,为菜单添加几个子项。
第二步:使用LoadMenu 获取菜单句柄,
第三步:使用GetSubMenu 激活下来菜单
第四步:使用TrackPopupMenu函数弹出浮动菜单
通过以上的步骤可以实现简单的弹出菜单,通过菜单设置的标识,可以实现一些类似按钮的触发事件。为了能够实现到鼠标右键弹出菜单,我们同样需要一点知道Windows消息WM_RBUTTONUP。这个消息的作用是当我们鼠标右键点击后产生的事件。
case WM_RBUTTONUP:
{
// 调用的函数
break;
问题:实现弹出菜单的用途?
弹出菜单里面有很多子菜单选项,创建菜单提供用户一个方便的功能选择。
实现的过程:
我们都知道,创建菜单后,每一个菜单的子项都会有一个ID值,这个值能唯一标识这个子菜单项。当我们的鼠标点击这个子菜单项后,让其触发一个事件,这个事件就会执行一个过程。如实现弹出一个设置对话框,或者弹出一个帮助文档等等。这个实现过程,我们主要处理WM_COMMAND 命令所发生的事件就可以实现菜单项的功能。
5 输入法部分问题研究
5.1 窗口移动实现
为什么要进行窗口移动?在输入法里面经常会出现这窗口移动的现象,这只是一个很简单的功能。我们所创建的窗口是一种无标题栏的弹出式窗口方式,客户区不能像标题栏那样可以接收相同的消息进行拖动。没有创建代码之前,窗口是不能拖动的,为了方便用户需要,因此需要对窗口进行一个移动的功能实现。实现的方法大概如下:
图5-1(该图为拖动的演示效果图)
窗口的移动其实就是两点之间坐标的移动。实现窗口移动,我们主要知道第一点的坐标,和第二点坐标。通过两点的坐标之间的差值就可以知道窗口移动位置大小。
图5-1(该图为计算的图)
假设,初始位置的左上角端点坐标为(x,y),拖动后坐上角的坐标变成了(x1,y1)那么他们实际上的坐标发上变化为(x1-1),(y1-y) 那么这就可以计算出拖动后的位置了。然后通过MoveWindow(HWND hWnd.int x.int y,int nWidth,int nHeight,BOOL BRePaint)这函数,实现窗口拖动。
注意到地方是,这个窗口是不带边框的窗口。因此当你鼠标按住窗口任何一个位置都是在客户区里面产生消息,让客户区产生移动,那么就需要捕获鼠标的消息,如按下,释放,右键等等这些消息被鼠标的拖动,让窗口发生移动。
5.2 输入法闪烁问题
当我们很高兴和几个朋友玩游戏的时候,输入利用输入法进行文字通信的时候,输入法的窗口总是出现不断闪烁的问题?身边很多网友都有相同的问题,每当在全屏游戏的时候,都会出现窗口闪烁的问题。为什么会这样呢?
查阅相关的资料,有一种说法是显卡的驱动程序引起的,由于显卡版本过低造成的原因,解决的办法是到显卡商的官方网站更新驱动。有一些说法是由于游戏本身的设计产生。造成这个原因的说法很多,有一些人提出是由于窗口重叠的问题产生窗口不断闪烁的原因。解决的办法是主窗口进行剪裁,让输入法的窗口与游戏的主窗口能够融合在一起。这些可以交给程序完成。但是,现今的输入法普遍都存在这样的闪烁的问题,也许是由于开发的时候没有注意到这样的闪烁问题,直接造成的结果,窗口像星星那些闪闪发光,如果你不介意的话,把它当作流星看待,也许你会容忍这样的问题。相反,如果你是一个追求完美的主义者,游戏发烧者,当然不会容忍这个一个在游戏当中让我不爽的地方。鉴于,研究的篇幅有限,以及对闪烁问题的解决办法水平有限,只能提出一点,就是在开发输入法当中,必须考虑到闪烁的问题,否则推出市场之前,这样的一个bug是很多客户不可以容忍的。告诫一句话,不要在客户面前装扮成若无其事。毕竟,消费者的眼光是雪亮的。这会导致不好的结果和连锁反应。
因此,在开发输入法的时候必须考虑到这样的一个闪烁问题,以及解决的办法
5.3字体变化与窗口颜色变化
怎样才可以改变输入窗口时候的字体变化,与窗口颜色变化呢?不管是字体颜色大小,类型或者窗口的颜色都可以使用到系统一些结构体来设置。为了实现这些功能,我们需要定义一些操作。大概的思路,假设我们要对这字进行改变,我们所做的事情可以调用系统的字体选择对话框,当对话框选择这些字体的大小,颜色或者类型,我们只需要知道这个结果,然后把这个结果返回到这输入窗口的字体句柄HFONT中。随后,我们进行需要窗口更新,改变其状态。
图5-3(字体对话框与输入窗口对话框值传输)
同样,如果我们想改变字体或者窗口的颜色,同样的原理是调用系统的颜色对话框,然后对其进行选择的值传给输入窗口
图5-3(输入窗口对话框与颜色窗口对话框值传输)
有一点不同的是窗口在改变颜色的时候,需要定义一个画刷,这个画刷比喻为现实中的画刷工具,我们把颜色对话框RGB的值传输给画刷,通过这些值改变了窗口颜色
参考文献
[1] 张之超 刘毅慧 孔凡敏 孙路.Windows 程序设计[M].北京:人民邮电出版社出版,1999.1-371
[2] 求是科技.Windows API 程序设计参考大全[M].北京:人民邮电出版2006.1-79,90-106
[3] 包晓露 李萱.Windows 编程指南[M].北京:电子工业出版社,1992.1-55
[4] 苏娜 张凯.炫数码色构网页[M].北京:中国宇航出版社,2005.1-31
[5] MSDN.Microsoft.www.msdn.com.
[6] 启程软件.浅谈输入法编程[Z].www.vckbase.com.
[7] 输入法编程指南[Z]. http://www.3800hk.com/Article/cxsj/cjiajia/xtkzcjj/ 2005-08-06 /Article_27345.html
[8] 色彩系列教程(1)[Z]. http://edu.itbulo.com/200510/57682.htm
[9] 第二篇 输入法发展简史[Z]. http://znwuhang.com/fazhanshi.htm
[10] 网页设计配色应用实例剖析——蓝色系[Z].http://edu.itbulo.com/200703/
112020.htm
[11] 关于DDB与DIB概念的问题[Z].
http://www.jcgc.com.cn/software/p272/A27233490.shtml
[12] 如何在DIRECTX全屏模式下正常显示输入法[Z]
http://topic.csdn.net/t/20010308/21/81503.html
[13] 属性表概述[2].教程在线.Host01.Com