posts - 58,  comments - 75,  trackbacks - 0
WTL中的窗口消息的映射和自定义窗口消息映射

窗口消息的映射是通过宏MESSAGE_HANDLER完成的。
MESSAGE_HANDLER( 消息ID,消息处理函数 )。
自定义的消息也是通过这个宏来映射的

添加窗口消息函数后的对话框的定义如下
#include < atlapp.h >
#include "resource.h"

const int WM_MY_MESSAGE = WM_USER+1; //自定义消息ID

class CMainDialog : public CDialogImpl< CMainDialog >
{
public:
    enum { IDD = IDD_MAINDLG };

public:
    BEGIN_MSG_MAP( CMainDialog )
        MESSAGE_HANDLER( WM_INITDIALOG, OnInitDialog ) //系统的窗口消息映射,窗口初始化消息
        MESSAGE_HANDLER( WM_MY_MESSAGE, OnMyMessage ) //自定义消息的映射
        COMMAND_ID_HANDLER( IDOK, OnOk ) //控件消息的映射
        COMMAND_ID_HANDLER( IDCANCEL, OnCancel )
        COMMAND_ID_HANDLER( IDC_SENDMESSAGE_BUTTON, OnSendMyMessage ) //用来发送自定义消息的按钮消息映射
    END_MSG_MAP()

public:
    //窗口初始化消息映射函数,这是个窗口系统消息
    LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
    {
        // center the dialog on the screen
        CenterWindow();

        return TRUE;
    }

    LRESULT OnOk( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled )
    {
        EndDialog( wID );
        return 0;
    }

    LRESULT OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled )
    {
        EndDialog( wID );
        return 0;
    }

    //发送自定义消息
    LRESULT OnSendMyMessage( WORD wNotfyCode, WORD wID, HWND hWndCtl, BOOL &bHandled )
    {
        //ATL::CWindow的SendMessage的调用
        SendMessage( WM_MY_MESSAGE );
        return 0;
    }

    //处理自定义消息
    LRESULT OnMyMessage( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
    {
        //ATL::CWindow的MessageBox的调用
        MessageBox( "This is MyMessage Handle" ); //弹出个对话框
        return 0;
    }
};
posted @ 2007-05-09 11:59 walkspeed 阅读(1005) | 评论 (0)编辑 收藏
WTL创建对话框。
要用到头文件 atlapp.h

对话框的定义如下
#include < atlapp.h >
class CMainDialog : public CDialogImpl< CMainDialog >
{
    //用户代码
}

CDialogImpl类是WTL中的模式对话框的基类。他利用了奇异自递归模板技术,来获得继承类的实际行为。
有了定义我们要给这个对话框一个窗口资源。很简单,只要代码中定义一个IDD的枚举量就可以了。
枚举量的值为窗口资源的ID。对话框的定义代码演化为如下
#include < atlapp.h >
class CMainDialog : public CDialogImpl< CMainDialog >
{
public:
    enum { IDD=IDD_MAINDLG };//一定要在public域,否则没办法访问,编译时报错
    //用户代码
}

就这样进行编译,编译器会报错,说CMainDialog是个抽象类,不能实例化。
其原因是ProessWindowMessage函数是个抽象地。
我们是不是要手动添加这个函数呢?可以。但对于编写代码来说并不方便。
这里要用到ATL中的消息映射宏了。
BEGIN_MSG_MAP( 类名 )
END_MSG_MAP()
有了这两个宏对后,就自动的添加了ProessWindowMessage函数了,而且添加消息映射的函数也方便。
现在对话框的定义代码演化为如下了
#include < atlapp.h >
class CMainDialog : public CDialogImpl< CMainDialog >
{
public:
    enum { IDD=IDD_MAINDLG };//一定要在public域,否则没办法访问,编译时报错
    
public:
    BEGIN_MSG_MAP( CMainDialog )
    END_MSG_MAP()
    //用户代码
}

