Visual C++ 5.0编程经验(上)

发表于:2007-07-04来源:作者:点击数: 标签:
北京大学计算机系 蒋志华 另一种改变窗口标题的方法 在1997年9月1日出版的《计算机世界》上有一篇名为《Visual C++4.0编程经验谈》的文章,其中提到过一种改变窗口标题的方法,即在应用程序的框架类CMainFrame类(注:它是CFrameWnd类的派生类)的成员函数PreCr
北京大学计算机系 蒋志华

另一种改变窗口标题的方法

  在1997年9月1日出版的《计算机世界》上有一篇名为《Visual C++4.0编程经验谈》的文章,其中提到过一种改变窗口标题的方法,即在应用程序的框架类CMainFrame类(注:它是CFrameWnd类的派生类)的成员函数PreCreateWindow()中修改CFrameWnd类的成员变量m_strTitle的值。这种方法的不足之处就是只能一次性的设置窗口标题的内容,不能在程序运行过程中随时修改它。比如当需要把鼠标的当前坐标在窗口标题上显示时,我们就要使用到Visual C++提供的全程函数BOOLSetWindowText(HWNDhWnd,LPCTSTRlpString)。这个函数实际上是一个Win32函数。它的第一个参数要求是一个窗口框架的句柄,而第二个参数要求是一个指向一个常量字符串的32位指针,即LPCTSTR类型的变量。通常情况下,我们往往会在应用程序的文档类或视类中动态改变窗口标题的内容,从而没有现成的指向窗口框架的句柄供我们使用,因此我们还需要在使用SetWindowText()函数前先调用另一个Win32函数AfxGetMainWnd(),来获得一个指向应用程序的框架类的指针,例如使用语句

-  CWnd *m_pCWnd = AfxGetMainWnd()

-  然后,再以如下形式调用SetWindowText()函数:

-  SetWindowText(*m_pCWnd,(LPCTSTR)m_WindowText);//m_WindowText可以是一个CString类的变量

-  如何把多于256色的位图作为资源加入到应用程序中

-  曾经使用过Visual C++进行应用程序开发的同行们都知道,Visual C++5.0以前版本中自带的位图编辑器不能浏览和编辑256色以上的位图,并且资源文件中也不允许嵌入(Import)256色以上的位图作为资源(否则,在应用程序运行时会报错)。这一特性使得我们用Visual C++开发应用程序时不得不使用其他方法来增强界面图画的美观性,于是就有使用Visual C++开发应用程序内核,用Visual Basic开发界面部分的组合方法。好在Visual C++5.0中这个问题有了改善。首先,位图编辑器可以创建并编辑256色的位图了。另外,Visual C++5.0允许程序员把256色以上的位图嵌入到资源中,尽管仍然无法在Visual C++的位图编辑器中浏览,并且还要求必须选择Win32Release作为编译方式生成可执行的应用程序。另外一个限制条件是作为资源的256色以上的位图不能由应用程序内核自动打开和关闭。比如说,在上述那篇名为《Visual C++4.0编程经验谈》的文章中曾经提到过一种为对话框加入位图式按钮的方法,即由程序开发者为每个按钮创建四幅位图,分别用于表示按钮的弹起状态(UP)、按下状态(DOWN)、输入焦点状态(FOCUS)和禁止状态(DISABLE),并且必须以该按钮的标题名与上述四种状态之一的组合作为位图的标识,以便应用程序在绘制位图按钮时,可以自动地找到相应的资源(即位图)。然而这一自动映射只限制于Visual C++位图编辑器能够打开的位图。因此如果选择256色以上的位图作为位图按钮的资源,并也希望达到上述四状态的相互切换的话,就必须用到下述的函数和程序设计参考模型。 设 置 四 个 常 量,BUTTON_UP,BUTTON_DOWN,BUTTON_FOCUS,BUTTON_DISABLE, 分 别 用 于 标 识 各 按 钮 的 当 前 状 态。
在 应 用 程 序 的 相 应 对 话 框 类 中 为 每 个 位 图 按 钮( 为 下 面 叙 述 方 便, 不 妨 假 设 为 两 个) 设 置 一 个CRect 类 的 对 象,m_rect1 和m_rect2, 来 记 载 各 按 钮 在 对 话 框 中 所 占 据 的 坐 标 矩 形。 再 在 该 对 话 框 类 中 为 每 个 按 钮 设 置 一 个 整 型 变 量,Buton1_Status,Button2_Status, 记 录 各 按 钮 的 当 前 状 态。 然 后 在 对 话 框 的 构 造 函 数 中 初 始 化 这 些CRect 类 的 对 象 和 整 型 变 量。
在 该 对 话 框 类 中 创 建 分 别 响 应 鼠 标 各 种 状 态 的 消 息 处 理 函 数, 如OnMouseMove(),OnLButtonUp(),OnLButtonDown() 等。
同 时 按 下Ctrl 和W 键 或 直 接 单 击 工 具 条 上 的ClassWizard 按 钮, 打 开ClassWizard 对 话 框。 在 类 名(Class name) 列 表 框 中 选 择 对 话 框 类, 在Object IDs 列 表 框 中 选 择 该 类 的 类 名 后, 在 消 息(Messages) 列 表 框 中 选 择WM_PAINT 消 息 并 双 击 它, 这 时ClassWizard 就 会 在 该 对 话 框 类 中 加 入 一 个OnPaint() 函 数。 该 函 数 将 在 我 们 的 程 序 中 起 重 要 作 用。 之 后, 再 在Object IDs 列 表 框 中 选 择 新 加 入 的 工 具 条 按 钮 的 标 识 名, 双 击 消 息 列 表 框 中 的COMMAND 消 息,ClassWizard 又 会 在 对 话 框 类 中 加 入 相 应 的 消 息 处 理 函 数。 关 闭ClassWizard 对 话 框。

 

