东北男生平均身高:VC编程小技巧之框架窗口及其他

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 05:58:13
积累的VC编程小技巧之框架窗口及其他

原 作 者:huzunbo

1.修改主窗口风格



AppWizard生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名、窗口是叠加型的、可改变窗口大小等。要修改窗口的缺省风格,需要重载CWnd::PreCreateWindow(CREATESTRUCT& cs)函数,并在其中修改CREATESTRUCT型参数cs。
CWnd::PreCreateWindow 函数先于窗口创建函数执行。如果该函数被重载,则窗口创建函数将使用CWnd::PreCreateWindow 函数返回的CREATESTRUCT cs参数所定义的窗口风格来创建窗口;否则使用预定义的窗口风格。
CREATESTRUCT结构定义了创建函数创建窗口所用的初始参数,其定义如下:

typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams; // 创建窗口的基本参数
HANDLE hInstance; // 拥有将创建的窗口的模块实例句柄
HMENU hMenu; // 新窗口的菜单句柄
HWND hwndParent; // 新窗口的父窗口句柄
int cy; // 新窗口的高度
int cx; // 新窗口的宽度
int y; // 新窗口的左上角Y坐标
int x; // 新窗口的左上角X坐标
LONG style; // 新窗口的风格
LPCSTR lpszName; // 新窗口的名称
LPCSTR lpszClass; // 新窗口的窗口类名
DWORD dwExStyle; // 新窗口的扩展参数
} CREATESTRUCT;

CREATESTRUCT结构的style域定义了窗口的风格。比如,缺省的MDI主窗口的风格中就包括FWS_ADDTOTITLE(在标题条中显示当前的工作文档名)、FWS_PREFIXTITLE(把文档名放在程序标题的前面)、WS_THICKFRAME(窗口具有可缩放的边框)等风格。由于多种风格参数由逻辑或(“|”)组合在一起的,因此添加某种风格,就只需用“|”把对应的参数加到CREATESTRUCT结构的style域中;删除已有的风格,则需用“&”连接CREATESTRUCT结构的style域与该风格的逻辑非值。
CREATESTRUCT结构的x、y、cx、cy域分别定义了窗口的初始位置和大小,因此,在CWnd::PreCreateWindow 函数中给它们赋值,将能定义窗口的初始显示位置和大小。
下例中的代码将主框窗口的大小将固定为1/4屏幕,标题条中仅显示窗口名,不显示文档名。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs

// 修改主窗风格
cs.style &= ~FWS_ADDTOTITLE; //去除标题条中的文档名
cs.style &= ~WS_THICKFRAME; //去除可改变大小的边框
cs.style |= WS_DLGFRAME; //增加不能改变大小的边框

// 确定主窗的大小和初始位置
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);//获得屏幕宽
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); //获得屏幕高
cs.x = 0; // 主窗位于左上角
cs.y = 0;
cs.cx = cxScreen/2; // 主窗宽为1/2屏幕宽
cs.cy = cxScreen/2; // 主窗高为1/2屏幕高
return CMDIFrameWnd::PreCreateWindow(cs);
}





2.窗口的分割与停靠                      
                  



一、新建一个类CMySplitter,基类为CSplitterWnd



二、重载该类的OnMouseMove函数:

void CMySplitter::OnMouseMove(UINT nFlags, CPoint point)
{ 
         // 限制切分条的运动范围。 
         if(point.x<228||point.x>600) 
         { 
                 CWnd::OnMouseMove(nFlags, point); 
         } 
         else 
         { 
                 CSplitterWnd::OnMouseMove(nFlags, point); 
         } 
}


三、 然后就可以跟一般的窗口分割那样去做了,if(point.x<228||point.x>600)这里的范围可以随你去设置了 ^_^,够简单吧。



四、切分窗口
在MaiFram.h建立切分条对象:



protected:



CMySplitter m_wndSplitter; //切分窗口对象

//在MaiFram.cpp中实现窗口切分: 
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,CCreateContext* pContext) 
{ 
         // 创建拆分器窗口 
if (!m_wndSplitter.CreateStatic(this, 1, 2)) 
                 return FALSE; 


if
(!m_wndSplitter.CreateView(0, 0,
RUNTIME_CLASS(CLeftView),CSize(228,100), pContext)
||!m_wndSplitter.CreateView(0,1, RUNTIME_CLASS(CDataEditView),  CSize(100, 100), pContext))

         { 
                 m_wndSplitter.DestroyWindow(); 
                 return FALSE; 
         } 
 
         return TRUE; 


}





