Visual C++是一種面向對象的可視化編程工具,由于生成的應用程序框架使程序的用戶界面和程序結構都只能具有標準形式,而在實際的程序設計中,常常需要設計一些非標準的應用程序,或實現一些特別的功能或操作,因此可以使用一些技巧來修改應用程序框架,以得到所需的應用效果。
一、修改主窗口風格
AppWizard生成的應用程序框架的主窗口具有缺省的窗口風格,比如在窗口標題條中自動添加文檔名、窗口是疊加型的、可改變窗口大小等。要修改窗口的缺省風格,需要重載CWnd::PreCreateWindow(CREATESTRUCT
&cs)函數,并在其中修改CREATESTRUCT型參數cs。
CWnd::PreCreateWindow函數先于窗口創建函數執行。如果該函數被重載,則窗口創建函數將使用CWnd::PreCreateWindow函數返回的CREATESTRUCTcs參數所定義的窗口風格來創建窗口;否則使用預定義的窗口風格。
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;
下例中的代碼將主框窗口的大小
固定為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);
}
二、創建不規則形狀窗口
標準的Windows窗口是矩形的,但在有些時候我們需要非矩形的窗口,比如圓形的、甚至是不規則的。借助CWnd類的SetWindowRgn函數可以創建不規則形狀窗口。
CWnd::SetWindowRgn的函數原型如下:
int SetWindowRgn( HRGN hRgn, //窗口區域句柄
BOOL bRedraw ); //是否重畫窗口
創建非矩形窗口的方法如下:首先,在窗口類中定義區域類成員數據(如CRgnm_rgnWnd);其次,在窗口的OnCreate函數或對話框的OnInitDialog函數中調用CRgn類的CreateRectRgn、CreateEllipticRgn或CreatePolygonRgn函數創建所需的區域,并調用SetWindowRgn函數。
下例將生成一個橢圓窗口。
1.在Developer Studio中選取File菜單中的New命令,在出現的New對話框中選擇創建MFCAppWizard(exe)框架應用程序,并輸入項目名為EllipseWnd。設定應用程序類型為基于對話框(Dialog
based),其它選項按缺省值創建項目源文件。
2.使用資源編輯器從主對話框(ID為IDD_ELLIPSEWND_DIALOG)刪除其中的所有控制,并從其屬性對話框(Dialog
Properties)中設定其風格為Popup、無標題條和邊框。
3.在EllipseWndDlg.h源文件中給主對話框類CEllipseWndDlg增加一個CRgn類保護型數據成員m_rgnWnd,它將定義窗口的區域。
4.在EllipseWndDlg.cpp源文件中修改主對話框類CEllipseWndDlg的OnInitDialog()函數,增加m_rgnWnd的創建,并將其定義為窗口區域。粗體語句為新增部分。
BOOL CEllipseWndDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX& 0xFFF0)== IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu
(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog.
The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);
// Set big icon
SetIcon(m_hIcon, FALSE);
// Set small icon
//設置窗口標題為"橢圓窗口",
雖然對話框沒有標題條,
//但在任務條的按鈕中仍需要標題
SetWindowText(_T("橢圓窗口"));
//取得屏幕寬、高
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN);
//設置橢圓X、Y方向的半徑
int nEllipseWidth = cxScreen/8;
int nEllipseHeight = cyScreen/8;
//將窗口大小設為寬nEllipseWidth,
高nEllipseHeight
//并移至左上角
MoveWindow(0, 0, nEllipseWidth, nEllipseHeight);
//創建橢圓區域m_rgnWnd
m_rgnWnd.CreateEllipticRgn(0, 0,
nEllipseWidth, nEllipseHeight);
// 將m_rgnWnd設置為窗口區域
SetWindowRgn((HRGN)m_rgnWnd, TRUE);
return TRUE; // return TRUE unless
you set the focus to a control
}
三、顯示旋轉文本
在有的應用中,為了達到特殊的效果,經常需要顯示旋轉的文本。文本的顯示方式,包括旋轉,都是由字體來設置的。
字體的屬性主要由創建字體時使用的LOGFONT結構規定,該結構中的lfEscapement域指定了文本行與X軸(水平軸)的角度,其角度單位是十分之一度。為了使所有的字體向相同的方向旋轉,還應同時將LOGFONT結構的lfClipPrecision域設為CLIP_LH_ANGLES。
下面的代碼將在對話框中顯示在同一起點每隔15度顯示一行文本:
void CRotateTextDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (IsIconic())
{
SendMessage(WM_ICONERASEBKGND,
(WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width()- cxIcon+ 1) / 2;
int y = (rect.Height()- cyIcon+ 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CRect rc;
GetClientRect(rc);
CString str(_T("............旋轉文本!"));
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(RGB(0,0,255));
CFont font;
LOGFONT lf;
memset(&lf,0,sizeof(LOGFONT));
lf.lfHeight =-14;
lf.lfWeight = FW_NORMAL;
lf.lfClipPrecision = CLIP_LH_ANGLES;
strcpy(lf.lfFaceName, "宋體");
for (int i=0;i<3600;i+=150)
{
lf.lfEscapement = i;
font.CreateFontIndirect(&lf);
CFont*pOldFont = dc.SelectObject(&font);
dc.TextOut(rc.right/2, rc.bottom/2,str);
dc.SelectObject(pOldFont);
font.DeleteObject();
}
CDialog::OnPaint();
}
}