下面是一些Visual C++ UI开发中遇到的问题的总结,专门记在此文中,以便将来查询。
由于文章较长,请用Ctrl+F查询关键字来定位到你需要的内容。
(1)程序运行时提示 VERIFY(strDocName.LoadString(AFX_IDS_UNTITLED)) 错误:
在一个基于Xtreme Toolkit的Visual C++ SDI工程中,为了创建Ribbon风格的界面,添加了一堆代码,然后编译,无问题。再运行,程序根本运行不起来,错误提示类似于:
Error Locating Toolkit Resources.
Make sure you have included the resources to your project's .rc2 file.
Add #include <XTToolkitPro.rc> to your project .rc2 file
——你当然需要照做,将你工程目录下的“res”子目录下的的*.rc2文件用记事本打开,你会看到这一句话:
// 在此处添加手动编辑的资源...
在这句话下面添加一句:
#include <XTToolkitPro.rc>
然后,重新编译,再运行,这回提示的是“Debug Assertion Failed”错误,很容易发现,程序问题产生于此处(红色的那一句代码):
void CSingleDocTemplate::SetDefaultTitle(CDocument* pDocument)
{
CString strDocName;
if (!GetDocString(strDocName, CDocTemplate::docName) || strDocName.IsEmpty())
{
// use generic 'untitled'
VERIFY(strDocName.LoadString(AFX_IDS_UNTITLED));
}
pDocument->SetTitle(strDocName);
}
这下子有点不知所云了,怎么解决呢?
方法如下:用记事本打开工程目录下的*.rc文件,找到下面的内容:
#include "res\XXX.rc2" // 非 Microsoft Visual C++ 编辑的资源
#include "afxres.rc" // 标准组件
#include "afxprint.rc" // 打印/打印预览资源
其中,XXX代表你的工程名,请将 #include "res\XXX.rc2" 移动到 #include "afxprint.rc" 的下方,即:
#include "afxres.rc" // 标准组件
#include "afxprint.rc" // 打印/打印预览资源
#include "res\XXX.rc2" // 非 Microsoft Visual C++ 编辑的资源
然后保存此文件,再重新编译程序,再运行,看,没问题了吧!
但是为什么改变一下顺序就好了呢?原因大致是由于语言环境不同造成的(中文,英文),在*.rc2文件中,#include <XTToolkitPro.rc> 使得英文的资源被包含到工程中,因此后面的资源都被附加到了英文的资源中,而我的工程在创建的时候,“资源语言”选择是的“中文(中国)”,因此就产生了问题。所以,我们要把 #include "res\XXX.rc2" 放到最后。
如果你有兴趣,可以到这个链接看更详细的描述。
(2)Resource-Neutral.rc(47) : error RC2170 : bitmap file Controls/res/font.bmp is not in 3.00 format:
出现此错误,先不要想这么多,先去看看提示的这个文件能不能打得开。我就遇到了文件根本打不开的情况,所以,先把一个正确的文件替换过去再说吧!当然,此错误产生的原因不只此一种,但是我只是想告诉大家,有时候错误很简单,不要忙活了半天,才发现是非常雷人的原因。
文章来源:http://www.codelast.com/
(3)获取CRichEditView中的文本:
可以用GetRichEditCtrl函数先获取与CRichEditView相关联的CRichEditCtrl对象,再用CRichEditCtrl类的GetLine函数来读取指定行的文本。
另一个办法就是获取CRichEditView的视图类指针,通过GetWindowText函数来取其中的所有文本。例如,你在文档类中,可以这样:
CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd(); // 获取主框架指针
CString strText;
pMainFrame->m_pEditView->GetWindowText(strText); // 获取edit view中的文本
其中,m_pEditView是我在CMainFrame类中定义的CRichEditView视图类指针。
(4)“old DIB in res XXX.ico; pass it through SDKPAINT”错误:
VC中使用图标发生的一个错误的解决办法:
错误提示类似于:
old DIB in res XXX.ico; pass it through SDKPAINT
这个错误通常发生在你用你自己的图标替换了原来的资源文件中的图标之后,据说是因为256色的图标和真彩色的图标之间的区别造成的。
解决办法也很简单:用 IconWorkshop 这个软件,将出错的图标中的256色以上的“子图标”全部删除(众所周知,一个图标文件是包含N个子图标的,不同的大小,不同的色深),再保存,然后再在VC中重新编译,就应该可以通过了。
文章来源:http://www.codelast.com/
(5)更改CTreeCtrl的结点的显示文字的字体:
此处以一个CTreeCtrl的派生类为例,说明如何更改树结点的显示文字的字体:
CXTTreeCtrl m_cTreeCtrl; // CXTTreeCtrl 为 CTreeCtrl的派生类
/* 改变item的显示效果 */
CXTLogFont logFont; // 字体对象,CXTLogFont 为 LOGFONT的派生类
m_cTreeCtrl.GetFont()->GetLogFont(&logFont); // 获取树控件原来的字体
_tcscpy(logFont.lfFaceName, _T("Arial")); // 更改字体
logFont.lfHeight = 20; // 重新定义字体高度
m_cTreeCtrl.SetItemFont(hItem, logFont); // 设置item的字体
其中,hItem为HTREEITEM类型,即你要操作的树结点的指针。
文章来源:http://www.codelast.com/
(6)有关GDI+的一个错误:“gdiplusimaging.h(156) : error C2146: 语法错误 : 缺少“;”(在标识符“PixelFormat”的前面)”:
此错误很搞笑,在gdiplusimaging.h文件中,有这样的代码段:
class BitmapData
{
public:
UINT Width;
UINT Height;
INT Stride;
PixelFormat PixelFormat;
VOID* Scan0;
UINT_PTR Reserved;
};
因此,摆明了是找不到PixelFormat的定义造成的。因此,添加了一堆与GDI+相关的include头文件之后,再编译,依然如故。最后经历了一番搜索,才发现犯了原则性错误:连GDI+的lib都没有引用到工程中,并且也没有在app类中进行GDI+的初始化,实在太笨了。解决方法如下:
①在VC工程的项目属性的“链接器”→“输入”→“附加依赖项”中填上GdiPlus.lib。它不是VC的默认链接库。
②在应用程序类(CXXApp)的头文件中添加:
#include <gdiplus.h>
using namespace Gdiplus;
③在应用程序类(CXXApp)中添加一个类成员变量:
private:
ULONG_PTR m_gdiplusToken;
④在应用程序类(CXXApp)的InitInstance()函数中添加:
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
注意这两句一定要加在CWinApp::InitInstance() 的前面,否则会造成窗口不能自动重绘等问题。
⑤重载应用程序类(CXXApp)的ExitInstance()函数,添加一句:
GdiplusShutdown(m_gdiplusToken); // 关闭GDI+
搞定。再编译程序,前面的错误就不会再出现了。
文章来源:http://www.codelast.com/
(7)更改了CEditView中的内容时,退出程序不弹出提示保存文档的对话框:
在CEditView中,有时候你不希望在输入了文字之后,再退出程序时程序自动提示你要保存文档,你可以这样做:
重载CEditView派生类的 =EN_CHANGE 消息,在函数体中只写一句话:
void CXXXEditView::OnEnChange()
{
GetEditCtrl().SetModify(FALSE);
}
其中,CXXXEditView是你的CEditView派生类。这样就能实现你想要的效果。
(8)更改与文档类相关联的视图类:
在怎样将一个你自己创建的视图类(例如class CMyRichEditView : public CRichEditView)与SDI项目中的文档类相关联呢?在创建工程的时候,文档类关联到了创建工程时自动创建的视图类上,要更改这个关联,可以在工程的App类的InitInstance()函数中,找到“pDocTemplate = new CSingleDocTemplate”这处代码,你会看到 RUNTIME_CLASS(CXXXView)) 这样的代码,没错,这就是将默认的CXXXView与文档类关联起来了,你只要改为自己创建的视图类就可以了。但是注意,你还需要将你的文档类改为继承自与你创建的视图类相对应的文档类,否则,编译不会出错,但是运行程序可能就会崩溃。
(9)从IWebBrowser2指针得到当前tab页的客户区句柄:
在得到了IWebBrowser2指针后(假设 IWebBrowser2* pWB),可以用如下方法获取当前tab页的客户区句柄(具体可看此MSDN):
IServiceProvider* pServiceProvider = NULL;
if (SUCCEEDED(pWB->QueryInterface(IID_IServiceProvider, (void**)&pServiceProvider)))
{
IOleWindow* pWindow = NULL;
if (SUCCEEDED(pServiceProvider->QueryService(SID_SShellBrowser, IID_IOleWindow,(void**)&pWindow)))
{
HWND hwndBrowser = NULL;
if (SUCCEEDED(pWindow->GetWindow(&hwndBrowser)))
{
// 这里的 hwndBrowser就是TabWindowClass的句柄了
}
pWindow->Release();
}
pServiceProvider->Release();
}
为了更直观地说明获取的这个句柄对应的是浏览器窗口的哪一块区域,我截了一张CB网站的图来示例(点击可放大):
你可能会注意到,上面的图中,最下方是包含IE状态栏的,你可以手动隐藏掉(IE菜单的“查看”→“工具栏”→“状态栏”),或者编程隐藏掉(参考我下面的说明)。
文章来源:http://www.codelast.com/
(9)利用IWebBrowser2指针隐藏浏览器的状态栏:
在得到了IWebBrowser2指针后(假设 IWebBrowser2* pWB),可以用如下方法使浏览器的状态栏隐藏起来:
pWB->put_StatusBar(VARIANT_FALSE);