3.如何使我的程序在启动时不创建一个新文档



[问题]
如何使我的程序在启动时不创建一个新文档?
[解答]
在程序的InitInstance中的ProcessShellCommand函数之前加入: cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing





4.初始化应用程序的大小



如果想使应用程序界面(文档)在开始运行是按你的尺寸展现在屏幕上,
  添加代码如下:
  BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
  {
      int xsize=::GetSystemMetrics(SM_CXSCREEN);
      int ysize=::GetSystemMetrics(SM_CYSCREEN);
      cs.cx=xsize*5/10;
      cs.cy=ysize*5/10;
      cs.x=(xsize-cs.cx)/2;
      cs.y=(ysize-cs.cy)/2;  

  }
  其中的5/10是你的初始界面占屏幕的百分比,可以自己修改。如果想使应用程序大小固定添加cs.style&=~WS_THICKFRAME;



5.如何全屏显示(没有标题,没有菜单,没有工具条)



  [解决方法]
    重载CMainFrame的ActivateFrame函数:
    void CMainFrame::ActivateFrame(int nCmdShow)
    {
         CRect cRectdesktop;
         WINDOWPLACEMENT windowplacement;
         ::GetWindowRect(::GetDesktopWindow(),&cRectdesktop);
         ::AdjustWindowRectEx(&cRectdesktop,GetStyle(),TRUE,GetExStyle());
         windowplacement.rcNormalPosition=cRectdesktop;
         windowplacement.showCmd=SW_SHOWNORMAL;
         SetWindowPlacement(&windowplacement);

         CFrameWnd::ActivateFrame(nCmdShow);



}



6.如何限制mdi子框架最大化时的大小



用ptMaxTrackSize代替prMaxSize,如下所示:



void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
   // TOD Add your message handler code here and/or call default
   CChildFrame::OnGetMinMaxInfo(lpMMI);
   lpMMI->ptMaxTrackSize.x = 300;
   lpMMI->ptMaxTrackSize.y = 400;
}





7.程序如何删除自己



/////////////////////////////////////////////////
 
int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {
 
// Is this the Original EXE or the clone EXE?
// If the command-line 1 argument, this is the Original EXE
// If the command-line >1 argument, this is the clone EXE
 
if (__argc == 1) {
 
// Original EXE: Spawn clone EXE to delete this EXE
// Copy this EXEcutable image into the user‘‘s temp directory
 
TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
GetTempPath(_MAX_PATH, szPathClone);
GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone);
CopyFile(szPathOrig, szPathClone, FALSE);
 
//***注意了***:
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTI
NG, FILE_FLAG_DELETE_ON_CLOSE, NULL);
 
// Spawn the clone EXE passing it our EXE‘‘s process handle
// and the full path name to the Original EXE file.
TCHAR szCmdLine[512];
HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());

wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, hProcessOrig, szPat
hOrig);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(hProcessOrig);
CloseHandle(hfile);
 
// This original process can now terminate.
} else {
// Clone EXE: When original EXE terminates, delete it
HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
WaitForSingleObject(hProcessOrig, INFINITE);
CloseHandle(hProcessOrig);
DeleteFile(__targv[2]);
// Insert code here to remove the subdirectory too (if desired).
 
// The system will delete the clone EXE automatically
// because it was opened with FILE_FLAG_DELETE_ON_CLOSE
}
return(0);
}

2006-12-29 23:28:21---------------------------------------------------------------
硬件之路~ 编辑帖子帖子评价单帖屏蔽删除帖子fipl等级:论坛版主头衔:社区公民帮派:无帮无派帖数:1672金钱:64900积分:10第 1 楼 信息 | 留言 | QQ | Email | 主页 | 编辑 | 引用 | 管理 这一段程序思路很简单:不是不能在运行时直接删除本身吗?好,那么程序先复制(CLONE)一个自己,用复制品起动另一个进程,然后自己结束运行,则原来的EXE文件不被系统保护.这时由新进程作为杀手删除原来的EXE文件,并且继续完成程序其他的功能。

  新进程在运行结束后,复制品被自动删除。这又是值得介绍的一个把戏了,注意:

// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,OPEN_EXISTIN
G, FILE_FLAG_DELETE_ON_CLOSE, NULL);
 
 这里面的FILE_FLAG_DELETE_ON_CLOSE标志,这个标志是告诉操作系统,当和这个文件相关的所有句柄都被关闭之后(包括上面这个
CREATEFILE创建的句炳),就把这个文件删除。几乎所有的临时文件在创建时,都指明了这个标志。另外要注意的是:在复制品进程对原始程序操刀之
前,应该等待原进程退出.在这里用的是进程同步技术.用HANDLE hProcessOrig =
OpenProcess(SYNCHRONIZE,
TRUE,GetCurrentProcessId());得到原进程句柄.SYNCHRONICE标志在NT下有效,作用是使OpenProcess得
到的句柄可以做为同步对象.复制品进程用WaitForSingleObject函数进行同步,然后一个DeleteFile,以及进行其它销毁证据(比
如删目录)的工作,一切就完事了。
 
  程序是基于CONSOLE的,通过传入的参数确定是原始的进程还是复制品新进程,并且得到需要操
作的目标文件的信息(主要是路径),复制品放在系统的TEMP目录(GetTempPath得到),你也可以随便找个你认为安全的地方(比如:
WINDOWS\SYSTEM32等等)。这里面没有甚么深的技术.再看其他的一些实现删除自己的例子,比如说在进程退出前,用fwrite等方法输出一
个.BAT文件,在里面写几句DEL,然后WINEXEC一下这个BAT文件即可.玩儿过DOS的虫虫大多都会。



8.如何实现SDI与MDI的转换



我想将一个编好的SDI应用程序转换为MDI,很明显要有多处的改变。



你可以这样做:建立一个继承于CMDIChidWnd的类,不防设为CChldFrm.在CWinApp中作如下变化。




InitInstance()
{
. ...
    //instead of adding CSingleDocTemplate
    // Add CMultiDocTemplate.
    pDocTemplate = new CMultiDocTemplate(
           IDR_MAINFRAME,
           RUNTIME_CLASS(CSDIDoc),
           RUNTIME_CLASS(CChldFrm),
// For Main MDI Frame change this frame window from
// CFrameWnd derivative ( i.e. CMainFrame )
// to your CMDIChildWnd derived CChldFrm.
           RUNTIME_CLASS(CSDIView));
/// After this it is required to create the main frame window
// which will contain all the child windows. Now this window is
// what was initially frame window for SDI.
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
            return FALSE;
     m_pMainWnd = pMainFrame;
.....
}



在从CMDIFrameWnd中继承的类CMainFrame代替CFramWnd后,所有的类都将从CMDIFrame继承,而不是CFrameWnd,编译运行后你就会发现程序已经从SDI变换到MDI。
注意:在CMainFram中必须将构造函数从private改为public.否则会出错。



9.想在程序一启动时就自动关闭窗口,不在任务栏里显示



CTRL+W打开ClassWizard;
点击Class Info,类名是工程名Dlg,
再在左下方的"Filter"中选择"Windows";
回到Message Maps,就可以看到消息中有WM_WINDOWPOSCHANGING,
加入代码,如上所示.
这样运行*.EXE,不但看不到主界面,任务栏也没有,就是任务管理器中的"应用程序"中也不列出,那该如何关闭它?
在任务管理器的"进程"中可以找到它,这是黑客程序常用的方法.
如果需要的话,"进程"中也看不到.这样要终止它就是问题了





10.如何修改frame窗口的背景颜色



MDI窗口的客户区是由frame窗口拥有的另一个窗口覆盖的。为了改变frame窗口背景的颜色,只需要这个客户区的背景颜色就可以了。你必须自己处理WM_ERASEBKND消息。下面是工作步骤:
  创建一个从CWnd类继承的类,就叫它CMDIClient吧;
  在CMDIFrameWnd中加入CMDIClient变量;(具体情况看下面的代码)
#include "MDIClient.h"
class CMainFrame : public CMDIFrameWnd
{
...
protected:
CMDIClient m_wndMDIClient;
}
  重载CMDIFrameWnd::OnCreateClient,下面是这段代码,请注意其中的SubclassWindow();
 
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )
{
m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
else
return FALSE;
}
  最后要在CMDIClient中加入处理WM_ERASEBKGND的函数。





11.在MFC下实现图像放大镜



一、 引言



当我们想仔细观察某个细微的东西时,一般都会使用放大镜。而要看清显示在计算机屏幕上的图片或文字时通常也