有了以上代码,对话框就可以显现在屏幕上了。但是这个对话框没有办法推出,应为没有一个消息映射函数。
接不到推出的消息。
我们有添加两个消息映射,分别对应界面上的OK按钮和Cancel按钮。这两个是button控件,我们用控件的消息映射
COMMAND_ID_HANDLER( ID, Fun )。
添加消息映射后的对话框类定义如下
#include < atlapp.h >
class CMainDialog : public CDialogImpl< CMainDialog >
{
public:
    enum { IDD=IDD_MAINDLG };//一定要在public域,否则没办法访问,编译时报错
   
public:
    BEGIN_MSG_MAP( CMainDialog )
        COMMAND_ID_HANDLER( IDOK, OnOk )
        COMMAND_ID_HANDLER( IDCANCEL, OnCancel )
    END_MSG_MAP()
   
public:
    LRESULT OnOk( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled )
    {
        EndDialog( wID );//推出对话框
        return 0;
    }

    LRESULT OnCancel( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL &bHandled )
    {
        EndDialog( wID );//推出对话框
        return 0;
    }
    //用户代码
};

posted @ 2007-05-09 11:18 walkspeed 阅读(1319) | 评论 (0)编辑 收藏
程序的进入函数不是C/C++的进入函数main,而是微软的进入函数winMain。其形式如下
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
    //用户代码
    ...............
    return 0;
}

WTL是在ATL的基础上发展起来的,要用到ATL中的模块类CComModule,所以要初始化COM库。
初始化COM库调用CoInitialize,卸载COM库调用CoUninitialize。程序形式如下
#include < atlbase.h >

int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
    CoInitialize( NULL );//用于应用程序
    //用户代码
    ...............
   
    CoUninitialize();
    return 0;
}

WTL的应用程序部分的代码封装在了CAppModule中。要定义一个CAppModule的全局变量,保证在程序启动前就被构造好
CAppModule是继承的ATL中的CComModule类。程序形式演变成如下
#include < atlbase.h >
#include < atlapp.h > //WTL要用到的

int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
    CoInitialize( NULL );//用于应用程序
     _Module.Init( NULL, hInstance );//初始化一个应用程序
    //用户代码
    ...............
    _Module.Term();//销毁
    CoUninitialize();
    return 0;
}
posted @ 2007-05-09 10:42 walkspeed 阅读(820) | 评论 (0)编辑 收藏
    C++标准库中的文件流类提供的各种操作中没有直接获得正在操作的文件的大小的函数。要获得文件大小得转个弯,用如下的方法
    假设我们有了一个已经打开的文件对象ifile。
    先将文件内的位置指针移到文件尾
    ifile.seekg( 0, ios::end );
    再读取当前位置,这就是文件的大小了。
    long filelength = ifile.tellg();

posted @ 2007-05-02 17:04 walkspeed 阅读(1032) | 评论 (0)编辑 收藏
通过文件流读取数据
ifstream类代表读文件对象,所有的读操作都在这个类中。

read成员函数,用来读取数据到指定的buf中。
这个成员函数来至basic_istream类。
函数原型(来直MSDN文档)
basic_istream& read( char_type *_Str, streamsize _Count );
_Str   字符指针
_Count 要读取的字符数量

get成员函数,用来读取一个或多个字符
这个成员函数来至basic_istream类。
函数原型(来直MSDN文档)
int_type get( ); 读取一个字符,不过是作为int类型返回
basic_istream& get( char_type& _Ch ); 读取一个字符
basic_istream& get( char_type *_Str, streamsize _Count ); 读取指定数量的字符
basic_istream& get( char_type *_Str, streamsize _Count, char_type _Delim ); 读取指定数量的字符,但与到与_Delim相同的字符就停止
basic_istream& get( basic_streambuf<Elem, Tr> *_Strbuf );
basic_istream& get( basic_streambuf<Elem, Tr> *_Strbuf, char_type _Delim );

peek成员函数,用来返回下一个字符,当不从istream的buf中移出
这个成员函数来至basic_istreamlei。
函数原型(来至MSDN文档)
int_type peek( );

getline成员函数,用来读取一行数据
这个成员函数来至basic_istream类
函数原型(来至MSDN文档)
basic_istream& getline( char_type *_Str, streamsize _Count );
basic_istream& getline( char_type *_Str, streamsize _Count, char_type _Delim );

