公告:     清河论坛已经开通,开始测试了!!!!!!  [王嵩峰  2006年9月15日]        
您现在的位置: 清河在线 >> 设计教程 >> 程序开发 >> 教程正文
最新热门教程
最新推荐教程
广告载入中...
Visual C++窗体设计灵活技术集1     ★★★
Visual C++窗体设计灵活技术集1
副标题:Visual C++窗体设计灵活技术集1
作者:佚名    教程来源:本站原创    点击数:    更新时间:2007-3-11

[前言:]有好的界面软件就成功了一半,本文将向您介绍怎样设计一些有“稀奇古怪”形状的窗体,如何设定窗体的颜色、如何设置任务栏和状态栏以及菜单图标等等,通过这些技巧能更深入的理解VC的文档-视图结构。

   如何制作透明窗体

   使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。



   SetLayeredWindowAttributes的函数原型如下:

BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window
COLORREF crKey, // specifies the color key
BYTE bAlpha, // value for the blend function
DWORD dwFlags // action
);

Windows NT/2000/XP: Included in Windows 2000 and later.
Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的)
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.


   一些常量:


WS_EX_LAYERED = 0x80000;
LWA_ALPHA = 0x2;
LWA_COLORKEY=0x1;

   其中dwFlags有LWA_ALPHA和LWA_COLORKEY

   LWA_ALPHA被设置的话,通过bAlpha决定透明度.

   LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示.

   要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000).

   例子代码:

   在OnInitDialog()加入:

//加入WS_EX_LAYERED扩展属性
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
  typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
  MYFUNC fun = NULL;
  //取得SetLayeredWindowAttributes函数指针
  fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
  if(fun)fun(this->GetSafeHwnd(),0,128,2);
  FreeLibrary(hInst);
}

   稍加修改还可以作出淡出淡入的效果. 注意第三个参数(128)不要取得太小了,为0的话就完全透明,看不到了。

   如何使框架窗口的图标为动画显示

   可以用TIMER,但是TIMER不能有效的定时。因为TIMER发送的是窗口消息,当窗口忙于处理键盘、鼠标等消息时就不能及时处理TIMER,会使间隔时间变得很长 。

   可以考虑用一个单独得TIMER线程,用Sleep()定时来解决此问题。


UINT Timer(LPVOID param)
{
  HWND hWnd=(HWND)param;
  while(1)
  {
   Sleep(ms);
   PostMessage(hWnd,CH_PICTURE,NULL,NULL)
  }
}

   Sleep(ms)后发送自定义消息。消息处理函数就选择某一个ICON或B99vMAP来显示。如 :


MyBotton.SetBitmap((HB99vMAP)Bitmap[i]);

   Bitmap是一个位图数组,存放有j个位图。消息处理函数运行一次,i就累加一次,当i==j时,i就回到0;

   防止窗口闪烁的方法

   1、将Invalidate()替换为InvalidateRect()。

   Invalidate()会导致整个窗口的图象重画,需要的时间比较长,而InvalidateRect()仅仅重画Rect区域内的内容,所以所需时间会少一些。虫虫以前很懒,经常为一小块区域的重画就调用Invalidate(),不愿意自己去计算需要重画的Rect,但是事实是,如果你确实需要改善闪烁的情况,计算一个Rect所用的时间比起重画那些不需要重画的内容所需要的时间要少得多。

   2、禁止系统搽除你的窗口。

   系统在需要重画窗口的时候会帮你用指定的背景色来搽除窗口。可是,也许需要重画的区域也许非常小。或者,在你重画这些东西之间还要经过大量的计算才能开始。这个时候你可以禁止系统搽掉原来的图象。直到你已经计算好了所有的数据,自己把那些需要搽掉的部分用背景色覆盖掉(如:dc.FillRect(rect,&brush);rect是需要搽除的区域,brush是带背景色的刷子),再画上新的图形。要禁止系统搽除你的窗口,可以重载OnEraseBkgnd()函数,让其直接返回TRUE就可以了。如

BOOL CMyWin::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
//return CWnd::OnEraseBkgnd(pDC);//把系统原来的这条语句注释掉。
}

   3、有效的进行搽除。

   搽除背景的时候,不要该搽不该搽的地方都搽。比如,你在一个窗口上放了一个很大的Edit框,几乎占了整个窗口,那么你频繁的搽除整个窗口背景将导致Edit不停重画形成剧烈的闪烁。事实上你可以CRgn创建一个需要搽除的区域,只搽除这一部分。如

GetClientRect(rectClient);
rgn1.CreateRectRgnIndirect(rectClient);
rgn2.CreateRectRgnIndirect(m_rectEdit);
if(rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR) == ERROR)//处理后的rgn1只包括了Edit框之外的客户区域,这样,Edit将不会被我的背景覆盖而导致重画。
{
ASSERT(FALSE);
return ;
}
brush.CreateSolidBrush(m_clrBackgnd);
pDC->FillRgn(&rgn1,&brush);
   注意:在使用这个方法的时候要同时使用方法二。别忘了,到时候又说虫虫的办法不灵。

   4、使用MemoryDC先在内存里把图画好,再复制到屏幕上。

   这对于一次画图过程很长的情况比较管用。毕竟内存操作比较快,而且复制到屏幕又是一次性的,至少不会出现可以明显看出一个东东从左画到右的情况。