可以借助于Windows操作系统附带的放大程序来实现。但该程序只能以固定的放大倍数
去进行观看,有时并不能满足我们的需要。本文就通过MFC基本类库提供的StretchBlt函数来实现对屏幕图象的局部放大,并且可以随意放大、缩小,
选取到合适的放大倍数来对图像的细节进行观察。



二、 设计与实现



本程序主要用来对图像的局部进行可调倍数的放大,应当具有以下主要功能:



1. 移动MOUSE放大显示图像的不同部位



2. 左击增加放大倍率、右击减少放大倍率。



从光学角度来看,对物体的放大成像是通过把较小的真实物体显示成尺寸较大的虚像来实现的。因此我们可以用类



似的原理,把图像中待放大的区间从较小的显示范围拉伸到一个比较大的显示范围即可达到图
像放大的效果,两个区间的比值也就是图像的放大倍率。可以通过缩小源区间的范围或扩大放大区间的范围来实现放大倍率的调整。在MFC基本类库中提供有
CDC类的StretchBlt函数可以将一幅位图从一个源矩形以一定的光栅操作拷贝到另外一个不同大小的目标矩形中去,因此可以用此函数来实现图象放大
的功能,其函数原形声明如下:



BOOL StretchBlt( int x, int y, //目标矩形的坐标原点



int nWidth, int nHeight, //目标矩形的长度和宽度



CDC* pSrcDC, //源设备环境句柄



int xSrc, int ySrc, //源矩形的坐标原点



int nSrcWidth, int nSrcHeight, //源矩形的长度和宽度



DWORD dwRop ); //光栅操作标志



当指定的源和目标矩形的宽度或高度不一样时,StretchBlt函数将创建一个位图的镜像。如果是宽度有变化,就沿x轴创建镜像;如果是高度上有变化就沿y轴创建镜像。而且该函数可以在内存中对源图象做拉伸或压缩处理后再拷贝到目标矩形中去。



要放大图像首先要把图像显示出来,一般可以从文件动态装载或者直接从资源中用LoadBitMap读取位图资源。下面的代码放在视类的OnDraw函数中,用以在第一次调用时将位图装载并显示出来,以后再被调用只是负责重画:



……



static bool load;



if (!load)



{



BITMAP bm;



load = !load;



//装载位图到 m_pBitmap



m_pBitmap->LoadBitmap(IDB_BITMAP1);



//创建相关的设备环境



m_pdcMem->CreateCompatibleDC(pDC);



//将位图从m_ pBitmap中装载到m_pdcMem中



m_pdcMem->SelectObject(m_pBitmap);



m_pBitmap->GetObject(sizeof(bm),&bm);



m_sizeSource.cx = bm.bmWidth;



m_sizeSource.cy = bm.bmHeight;



m_sizeDest = m_sizeSource;



//把位图从m_pdcMem中装载到当前正在使用的设备环境中



pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana);



}



else



{



//重画图像



pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana);



SetCursor(NULL);//隐藏鼠标



}



要实现前面提到的第一个功能:移动MOUSE放大显示图像的不同部位,显然首先要在
WM_MOUSEMOVE消息的响应函数里编写代码。以整形变量s和d来分别表示所选取的源和目标区域的大小,再通过消息响应函数OnMouseMove
的入口参数point来确定当前的鼠标位置就可以计算出我们要选取的源和目标区域在图像的位置。放大的工作只需通过StretchBlt函数将源区域中所
在的图像拉伸到目标矩形那么大,并拷贝给目标区域即可实现所选区域的放大效果,下面是部分主要代码:



……



//确定目标区域、源区域的坐标位置



CRect srect,drect,mrect;



srect.left = point.x - s;



srect.top = point.y - s;



srect.right = point.x + s;



srect.bottom = point.y + s;



drect.left = point.x - d;



drect.top = point.y - d;



drect.right = point.x + d;



drect.bottom = point.y + d;



mrect.left = oldx - d;



mrect.top = oldy - d;



mrect.right = oldx + d;



mrect.bottom = oldy + d;



dd = 2*d;



//获取可用设备环境句柄



CDC * pDC = GetDC();



OnPrepareDC(pDC);



if (recover)



{



pDC->BitBlt(mrect.left,mrect.top,dd,dd,m_pdcMem,mrect.left,mrect.top,mana);



}



//隐藏鼠标



SetCursor(NULL);



//拉伸放大



pDC->StretchBlt(drect.left,drect.top,drect.Width(),drect.Height(),m_pdcMem,srect.left,srect.top,srect.Width(),srect.Height(),SRCCOPY);