readsome成员函数,用于读取指定数量的数据到buf中
这个函数来至basic_istream类。
函数原型(来至MSDN文档)
streamsize readsome( char_type *_Str, streamsize _Count );

>>运算符重载
对C++基本类型进行了重载操作。可以直接读取这些数据。但会跳过控制字符。
用户可以扩展这个运算符操作的类型。
这个读取是有类型的。


posted @ 2007-05-02 16:57 walkspeed 阅读(3399) | 评论 (1)编辑 收藏
C++ STL中的对文件操作的类
ifstream 用于读文件
ofstream 用于写文件
fstream  用于读写文件

打开文件
可以在够高文件流对象时直接打开
ifstream ifile( 文件名 )
ofstream ofile( 文件名 )
fstream  file( 文件名 )

也可以用open行为
ifstream ifile
ifile.open( 文件名 )
ofstream ofile
ofile.open( 文件名 )
fstream file
file.open( 文件名 )

关闭文件
文件对象销毁时自动关闭文件。
也可用close关闭文件。
ifile.close()
ofile.close()
file.close()

文件大开放式标致
这写标致定义在iso_base类中。分别如下
in     打开,用于读取(这是ifstream的缺省模式)
out    打开,用于改写(这是ofstream的缺省模式)
app    写入是始终添加与尾端
ate    打开文件之后令读写位置移至文件尾端
trunc  将先前的文件内容移除
binary 二进制方式打开
这些标致和或在一起。
这些标致作为对象构造或open行为的第二个参数,来定义文件打开分方式。

随机存储
用于读文件的随机存储
tellg()     返回读取的位置
seekg( pos )  从当前位置移动pos个位子(绝对移送)
seekg( offset, rpos )  以rpos位置开始移动offset个位置(相对移动)

用于写文件的随机存储
tellp()       返回写入的位置
seekp( pos )  从当前位置移动pos个位子(绝对移送)
seekp( offset, rpos )  以rpos位置开始移动offset个位置(相对移动)

读数据
利用read行为
ifstream ifile
ifile.read(buf,length)

写数据
利用write行为
ofstream ofile
ofile.write(buf,length)  
posted @ 2007-05-02 13:31 walkspeed 阅读(1528) | 评论 (0)编辑 收藏
       Signal会安优先级的不同来调用不同组的slot。这样要求signal能根据不同的优先级来管理slot组。典型的实现方法是用std::map。将其定义为如下形式std::map< int, slot >。由于每个优先级下可能有一组slot,所以要将这一组slot组织到一起管理,在boost signal中使用std::list来管理,其可能的形式大体如下std::list< slot >。这样就要修改刚才定义的map了,修改后的map可能的定义如下std::map< int, std::list< slot > >

      在实际的boost signal中并没有直接的存储slotboost signal库中有个slot类),而是存储了functionboost function类的对象)对象。而且为了方便控制signalfunction之间的联系,引入了connection类,用来表示signalfunction之间的联系。Connection的对象当然和一个function放在了一起。这样boost signal提供了一个connection_slot_pair类来存储一个functionconnection对。这样在boost signal中一个slot组的实际定义如下std::list< connection_slot_pair >。并且被重定义为group_list类型(typedef std::list<connection_slot_pair> group_list)。相应的在boost signalmap的实际定义如下std::map<stored_group, group_list, compare_type>,并且被重定义为slot_container_typetypedef std::map<stored_group, group_list, compare_type> slot_container_type)。将以上的这些东西组织到一个类中,以便于管理。这个类就是named_slot_mapSignal中真正用来管理slot的管理器。

         Named_slot_map的类数据成员如下定义(boost源码中的一部分,数据成员部分)

 

class BOOST_SIGNALS_DECL named_slot_map