void CMyWin::OnPaint()
{
CPaintDC dc1(this); // device context for painting
dcMemory.CreateCompatibleDC(&dc1);
CBitmap bmp;//这里的Bitmap是必须的,否则当心弄出一个大黑块哦。
bmp.CreateCompatibleBitmap(&dc1,rectClient.Width(),rectClient.Height());
dcMemory.SelectObject(&bmp);
//接下来你想怎么画就怎么画吧。
//dcMemory.FillRect(rectClient,&brush);

dc1.BitBlt(0,0,rectClient.Width(),rectClient.Height(),&dcMemory,0,0,SRCCOPY);
dcMemory.DeleteDC();
// Do not call CWnd::OnPaint() for painting messages
}


如何实现全屏显示



   全屏显示是一些应用软件程序必不可少的功能。比如在用VC++编辑工程源文件或编辑对话框等资源时,选择菜单“ViewFull Screen”,即可进入全屏显示状态,按“Esc”键后会退出全屏显示状态。

   在VC++6.0中我们用AppWizard按默认方式生成单文档界面的应用程序框架。下面将先讨论点击菜单项“ViewFull Screen”实现全屏显示的方法,再讲述按“Esc”键后如何退出全屏显示状态。

   1) 在CMainFrame类中,增加如下三个成员变量。

   private:
    WINDOWPLACEMENT m_OldWndPlacement; //用来保存原窗口位置
    BOOL m_bFullScreen; //全屏显示标志
    CRect m_FullScreenRect; //表示全屏显示时的窗口位置

   2)在资源编辑器中编辑菜单IDR_MAINFRAME。在“View”菜单栏下添加菜单项“Full Screen”。在其属性框中,ID设置为ID_FULL_SCREEN,Caption为“Full Screen”。还可以在工具栏中添加新的工具图标,并使之与菜单项“Full Screen”相关联,即将其ID值也设置为ID_FULL_SCREEN。

   3)设计全屏显示处理函数,在CMainFrame类增加上述菜单项ID_FULL_SCREEN消息的响应函数。响应函数如下:


   void CMainFrame::OnFullScreen()
   {
GetWindowPlacement(&m_OldWndPlacement);
   CRect WindowRect;
   GetWindowRect(&WindowRect);
   CRect ClientRect;
   RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &ClientRect);
    ClientToScreen(&ClientRect);
   // 获取屏幕的分辨率
   int nFullWidth=GetSystemMetrics(SM_CXSCREEN);
   int nFullHeight=GetSystemMetrics(SM_CYSCREEN);
   // 将除控制条外的客户区全屏显示到从(0,0)到(nFullWidth, nFullHeight)区域, 将(0,0)和(nFullWidth, nFullHeight)两个点外扩充原窗口和除控制条之外的 客户区位置间的差值, 就得到全屏显示的窗口位置
   m_FullScreenRect.left=WindowRect.left-ClientRect.left;
   m_FullScreenRect.top=WindowRect.top-ClientRect.top;
   m_FullScreenRect.right=WindowRect.right-ClientRect.right+nFullWidth;
   m_FullScreenRect.bottom=WindowRect.bottom-ClientRect.bottom+nFullHeight;
   m_bFullScreen=TRUE; // 设置全屏显示标志为 TRUE
   // 进入全屏显示状态
   WINDOWPLACEMENT wndpl;
   wndpl.length=sizeof(WINDOWPLACEMENT);
   wndpl.flags=0;
   wndpl.showCmd=SW_SHOWNORMAL;
   wndpl.rcNormalPosition=m_FullScreenRect;
   SetWindowPlacement(&wndpl);

}


   4)重载CMainFrame类的OnGetMinMaxInfo函数,在全屏显示时提供全屏显示的位置信息。


   void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
   {
if(m_bFullScreen)
    {

lpMMI->ptMaxSize.x=m_FullScreenRect.Width();
   lpMMI->ptMaxSize.y=m_FullScreenRect.Height();
   lpMMI->ptMaxPosition.x=m_FullScreenRect.Width();
   lpMMI->ptMaxPosition.y=m_FullScreenRect.Height();
   //最大的Track尺寸也要改变
   lpMMI->ptMaxTrackSize.x=m_FullScreenRect.Width();
   lpMMI->ptMaxTrackSize.y=m_FullScreenRect.Height();
   }

CFrameWnd::OnGetMinMaxInfo(lpMMI) ;
   }


   完成上面的编程后,可以联编执行FullScreen.exe,选择菜单“ViewFull Screen”或点击与之关联的工具栏按钮即可进入全屏显示状态。但现在还需要增加用户退出全屏显示状态的操作接口,下面讲述如何编程实现按“Esc”键退出全屏显示状态。

   1)在ClassView中选中CMainFrame并单击鼠标右键,选择“Add Member Function...”,添加public类型的成员函数EndFullScreen,该函数将完成退出全屏显示的操作。

