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 閱讀(1041) |
評論 (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 閱讀(1362) |
評論 (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 閱讀(858) |
評論 (0) |
編輯 收藏
C++標準庫中的文件流類提供的各種操作中沒有直接獲得正在操作的文件的大小的函數。要獲得文件大小得轉個彎,用如下的方法
假設我們有了一個已經打開的文件對象ifile。
先將文件內的位置指針移到文件尾
ifile.seekg( 0, ios::end );
再讀取當前位置,這就是文件的大小了。
long filelength = ifile.tellg();
posted @
2007-05-02 17:04 walkspeed 閱讀(1075) |
評論 (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 閱讀(3437) |
評論 (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 閱讀(1563) |
評論 (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中并沒有直接的存儲slot(boost signal庫中有個slot類),而是存儲了function(boost function類的對象)對象。而且為了方便控制signal與function之間的聯系,引入了connection類,用來表示signal與function之間的聯系。Connection的對象當然和一個function放在了一起。這樣boost signal提供了一個connection_slot_pair類來存儲一個function與connection對。這樣在boost signal中一個slot組的實際定義如下std::list< connection_slot_pair >。并且被重定義為group_list類型(typedef std::list<connection_slot_pair> group_list)。相應的在boost signal中map的實際定義如下std::map<stored_group, group_list, compare_type>,并且被重定義為slot_container_type(typedef std::map<stored_group, group_list, compare_type> slot_container_type)。將以上的這些東西組織到一個類中,以便于管理。這個類就是named_slot_map。Signal中真正用來管理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 閱讀(1501) |
評論 (1) |
編輯 收藏
敏捷開發中提倡依賴關系倒置,即1依賴接口而非具體類,2使用接口的對象定義接口。
boost signal中的signal的模板參數是個函數類型。可以將其看成一個接口。signal對象依賴這個接口,而且是有signal定義的。具體類去實現鎮魂歌接口(即實現這個函數類型)
signal和slot框架組成了一個observer模式的實現。signal是出版者,slot是訂閱者
posted @
2007-04-24 19:36 walkspeed 閱讀(429) |
評論 (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 閱讀(856) |
評論 (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 閱讀(1068) |
評論 (0) |
編輯 收藏