小白羊的青春 小白羊的青春
去努力,不一定会失败,不去努力,已代表失败!
关注数: 101 粉丝数: 126 发帖数: 6,690 关注贴吧数: 68
wxWidgets 使用总结 wxWidgets 使用总结 //--------------------------------------------------- 设置vc的include lib include:D:\Trunk\External\wxWidgets-2.9.0\include D:\Trunk\External\wxWidgets-2.9.0\lib\vc_lib\mswu lib:D:\Trunk\External\wxWidgets-2.9.0\lib\vc_lib //--------------------------------------------------- 最大化 必须在Frame create的时候给style一个 wxMAXIMIZE | wxMAXIMIZE_BOX . 表示,窗口可以最大化显示,有一个最大化按钮. 调用函数 Maximize( true ); 来最大化窗口 //----------------------------------------------------- 窗口大小 必须注意,要在 Show( 1 ) 之后才能获得窗口大小 不要使用 GetClientSize() 之类的函数. 首先使用 GetSize() 获得应用程序的大小, 使用 WindowToClientSize() 便可获得client实际大小 //----------------------------------------------------- DC使用 wxClientDx( wxWindow *win ); 随后就可以使用dc的成员函数进行绘图了. //----------------------------------------------------- 分割窗口 #inlcude "wx/splitter.h" 首先创建具有分割功能的窗口 wxSplitterWindow ,算是一个中间容器,注意其父窗口。 使用 SplitVertically( left, right, nWidth ) 对其进行左右分割。 右边panel的宽度(如果不想双击隐藏右侧窗口),则需要设置pane大小 SetMinimumPaneSize( nSize ) 这个窗口只能分割成两个,若需再次分割,要在 wxSplitterWindow 内继续创建 wxSplitterWindow //------------------------------------------------------ 菜单 分为两部分:菜单项 wxMenu 、菜单栏 wxMenuBar 。 创建菜单栏、创建菜单项,将菜单栏通过 wxFrame 的 SetMenuBar() 加载在窗口内。 Append() 至菜单栏的菜单项,点击后产生下拉菜单。通过调用自己的 Append() 添加下拉菜单的菜单项。 //------------------------------------------------------ 标签页 需要一个标签容器 wxNotebook ,通过 AddPage() 向标签页内添加标签。 //------------------------------------------------------ 按钮 wxButton 注意父窗口 位图按钮 wxBitmap 指针,调用 LoadFile() 加载相应的文件。若资源是png。则需要添加 wxImage::AddHandler( new wxPNGHandler ); wxBitmap 创建按钮 //------------------------------------------------------ 组框 #include "wx/combobox.h" 创建 wxComboBox 对象,style 赋值为 wxCB_READONLY ,则为只能选择而不能输入。 删除某项 调用成员函数 Delete( n ); n为选项的下标值 增加新项 调用成员函数 Insert( str, n ); str 为添加的字符串,n为选项下标。 //------------------------------------------------------- 单选框 创建 wxRadioBox 对象,第3个参数为标题名。 参数6 选框数量 参数7 选框字符串数组名 wxString str[]; 参数8 每行几个 //-------------------------------------------------------- 复选框 创建 wxCheckBox 对象,第3个参数为选项内容。 //-------------------------------------------------------- 旋转控件 #include "wx/spinctrl.h" 整数变化,创建 wxSpinCtrl 对象, 参数 7,8,9 分别为 最小值,最大值,每次的差值。 小数变化创建 wxSpinCtrlDouble 参数8 如果第3个参数为空,则以此数字为开始计数。 参数9 每次差值 //--------------------------------------------------------- 滑块 创建 wxSlider 对象, 参数3 默认值 参数4 最小值 参数5 最大值 style wxSL_LABELS 显示数字 wxSL_TOP 滑块的方向 //--------------------------------------------------------- 消息 消息响应函数 Function 的形参一定要注意,普通的是 wxCommandEvent 引用 如果是splitter窗口则要 wxSplitterEvent 在wxFrame子类定义中加入宏 DECLARE_EVENT_TABLE() 在类外定义 event table BEGIN_EVENT_TABLE( xxxx, wxFrame ) EVT_XXXXX( ID, Function ) END_EVENT_TABLE() EVT_XXXX 可在 wx/event.h 内找到相应定义。
wxWidgets实现拖放操作(转) 你可以在你的应用程序中实现拖放源,拖放目标或者两者同时实现. 实现拖放源 要实现一个拖放源,也就是说要提供用户用于拖放操作的数据,你需要使用一个wxDropSource类的实例.要注意下面描述的事情都是在你的应用程序已 经认定一个拖放操作已经开始以后发生的.决定拖放是否开始的逻辑,是完全需要由应用程序自己决定的,一些控件会通过产生一个拖放开始事件来通知应用程序, 在这种情况下,你不需要自己关心这一部分的逻辑(对这一部分的逻辑的关心,可能会让你的鼠标事件处理代码变得混乱).在本章中,也会提供一个何时 wxWidgets通知你拖放操作开始的大概描述. 一个拖放源需要采取的动作包括下面几步: 1 准备工作 首先,必须先创建和初始化一个将被拖动的数据对象,如下所示: wxTextDataObject myData(wxT("This text will be dragged.")); 2 开始拖动 要开始拖动操作,最典型的方式是响应一个鼠标单击事件,创建一个wxDropSource对象,然后调用它的wxDropSource::DoDragDrop函数,如下所示: wxDropSource dragSource(this); dragSource.SetData(myData); wxDragResult result = dragSource.DoDragDrop(wxDrag_AllowMove); 下表列出的标记,可以作为DoDragDrop函数的参数: wxDrag_CopyOnly 只允许进行拷贝操作. wxDrag_AllowMove 允许进行移动操作. wxDrag_DefaultMove 默认操作是移动数据. 当创建wxDropSource对象的时候,你还可以指定发起拖动操作的窗口,并且可以选择拖动使用的光标,可选的范围包括拷贝,移动以 及不能释放等.这些光标在GTK+上是图标,而在别的平台上是光标,因此你需要使用wxDROP_ICON来屏蔽这种区别,正如我们很快就将看到的拖动文 本的例子中演示的那样. 3 拖动 对DoDragDrop函数的调用将会阻止应用程序进行其他处理,直到用户释放鼠标按钮(除非你重载了GiveFeedback函数以便 进行其他的特殊操作)当鼠标在应用程序的一个窗口上移动时,如果这个窗口可以识别这个拖动操作协议,对应的wxDropTarget函数就会被调用,参考 接下来的小节"实现一个拖放目的" 4 处理拖放结果 DoDragDrop函数返回一个拖放操作的结果,这个返回值的类型为wxDragResult,它的枚举值如下表所示: wxDragError 在拖动操作的执行过程中出现了错误. wxDragNone 数据源不被拖动目的接受. wxDragCopy 数据已经被成功拷贝. wxDragMove 数据已经被成功移动(仅适用于Windows). wxDragLink 以完全一个链接操作. wxDragCancel 用户已经取消了拖放操作. 你的应用程序可以针对不同的返回值进行自己的操作,如果返回值是wxDragMove,通常你需要删除绑定在数据源中的数据,然后更新屏幕显示.而如果返回值是wxDragNone,则表示拖动操作已经被取消了.下面举例说明: switch (result) { case wxDragCopy: /* 数据被拷贝或者被链接: 无需特别操作 */ case wxDragLink: break; case wxDragMove: /* 数据被移动,删除原始数据 */ DeleteMyDraggedData(); break; default: /* 操作被取消或者数据不被接受 或者发生了错误: 不做任何操作 */ break; } 下面的例子演示了怎样实现一个文本数据拖放源.DnDWindow包含一个m_strText成员变量,当鼠标左键按下的时候,针对 m_strText的拖放操作开始,拖放操作的结果通过一个消息框显示.另外,拖放操作将会在鼠标已经拖动了一小段距离后才会开始,因此单击鼠标动作并不 会导致一个拖放操作. void DnDWindow::OnLeftDown(wxMouseEvent& event ) { if ( !m_strText.IsEmpty() ) { // 开始拖动操作 wxTextDataObject textData(m_strText); wxDropSource source(textData, this, wxDROP_ICON(dnd_copy), wxDROP_ICON(dnd_move), wxDROP_ICON(dnd_none)); int flags = 0; if ( m_moveByDefault ) flags |= wxDrag_DefaultMove; else if ( m_moveAllow ) flags |= wxDrag_AllowMove; wxDragResult result = source.DoDragDrop(flags); const wxChar *pc; switch ( result ) { case wxDragError: pc = wxT("Error!"); break; case wxDragNone: pc = wxT("Nothing"); break; case wxDragCopy: pc = wxT("Copied"); break; case wxDragMove: pc = wxT("Moved"); break; case wxDragCancel: pc = wxT("Cancelled"); break; default: pc = wxT("Huh?"); break; } wxMessageBox(wxString(wxT("Drag result: ")) + pc); } } 实现一个拖放目的 要实现一个拖放目的,也就是说要接收用户拖动的数据,你需要使用wxWindow::SetDropTarget函数,将某个窗口和一个 wxDropTarget绑定在一起,你需要实现一个wxDropTarget的派生类,并且重载它的所有纯虚函数.另外还需要重载OnDragOver 函数,以便返回一个wxDragResult类型的返回码,以说明当鼠标指针移过这个窗口的时候,光标应该怎样显示,并且重载OnData函数来实现放置 操作.你还可以通过继承wxTexTDropTarget或者wxFileDropTarget,或者重载它们的OnDropText或者 OnDropFiles函数来实现一个拖放目的. 下面的步骤将发生在拖放操作过程当中的拖放目的对象上. 1 初始化 wxWindow::SetDropTarget函数在窗口创建期间被调用,以便将其和一个拖放目的对象绑定.在窗口创建或者应用程序的 其他某个部分,通过函数wxDropTarget::SetDataObject,拖放目的对象和某一种数据类型绑定,这种数据类型将用来作为拖放源和播 放目的进行协商的依据. 2 拖动 当鼠标在拖放目的上以拖动的方式移动时,wxDropTarget::OnEnter,wxDropTarget:: OnDragOver和 wxDropTarget::OnLeave函数将在适当的时候被调用,它们都将返回一个对应的wxDragResult值.以便拖放操作可以对其进行合 适的用户界面反馈. 3 放置 当用户释放鼠标按钮的时候,wxWidgets通过调用函数wxDataObject::GetAllFormats询问窗口绑定的 wxDropTarget对象是否接受正在拖动的数据.如果数据类型是可接受的,那么wxDropTarget::OnData将被调用.拖放对象绑定的 wxDataObject对象将进行对应的数据填充动作.wxDropTarget::OnData函数将返回一个wxDragResult类型的值,这 个值将作为wxDropSource::DoDragDrop函数的返回值. 使用标准的拖放目的对象 wxWidgets提供了了标准的wxDropTarget的派生类,因此你不必在任何时候都需要实现自己的拖放对象.你只需要实现重载这些类的一个虚函数,以便在拖放的时候得到提示. wxTextdropTarget对象可以接收被拖动的文本数据,你只需要重载OnDropText函数以便告诉wxWidgets当有文本数据被放置的时候做什么事情就可以了.下面的例子演示了当有文本数据被放置的时候,怎样将其添加列表框内. // 一个拖放目的用来将文本填加到列表框 class DnDText : public wxTextDropTarget { public: DnDText(wxListBox *owner) { m_owner = owner; } virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text) { m_owner->Append(text); return true; } private: wxListBox *m_owner; }; // 设置拖放目的对象 wxListBox* listBox = new wxListBox(parent, wxID_ANY); listBox->SetDropTarget(new DnDText(listBox)); 下面的例子展示了怎样使用wxFileDropTarget,这个对象可接收从资源管理器里拖动的文件对象,并且报告拖动文件的数目以及它们的名称. // 一个拖放目的类用来将拖动的文件名添加到列表框 class DnDFile : public wxFileDropTarget { public: DnDFile(wxListBox *owner) { m_owner = owner; } virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) { size_t nFiles = filenames.GetCount(); wxString str; str.Printf( wxT("%d files dropped"), (int) nFiles); m_owner->Append(str); for ( size_t n = 0; n < nFiles; n++ ) { m_owner->Append(filenames[n]); } return true; } private: wxListBox *m_owner; }; // 设置拖放目的类 wxListBox* listBox = new wxListBox(parent, wxID_ANY); listBox->SetDropTarget(new DnDFile(listBox)); 创建一个自定义的拖放目的 现在我们来创建一个自定义的拖放目的,它可以接受URLs(网址).这一次我们需要重载OnData和 OnDragOver函数,我们还将实现一个可以被重载的虚函数OnDropURL. // 一个自定义的拖放目的对象,可以拖放URL对象 class URLDropTarget : public wxDropTarget { public: URLDropTarget() { SetDataObject(new wxURLDataObject); } void OnDropURL(wxCoord x, wxCoord y, const wxString& text) { // 当然, 一个真正的应用程序在这里应该做些更有意义的事情 wxMessageBox(text, wxT("URLDropTarget: got URL"), wxICON_INFORMATION | wxOK); } // URLs不能被移动,只能被拷贝 virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def) { return wxDragLink; } // 这个函数调用了OnDropURL函数,以便它的派生类可以更方便的使用 virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) { if ( !GetData() ) return wxDragNone; OnDropURL(x, y, ((wxURLDataObject *)m_dataObject)->GetURL()); return def; } }; // 设置拖放目的对象 wxListBox* listBox = new wxListBox(parent, wxID_ANY); listBox->SetDropTarget(new URLDropTarget); 更多关于wxDataObject的知识 正如我们已经看到的那样,wxDataObject用来表示所有可以被拖放.以及可以被剪贴板操作的数据.wxDataObject最重要的特性之一,是 在于它是一个"聪明"的数据块,和普通的包含一段内存缓冲,或者一些文件的哑数据不同.所谓"聪明"指的是数据对像自己可以知道它内部的数据可以支持什么 数据格式,以及怎样将它的内部数据表现为那种数据格式. 所谓支持的数据格式,意思是说,这种格式可以从一个数据对象的内部数据或者将被设置的内部数据产生.通常情况下,一个数据对象可以支持多种数据格式作为输入或者输出.因此,一个数据对象可以支持从一种格式创建内部数据,并将其转换为另外一种数据格式,反之亦然. 当你需要使用某种数据对象的时候,有下面几种可选方案: 使用一种内建的数据对象.当你只需要支持文本数据,图片数据,或者是文件列表数据的时候,你可以使用wxTextdataObject,wxBitmapDataObject,或wxFileDataObject. 使用wxDataObjectSimple.从wxDataObjectSimple产生一个派生类,是实现自定义数据格式的最简便的 方法,不过,这种派生类只能支持一种数据格式,因此,你将不能够使用它和别的应用程序进行交互.不过,你可以用它在你的应用程序以及你应用程序的不同拷贝 之间进行数据传输. 使用wxCustomDataObject的派生类(它是wxDataObjectSimple的一个子类)来实现自定义数据对象. 使用wxDataObjectComposite.这是一个简单而强大的解决方案,它允许你支持任意多种数据格式(如果你和前面的方法结合使用的话,可以实现同时支持标准数据和自定义数据). 直接使用wxDataObject.这种方案可以实现最大的灵活度和效率,但也是最难的一种实现方案. 在拖放操作和剪贴板操作中,使用多重数据格式最简单的方法是使用wxDataObjectComposite对象,但是,这种使用方法的 效率是很低的,因为每一个wxDataObjectSimple都使用自己定义的格式来保存所有的数据.试想一下,你将从剪贴板上以你自己的格式粘贴超过 两百页的文本,其中包含Word,RTF,HTML,Unicode,和普通文本,虽然现在计算机的能力已经足可以应付这样的任务,但是从性能方面考虑, 你最好还是直接从wxDataObject实现一个派生类,用它来定义你的数据格式,然后在程序中指定这种类型的数据. 剪贴板操作和拖放操作,潜在的数据传输机制将在某个应用程序真正请求数据的时候,才会进行数据拷贝.因此,尽管用户可能认为在自己点击了应用程序的拷贝按钮以后数据就已存在于剪贴板了,但实际上这时候仅仅是告诉剪贴板有数据存在了. 实现wxDataObject的派生类 我们来看一下实现一个新的wxDataObject的派生类要用到哪些东西.至于怎样实现的过程,我们前面已经介绍过了,它是非常简单的.因此,我们在这里不多说了. 每一个wxDataObject的派生类,都必须重载和实现它的纯虚成员函数,那些只能用来输出数据或者保存数据(意味着只能进行单向操作)的数据对象的GetFormatCount函数在其不支持的方向上应该总是返回零. GetAllFormats函数的参考为一个wxDataFormat类型的列表,以及一个方向(获取或设置).它将所有自己在这个方向上支持的数据格式填入这个列表.GetFormatCount函数则用来检测列表中元素的个数. GetdataHere函数的参数是一个wxDataFormat参数,以及一个void*缓冲区.如果操作成功,返回TRue,否则返 回false.这个函数必须将数据以给定的格式填入这个缓冲区,数据可以是任意的二进制数据,或者是文本数据,只要SetData函数可以识别就行了. GetdataSize函数则返回在某种给定的数据格式下数据的大小. GetFormatCount函数返回用于转换或者设置的当前支持数据类型的个数. GetPreferredFormat函数则返回某个指定方向上优选的数据类型. SetData函数的参考包括一个数据类型,一个整数格式的缓冲区大小,以及一个void*类型的缓冲区指针.你可以在适当的时候(比如将其拷贝到自己的内部结构的时候)对其进行适当的解释.这个函数在成功的时候返回TRue,失败的时候返回false. wxWidgets的拖放操作例子 我们通过使用位于samples/dnd目录的wxWidgets的拖放操作的例子,来演示一下怎样制作一个自定义的拥有自定义数据类型 的数据对象.这个例子演示了一个简单的绘图软件,可以用来绘制矩形,三角形,或者椭圆形,并且允许你对其进行编辑,拖放到一个新的位置,拷贝到剪贴板以及 从新粘贴到应用程序等操作.你可以通过选择文件菜单中的新建命令来创建一个应用程序的主窗口.这个窗口的外观如下图所示:这些图形是用继承字DnDShape的类来建模的,数据对象被称为DnDShapeDataObject.在学习怎样实现这个数据对象之前,我们先看一下应用程序是怎样使用它们的. 当一个剪贴板拷贝操作被请求的时候,一个DnDShapeDataObject对象将被增加到剪贴板,这个对象包含当前正在操作的图形的拷贝,如果剪贴板上已经有了一个对象,那么旧的对象将被释放.代码如下所示: void DnDShapeFrame::OnCopyShape(wxCommandEvent& event) { if ( m_shape ) { wxClipboardLocker clipLocker; if ( !clipLocker ) { wxLogError(wxT("Can't open the clipboard")); return; } wxTheClipboard->AddData(new DnDShapeDataObject(m_shape)); } } 剪贴板的粘贴操作也很容易理解,调用wxClipboard::GetData函数来获取位于剪贴板的图形数据对象,然后从其中获取图形 数据.前面我们已经介绍过怎样在剪贴板拥有对应数据的时候允许paste菜单.shapeFormatId是一个全局变量,其中包含了自定义的数据格式名 称:wxShape. void DnDShapeFrame::OnPasteShape(wxCommandEvent& event) { wxClipboardLocker clipLocker; if ( !clipLocker ) { wxLogError(wxT("Can't open the clipboard")); return; } DnDShapeDataObject shapeDataObject(NULL); if ( wxTheClipboard->GetData(shapeDataObject) ) { SetShape(shapeDataObject.GetShape()); } else { wxLogStatus(wxT("No shape on the clipboard")); } } void DnDShapeFrame::OnUpdateUIPaste(wxUpdateUIEvent& event) { event.Enable( wxTheClipboard-> IsSupported(wxDataFormat(shapeFormatId)) ); }
调用dll 两种方案 1.隐式的调用 这种调用方式需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,在使用DLL中的函数时,只须说明一下后就可以直接通过函数名调用DLL的输出函数,调用方法和程序内部其他的函数是一样的。隐式调用不需要调用LoadLibrary()和FreeLibrary()。程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。   当程序员通过隐式调用方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号被写入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序也将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL函数的动态链接。所有被应用程序调用的DLL文件都会在应用程序EXE文件加载时被加载在到内存中。 2.显式调用 这种调用方式是指在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来,并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数,应用程序在调用GetProcAddress函数时使用这一参数。当完成对动态链接库的导入以后,再使用GetProcAddress()获取想要引入的函数,该函数将符号名或标识号转换为DLL内部的地址,之后就可以象使用本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态连接库。
dll 隐式的调用 这种调用方式需要把产生动态连接库时产生的.LIB文件加入到应用程序的工程中,在使用DLL中的函数时,只须说明一下后就可以直接通过函数名调用DLL的输出函数,调用方法和程序内部其他的函数是一样的。隐式调用不需要调用LoadLibrary()和FreeLibrary()。程序员在建立一个DLL文件时,链接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每一个DLL导出函数的符号名和可选的标识号,但是并不含有实际的代码。LIB文件作为DLL的替代文件被编译到应用程序项目中。   当程序员通过隐式调用方式编译生成应用程序时,应用程序中的调用函数与LIB文件中导出符号相匹配,这些符号或标识号被写入到生成的EXE文件中。LIB文件中也包含了对应的DLL文件名(但不是完全的路径名),链接程序也将其存储在EXE文件内部。当应用程序运行过程中需要加载DLL文件时,Windows根据这些信息发现并加载DLL,然后通过符号名或标识号实现对DLL函数的动态链接。所有被应用程序调用的DLL文件都会在应用程序EXE文件加载时被加载在到内存中。 2显式调用 这种调用方式是指在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将自己所做的动态连接库调进来,并指定DLL的路径作为参数。LoadLibary返回HINSTANCE参数,应用程序在调用GetProcAddress函数时使用这一参数。当完成对动态链接库的导入以后,再使用GetProcAddress()获取想要引入的函数,该函数将符号名或标识号转换为DLL内部的地址,之后就可以象使用本应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态连接库。
C++ .hpp与.h的区别 源文件扩展名 hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该hpp文件即可,无需再将cpp加入到project中进行编译。而实现代码将直接编译到调用者的obj文件中,不再生成单独的obj,采用hpp将大幅度减少调用 project中的cpp文件数与编译次数,也不用再发布烦人的lib与dll,因此非常适合用来编写公用的开源库。 hpp的优点不少,但是编写中有以下几点要注意: 1、是Header Plus Plus 的简写。 2、与*.h类似,hpp是C++程序头文件。 3、是VCL专用的头文件,已预编译。 4、是一般模板类的头文件。 5、一般来说,*.h里面只有声明,没有实现,而*.hpp里声明实现都有,后者可以减少.cpp的数量。 6、*.h里面可以有using namespace std,而*.hpp里则无。 7、不可包含全局对象和全局函数。 由于hpp本质上是作为.h被调用者include,所以当hpp文件中存在全局对象或者全局函数,而该hpp被多个调用者include时,将在链接时导致符号重定义错误。要避免这种情况,需要去除全局对象,将全局函数封装为类的静态方法。 8、类之间不可循环调用。 在.h和.cpp的场景中,当两个类或者多个类之间有循环调用关系时,只要预先在头文件做被调用类的声明即可,如下: class B; class A{ public: void someMethod(B b); }; class B{ public : void someMethod(A a); }; 在hpp场景中,由于定义与实现都已经存在于一个文件,调用者必需明确知道被调用者的所有定义,而不能等到cpp中去编译。因此hpp中必须整理类之间调用关系,不可产生循环调用。同理,对于当两个类A和B分别定义在各自的hpp文件中,形如以下的循环调用也将导致编译错误: //a.hpp #include "b.hpp" class A{ public : void someMethod(B b); }; //b.hpp #include "a.hpp" class B{ public : void someMethod(A a); }; 9、不可使用静态成员。 静态成员的使用限制在于如果类含有静态成员,则在hpp中必需加入静态成员初始化代码,当该hpp被多个文档include时,将产生符号重定义错误。唯一的例外是const static整型成员,因为在vs2003中,该类型允许在定义时初始化,如: class A{ public: const static int intValue = 123; }; 由于静态成员的使用是很常见的场景,无法强制清除,因此可以考虑以下几种方式(以下示例均为同一类中方法) 1.类中仅有一个静态成员时,且仅有一个调用者时,可以通过局域静态变量模拟 //方法模拟获取静态成员 someType getMember() { static someType value(xxx);//作用域内静态变量 return value; } 2.类中有多个方法需要调用静态成员,而且可能存在多个静态成员时,可以将每个静态成员封装一个模拟方法,供其他方法调用。 someType getMemberA() { static someType value(xxx);//作用域内静态变量 return value; } someType getMemberB() { static someType value(xxx);//作用域内静态变量 return value; } void accessMemberA() { someType member = getMemberA();//获取静态成员 }; //获取两个静态成员 void accessStaticMember() { someType a = getMemberA();//获取静态成员 someType b = getMemberB(); }; 3.第二种方法对于大部分情况是通用的,但是当所需的静态成员过多时,编写封装方法的工作量将非常巨大,在此种情况下,建议使用Singleton模式,将被调用类定义成普通类,然后使用Singleton将其变为全局唯一的对象进行调用。 如原h+cpp下的定义如下: class A{ public : type getMember(){ return member; } static type member;//静态成员 } 采用singleton方式,实现代码可能如下(singleton实现请自行查阅相关文档) //实际实现类 class Aprovider{ public : type getMember(){ return member; } type member;//变为普通成员 } //提供给调用者的接口类 class A{ public : type getMember(){ return Singleton<AProvider >::getInstance()->getMember(); } }
推荐几款免费的C++图形和游戏库(转) 免费的C++图形和游戏库 C++   成为最流行的编程语言有多种原因,它的应用领域比较广泛其中包括系统软件、设备驱动程序、应用软件、客户端应用以及娱乐应用软件而其中最好的当属视频游戏。   在这篇文章中,我们将介绍一些非常有用的C++图形和游戏方面的库。这些库提供了应用接口,开发者们可以轻易的添加到自己的项目和应用程序里,相信这些库能对您的项目开发有所帮助。   1. Antigrain   AGG(Anti-Grain Geometry)是利用C++编写的一款开源且免费的图形库。AGG不依赖与任何图形API或技术。基本上你可理解为AGG是在内存中使用一些矢量数据进行渲染图片像素引擎。   2. Amanith   AmanithVG SRE是一款纯软件解决方案。市面上已推出最新的OpenVG软件矢量图形引擎。   3. Codehead   4. Oscilloscope Lib   5. Lib SDL   SDL(Simple DirectMedia Layer)是一款跨平台的多媒体库,基于OpenGL提供音频,键盘,鼠标,joystick,2D,3D等多种开发包;支持MPEG播放软件,仿真软件以及多款流行游戏,包括获得Linux大奖的"Civilization: Call To Power".  6. Ogre 3d   OGRE (Object-Oriented Graphics Rendering Engine)是一款利用C++编写的3D图形渲染引擎,OGRE面向对象,便于开发。这些类库使用底层系统库比如Direct3D和 OpenGL,支持world objects以及其他类接口,支持多种场景。 这原文出自【比特网】,转载请保留原文链接: http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fsoft.chinabyte.com%2Fdatabase%2F189%2F12382189.shtml&urlrefer=0fa406990c30e53347648e1583e90453
wxWidgets体系结构 1 体系结构 wxWidgets的体系结构下图所示。wxWidgets的体系结构可以分为4层:wxWidgets公共API层,各个平台Port,用于各个平台的API以及操作系统。2 Libraries 列表 从版本 2.5.0以后,wxWidgets既可以编译成单一的一个大的ibrary(monolithic build),也可以编译成几个小的libraries(multilib build)。WxWidgets默认的是编译成multilib build。 下图列出了wxWidgets libraries以及他们之间的依赖关系。1)wxAui 包含着高级用户界面 docking library。 2) wxBase 所有wxWidgets程序都必须链接本 library。包含了许多数据结构类以及其他公共基类(如wxString,wxWindowbase等)。抽象了平台间的不同。wxBase 可以用来开发控制台程序,不需要任何GUI libraries。 3) wxNet 网络开发有关类: wxSocket 类 (wxSocketClient, wxSocketServer 以及其他相关类) wxSocketOutputStream 和 wxSocketInputStream sockets-based IPC 类 (wxTCPServer, wxTCPClient and wxTCPConnection) wxURL wxInternetFSHandler (a wxFileSystem handler)。 4) wxRichText 通用 rich text 控件。 5) WxXML 包含解析XML文档的类。不建议使用。将来的版本将包含新的XML处理类,包含类似DOM的API。 6) wxCore 基本GUI类,如 GDI类或控件。所有wxWidgets GUI 应用程序必须引用本库。 7) wxAdvanced 高级或是不常用的GUI类。 wxBufferedDC wxCalendarCtrl wxGrid classes wxJoystick wxLayoutAlgorithm wxSplashScreen wxTaskBarIcon wxSound wxWizard wxSashLayoutWindow wxSashWindow 8) wxMedia 多媒体类。目前仅包括wxMediaCtrl ,将来将加入更多的类。 9) wxGL 包含wxGLCanvas 集成OpenGL library。与其他类不同的是,本library不是 monolithic library的一部分,而是总是编译成一个独立的library。 10) wxHTML HTML renderer及其相关类。 11 )wxODBC 数据库类。 12 )wxQA 质量保证类库。目前仅有 wxDebugReport 以及相关类。 13 )wxDbGrid wxDbGridTableBase 类组合了 wxGrid and wxDbTable。 14 )wxXRC 包含wxXmlResource类,读取XRC 格式的XML资源文件。 3 内部代码组织结构如图,是wxWidgets源代码组织结构,大体可以分为六层: 1 )通用代码部分(位于common目录内)。被所有的版本使用,包括数据结构,运行期类型信息,一些被其他类继承的基类,如wxWindowBase等。 2) 一般代码部分(位于generic目录内)。实现与平台无关的高级 widgets。如 wxWizard 和wxCalendarCtrl等。 3) wxUniversal部分(位于univ目录内)。基本窗口控件类,可以用于不提供本地窗口控件的平台如X11和MGL使用。 4 )平台相关代码(位于gtk、msw等目录内)。使用本地API实现类。 5 )外来代码部分,放在一个单独的目录结构中(contrib目录,本图没有列出,位于上一级目录)。 6)第三方代码(位于jpeg,png,regex,zlib等目录中),这些都是独立于wxWidgets的项目,但是wxWidgets使用来实现许多重要的功能。 wxWidgets libraries 和内部代码组织具有交叉关系。如wxNet库里既包含通用代码又包括平台相关代码部分,其他的库又可能包括一般代码部分。 4 类继承关系如图,列举了wxBase和wxCore中部分类的继承关系。 其中wxObject是其他绝大部分类的基础,是万类之首。凡派生于wxObject的类,得以继承数个面向对象的重要特性,包括RTTI(执行期类型识别),Dynamic Creation(动态生成)等。 其中wxWindowGTK和wxTopLevelWindowGTK是于平台有关的类,源码位于gtk目录下。Window下对应的类是wxWindowMSW和wxTopLevelWindowMSW,位于msw目录下。当编译代码时,wxWidgets怎么知道编译哪一个类呢?主要是wxWidgets通过不同的宏定义来实现的: 在app.h中,你可以发现以下代码: #if defined(__WXPALMOS__) #include "wx/palmos/app.h" #elif defined(__WXMSW__) #include "wx/msw/app.h" #elif defined(__WXMOTIF__) #include "wx/motif/app.h" #elif defined(__WXMGL__) #include "wx/mgl/app.h" #elif defined(__WXDFB__) #include "wx/dfb/app.h" #elif defined(__WXGTK20__) #include "wx/gtk/app.h" #elif defined(__WXGTK__) #include "wx/gtk1/app.h" #elif defined(__WXX11__) #include "wx/x11/app.h" #elif defined(__WXMAC__) #include "wx/mac/app.h" #elif defined(__WXCOCOA__) #include "wx/cocoa/app.h" #elif defined(__WXPM__) #include "wx/os2/app.h" 类似的在window.h中,你可以发现: #if defined(__WXMSW__) #define wxWindowNative wxWindowMSW #elif defined(__WXGTK__) #define wxWindowNative wxWindowGTK #elif defined(__WXMGL__) #define wxWindowNative wxWindowMGL #elif defined(__WXX11__) #define wxWindowNative wxWindowX11 #elif defined(__WXMAC__) #define wxWindowNative wxWindowMac #endif class WXDLLEXPORT wxWindow : public wxWindowNative { ...... } 通过指定不同的编译开关,可以编译出平台相关的类库。 参考文献 《Cross-Platform GUI Programming with wxWidgets》,Julian Smart and Kevin Hock with Stefan Csomor. 《wxWidgets 2.8.9: A portable C++ and Python GUI toolkit》,Julian Smart, Robert Roebling, Vadim Zeitlin, Robin Dunn, et al
C++ 使用winsock2.h可能出现的两种编译错误(转) 先整理一些以后会用到的,到时候做个目录以便查找 在我初学Windows网络编程时,曾经遇到过两类编译错误(VC6的Build窗口哗哗的显示了102个Errors),都是些类型未定义或者重复定义问题,让我感到很郁闷。这两种错误情况下的第一条错误信息分别为:错误情形1:mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier 错误情形2:winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition 后来,我静下心来仔细分析一下错误提示及相关文件,终于找到了原因。 我们知道,Windows网络编程至少需要两个头文件:winsock2.h和windows.h,而在WinSock2.0之前还存在一个老版本的winsock.h。正是这三个头文件的包含顺序,导致了上述问题的出现。 先让我们看看winsock2.h的内容,在文件开头有如下宏定义:#ifndef _WINSOCK2API_ #define _WINSOCK2API_ #define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ _WINSOCK2API_很容易理解,这是最常见的防止头文件重复包含的保护措施。_WINSOCKAPI_的定义则是为了阻止对老文件winsock.h的包含,即是说,如果用户先包含了winsock2.h就不允许再包含winsock.h了,否则会导致类型重复定义。这是怎样做到的呢?很简单,因为winsock.h的头部同样存在如下的保护措施:#ifndef _WINSOCKAPI_ #define _WINSOCKAPI_ 再回过头来看winsock2.h,在上述内容之后紧跟着如下宏指令:/* * Pull in WINDOWS.H if necessary */ #ifndef _INC_WINDOWS #include #endif /* _INC_WINDOWS */ 其作用是如果用户没有包含windows.h(_INC_WINDOWS在windows.h中定义)就自动包含它,以定义WinSock2.0所需的类型和常量等。 现在切换到windows.h,查找winsock,我们会惊奇的发现以下内容:#ifndef WIN32_LEAN_AND_MEAN #include #include #include #include #ifndef _MAC #include #include #include #include #endif #include #ifndef _MAC #include #if(_WIN32_WINNT >= 0x0400) #include #include #else #include #endif /* _WIN32_WINNT >= 0x0400 */#endif // 这里省略掉一部分内容 #endif /* WIN32_LEAN_AND_MEAN */ 看到没?windows.h会反向包含winsock2.h或者winsock.h!相互间的包含便是万恶之源! 下面具体分析一下问题是怎么发生的。 错误情形1:我们在自己的工程中先包含winsock2.h再包含windows.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT大于或等于0x400,那么windows.h会在winsock2.h开头被自动引入,而windows.h又会自动引入mswsock.h,此时,mswsock.h里所用的socket类型还尚未定义,因此会出现类型未定义错误。 错误情形2:先包含windows.h再包含winsock2.h,如果WIN32_LEAN_AND_MEAN未定义且_WIN32_WINNT未定义或者其版本号小于0x400,那么windows.h会自动导入旧有的winsock.h,这样再当winsock2.h被包含时便会引起重定义。 这里要说明的是,宏WIN32_LEAN_AND_MEAN的作用是减小win32头文件尺寸以加快编译速度,一般由AppWizard在stdafx.h中自动定义。_WIN32_WINNT的作用是开启高版本操作系统下的特殊函数,比如要使用可等待定时器(WaitableTimer),就得要求_WIN32_WINNT的值大于或等于0x400。因此,如果你没有遇到上述两个问题,很可能是你没有在这些条件下进行网络编程。 问题还没有结束,要知道除了VC自带windows库文件外,MS的Platform SDK也含有这些头文件。我们很可能发现在之前能够好好编译的程序在改变了windows头文件包含路径后又出了问题。原因很简单,Platform SDK中的windows.h与VC自带的文件存在差异,其相同位置的代码如下: #ifndef WIN32_LEAN_AND_MEAN #include #include #include #include #ifndef _MAC #include #include #include #include #endif #include #ifndef _MAC #include #include // 这里直接包含winsock.h #endif #ifndef NOCRYPT #include #include #include #endif #ifndef NOGDI #ifndef _MAC #include #ifdef INC_OLE1 #include #else #include #endif /* !INC_OLE1 */ #endif /* !MAC */ #include #endif /* !NOGDI */ #endif /* WIN32_LEAN_AND_MEAN */ 唉,我们不禁要问MS为什么要搞这么多花样,更让人气愤的是,既然代码不一样,windows.h里却没有任何一个宏定义能够帮助程序辨别当前使用的文件是VC自带的还是PSDK里的。 后来,我写了一个头文件专门处理winsock2.h的包含问题,名为winsock2i.h,只需在要使用WinSock2.0的源文件里第一个包含此文件即可,不过由于前面提到的问题,当使用PSDK时,需要手工定义一下USING_WIN_PSDK,源码如下:// // winsock2i.h - Include winsock2.h safely. // // Copyleft 02/24/2005 by freefalcon // // // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is LESS THAN 0x400, // if we include winsock2.h AFTER windows.h or winsock.h, we get some compiling // errors as following: // winsock2.h(99) : error C2011: 'fd_set' : 'struct' type redefinition // // When WIN32_LEAN_AND_MEAN is not defined and _WIN32_WINNT is NOT LESS THAN 0x400, // if we include winsock2.h BEFORE windows.h, we get some other compiling errors: // mswsock.h(69) : error C2065: 'SOCKET' : undeclared identifier // // So, this file is used to help us to include winsock2.h safely, it should be // placed before any other header files. // #ifndef _WINSOCK2API_// Prevent inclusion of winsock.h #ifdef _WINSOCKAPI_ #error Header winsock.h is included unexpectedly. #endif// NOTE: If you use Windows Platform SDK, you should enable following definition: // #define USING_WIN_PSDK#if !defined(WIN32_LEAN_AND_MEAN) && (_WIN32_WINNT >= 0x0400) && !defined(USING_WIN_PSDK) #include #else #include #endif#endif//_WINSOCK2API_
C/C++中宏使用总结(转) C/C++中宏使用总结 . C/C++中宏总结C程序的源代码中可包括各种编译指令,这些指令称为预处理命令。虽然它们实际上不是C语言的一部分,但却扩展了C程 序设计的环境。本节将介绍如何应用预处理程序和注释简化程序开发过程,并提高程序的可读性。 ANSI标准定义的C语言预处理程序包括下列命令: #define,#error,#i nclude,#if,#else,#elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma等。非常明显,所有预处理命令均以符号#开头,下面分别加以介绍。 1、#define 命令#define定义了一个标识符及一个串。在源程序中每次遇到该标识符时,均以定义的串代换它。ANSI标准将标识符定义为宏名,将替换过程称为宏 替换。命令的一般形式为: #define identifier string 注意: ? 该语句没有分号。在标识符和串之间可以有任意个空格,串一旦开始,仅由一新行结束。 ? 宏名定义后,即可成为其它宏名定义中的一部分。 ? 宏替换仅仅是以文本串代替宏标识符,前提是宏标识符必须独立的识别出来,否则不进行替换。例如: #define XYZ this is a test,使用宏printf("XYZ");//该段不打印"this is a test"而打印"XYZ"。因为预编译器识 别出的是"XYZ" ? 如果串长于一行,可以在该行末尾用一反斜杠' \'续行。 2、#error 处理器命令#error强迫编译程序停止编译,主要用于程序调试。 3、#include 命令#i nclude使编译程序将另一源文件嵌入带有#i nclude的源文件,被读入的源文件必须用双引号或尖括号括起来。例如: #i nclude"stdio.h"或者#i nclude 这两行代码均使用C编译程序读入并编译用于处理磁盘文件库的子程序。 将文件嵌入#i nclude命令中的文件内是可行的,这种方式称为嵌套的嵌入文件,嵌套层次依赖于具体实现。 如果显式路径名为文件标识符的一部分,则仅在哪些子目录中搜索被嵌入文件。否则,如果文件名用双引号括起来,则首先检索当前工作目录。如果未发现文件, 则在命令行中说明的所有目录中搜索。如果仍未发现文件,则搜索实现时定义的标准目录。 如果没有显式路径名且文件名被尖括号括起来,则首先在编译命令行中的目录内检索。 如果文件没找到,则检索标准目录,不检索当前工作目录。 4、条件编译命令 有几个命令可对程序源代码的各部分有选择地进行编译,该过程称为条件编译。商业软件公司广泛应用条件编译来提供和维护某一程序的许多顾客版本。 #if、#else,#elif及#endif #if的一般含义是如果#if后面的常量表达式为true,则编译它与#endif之间的代码,否则跳过这些代码。命令#endif标识一个#if块的 结束。 #if constant-expression statement sequence #endif 跟在#if后面的表达式在编译时求值,因此它必须仅含常量及已定义过的标识符,不可使用变量。表达式不许含有操作符sizeof(sizeof也是编译 时求值)。 #else命令的功能有点象C语言中的else;#else建立另一选择(在#if失败的情况下)。 注意,# else属于# if块。 #elif命令意义与ELSE IF 相同,它形成一个if else-if阶梯状语句,可进行多种编译选择。 #elif 后跟一个常量表达式。如果表达式为true,则编译其后的代码块,不对其它#elif表达式进行测试。否则,顺序测试下一块。 #if expression statement sequence #elif expression1 statement sequence #endif 在嵌套的条件编译中#endif、#else或#elif与最近#if或#elif匹配。 # ifdef 和# ifndef 条件编译的另一种方法是用#ifdef与#ifndef命令,它们分别表示"如果有定义"及"如果无定义"。 # ifdef的一般形式是: # ifdef macroname statement sequence #endif #ifdef与#ifndef可以用于#if、#else,#elif语句中,但必须与一个#endif。 5、#undef 命令#undef 取消其后那个前面已定义过有宏名定义。一般形式为: #undef macroname 6、#line 命令# line改变__LINE__与__FILE__的内容,它们是在编译程序中预先定义的标识符。命令的基本形式如下: # line number["filename"] 其中的数字为任何正整数,可选的文件名为任意有效文件标识符。行号为源程序中当前行号,文件名为源文件的名字。命令# line主要用于调试及其它特殊 应用。 注意:在#line后面的数字标识从下一行开始的数字标识。 7、预定义的宏名 ANSI标准说明了C中的五个预定义的宏名。它们是: __LINE__ __FILE__ __DATE__ __TIME__ __STDC__ 如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序也许还提供其它预定义的宏名。 __LINE__及__FILE__宏指令在有关# line的部分中已讨论,这里讨论其余的宏名。 __DATE__宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。 源代码翻译到目标代码的时间作为串包含在__TIME__中。串形式为时:分:秒。 如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的。编译C++程序时,编译器自动定义了一个预处理名 字__cplusplus,而编译标准C时,自动定义名字__STDC__。 注意:宏名的书写由标识符与两边各二条下划线构成。 (部分内容出自:http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fwww.bc-cn.net%2FArticle%2Fkfyy%2Fcyy%2Fjc%2F200511%2F919.html&urlrefer=3c7375f9a091b88138a45d68eeabfc14) 8、C、C++宏体中出现的#,#@,## 宏体中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个 双引号。 而##被称为连接符(concatenator),用来将两个Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变 量。比如你要做一个菜单项命令名和函数指针组成的结构体的数组,并且希望在函数名和菜单项命令名之间有直观的、名字上的关系。那就可以使用:宏参数## 固定部分。当然还可以n个##符号连接 n+1个Token,这个特性也是#符号所不具备的。 #@的功能是将其后面的宏参数进行字符化。 9、C宏中的变参... ...在C宏中称为Variadic Macro,也就是变参宏。比如: #define myprintf(templt,...) fprintf(stderr,templt,__VA_ARGS__) 或者#define myprintf(templt,args...) fprintf(stderr,templt,args) 第一个宏中由于没有对变参起名,我们用默认的宏__VA_ARGS__来替代它。第二个宏中,我们显式地命名变参为args,那么我们在宏定义中就可以 用args来代指变参了。同C语言的stdcall一样,变参必须作为参数表的最后有一项出现。当上面的宏中我们只能提供第一个参数templt时,C 标准要求我们必须写成: myprintf(templt,);的形式。这时的替换过程为:myprintf("Error!\n",);替换为: fprintf(stderr,"Error!\n",). 这是一个语法错误,不能正常编译。这个问题一般有两个解决方法。首先,GNU CPP提供的解决方法允许上面的宏调用写成: myprintf(templt);而它将会被通过替换变成: fprintf(stderr,"Error!\n",); 很明显,这里仍然会产生编译错误(非本例的某些情况下不会产生编译错误)。除了这种方式外,c99和GNU CPP都支持下面的宏定义方式: #define myprintf(templt, ...) fprintf(stderr,templt, ##__VAR_ARGS__) 这时,##这个连接符号充当的作用就是当__VAR_ARGS__为空的时候,消除前面的那个逗号。那么此时的翻译过程如下: myprintf(templt);被转化为: fprintf(stderr,templt); 这样如果templt合法,将不会产生编译错误。
wxWidgets Windows下codeblocks的安装配置含常见问题(转)  codeblocks+wxWidgets这一对开源组合真是够强大,codeblocks支持的项目类型多的惊人,wxWidgets又为codeblocks加上了相当强劲的可视化程序开发功能,可以说用这对组合来开发程序丝毫不比在VS中用C#困难,而且由于codeblocks和wxWidgets都是开源软件,在windows和linux下都有相应的版本,移植程序就成为一件相当轻松的事情。 以下内容转载自http://tieba.baidu.com/mo/q/checkurl?url=http%3A%2F%2Fshiningray.cn%2Fwindows-shang-pei-zhi-codeblocks-wxwidgets.html&urlrefer=87453759be0c151342df2adbc2c1eb2a,内容有所改动,原文图片没有附上,有需要的去上面的地址查看 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 前提准备   编译器   你至少应该正确安装了免费的MinGW/GCC编译器或者是某种微软的编译器(Express editions是免费的,但是你还需要安装Platform SDK)。如果是用MinGW/GCC,至少要准备gcc-core、gcc-g++、binutils、w32api以及mingw32-make包;同时,确保包含编译器可执行文件的目录(一般是C:\MinGW\bin)在Windows的PATH环境变量中。   提示:设置完环境变量之后需要重启计算机才能生效。 如果选择MinGW/GCC编译器,可以在直接选择包含MinGW的Code::Blocks安装包,见下一节。 最新版的Code::Blocks最好含 MinGw   wxWidgets   你可以选择下载wxWidgets的源代码然后自己进行构建,或者是直接安装预编译的wxPack。 wxWidgets源代码   安装包较小,可以根据自己的需求进行自定义构建,但是需要花费长时间进行编译。如果不清楚编译选项,可能导致无法成功配置Code::Blocks。 目前推荐的wxWidgets的版本是2.9.5。你也可以检查一下wxWidgets的下载页面看看有没有更新的稳定版下载。强烈建议你将代码安装到不带空格的路径中。必须保证盘中至少有300MB的剩余空间。 wxPack 虽然安装包达200MB,全部安装需要3G,但是包含了预编译的所有可能用到的库文件,而且包含VC和GCC的两种版本,可以不用去考虑构建选项了。   提示   如果磁盘使用了NTFS格式,可以开启文件压缩功能,上述的目录在压缩后可以减少50%的空间占用。 编译wxWidgets   使用wxPack则可以跳过这一步。 打开命令行(在开始菜单中点击“运行”,输入cmd并回车)。如果使用的MSVC,你可以使用特定的用于设置环境变量的命令行。如果你使用的MSVC版本还要求你单独下载Platform SDK,确保全部包含了标准编译工具和Platform SDK中要用到的环境变量。 转到wxWidgets的构建目录,其中是源码所在路径,通常是C:\wxWidgets-2.9.5: cd \build\msw执行构建命令,MinGW/GCC推荐的命令是: mingw32-make -f makefile.gcc BUILD=release SHARED=1 MONOLITHIC=1 UNICODE=1 MSVC推荐的构建命令是: nmake -f makefile.vc BUILD=release SHARED=1 MONOLITHIC=1 UNICODE=1这个过程需要花很久,快的机器大概30分钟可以完成,慢的可能就需要几个小时了。 如果使用的GCC的版本较新,构建过程中可能会出现大量的警告。这样会明显导致构建过程变慢;你可以将错误信息重定向到文件中,在上述命令后面添加2> err.log,也可以通过2>nul直接禁止警告信息。 其中关于BUILD、SHARED、MONOLITHIC以及UNICODE选项的解释,请仔细参考文章后面关于wxWidgets的构建参数的解释,这些参数十分关键,他们直接定义了你所使用的基本的wxWidgets开发环境。你必须严格按照你的编译参数设置Code::Blocks的配置向导。 在Code::Blocks中创建wxWidgets项目   在Code::Blocks的起始页面中,选择“Create a new project”,也可以在File菜单中,选择“New” -> “Project…”。 找到并选择“wxWidgets project”,并创建,接下来会出现一个向导帮助进行wxWidgets项目的配置: 第一个页面是简介,可以选择以后跳过。   选择你要使用的wxWidgets版本。如果你是按照本文的过程配置的,那么你应该选择“wxWidgets 2.9.x”。   设置你的项目的名字的位置。   输入作者的信息(非必要)   选择自动代码和文件生成的选项。   选择wxWidgets的位置。强烈建议在此使用全局变量:输入“$(#wx)”(不包含引号)。如果你还没定义这个全局变量,那么全局变量对话框会出现,在Base Path中,选择你的wxWidgets安装路径。其他路径可以不用填。   为你的项目选择debug/release配置。推荐至少选择debug配置。   选择你的wxWidgets构建选项。必须和你构建wxWidgets时所使用的选项一致!如果你按照本文之前的方式构建的,应该将“wxWidgets Library Settings”下的全部三个选项选中。如果用的是wxPack,由于wxPack包含了各种不同的版本,所以你只需要选择你需要的选项。这个页面的另一个设置和wxWidgets的构建选项没有关系,你可以按照喜好来选择。如果,出于某种原因,你想使用调试版本的wxWidgets构建,选择“Configure Advanced options”然后在下一页选择“Use __WXDEBUG__ and Debug wxWidgets lib”。   如果需要,选择额外的库。一般应用的话应该无须选择其中任何一个。   构建并运行程序   接下来,就可以选择“Build and run”(F9)对程序进行构建并运行了。如果顺利,你的wxWidgets应用程序就会出现。如果出现了什么问题,你可以参考后面的常见问题。 wxWidgets编译选项简介   BUILD   BUILD控制wxWidgets构建调试版本(BUILD=debug)或者是发布版本(BUILD=release)。绝大多数情况下你只需要wxWidgets的发布版本就可以了,因为你应该不想要去调试wxWidgets自身,同时你依然可以通过链接wxWidgets的发布版本来构建你自己的程序的调试版本。 调试构建wxWidgets会创建带有”d”后缀的库,例如”libwxmsw29d.a”、”wxmsw29d_gcc_custom.dll”。   调试构建wxWidgets会在wxWidgets库的输出目录中创建”mswd” 或者 “mswud” 目录。   发布构建wxWidgets创建的库没有”d”后缀,例如”libwxmsw29.a”、”wxmsw29_gcc_custom.dll”。   发布构建wxWidgets会在wxWidgets库的输出目录中创建”msw” 或者 “mswu” 目录。   SHARED   SHARED控制wxWidgets是构建DLL(SHARED=1)还是静态库(SHARED=0)。利用构建的DLL,主程序构建时间较快,可执行文件更小。但是可执行文件加上wxWidgets DLL的总大小更大,但是不同的可执行文件可以使用同一个DLL。 wxWidgets的DLL构建会创建导入库(如 libwxmsw29.a)以及DLL文件(如wxmsw29_gcc_custom.dll)。你必须在发布你的程序的时候包含这个DLL。   wxWidgets的静态构建只会创建静态库(如 libwxmsw29.a),发布的时候也无须包含wxWidgets的DLL。   MONOLITHIC   MONOLITHIC控制是构建一个单一的库(MONOLITHIC=1)还是多个组件库(MONOLITHIC=0)。使用单一构建,项目的设置和开发会更加简单,如果你同时使用DLL构建的话,你只需要分发一个DLL文件。如果使用非单一构建(multilib),会构建出多个不同的库同时你可以避免将整个wxWidgets的基本代码链接到主程序,就可以去掉不需要的库。同时你也必须确保你选择了正确的组件库。 wxWidgets的单一构建仅会创建一个wxWidgets导入库(如libwxmsw29.a)以及一个DLL(如wxmsw29_gcc_custom.dll)。   wxWidgets的多库(multilib)构建会创建多个导入库(libwx29_base.a等)以及多个DLL文件。   无论何种wxWidgets构建,都会创建额外的静态库(如libwxexpat.a、libwxjpeg.a等)。这些库对于wxWidgets的DLL构建一般是不需要的,但是当使用静态构建的时候,则是必须的。   UNICODE   UNICODE控制wxWidgets以及你的程序是否使用支持Unicode的宽字符串。大多数Windows 2000或更高系统上的应用程序都应该支持Unicode。早期的Windows版本不一定有Unicode支持。你应该总是使用wxWidgets的_("string")和_T("string")宏来确保硬编码的字符串编译时是正确的类型。 wxWidgets的Unicode(UNICODE=1)构建将会创建带有”u”后缀的库,例如”libwxmsw29u.a”、”wxmsw29u_gcc_custom.dll”。   wxWidgets的Unicode构建会在wxWidgets库的输出目录中创建”mswu”或”mswud”目录。   wxWidgets的ANSI(UNICODE=0)构建创建的库没有”u”后缀,例如”libwxmsw29.a”、”wxmsw29_gcc_custom.dll”。   wxWidgets的ANSI构建会在wxWidgets库的输出目录中创建”msw”或”mswd”目录。   常见问题   出现类似于”wx/setup.h: No such file or directory”的错误   你在构建选项中缺少了很重要的编译器搜索路径。首先确认你是否在运行wxWidgets项目向导的时候正确选择了wxWidgets的构建配置。如果重新运行向导并配置依然无效,那么打开你的项目的构建选项并给编译起的搜索路径中添加”$(#wx.lib)\gcc_dll\mswu“(这里假设是一个单一的Unicode DLL构建)。 出现类似于”cannot find -lwxmsw28u”的错误   构建选项中的链接库错了。首先确认你是否在运行wxWidgets项目向导的时候正确选择了wxWidgets的构建配置。如果重新运行向导并配置依然无效,确定你构建了什么库,并相应在构建选项中调整库的名字。 项目->构建选项 ->选择Debug或者release ->链接器设置->添加链接库 libwxbase29ud.a libwxmsw29ud_core.a   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   若要构建的程序能够显示中文,要对codeblocks进行一下设置,在edit(编辑)菜单里面的文件编码选择UTF-8,否则编译报错。 感谢 @daliugo 提出问题~   
wxWidgets 窗口的基本知识(转) 窗口解析 窗口绘制 当一个窗口需要重绘的时候,它将收到两个事件,wxEVT_ERASE_BACKGROUND事件用于通知应用程序重新绘制背景,wxEVT_PAINT则用于通知重新绘制前景。 颜色和字体 每一个窗口都有一个前景色和一个背景色。默认的背景擦除函数会使用背景色来清除窗口背景,如果没有设置背景色,则会使用当前的系统皮肤推 荐的颜色进行背景的清除。前景色则相对来说很少被用到。 改变大小 当一个窗口的大小,无论是来自用户还是应用程序本身的原因,发生变化时,它将收到一个wxEVT_SIZE事件。如果这个窗口拥有子窗 口,它们可能需要被重新放置和重新计算大小。处理这种情况推荐的方法是使用sizer类。大多数已经确定的窗口类都有一个默认的大小和位置,这需要你在创建这些窗口的时候使用wxDefaultSize和 wxDefaultPosition这两个特殊的值。 输入 正变成活动状 态的窗口会收到wxEVT_SET_FOCUS事件,而正失去焦点的窗口会收到wxEVT_KILL_FOCUS事件。 空闲事件处理和用户界面更新 所有的窗口(除非特殊声明)都将收到空闲事件wxEVT_IDLE,这个事件是在所有其它的事件都已经被处理完以后发出的。使用EVT_IDLE事件映射宏来处理。其中一个特殊的空闲时间操作就是进行用户界面更新,在这个操作中所有的窗口都可以定义一个函数来更新自己的状态。这个函数将会被周期性的 在系统空闲时调用。而EVT_UPDATE_UI(id, func)这个宏则通常不需要作什么事情。 窗口的创建和删除 一般来说,窗口都是在堆上使用new方法创建的。大多数的窗口类都可以通过两种方法被创建:单步创建和两步创建。 使用一步创建的方法:wxButton* button = new wxButton(parent, wxID_OK); 除非是frame或者dialog窗口,对于别的窗口,都必须在构造函数中传入一个非空的父窗口。这会自动把这个新窗口作为这个父窗口的子窗口。当父窗口被释放的时候,它的所有的子窗口也将被释放。 两步创建的意思是说,你先使用默认的构造函数创建一个实例,然后再使用这个实例Create方法实际创建这个对象。Create的参数和前面使用的构造函数的参数完全相同。 wxButton* button = new wxButton; button->Create(parent, wxID_OK); 窗口在你调用Create函数的时候会收到wxEVT_CREATE事件,你可以对这个事件进行进一步的处理。 使用两步创建的原因是什么呢?第一个原因是有时侯你可能想在晚些时候,在真正需要的时候才完整的创建窗口。另外一个原因是你希望在调用 Create函数之前设置窗口的某些属性值。 窗口是通过调用其Destroy函数(对于顶层窗口来说)或者delete函数(对于其子窗口来说)来释放的。wxEVT_DESTROY事件会在窗口刚刚要被释放之前被调用。实际上,子窗口是被自动释放的,所以delete函数是很少直接被手动调用的。 窗口类型 窗口拥有一个类型和一个扩展类型。窗口类型是设置窗口创建时的行为和外观的一种简洁的方法。这些类型的值被设置成可以使用类似比特位的方法操作,例如下面的例子: wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxTHICK_FRAME 窗口类概览 基本窗口类 wxWindow. 这是所有窗口类的基类。 wxControl. 所有控件(比如wxButton)的基类. wxControlWithItems. 是那些拥有多个子项目的控件的基类. 顶层窗口类 顶层窗口类通常指那些独立的位于桌面上的类。 wxFrame. 一个可以包含其他窗口,并且大小可变的窗口类。 wxMDIParentFrame. 是一个可以管理其他Frame类的类. wxMDIChildFrame. 是一个可以被其父窗口管理的frame类. wxDialog. 是一种可变大小的用于给用户提供选项的窗口类. wxPopupWindow. 是一种暂态的只有很少修饰的顶层窗口. 容器窗口类 容器窗口类可以管理其他窗口 wxPanel. 这是一个给其它窗口提供布局的窗口. wxNotebook. 可以实用TAB页面进行切换的窗口. wxScrolledWindow. 可以有滚动条的窗口. wxSplitterWindow. 可以管理两个子窗口的一种特殊窗口类. 非静态控件窗口类 这些控件是用户可以操作或者编辑的。 wxButton. 一种拥有一个标签的按钮控件. wxBitmapButton. 一种拥有图片和标签的按钮控件. wxChoice. 拥有一个下拉列表的选择控件. wxComboBox. 拥有一组选项的可编辑的选择控件. wxCheckBox. 拥有一个复选框的控件,复选框有选中和未选中两种状态. wxListBox. 拥有一组可选择的字符串项目的列表框. wxRadioBox. 拥有一组选项的单选框. wxRadioButton. 单选框. wxScrollBar. 滚动条控件。 wxSpinButton. 一个拥有增加和减小两个选项的按钮. wxSpinCtrl. 拥有一个文本编辑框和一个wxSpinButton用来编辑整数. wxSlider. 这个控件用来在一个固定的范围内选择一个整数. wxTextCtrl. 单行或者多行的文本编辑框. wxToggleButton. 两态按钮. 静态控件 这些控件提供不能被最终用户编辑的静态信息 wxGauge. 用来显式数量的控件. wxStaticText. 文字标签控件. wxStaticBitmap. 用来显示一幅静态图片. wxStaticLine. 用来显式静态的一行. wxStaticBox. 用来在别的控件周围显示一个静态的方框. 控件条 控件条通常在Frame窗口中使用,用来为信息或者命令的访问提供快捷操作 wxMenuBar. wxFrame上的菜单条. wxToolBar. 工具条. wxStatusBar. 状态条用来在程序运行过程中显示运行期信息. 基础窗口类 窗口类wxWindow wxWindow窗口类既是一个重要的基类,也是一个你可以直接在代码中使用的类。 构造函数原型如下: wxWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxT("panel")); 窗口类型 如果在创建窗口的时候你没有指定窗口的边框类型,那么在不同的平台上将会有不同的边框类型的缺省值。在windows平台上,控件边框的缺省值为 wxSUNKEN_BORDER,意为使用当前系统风格的边框。你可以使用类似wxNO_BORDER这样的值来覆盖系统的默认值。 wxSIMPLE_BORDER 在窗口周围显示一个瘦边框. wxDOUBLE_BORDER 显示一个双层边框. wxSUNKEN_BORDER 显示一个凹陷的边框,或者使用当前窗口风格设置. wxRAISED_BORDER 显示一个凸起的边框. wxSTATIC_BORDER 显示一个适合静态控件的边框. 只支持Windows平台. wxNO_BORDER 不显示任何边框. wxTRANSPARENT_WINDOW 定义一个透明窗口 (意思是这个窗口不接收paint事件).只支持windows平台. wxTAB_TRAVERSAL 使用这个类型允许非Dialog窗口支持使用TAB进行遍历. wxWANTS_CHARS 使用这个类型来允许窗口接收包括回车和TAB在内的所有的键盘事件。TAB用来在Dialog类型的窗口中遍历各控件。如果没有设置这个类型,这些特殊的按键事件将不会被产生。 wxFULL_REPAINT_ON_RESIZE 在默认情况下,在窗口客户区大小发生改变时,wxWidgets并不会重画整个客户区。设置这个类型将使得wxWidgets改变这种默认的作法,而保持整个客户区的刷新 wxVSCROLL 显示垂直滚动条. wxHSCROLL 显示水平滚动条. wxALWAYS_SHOW_SB 如果一个窗口有滚动条,那么在不需要滚动条的时候(当窗口足够大不需要使用滚动条的时候),禁止滚条而不隐藏滚动条。这个类型目前只支持Windows平台和wxWidgets的wxUniversal版本. wxCLIP_CHILDREN 只支持Windows平台,用于消除由于擦除子窗口的背景而引起的闪铄. 窗口的扩展类型,这些扩展类型不能直接和类型混用,而要使用wxWindow::SetExtraStyle函数来进行设置。 wxWS_EX_VALIDATE_RECURSIVELY 在默认情况下,Validate,transferDataToWindow,和transferDataFromWindow只在窗口的直接子窗口上才可以使用。如果设置了这个扩展类型,那么将可以递归的在各个子窗口上使用。 wxWS_EX_BLOCK_EVENTS wxCommandEvents事件将会在无法在当前事件表中找到匹配的时候在其父窗口中尝试匹配,设置这个扩展属性可以阻止这个行为。Dialog类型的窗口默认设置了这个类型,但是如果SetExtraStyle被应用程序类调用过的话,默认设置可能被覆盖. wxWS_EX_TRANSIENT 不要使用这个窗口作为其它窗口的父窗口.这个类型一定只能用于瞬间窗口;否则,如果使用它作为一个dialog或者frame类型窗口的父窗口,如果父窗口在子窗口之前释放,可能导致系统崩溃。 wxWS_EX_PROCESS_IDLE 这个窗口应该处理所有的idle事件,包括那些设置了wxIDLE_PROCESS_SPECIFIED模式的idle事件。 wxWS_EX_PROCESS_UI_UPDATES 这个窗口将处理所有的Ui刷新事件,包括那些设置了wxUPDATE_UI_PROCESS_SPECIFIED的UI刷新事件。参考第9章获得和界面刷新有关的更多的内容. 窗口事件 EVT_WINDOW_CREATE(func) 用于处理wxEVT_CREATE事件, 这个事件在窗口刚刚被产生的时候生成,处理函数的参数类型是wxWindowCreateEvent. EVT_WINDOW_DESTROY(func) 用于处理wxEVT_DELETE事件,在这个窗口即将被删除的时候产生,处理函数的参数类型是wxWindowDestroyEvent. EVT_PAINT(func) 用于处理wxEVT_PAINT事件,在窗口需要被刷新的时候产生.处理函数的参数类型是wxPaintEvent. EVT_ERASE_BACKGROUND(func) 用于处理wxEVT_ERASE_BACKGROUND事件,在窗口背景需要被更新的时候产生. 处理函数的参数是wxEraseEvent. EVT_MOVE(func) 用于处理wxEVT_MOVE事件, 在窗口移动的时候产生.处理函数的参数类型是wxMoveEvent. EVT_SIZE(func) 用于处理wxEVT_SIZE事件, 在窗口大小发生变化以后产生.处理函数的参数类型是wxSizeEvent. EVT_SET_FOCUS(func)EVT_KILL_FOCUS(func) 用于处理wxEVT_SET_FOCUS和wxEVT_KILL_FOCUS事件,在窗口得到或者失去键盘焦点的时候产生. 处理函数参数类型是wxFocusEvent. EVT_SYS_COLOUR_CHANGED(func) 用于处理wxEVT_SYS_COLOUR_CHANGED事件,当用户在控制面板里更改了系统颜色的时候产生(只支持windows平台). 处理函数参数类型为wxSysColourChangedEvent. EVT_IDLE(func) 用于处理wxEVT_IDLE事件,在空闲事件产生.处理函数参数类型位wxIdleEvent. EVT_UPDATE_UI(func) 用于处理wxEVT_UPDATE_UI事件,在系统空闲时间产生用来给窗口一个更新自己的机会. wxWindow类的成员函数 函数太多了,需要时再查询吧。 wxControl 类 wxControl是一个虚类。它继承自wxWindow,用来作为控件的基类: 所谓控件指的是那些可以显示数据项并且通常需要响应鼠标或者键盘事件的那些窗口类. wxControlWithItems 类 wxControlWithItems也是一个虚类,用来作为wxWidgets的一些包含多个数据项的控件(比如wxListBox, wxCheckListBox,wxChoice和wxComboBox等)的基类。使用这个基类的目的为了给这些具有相似功能的控件提供一致的API函 数。 wxControlWithItems的数据项拥有一个字符串和一个和这个字符串绑定的可选的客户数据。客户数据可以是两种类型,要么是无类型指针(void*),这意味这这个控件只帮忙存储客户数据但是永远不会使用客户数据。另外一种是有类型(wxClientData)指针,对于后一种情况,客户数据会在控件被释放或者数据项被清除的时候被自动释放。同一个控件的所有数据项必须拥有同样的客户区数据类型:要么是前者,要么是后者。客户区数据的类型是在第一次调用Append函数或者,SetClientData函数或者SetClientObject函数的时候被确定的。如果要使用有类型指针客户数据,你应该自定义一个继承自wxClientData的类,然后将它的实例指针传递给Append函数或者 SetClientObject函数。
1 下一页