reen()
   {
if(m_bFullScreen)
   {// 退出全屏显示, 恢复原窗口显示
   ShowWindow(SW_HIDE);
   SetWindowPlacement(&m_OldWndPlacement);

}

}


   2)函数EndFullScreen可以退出全屏显示状态,问题是如何在“Esc”键被按下之后调用执行此函数。由于视图类可以处理键盘输入的有关消息(如WM_KEYDOWN表示用户按下了某一个键),我们将在视图类CFullScreenView中添加处理按键消息WM_KEYDOWN的响应函数OnKeyDown。判断如果按的键为“Esc”键,则调用CMainFrame类的函数EndFullScreen,便可退出全屏显示状态。


   void CFullScreenView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
   {
if(nChar==VK_ESCAPE) // 如果按的键为Esc键
   {// 获取主框架窗口的指针

   CMainFrame *pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
   // 调用主窗口类的自定义函数 EndFullScreen ,便可退出全屏显示状态
   pFrame->EndFullScreen();

}
   CView::OnKeyDown(nChar, nRepCnt, nFlags);

}


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

   以下两个函数可以为应用程序中的各子窗口显示一个任务条到任务栏并更改它们的图标。对那些象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;
}




   如何隐藏应用程序在任务栏上的显示

   对于CFrameWnd可以在PreCreateWindow()函数中修改窗口的风格。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |=WS_POPUP;//使主窗口不可见
cs.dwExStyle |=WS_EX_TOOLWINDOW;//不显示任务按钮
return CFrameWnd::PreCreateWindow(cs);
}

   对于其他窗口,可以在窗口被Create出来之后ShowWindow之前使用ModifyStyle()和ModifyStyleEx()来修改它的风格。

   如何控制窗口框架的最大最小尺寸?

   要控制一个框架的的最大最小尺寸,你需要做两件事情。

   第一步:在CFrameWnd的继承类中处理消息WM_GETMINMAXINFO,结构MINMAXINFO设置了整个窗口类的限制,因此记住要考虑工具条,滚动条等等的大小。

// 最大最小尺寸的象素点 - 示例
#define MINX 200
#define MINY 300
#define MAXX 300
#d

efine MAXY 400
void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
  CRect rectWindow;
  GetWindowRect(&rectWindow);

  CRect rectClient;
  GetClientRect(&rectClient);

  // get offset of toolbars, scrollbars, etc.
  int nWidthOffset = rectWindow.Width() - rectClient.Width();
  int nHeightOffset = rectWindow.Height() - rectClient.Height();

  lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;
  lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;
  lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;
  lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset;
}



   第二步:在CFrameWnd的继承类的PreCreateWindow函数中去掉WS_MAXIMIZEBOX消息,否则在最大化时你将得不到预料的结果.

BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs)
{
  cs.style &= ~WS_MAXIMIZEBOX;
  return CFrameWnd::PreCreateWindow(cs);
}





   如何修改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的函数。

   如何改变view的背景颜色?

   若要改变CView,CFrameWnd或CWnd对象的背景颜色需要处理WM_ERASEBKGND消息,下面就是一个范例代码:

BOOL CSampleView::OnEraseBkgnd(CDC* pDC)
{
//设置brush为希望的背景颜色
CBrush backBrush(RGB(255, 128, 128));

//保存旧的brush
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect);

//画需要的区域
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);

return TRUE;

}


   若要改变CFromView继承类的背景颜色,下面是一个范例代码:

HBRUSH CMyFormView::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));

}


在任务栏状态区如何显示应用程序图标

   有关的数据由NOTIFYICONDATA结构描述:



typedef struct _NOTIFYICONDATA
{
DWORD cbSize; //结构的大小,必须设置
HWND hWnd; //接受回调消息的窗口的句柄
UINT uID; //应用程序定义的图标标志
UINT uFlags; //标志,可以是NIF_ICON、NIF_MESSAGE、NIF_TIP或其组合
UINT uCallbackMessage;//应用程序定义的回调消息标志
HICON hIcon; //图标句柄
char szTip[64]; //提示字串
} NOTIFYICONDATA, *PNOTIFYICONDATA;

   函数说明

   由Shell_NotifyIcon()函数向系统发送添加、删除、更改图标的消息。

WINSH

教程录入:HBctong    责任编辑:HBctong 
  • 上一篇教程:
  • 下一篇教程: 没有了
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    (只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    姓 名: * Oicq:
    性 别: Msn:
    E-mail: Icq:
    主 页:
    评 分: 1分 2分 3分 4分 5分
    评论内容:
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  • 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 |   

    感谢邢台创通公司 提供空间 | 冀ICP备05018085号

    清河在线 All Rights Reserved (C) Copyright 2006 TEL:0319-7502356     创通网站工作室
    清河在线 *卡通版*