子窗口控件 |
|
回忆第七章的CHECKER程序。这些程序显示了矩形网格。当您在一个矩形中按下鼠标按键时,该程序就画一个x;如果您再按一次鼠标按键,那么x就消失。虽然这个程序的CHECKER1和CHECKER2版本只使用一个主窗口,但CHECKER3版本却为每个矩形使用一个子窗口。这些矩形由一个叫做ChildProc的独立窗口消息处理程序维护。
如果有必要,无论矩形是否被选中,都可以给ChildProc增加一种向其父窗口消息处理程序(WndProc)发送消息的手段。通过呼叫GetParent,子窗口消息处理程序能确定其父窗口的窗口句柄:
其中,hwnd是子窗口的窗口句柄。它可以向其父窗口消息处理程序发送消息:
那么message应该设定为什么呢?您可以随意地设定,数值大小可以与WM_USER相同或更大,这些数字代表和预先定义的WM_ 消息不冲突的消息。也许对这个消息,子窗口可以将wParam设定为它的子窗口ID。如果在该子窗口单击,那么lParam可以被设为1;如果未在该子窗口上单击,那么lParam将被设为0。这是处理方式的一种选择。
事实上,这是在建立一个「子窗口控件」。当子窗口的状态改变时,子窗口处理鼠标和键盘消息并通知父窗口。使用这种方法,子窗口就变成了其父窗口的高阶输入设备。它将与自己在屏幕上的图形外观相应的处理,对使用者输入的响应以及在发生重要的输入事件时通知另一个窗口的方法给封装起来。
虽然您可以建立自己的子窗口控件,但是也可以利用一些预先定义的窗口类别(和窗口消息处理程序)来建立标准的子窗口控件,您一定在别的Windows程序中看到过这些控件。这些控件采用的形式有:按钮、复选框、编辑方块、清单方块、下拉式清单方块、字符串卷标和卷动列。例如,如果想在您的电子表格程序的某个角落放置一个标有「Recalculate」的按钮,那么您可以通过呼叫CreateWindow来建立这个按钮。您不必担心鼠标操作、按钮显示操作或按下该按钮时的自动闪烁操作,这些是由Windows内部完成的。您所要做的只是拦截WM_COMMAND消息-当按钮被按下时,它通过这一消息通知您的窗口消息处理程序。真的这样简单吗?是的,一点也没错。
子窗口控件在对话框中最常用。在第十一章中您将会看到,子窗口控件的位置和尺寸,是在范例程序的资源描述叙述中的对话框模板里定义的。但是,您也可以使用预先定义的,在普通窗口显示区域里的子窗口控件。您可以呼叫一次CreateWindow来建立一个子窗口,并通过呼叫MoveWindow来调整子窗口的位置和尺寸。父窗口消息处理程序向子窗口控件发送消息,子窗口控件向父窗口消息处理程序传回消息。
在建立普通窗口时,首先定义窗口类别,并使用RegisterClass将其注册到Windows中,然后用CreateWindow命令依据该窗口类别建立一个普通窗口,从第三章开始,我们就是这么做的。但是,当您使用预先定义的某个控件时,不必为子窗口注册窗口类别,窗口类别已经存在于Windows之中,并且有一个预先定义的名字。您只需在CreateWindow中把它们用作窗口类别参数。CreateWindow中的窗口样式参数准确地定义了子窗口控件的外形和功能。Windows内建了处理发送给依据这些窗口类别建立的子窗口消息的窗口消息处理程序。
直接在您的窗口上使用子窗口控件完成某些任务,这些任务的层次低于在对话框中使用子窗口控件所要求的层次。这里,对话框管理器在您的程序和控件之间增加一个隔离层。值得一提的,您可能会发现在您的窗口上建立的子窗口控件,没有利用Tab键或方向键将输入焦点从一个控件移动到另一个控件的内部功能。子窗口控件能够获得输入焦点,但是获得后,它将不能把输入焦点传回给父窗口。这就是本章要解决的问题。
Windows程序设计的文件在两个地方讨论了子窗口控件:首先是,简单的常用控件,我们可以在/Platform SDK/User Interface Services/Controls的文件所描述的无数对话框中看到。这些子窗口包括按钮(其中包括复选框的单选按钮)、静态控件(例如文字卷标)、编辑方块(您可以在此编辑一行或多行文字)、卷动列、清单方块和下拉式清单方块。除下拉式清单方块以外,在Windows 1.0中就包括了这些控件。这部分的Windows文件还包括Rich Text文字编辑控件,它与编辑方块相似,但还允许编辑不同字体与样式的格式化文字,以及桌面应用工具列。
相对于「常用控件」,还有一些神秘的特殊控件。这些控件在/Platform SDK/User Interface Services/Shell and Common Controls/Common Controls描述。本章不讨论常用控件,但它们将出现在本书的其它部分。在这部分的Windows文件中,很容易找到您想从别的Windows应用程序中应用到您自己的应用程序里头那些部分信息。
下面我们将通过叫做BTNLOOK(「button look」)的程序来开始介绍按钮窗口类别,如程序9-1所示。BTNLOOK建立10个子窗口按钮控件,每个控件对应一个标准的按钮样式,因此共有10种标准按钮样式。
BTNLOOK.C
/*--------------------------------------------------------------------------
BTNLOOK.C -- Button Look Program
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include <windows.h>
struct
{
int iStyle ;
TCHAR * szText ;
}
button[] =
{
BS_PUSHBUTTON, TEXT ("PUSHBUTTON"),
BS_DEFPUSHBUTTON, TEXT ("DEFPUSHBUTTON"),
BS_CHECKBOX, TEXT ("CHECKBOX"),
BS_AUTOCHECKBOX, TEXT ("AUTOCHECKBOX"),
BS_RADIOBUTTON, TEXT ("RADIOBUTTON"),
BS_3STATE, TEXT ("3STATE"),
BS_AUTO3STATE, TEXT ("AUTO3STATE"),
BS_GROUPBOX, TEXT ("GROUPBOX"),
BS_AUTORADIOBUTTON, TEXT ("AUTORADIO"),
BS_OWNERDRAW, TEXT ("OWNERDRAW")
} ;
#define NUM (sizeof button / sizeof button[0])
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("BtnLook") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Button Look"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton[NUM] ;
static RECT rect ;
static TCHAR szTop[] = TEXT ("message wParam lParam"),
szUnd[] = TEXT ("_______ ______ ______"),
szFormat[] = TEXT ("%-16s%04X-%04X %04X-%04X"),
szBuffer[50] ;
static int cxChar, cyChar ;
HDC hdc ;
PAINTSTRUCT ps ;
int i ;
switch (message)
Apache MINA(Multipurpose Infrastructure for Network Applications) 是 Apache 组织一个较新的项目,它为开发高性能和高可用性的网络应用程序提供了非常便利的框架。当前发行的 MINA 版本支持基于 Java NIO 技术的 TCP/UDP 应用程序开发、串口通讯程序(只在最新的预览版中提供),MINA 所支持的功能也在进一步的扩展中。目前正在使用 MINA 的软件包括有:Apache Directory Project、AsyncWeb、AMQP(Advanced Message Queuing Protocol)、RED5 Server(Macromedia Flash Media RTMP)、ObjectRADIUS、Openfire 等等。 以上是从网上找到的mina框架简单介绍。 一、相关资源下载 (1)Apache官方网站:http://mina.apache.org/downloads.html (2) Android用jar包(包括官网的资源,我会一律放在百度网盘下) 二、Mina简单配置 二、Mina服务端 我这边使用的是mina2.0版本,所以可能与mina1.0的版本有所不同。那么首先在服务器端创建开始
由于正在开发的项目中要求加入及时通信功能(游戏方面),所以在网上找了好几种框架,像openfire、tigase等都是基于Xmpp协议开发的优秀框架。但这些侧重于消息的推送,不适合游戏上的简单交互。所以后来找到了mina这个框架,顺手搭建起来。接下来就是这几天学习的总结了,文章里面没有涉及到逻辑层的方面,只是简单的实现即时通信功能。资源下载我会放在文章的最后面。
分别为 mina-core-2.0.7.jar slf4j-log4j12-1.7.6.jar slf4j-api-1.7.6.jar log4j-1.2.14.jar(日志管理包)
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\Tomcat 5.5\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL
log4j.logger.com.canoo.webtest=WARN
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN
log4j.rootCategory=INFO, stdout , R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R.File=D:\\Tomcat 5.5\\logs\\qc.log
log4j.appender.R.layout=org.apache.log4j.PatternLayout
1log4j.appender.R.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
log4j.logger.com.neusoft=DEBUG
log4j.logger.com.opensymphony.oscache=ERROR
log4j.logger.net.sf.navigator=ERROR
log4j.logger.org.apache.commons=ERROR
log4j.logger.org.apache.struts=WARN
log4j.logger.org.displaytag=ERROR
log4j.logger.org.springframework=DEBUG
log4j.logger.com.ibatis.db=WARN
log4j.logger.org.apache.velocity=FATAL
log4j.logger.com.canoo.webtest=WARN
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=DEBUG
log4j.logger.org.logicalcobwebs=WARN
2 //日志类的实现
3 private static Logger logger = Logger.getLogger(Demo1Server.class);
4 //端口号,要求客户端与服务器端一致
5 private static int PORT = 4444;
6
7 public static void main(String[] args){
8 IoAcceptor acceptor = null;
9 try{
10 //创建一个非阻塞的server端的Socket
11 acceptor = new NioSocketAcceptor();
12 //设置过滤器(使用mina提供的文本换行符编解码器)
13 acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"),LineDelimiter.WINDOWS.getValue(),LineDelimiter.WINDOWS.getValue())));
14 //自定义的编解码器
15 //acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new CharsetCodecFactory()));
16 //设置读取数据的换从区大小
17 acceptor.getSessionConfig().setReadBufferSize(2048);
18 //读写通道10秒内无操作进入空闲状态
19 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
20 //为接收器设置管理服务
21 acceptor.setHandler(new Demo1ServerHandler());
22 //绑定端口
23 acceptor.bind(new InetSocketAddress(PORT));
24
25 logger.info("服务器启动成功... 端口号未:"+PORT);
26
27 }catch(Exception e){
28 logger.error("服务器启动异常...",e);
29 e.printStackTrace();
30 }
31 阅读更多内容
没有评论:
发表评论