//保存当前鼠标位置备用



oldx = point.x; oldy = point.y;



//释放设备环境句柄



ReleaseDC(pDC);



recover = true;



……



为了实现第二个功能:左击增加放大倍率、右击减少放大倍率,可以分别在消息
WM_LBUTTONDOWN和消息WM_RBUTTONDOWN中添加改变选取区域大小的代码来实现。如果选取源矩形不变而改变目标矩形的大小会随着放
大倍数的增大,显示区域也不断增大,当放大到一定程度的时候会另人无法忍受,因此选取通过缩放源矩形大小来控制放大倍数的方案:



void CZoomInView::OnRButtonDown(UINT nFlags, CPoint point)



{



if (s < 60)



{



SetCursor(NULL);



s+=3;



OnMouseMove(nFlags, point);



}



CView::OnRButtonDown(nFlags, point);



}



……



void CZoomInView::OnLButtonDown(UINT nFlags, CPoint point)



{



if(s>5)



{



s-=3;



SetCursor(NULL);



OnMouseMove(nFlags, point);



}



CView::OnLButtonDown(nFlags, point);



}



(完)

2006-12-29 23:29:49---------------------------------------------------------------
硬件之路~ 编辑帖子帖子评价单帖屏蔽删除帖子fipl等级:论坛版主头衔:社区公民帮派:无帮无派帖数:1672金钱:64900积分:10第 2 楼 信息 | 留言 | QQ | Email | 主页 | 编辑 | 引用 | 管理
积累的VC编程小技巧之图标、光标及位图



1.图标透明



(1).Windows中的图标其实是有两个图像组成的,其中一个用于与它要显示的位置的图像做“AND”操作,另一个作“XOR”操作。

透明:用“白色”AND,用“黑色”XOR
反色:用“白色”AND,用“白色”XOR
正常色:用“黑色”AND,用正常颜色XOR.
(2). WIN9X中好像是对像素的操作实现透明的
WIN2K中就有API直接实现透明了!
WIN2K中
GetWindowLong
SetWindowLong
SetLayeredWindowAttributes
三个API就可以实现透明了!
(3) 


::DrawIconEx(pDC->GetSafeHdc(),point.x,point.y,icon,icosize,icosize,0,NULL,DI_NORMAL);





2.如何获得其他程序的图标,并显示在View中



  [问题提出]
  有的时候,如:类资源管理器会遇到获得程序图标并显示的操作,如何实现呢?
  [解决方法]
  SDK函数SHGetFileInfo来获得有关文件的很多信息:如大小图标,属性,类型等.
  [程序实现]
  建立名为My的SDI工程.在OnPaint()函数中加入:
  void CMyView::OnPaint()
  {
   CPaintDC dc(this); // device context for painting
   HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);
   if (hIcon && hIcon!=(HICON)-1)
   dc.DrawIcon(10,10,hIcon);

   // TODO: Add your message handler code here
   // Do not call CView::OnPaint() for painting messages
  }
  说明:_T("NotePad.exe")指的是要获得什么程序的图标.
  或者在OnDraw()中(此时必须保证没有OnPaint()函数,想想为何?)
  void CMyView::OnDraw(CDC* pDC)
  {
   CMyDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   // TODO: add draw code for native data here
   HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T("NotePad.exe"),0);
   if (hIcon &&hIcon!=(HICON)-1)
   pDC->DrawIcon(10,10,hIcon);
  }





3.如何改变默认的光标形状



在对话框/窗口/你需要的地方加上对WM_SETCURSOR消息的处理.



BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    // TOD Add your message handler code here and/or call default
    ::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR));
    return TRUE;
    //return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
窗口类光标风格不能为NULL.





4.改变应用程序的图标静态更改



  修改图标资源IDR_MAINFRAME。它有两个图标,一个是16*16的,另一个是32*32的,注意要一起修改。



  动态更改: 向主窗口发送WM_SETICON消息.代码如下:



HICON hIcon=AfxGetApp()->LoadIcon(IDI_ICON);
ASSERT(hIcon);
AfxGetMainWnd()->SendMessage(WM_SETICON,TRUE,(LPARAM)hIcon);





5.更改窗口图标并将其显示在任务栏



以下两个函数可以为应用程序中的各子窗口显示一个任务条到任务栏并更改它们的图标。对那些象QQ一样隐藏主窗口的应用程序特别有用。