-  下 面 给 出 部 分 程 序 代 码, 仅 供 参 考。

void CTESTDlg::OnPaint() { CWnd* pWnd; CDC* pDC; CDC* pDisplayMemDC; CBitmap* pBitmap; pWnd=GetDlgItem(IDC_IMAGE1);//得到指向第一个位图按钮的指针 pDC=pWnd->GetDC();//获得一个窗口设备用于画图 pWnd->Invalidate();//使窗口无效,从而更新它 pWnd->UpdateWindow(); pDisplayMemDC=new CDC; pBitmap=new CBitmap; pDisplayMemDC->CreateCompatibleDC(pDC); if (Change1) {//说明第一个按钮的状态发生了变化 switch (Button1_Status){ case BUTTON_DISABLE: pBitmap->LoadBitmap(IMAGE1_DISABLE);//装入位图 pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); //把位图拷贝到指定区域 break; case BUTTON_UP: pBitmap->LoadBitmap(IMAGE1_UP); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC, 0,0,SRCCOPY); break; case BUTTON_FOCUS: pBitmap->LoadBitmap(IMAGE1_FOCUS); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; case BUTTON_DOWN: pBitmap->LoadBitmap(IMAGE1_DOWN); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; } } delete pDisplayMemDC; delete pBitmap; pWnd=GetDlgItem(IDC_IMAGE2); pDC=pWnd->GetDC(); pWnd->Invalidate(); pWnd->UpdateWindow(); pDisplayMemDC=new CDC; pBitmap=new CBitmap; pDisplayMemDC->CreateCompatibleDC(pDC); if (Change2) {//说明第二个按钮的状态发生了变化 switch (Button2_Status){ case BUTTON_DISABLE: pBitmap->LoadBitmap(IMAGE2_DISABLE); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; case BUTTON_UP: pBitmap->LoadBitmap(IMAGE2_UP); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; case BUTTON_FOCUS: pBitmap->LoadBitmap(IMAGE2_FOCUS); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; case BUTTON_DOWN: pBitmap->LoadBitmap(IMAGE2_DOWN); pDisplayMemDC->SelectObject(pBitmap); pDC->BitBlt(0,0,140,30,pDisplayMemDC,0,0,SRCCOPY); break; } } delete pDisplayMemDC; delete pBitmap; CDialog::OnPaint(); } void CTESTDlg::OnMouseMove(UINT nFlags, CPoint point) { CRect rect=CRect(0,0,1,1); CRgn rgn1,rgn2;//记录各位图按钮所占据的矩形区域 rgn1.CreateRectRgnIndirect(m_rect1); //rgn1记录第一个位图按钮所占据的矩形区域 if (rgn1.PtInRegion(point)) {//鼠标当前是否已落入第一个位图按钮所占据的矩形区域 if ( (Button1_Status!=BUTTON_FOCUS) && (Button1_Status!=BUTTON_DISABLE) ) { //如果位图按钮的当前状态不是输入焦点状态并且也不是禁止状态 Button1_Status= BUTTON_FOCUS; Change1=true; InvalidateRect(rect,FALSE); } if ( (Button2_Status!=BUTTON_UP) && (Button2_Status!=BUTTON_DISABLE) ) { Button2_Status= BUTTON_UP; Change2=true; InvalidateRect(rect,FALSE); } } else{ rgn2.CreateRectRgnIndirect(m_rect2); if (rgn2.PtInRegion(point)){ if ( (Button2_Status!=BUTTON_FOCUS) && (Button2_Status!=BUTTON_DISABLE) ) { Button2_Status= BUTTON_FOCUS; Change2=true; InvalidateRect(rect,FALSE); } if ( (Button1_Status!=BUTTON_UP) && (Button1_Status!=BUTTON_DISABLE) ) { Button1_Status= BUTTON_UP; Change1=true; InvalidateRect(rect,FALSE); } } } CDialog::OnMouseMove(nFlags, point); } void CTESTDlg::OnLButtonUp(UINT nFlags, CPoint point) { CRect rect=CRect(0,0,1,1); CRgn rgn1,rgn2; rgn1.CreateRectRgnIndirect(m_rect1); if (rgn1.PtInRegion(point)){ if ( (Button1_Status!=BUTTON_UP) && (Button1_Status!=BUTTON_DISABLE) ) { Button1_Status=BUTTON_UP; Change1=true; InvalidateRect(rect,FALSE); } } else{ rgn2.CreateRectRgnIndirect(m_rect2); if (rgn2.PtInRegion(point)){ if ( (Button2_Status!=BUTTON_UP) && (Button2_Status!=BUTTON_DISABLE) ) { Button2_Status=BUTTON_UP; Change2=true; InvalidateRect(rect,FALSE); } } } CDialog::OnLButtonUp(nFlags, point); } void CTESTDlg::OnLButtonDown(UINT nFlags, CPoint point) { CRect rect=CRect(0,0,1,1); CRgn rgn1,rgn2; rgn1.CreateRectRgnIndirect(m_rect1); if (rgn1.PtInRegion(point)){ if ( (Button1_Status!=BUTTON_DOWN) && (Button1_Status!=BUTTON_DISABLE) ) { Button1_Status=BUTTON_DOWN; Change1=true; InvalidateRect(rect,FALSE); } if ( (Button2_Status!=BUTTON_UP) && (Button2_Status!=BUTTON_DISABLE) ) { Button2_Status=BUTTON_UP; Change2=true; InvalidateRect(rect,FALSE); } } else{ rgn2.CreateRectRgnIndirect(m_rect2); if (rgn2.PtInRegion(point)){ if ( (Button2_Status!=BUTTON_DOWN) && (Button2_Status!=BUTTON_DISABLE) ) { Button2_Status=BUTTON_DOWN; Change2=true; InvalidateRect(rect,FALSE); } if ( (Button1_Status!=BUTTON_UP) && (Button1_Status!=BUTTON_DISABLE) ) { Button1_Status=BUTTON_UP; Change1=true; InvalidateRect(rect,FALSE); } } } CDialog::OnLButtonDown(nFlags, point); } 如何在应用程序中不加载菜单、工具条和状态条

  在 通 过AppWizard 生 成 的 具 有 窗 口 框 架 结 构 的 应 用 程 序(SDI 和MDI) 中,MFC 类 库 已 为 我 们 加 载 上 了 菜 单( 包 括 一 个 系 统 菜 单)、 工 具 条 和 状 态 条。 但 有 时 由 于 特 殊 需 要, 我 们 可 能 希 望 在 自 己 的 应 用 程 序 中 事 先 不 加 载 菜 单、 工 具 条 和 状 态 条。 这 时 就 需 要 我 们 手 动 地 删 除 和 修 改 一 些 类 中 的 语 句。 打 开MainFrm.cpp 文 件, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到OnCreate() 函 数。 按 照 下 述 程 序 注 释 掉 创 建 工 具 条 和 状 态 条 部 分 的 语 句。 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; //在此处开始加注释符号 /* if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // TODO: Remove this if you don't want tool tips or a resizeable toolbar m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // TODO: Delete these three lines if you don't want the toolbar to be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); 在处结束注释*/ return 0; } 在MainFrm.cpp 文 件 中, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到PreCreateWindow() 函 数。 参 照 第 三 部 分 中 的 程 序, 加 入 特 定 的 窗 口 框 架 属 性, 不 妨 把cs.style 设 置 成 如 下 形 式, 即 不 加 载 系 统 菜 单。
// Create a window without min/max buttons,system menu, or sizable border
cs.style =WS_OVERLAPPED | WS_BORDER; 在 主 应 用 程 序, 即 含 有 定 义theApp 全 程 变 量 的.cpp 文 件 中, 使 用 工 具 条 上 的 函 数 下 拉 列 表 框 找 到InitInstance() 函 数。 在“pDocTemplate = new CSingleDocTemplate” 一 句 中, 用NULL 替 换IDR_MAINFRAME。 如 下 段 程 序 所 示。 BOOL CYourMainApp::InitInstance() { //.....此处略去一部分无关语句 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( NULL, //IDR_MAINFRAME, //用NULL替换IDR_MAINFRAME RUNTIME_CLASS(CNoBarDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CNoBarView)); AddDocTemplate(pDocTemplate); //.....此处略去一部分无关语句 } 找到Visual C++ 编辑器的工具条上的编译方式下拉列表框,选择Win32 Release, 生成Release版本的应用程序。

 

  至此,我们就得到了不含菜单、工具条和状态条结构的应用程序。

 

 

back.gif (1185 字节)

原文转自:http://www.ltesting.net