第三部分 一个Demo程序及相关说明
3.1 在Eclipse中导入并运行一个C++项目
点此处可以下载本文中用到的C++项目(Eclipse+CDT项目,环境按第一部分的说明配置),下载后解压。
然后在Eclipse中使用File->Import->Genaral::Existing Project into Workspace向导即可把下载的项目导入到开发环境中。便会看到如下图的项目:
如果Build成功,Run起来以后,可以看到如下的运行结果:
同时控制台给出以下输出:
Main Program Started!
Application::SetWinMainArgs(...)
MyApp::InitInstance() -- start
Window::Create(...) <--> start
Application::RegisterWndClass(...) <--> start
Application::RegisterWndClass(...) <--> end
Window::Create(...) <--> end
MyApp::InitInstance() -- end
Application::Run()
但是需要注意的是,如果是直接新建一个项目,再编写如此的程序代码,调用WindowsAPI,一般情况下直接编是编不通的,会提示某种错误
比如:undefined reference to `TextOutA@20'
或者是:undefined reference to `SetBkColor@8'等
因此要对项目加上一个参数设置。具体的设置项目如下:
在项目上点右键,选择“属性”,就会弹出Eclipse的项目设置对话框,在按图所示的地方添加-mwindows参数即可(C/C++Build
-> Settings ->MinGW C++ Linker -> Expert settings:)。注意,这些选项页中有很多相似的页面,看清图示的设置框究竟是哪一个(MinGW C++ Linker),不要加错地方了(=0=|||)。
顺便提一句,随着我们对项目的扩展,可能有越来越多的项目需求,比如引用静态库、引用DLL、使用rc资源等,这些要求都涉及到对项目属性中某些参数的修改。本部分中只涉及-mwindows参数,其它的参数会在后续的部分中分别介绍。
OK,如果项目运行成功,我们就来分析一下这个项目的结构,看是否和第一部分描述的是同样的组织方式。
3.2 源代码说明
回顾一下第一部分中提到的Windows应用程序的运行示意图:
对照本文中给出的项目,可以看出Main.cpp中就是程序的入口WinMain()函数;Application类(包括.h与.cpp两部分)就是
图示的Application;Window类(包括.h与.cpp两部分)就是图示的Window部分;而application变量(在
Application.cpp中声明)就是图中左上角那全局变量。
也就是说,本项目中的Application、Window两个类再加上一个WinMain()函数就完成了一个Windows程序需要的基本框架。这三个类写定以后,就不需要再作改变(架构意义上而言…)!而我们的后续开发扩展功能的工作,就只需要进行一些简单的添加就能完成(下面马上讲到的MyWin和MyApp两个类的作用),下面就是扩展部分的说明。
还是先看看第一部分中提到的扩展程序示意图:
MyApp和MyWin两个类,就是我们自己扩展出来的。实现上图中My Program的功能。可以看到,我们的子类MyWin的OnPaint()方法在运行过程中已经取代了基类Window的OnPaint()方法,替我们输出了一个文本。
总结一下,整个这个例子想要说明的一个问题就是:如果我们的底层结构(Application、Window两个类)写得足够好了,我们以后的开发只需
要做MyWin和MyApp两个类,在其中添加我们的功能即可,这种添加只需要很少的代码量,如本例中的这两个扩展类其实只有如下的内容,并且结构很清晰。
(MyApp和MyWin类)
namespace inshion {
class MyApp: public inshion::Application {
public:
MyApp(){}
virtual ~MyApp(){}
bool InitInstance(){
if (!MainWin.Create(this, "Inshion - Test - 001", 0, 0)){
return FALSE;
}
MainWindow = &MainWin;
return TRUE;
}
protected:
MyWin MainWin;
};
MyApp theApp;
}
namespace inshion {
class MyWin : public inshion::Window{
public:
MyWin(){}
virtual ~MyWin(){}
LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam){
switch (uMsg) {
case WM_PAINT:
OnPaint();
break;
default:
return Window::WindowProc(uMsg, wParam, lParam);
}
return 0L;
}
void OnPaint(){
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
PrintText("Hello,I'm Inshion~");
EndPaint(hWnd, &ps);
}
};
}
另外再提一下,我们可以试着把MyApp.h中的成员变量定义
MyWin MainWin;
改回基类
Window MainWin;
此时的运行结果就是弹出一个基类的Window,而与MyWin无关(可以把MyWin相关的代码删掉,依然不影响运行)。这一方面说明,如果我们的
很多需求是大量重复的,就完全可以在基类里做好,扩展时都不用写MyWin这样的窗口类;另一方面说明,即使我们要自己做扩展,也是非常方便地添加一个窗
口类就可以。
下一部分将介绍如何把基类们封装成静态库项目,以便更方便地复用。
附:本文中的源代码项目下载(MyMain_Inshion_Exa001.rar)