//函数用途:更改一个窗口的图标并将其显示在任务栏、任务切换条、任务管理器里
//参数说明:
//hWnd
要改变图标的窗口句柄
//hLargeIcon 显示到任务切换条上的图标 32*32
//hSmallIcon
显示到除任务切换条之外的图标 16*16
//hIcon
显示的图标,32*32,在显示到任务切换条之外的其余地方时会被自动压缩成16*16的。
//注释:
//此函数对于模式对话框无能为力。
//如果HICON NULL,函数不改变窗口图标,但是将原有图标显示到任务栏、
// 任务切换条、任务管理器里。
//此函数是通过将窗口的父窗口指针置空来实现将图标显示到任务栏、任务切换条、
// 任务管理器里的,所以调用完成后,其父窗口指针不再可用。
BOOL SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon);
BOOL SendWndIconToTaskbar(HWND hWnd,HICON hIcon);
BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon)
{
 BOOL ret = TRUE;
 ASSERT(hWnd);
 if(!::IsWindow(hWnd))
  return FALSE;
 //获取窗口指针
 CWnd* pWnd;
 pWnd = pWnd->FromHandle(hWnd);
 ASSERT(pWnd);
 if(!pWnd)
  return FALSE;
 //将父窗口设为NULL
 if(pWnd->GetParent())
  if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)
   return FALSE;

  if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))
   ret = FALSE;
  //设置窗口图标
  if(hLargeIcon && hSmallIcon)
  {
   pWnd->SetIcon(hSmallIcon,FALSE);
   pWnd->SetIcon(hLargeIcon,TRUE);
  }

  return ret;
 }

BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hIcon)
{
 BOOL ret = TRUE;
 ASSERT(hWnd);
 if(!::IsWindow(hWnd))
  return FALSE;
  //获取窗口指针
 CWnd* pWnd;
 pWnd = pWnd->FromHandle(hWnd);
 ASSERT(pWnd);
 if(!pWnd)
  return FALSE;
 //将父窗口设为NULL
 if(pWnd->GetParent())
  if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)
   return FALSE;

 if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))
  ret = FALSE;
 //设置窗口图标
 pWnd->SetIcon(hIcon,TRUE);
 pWnd->SetIcon(hIcon,FALSE);

 return ret;
}





6.如何将位图缩放显示在Static控件中



//在Staic控件内显示位图
void CShowBmpInDlgDlg::ShowBmpInStaic()
{
    CBitmap hbmp;
    HBITMAP hbitmap;
    //将pStatic指向要显示的地方
    CStatic *pStaic;
    pStaic=(CStatic*)GetDlgItem(IDC_IMAGE);
    //装载资源 MM.bmp是我的一个文件名,用你的替换
    hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),"MM.bmp",
        IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    
    hbmp.Attach(hbitmap);
    //获取图片格式
    BITMAP bm;
    hbmp.GetBitmap(&bm);
    CDC dcMem;
    dcMem.CreateCompatibleDC(GetDC());
    CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
    CRect lRect;
    pStaic->GetClientRect(&lRect);
    //显示位图
    pStaic->GetDC()->StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Height(),
        &dcMem,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
    dcMem.SelectObject(&poldBitmap);
}



2006-12-29 23:30:45---------------------------------------------------------------
硬件之路~ 编辑帖子帖子评价单帖屏蔽删除帖子fipl等级:论坛版主头衔:社区公民帮派:无帮无派帖数:1672金钱:64900积分:10第 3 楼 信息 | 留言 | QQ | Email | 主页 | 编辑 | 引用 | 管理           
          
            积累的VC编程小技巧之视图

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));
}



2006-12-29 23:32:06---------------------------------------------------------------
硬件之路~ 编辑帖子帖子评价单帖屏蔽删除帖子fipl等级:论坛版主头衔:社区公民帮派:无帮无派帖数:1672金钱:64900积分:10第 4 楼 信息 | 留言 | QQ | Email | 主页 | 编辑 | 引用 | 管理           
          
          
    积累的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(); ///打印



}



2006-12-29 23:33:30---------------------------------------------------------------
硬件之路~ 编辑帖子帖子评价单帖屏蔽删除帖子fipl等级:论坛版主头衔:社区公民帮派:无帮无派帖数:1672金钱:64900积分:10第 5 楼 信息 | 留言 | QQ | Email | 主页 | 编辑 | 引用 | 管理           
          
        积累的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);
}


2006-12-29 23:34:34---------------------------------------------------------------
硬件之路~