{

public:

typedef named_slot_map_iterator iterator;//named_slot_map容器的迭代器

private:

typedef std::list<connection_slot_pair> group_list;//function connection对组类型

typedef std::map<stored_group, group_list, compare_type> slot_container_type;//容器类型

typedef slot_container_type::iterator group_iterator;//容器迭代器类型

typedef slot_container_type::const_iterator const_group_iterator;

 

slot_container_type groups;//定义一个用来管理function connection组的容器对象

group_iterator back;//容器的迭代器对象

};

 

         Named_slot_map也是一个容器。Stl的容器为了外界方便访问容器内数据单元,提供了迭代器。Named_slot_map也有自己的迭代器。这个迭代器就是named_slot_map_iterator类。Named_slot_map提供了以下方法来获得迭代器iterator begin()iterator end()Begin方法提供首迭代器,end方法提供尾迭代器。向容器中插入数据用insert。清除某个数据用而而然erase,清空容器中的所有数据用clear

posted @ 2007-04-25 15:18 walkspeed 阅读(1459) | 评论 (1)编辑 收藏
  敏捷开发中提倡依赖关系倒置,即1依赖接口而非具体类,2使用接口的对象定义接口。
  boost signal中的signal的模板参数是个函数类型。可以将其看成一个接口。signal对象依赖这个接口,而且是有signal定义的。具体类去实现镇魂歌接口(即实现这个函数类型)
  signal和slot框架组成了一个observer模式的实现。signal是出版者,slot是订阅者
posted @ 2007-04-24 19:36 walkspeed 阅读(383) | 评论 (0)编辑 收藏

  本以为slot就是被signal存储并管理的slot。但是通过解读boost的源代码发现这个类并没有被signal直接管理,而仅仅用来构造了下connection。没有发现其他的用途。如果这样,那为何不直接在signal的connect中直接进行connection的构造呢。
  signal的connect函数没有直接接收function对象,而是接收的slot<>对象,而slot<>对象用来接收function。这个function看来未必一定是个函数对象了。可以是个原始函数或类函数了。 这个猜测要证实了才能确定。即便如此,这个类的作用是有限的。不过关于那个tackeable的用法还没有完全高清楚,可能那是这个类存在的理由,也许以后会有什么的发展。但现在确实看不出什么大的用途。
  奇怪于为何在signal中的slot管理器,不去直接管理slot<>的实例,而是管理connection和function的pair。

  个人觉得在slot<>中的最有用处的函数。
void slot_base::create_connection()
{
 basic_connection* con = new basic_connection();

 {
  con->signal = static_cast<void*>(this);
  con->signal_data = 0;
  con->blocked_ = false ;
  con->signal_disconnect = &bound_object_destructed;
 }
 
 data->watch_bound_objects.reset(con);

 scoped_connection safe_connection(data->watch_bound_objects);

 for(std::vector<const trackable*>::iterator i = data->bound_objects.begin();
  i != data->bound_objects.end(); ++i)
 {
  BOOST_SIGNALS_NAMESPACE::detail::bound_object binding;
  (*i)->signal_connected(data->watch_bound_objects, binding);

  BOOST_SIGNALS_NAMESPACE::detail::auto_disconnect_bound_object disconnector(binding);

  con->bound_objects.push_back(binding);
  disconnector.release();
 }

 safe_connection.release();
 data->watch_bound_objects.set_controlling(true);
}

posted @ 2007-04-23 16:57 walkspeed 阅读(815) | 评论 (2)编辑 收藏
        类的数据成员的布局是按某种顺序的,有一个相对与类的头位子的偏移量,这个偏移量的计算方法如下:
     
        (size_t)&(((classname*)0)->members)

        classname 是一个类名,members是类中任何一个数据成员的名字。0在这里是一个地址,这是一个保留地址,它不能作为左值,但可以作为右值,去提取其中的对象。
        在0地址位,构造了一个classname的结构布局。

        在使用中去每次写这个表达式还是很麻烦的。可以用个宏将其包起来,如下

        #difine offsetof( ClassName, MemberName ) (size_t)&(((classname*)0)->members)

        其实这个宏在windows和linux平台下都以提供了。
posted @ 2007-04-08 10:54 walkspeed 阅读(1023) | 评论 (0)编辑 收藏
仅列出标题
共6页: 1 2 3 4 5 6 

<2007年1月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(4)

随笔分类(64)

随笔档案(58)

文章分类(3)

文章档案(3)

相册

收藏夹(9)

C++零碎

好友

搜索

  •  

积分与排名

  • 积分 - 157945
  • 排名 - 163

最新评论

阅读排行榜

评论排行榜