1. 如何得到视图指针
[ 问题提出]
现在你有一个多线程的Demo, 你想在多线程里处理视图指针里的函数, 我们给这个函数起个名字:Put(); 该如何实现呢?
// 有两种方法可以实现你的要求:
//1) 第一种方法:
// 要是多线程不是在App.cpp 里出现, 那么要在多线程的.cpp 中加上extern CYourApp theApp;
// 获得文档模板:
POSITION curTemplatePos = theApp.GetFirstDocTemplatePosition();
CDocTemplate *m_doc=theApp.GetNextDocTemplate(curTemplatePos);
// 获得文档:
curTemplatePos=m_doc->GetFirstDocPosition();
CYourDoc *m_pdoc=(CA8Doc*)m_doc->GetNextDoc(curTemplatePos);
// 获得视图:
curTemplatePos=m_pdoc->GetFirstViewPosition();
CYourView *m_pview=(CYourView*)m_pdoc->GetNextView(curTemplatePos);
// 调用视图函数:
m_pview->Put();
//2) 第二种方法:
// 获得窗体指针:
CMainFrame *pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd;
// 获得与该窗体符合的视图:
CYourView *m_pView = (CYourView *) pFrame->GetActiveView();
// 调用视图函数:
m_pView->Put();
2. 如何设置有背景颜色的文本
(1)[ 解决方法]
用到了CDC::SetBkMode();
[ 程序实现]
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rcView;// 加这两句
GetClientRect(rcView);
// TODO: add draw code for native data here
CString str (_T("Perfect Text ..."));
pDC->SetBkMode(TRANSPARENT);
rcView.OffsetRect (1,1);
pDC->SetTextColor(RGB (0,0,0));
pDC->DrawText(str,str.GetLength(),rcView,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
rcView.OffsetRect(-1,-1);
pDC->SetTextColor(RGB (255,0,0));
pDC->DrawText(str,str.GetLength(),rcView,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
(2) 建立名为My 的SDI 或MDI, 并响应WM_ERASEBKGND.
BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CBrush Brush (RGB(114,147,171));
// Select the brush into the device context .
CBrush* pOldBrush = pDC->SelectObject(&Brush);
// Get the area that needs to be erased .
CRect ViewClip;
pDC->GetClipBox(&ViewClip);
//Paint the area.
pDC->PatBlt(ViewClip.left,ViewClip.top,ViewClip.Width(),ViewClip.Height(),PATCOPY);
//Unselect brush out of device context .
pDC->SelectObject (pOldBrush );
// Return nonzero to half fruther processing .
return TRUE;
return CView::OnEraseBkgnd(pDC);
}
此方法也适合基类是EditView 的SDI 或MDI 的情况, 但是字体的颜色和底色不行. 建议用WM_CTLCOLOR.
3.CDC 中的竖排文本
在OnDraw 成员函数中我想让文本竖直对齐, 但CDC 类似乎不支持该处理
方法一: 如果你的竖直对齐是指旋转文本的话, 下面的代码会对你有帮助: 该代码检查一个Check box 控制, 查看文本是否需要旋转.
// m_pcfYTitle is a CFont* to the selected font.
// m_bTotateYTitle is a bool (==TRUE if rotated)
void CPage1::OnRotateytitle()
{
LOGFONT lgf;
m_pcfYTitle->GetLogFont(&lgf);
m_bRotateYTitle=
((CButton*)GetDlgItem(IDC_ROTATEYTITLE))->GetCheck()>0;
// escapement is reckoned clockwise in 1/10ths of a degree:
lgf.lfEscapement=-(m_bRotateYTitle*900);
m_pcfYTitle->DeleteObject();
m_pcfYTitle->CreateFontIndirect(&lgf);
DrawSampleChart();
}
注意如果你从CFontDialog 中选择了不同的字体, 你应该自己设定LOGFONT 的lfEscapement 成员. 将初始化后的lfEscapement 值传到CFontDialog 中.
方法二: 还有一段代码可参考:
LOGFONT LocalLogFont;
strcpy(LocalLogFont.lfFaceName, TypeFace);
LocalLogFont.lfWeight = fWeight;
LocalLogFont.lfEscapement = Orient;
LocalLogFont.lfOrientation = Orient;
if (MyFont.CreateFontIndirect(&LocalLogFont))
{
cMyOldFont = cdc->SelectObject(&MyFont);
}
4. 串太长时往让其末尾显示一个省略号( 在SDI 或MDI 的View 中)
[ 问题提出]
如何在串太长时往让其末尾显示一个省略号( 在SDI 或MDI 的View 中)?
[ 程序实现]
建立名为My 的SDI 或MDI 工程.
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->DrawText(CString("It ‘ s a long string,so we will add a ‘ ... ‘ at
the end."),CRect (110, 110, 180, 130),DT_LEFT | DT_END_ELLIPSIS);
//Add ellpsis to middle of string if it does not fit
pDC->DrawText(CString("It ‘ s a long string,so we will add a ‘ ... ‘ at
the end."),CRect (110, 140, 300, 160),DT_LEFT | DT_PATH_ELLIPSIS);
}
5. 修改视图背景
How do I change the background color of a view?
To
change the background color for a CView, CFrameWnd, or CWnd object,
process the WM_ERASEBKGND message. The following code shows how:
BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
// Set brush to desired background color.
CBrush backBrush(RGB(255, 128, 128));
// Save old brush.
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // Erase the area needed.
pDC->PatBlt(rect.left, rect.top, rect.Width(),
rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
I solved the problem like this:
HBRUSH dlgtest::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_BTN:
case CTLCOLOR_STATIC:
{
pDC->SetBkMode(TRANSPARENT);
}
case CTLCOLOR_DLG:
{
CBrush* back_brush;
COLORREF color;
color = (COLORREF) GetSysColor(COLOR_BTNFACE);
back_brush = new CBrush(color);
return (HBRUSH) (back_brush->m_hObject);
}
}
return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor));
}
积累的VC 编程小技巧之打印相关
1. 修改打印预览的ToolBar
为AFX_IDD_PREVIEW_TOOLBAR 这个ID 创建一个DialogBar 。则系统就会用新创建的DialogBar 代替系统默认的那个
2. 关于打印
1. 要打印哪个视就
((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.SetActivePane(...)
// 要打印的那个视对应的Pane
2. 有一个单文档工程,文档窗口被切分:左视图由CTreeView 的派生类管理,右视图由CListView 的派生类CMyListView (其为风格为LVS_REPORT )管理, 我想为右视图添加打印和打印预览,我在MyListView.cpp 中添加了
ON_COMMAND(ID_FILE_PRINT,CListView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CListView::OnFilePrintPreview) 还有
BOOL CMyListView::OnPreparePrinting(CPrintInfo* pInfo)
{
// TODO: call DoPreparePrinting to invoke the Print dialog box
// return CListView::OnPreparePrinting(pInfo);
pInfo->SetMaxPage(2);
BOOL bret=DoPreparePrinting(pInfo);
pInfo->m_nNumPreviewPages=2;
return bret;
}
3. 下面是从MSDN 中摘出来的一段,是用来改变消息路由的。用了这段代码之后,CView 中的消息(菜单,控件,子窗口)将先被CMyShape 类来处理。不知道你要的是不是这样的效果。
// This example illustrates extending the framework ‘ s standard command
// route from the view to objects managed by the view. This example
// is from an object-oriented drawing application, similar to the
// DRAWCLI sample application, which draws and edits "shapes".
BOOL CMyView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
// Extend the framework ‘ s command route from the view to
// the application-specific CMyShape that is currently selected
// in the view. m_pActiveShape is NULL if no shape object
// is currently selected in the view.
if ((m_pActiveShape != NULL)
&& m_pActiveShape->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// If the object(s) in the extended command route don ‘ t handle
// the command, then let the base class OnCmdMsg handle it.
return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
// The command handler for ID_SHAPE_COLOR (menu command to change
// the color of the currently selected shape) was added to
// the message map of CMyShape (note, not CMyView) using ClassWizard.
// The menu item will be automatically enabled or disabled, depending
// on whether a CMyShape is currently selected in the view, that is,
// depending on whether CMyView::m_pActiveView is NULL. It is not
// necessary to implement an ON_UPDATE_COMMAND_UI handler to enable
// or disable the menu item.
BEGIN_MESSAGE_MAP(CMyShape, CCmdTarget)
//{{AFX_MSG_MAP(CMyShape)
ON_COMMAND(ID_SHAPE_COLOR, OnShapeColor)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
如果你只是想调用OnFilePrint( ) 函数,可以试一试下面的代码,就和调用其它类中的函数一样。
CMDIFrameWnd *pFrame =
(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
// Get the active MDI child window.
CMDIChildWnd *pChild =
(CMDIChildWnd *) pFrame->GetActiveFrame();
// or CMDIChildWnd *pChild = pFrame->MDIGetActive();
// Get the active view attached to the active MDI child
// window.
CMyView *pView = (CMyView *) pChild->GetActiveView();
pView->OnFilePrint( );
4.
void CMyReportView::OnFileOpen()
{
char Filter[] = "Crystal Report files(*.rpt)|*.rpt|All files(*.*)|*.*||";
CRect rect;
CFileDialog OpenDlg(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(OpenDlg.DoModal()!=IDOK) /// 显示文件对话框
return;
CString m_fName=OpenDlg.GetPathName(); /// 取得文件名
if(m_CrystalReport)
m_CrystalReport.DestroyWindow();
GetClientRect(rect);
/////////////////// 创建控件///////////////
if
(!m_CrystalReport.Create(AfxRegisterWndClass(0,
AfxGetApp()->LoadStandardCursor(IDC_ARROW)),WS_CHILD|WS_VISIBLE,rect,this,IDC_CRYSTALREPORT1))
{
AfxMessageBox(" 控件创建失败!");
return ;
}
m_CrystalReport.SetWindowParentHandle((long)(this->m_hWnd));/// 设置父窗口
m_CrystalReport.SetWindowBorderStyle(0); /// 设置为没有边框
m_CrystalReport.SetWindowLeft(0); /// 左空间
m_CrystalReport.SetWindowTop(0); /// 顶部空间
m_CrystalReport.SetWindowControls(FALSE); /// 不显示工具条
m_CrystalReport.SetReportFileName(m_fName); /// 设置报表文件
m_CrystalReport.SetWindowWidth(rect.Width()); /// 设置窗口宽度
m_CrystalReport.SetWindowHeight(rect.Height()); /// 设置窗口高度
m_CrystalReport.SetFormulas(0, "Company=/"VC 知识库/""); /// 将报表中的Company 变量的值设置为VC 知识库
m_CrystalReport.SetDestination(0); /// 设置输出对象是屏幕
m_CrystalReport.PrintReport(); /// 显示报表
}
void CMyReportView::OnFilePrint()
{
if(m_CrystalReport && m_CrystalReport.GetReportFileName() != "")
{
m_CrystalReport.SetDestination(1); /// 设置输出对象是打印机
m_CrystalReport.PrintReport(); /// 打印
}
积累的VC 编程小技巧之文件操作
1. 删除文件夹
// 删除文件夹及其所有内容
void CBaseDoc::RemoveFolder(const CString &strPathName)
{
CString path = strPathName;
if (path.Right(1) != _T("//"))
path += _T("//");
path += _T("*.*");
CFileFind ff;
BOOL res = ff.FindFile(path);
while (res)
{
res = ff.FindNextFile();
// 是文件时直接删除
if (!ff.IsDots() && !ff.IsDirectory())
DeleteFile(ff.GetFilePath());
else if (ff.IsDots())
continue;
else if (ff.IsDirectory())
{
path = ff.GetFilePath();
// 是目录时继续递归,删除该目录下的文件
RemoveFolder(path);
::RemoveDirectory(path);
}
}
}
2. 遍历整个目录查找文件
在应用程序的开发过程中,会遇到如何查找某一文件以确定此文件路径的问题。利用CFileFind 类可以比较方便地在当前目录下进行文件查找,但却不能对其子目录中的文件进行搜寻。而实际应用中往往需要对某一整个目录树,甚至是整个C 盘或D 盘驱动器进行文件搜寻。通过实践,我们在Visual C ++ 6.0 中编程实现了如何遍历任意目录树,以查找某一特定的文件。
在下面的具体陈述中可以看到,在确定要查找的文件名和要进行搜索的目录的名称后,将调用函数Search_Directory 进行文件的查找。首先依次查找当前目录下的每一个实体(文件或是子目录),如果是某一子目录,则进入该子目录并递归调用函数Search_Dirctory 进行查找,查找完毕之后, 再返回上一级目录;如果不是子目录而是某一文件,则判断其是否就是我们要查找的文件,如果是则输出其完整的文件路径。这样,通过Search_Directory 函数的反复递归调用,就可以实现对整个目录,包括子目录的遍历搜索。下面将举例详细讲述如何在VC ++中编程实现在整个目录树中的文件查找。
1 . 在Visual C ++ 6.0 (VC ++ 5.0 与之类似)中用默认方式创建了一基于对话框的应用程序Search 。在主窗口对话框上放置一命令按钮,其Caption 为 “ Search File ” ,ID 为ID_BUTTON_SEARCH 。单击此按钮将完成文件的查找工作。
2 . 利用ClassWizard 为 “ Search File ” 按钮的BN_CLICKED 事件添加处理函数OnButtonSearch ,代码如下:
#include 〈direct.h 〉
#include 〈io.h 〉
void CSearchDlg::OnButtonSearch()
{
// TODO: Add your control notification handler code here
char szFilename[80];
// 字符串 szFilename 表示要查找的文件名
strcpy(szFilename,"Mytext.txt");
_chdir("d://"); // 进入要查找的路径(也可为某一具体的目录)
// 查找文件, 如果查到则显示文件的路径全名
Search_Directory(szFilename);
// 为CSearchDlg 类的一成员函数
MessageBox( ″查找文件完毕! ″);
// 显示查找完毕的信息
}
3. 在CSearchDlg 类中增加成员函数Search_Directory ,它将完成具体的文件查找工作,代码如下:
void CSearchDlg::Search_Directory(char* szFilename)
{
long handle;
struct _finddata_t filestruct;
// 表示文件( 或目录) 的信息
char path_search[_MAX_PATH];
// 表示查找到的路径结果
// 开始查找工作, 找到当前目录下的第一个实体( 文件或子目录) ,
// "*" 表示查找任何的文件或子目录, filestruct 为查找结果
handle = _findfirst("*", &filestruct);
// 如果handle 为-1, 表示当前目录为空, 则结束查找而返回
if((handle == -1)) return;
// 检查找到的第一个实体是否是一个目录(filestruct.name 为其名称)
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
// 如果是目录, 则进入该目录并递归调用函数Search_Dirctory 进行查找,
// 注意: 如果目录名的首字符为 ‘ . ‘ ( 即为"." 或".."), 则不用进行查找
if( filestruct.name[0] != ‘ . ‘ )
{
_chdir(filestruct.name);
Search_Directory(szFilename);
// 查找完毕之后, 返回上一级目录
_chdir("..");
}
}
else // 如果第一个实体不是目录, 则检查是否是要查找的文件
{
// stricmp 对两字符串进行小写形式的对比, 返回为0 表示完全一致
if( !stricmp(filestruct.name, szFilename) )
{
// 先获得当前工作目录的全路径
_getcwd(path_search,_MAX_PATH);
// 再获得文件的完整的路径名( 包含文件的名称)
strcat(path_search,"//");
strcat(path_search,filestruct.name);
MessageBox(path_search); // 输出显示
}
}
// 继续对当前目录中的下一个子目录或文件进行与上面同样的查找
while(!(_findnext(handle,&filestruct)))
{
if( ::GetFileAttributes(filestruct.name) & FILE_ATTRIBUTE_DIRECTORY )
{
if(*filestruct.name != ‘ . ‘ )
{
_chdir(filestruct.name);
Search_Directory(szFilename);
_chdir("..");
}
}
else
{
if(!stricmp(filestruct.name,szFilename))
{
_getcwd(path_search,_MAX_PATH);
strcat(path_search,"//");
strcat(path_search,filestruct.name);
MessageBox(path_search);
}
}
}
_findclose(handle);
// 最后结束整个查找工作
}
这样我们就可以对整个目录进行遍历搜索,查找某一特定的文件,并输出显示其完整的文件路径。以上的程序在Visual C ++ 6.0 中已调试通过。
3. 创建多级目录
BOOL mkdirEx(const char* lpPath)
{
CString pathname = lpPath;
if(pathname.Right(1) != "/")
pathname += "/" ;
int end = pathname.ReverseFind( ‘ / ‘ );
int pt = pathname.Find( ‘ / ‘ );
if (pathname[pt-1] == ‘ : ‘ )
pt = pathname.Find( ‘ / ‘ , pt+1);
CString path;
while(pt != -1 && pt<=end)
{
path = pathname.Left(pt+1);
if(_access(path, 0) == -1)
_mkdir(path);
pt = pathname.Find( ‘ / ‘ , pt+1);
}
return true;
}
4. 创建包含多个子目录的目录
void CreateAllDirectories(CString strDir)
{
//remove ending / if exists
if(strDir.Right(1)=="//")
strDir=strDir.Left(strDir.GetLength()-1);
// base case . . .if directory exists
if(GetFileAttributes(strDir)!=-1)
return;
// recursive call, one less directory
int nFound = strDir.ReverseFind( ‘ // ‘ );
CreateAllDirectories(strDir.Left(nFound));
// actual work
CreateDirectory(strDir,NULL);
}