// CApp 消息处理程序
BOOL CAboutDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CRect rect, rc;
GetClientRect(rect);
m_ok.GetWindowRect(rc); //这个取得屏幕 全屏的坐标
ScreenToClient(rc); // 转化为同一坐标系
m_cxMargin = rect.right - rc.right;
m_cyMargin = rect.bottom - rc.bottom;
return TRUE;
}
void CAboutDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
if (m_ok)
{
CRect rect;
m_ok.GetWindowRect(rect);
int x = cx - m_cxMargin - rect.Width();
int y = cy - m_cyMargin - rect.Height();
m_ok.SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
点击相应控件的属性,对其进行动态布局的设置,选择两者,窗口再次进行拉伸就会进行改变。
a)CFrameWnd类偏爱WM_CREATE,因为所有的内部窗口都是代码创建的。
而不像对话框是拖入的。
b)CFrameWnd::rectDefault管理层叠
static const CRect rectDefault;
c)LoadFrame内部包含CreateFrame,同时执行注册以及加载快捷键等(参见附录)
class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
// Constructors
public:
static AFX_DATA const CRect rectDefault;
CFrameWnd();
BOOL LoadAccelTable(LPCTSTR lpszResourceName);
//创建框架
virtual BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle = WS_OVERLAPPEDWINDOW,
const RECT& rect = rectDefault,
CWnd* pParentWnd = NULL, // != NULL for popups
LPCTSTR lpszMenuName = NULL,
DWORD dwExStyle = 0,
CCreateContext* pContext = NULL);
// 加载框架 - load frame and associated resources
virtual BOOL LoadFrame(UINT nIDResource,
DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
CWnd* pParentWnd = NULL,
CCreateContext* pContext = NULL);
// 创建中央视图 helper for view creation
CWnd* CreateView(CCreateContext* pContext, UINT nID = AFX_IDW_PANE_FIRST);
// 第十三章文档架构时获取激活文档
virtual CDocument* GetActiveDocument();
//多文档架构获取激活视图 Active child view maintenance
CView* GetActiveView() const; // active view or NULL
void SetActiveView(CView* pViewNew, BOOL bNotify = TRUE);
// active view or NULL, bNotify == FALSE if focus should not be set
// 多文档架构的让某个子框架激活,Active frame (for frames within frames -- MDI)
virtual CFrameWnd* GetActiveFrame();
// For customizing the default messages on the status bar
virtual void GetMessageString(UINT nID, CString& rMessage) const;
BOOL m_bAutoMenuEnable;
// TRUE => menu items without handlers will be disabled
BOOL IsTracking();
// Operations
virtual void RecalcLayout(BOOL bNotify = TRUE); //核心排版
virtual void ActivateFrame(int nCmdShow = -1);
void InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible);
void SetTitle(LPCTSTR lpszTitle);
CString GetTitle() const;
virtual UINT GetTrackingID() { return m_nIDTracking; }
// set/get menu bar visibility style
virtual void SetMenuBarVisibility(DWORD dwStyle);
virtual DWORD GetMenuBarVisibility() const;
// set/get menu bar visibility state
virtual BOOL SetMenuBarState(DWORD dwState);
virtual DWORD GetMenuBarState() const;
BOOL GetMenuBarInfo(LONG idObject, LONG idItem, PMENUBARINFO pmbi) const;
protected:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
friend class CWinApp;
};
为啥对话框CDialog类不偏爱WM_CREATE消息?
a)对话框类使用WM_INITDIALOG消息或者虚函数来初始化;
b)WM_CREATE消息对于对话框也是有效的,为什么对话框很少用这 个消息呢?
c)对话框程序需要初始化控件,WM_CREATE是主窗口刚刚创建好,控件还没有。
d)所以它偏爱OnInitDialog虚函数,控件都被创建好之后方便初始化那些控件。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
static CMenu menu; //临时对象生命周期不够需要加static
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
CCreateContext cc;
cc.m_pNewViewClass = RUNTIME_CLASS(CMainView);
CreateView(&cc);
}
#include "CTestBtn.h"
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
//创建客户区的主区视图
{
CCreateContext cc;
// cc.m_pNewViewClass = RUNTIME_CLASS(CTestBtn);
cc.m_pNewViewClass = RUNTIME_CLASS(CMainView);
m_pMainView = (CMainView*)CreateView(&cc, AFX_IDW_PANE_FIRST);
//AFX_IDW_PANE_FIRST在中间区域自动缩放
return m_pMainView!=NULL;
}
int CTestBtn::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CButton::OnCreate(lpCreateStruct) == -1)
return -1;
SetWindowText(_T("按钮?"));
return 0;
}
BOOL CTestBtn::PreCreateWindow(CREATESTRUCT& cs) //视图就是CreateView
{
cs.lpszClass = _T("BUTTON");
return CButton::PreCreateWindow(cs);
}
a)例如:注册时你指定灰色背景,窗口生成后可以在WM_ERASEBKGND消息中改成别的颜色。
b)其他包括图标(SetIcon),光标WM_SETCURSOR消息中改,以及菜单(SetMenu)。
c)例如:但凡Create一个Edit注册时的要素都会默认呈现,比如光标的形状,背景是白色。
d)但是后面都是可以改的,比如你想把某个edit改为绿底红字的。(WM_CTLCOLOR)
BOOL CMainFrame::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(rect);
pDC->FillSolidRect(rect, 0xffee00); //可指定其他的颜色 注册可以该 默认的实施 按照注册来实施
return TRUE;
//你注册的灰色是由return CFrameWnd::OnEraseBkgnd(pDC);来实施的
//return CFrameWnd::OnEraseBkgnd(pdc) 改为return TRUE 则没有注册的颜色
}
创建窗口的预处理函数:virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
a)预处理核心的一个工作就是注册窗口规格,包括光标,图标以及背景颜色等;
b)预处理函数的结构体中包含,位置、高宽以及菜单,style和dwExStyle
c)为什么LoadFrame中使用注册,而CreateFrame根本没注册都好使?
那就是因为窗口预处理中执行注册,可以说即使从CWnd类派生你只要做预处理就不用RegisterClass
//预处理核心的一个工作就是注册窗口规格,包括光标,图标以及背景颜色等
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// CREATESTRUCT cs 来修改窗口类或样式
/*cs.x = 100;
cs.y = 100;
cs.cx = 200;
cs.cy = 300;*/ //没有这几行的代码的话 默认是重叠的 有了的话不会重叠
// cs.style |= WS_THICKFRAME; //拖动大小开关
// cs.hMenu = ::LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
typedef struct tagCREATESTRUCTW {
LPVOID lpCreateParams;
HINSTANCE hInstance;
HMENU hMenu;
HWND hwndParent;
int cy;
int cx;
int y;
int x;
LONG style;
LPCWSTR lpszName;//标题
LPCWSTR lpszClass;//类型名
DWORD dwExStyle;//扩展风格
} CREATESTRUCTW, *LPCREATESTRUCTW;
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
// attempt to create the window
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
CString strTitle = m_strTitle;
if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,
pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext))
{
return FALSE; // will self destruct on failure normally
}
// save the default menu handle
ASSERT(m_hWnd != NULL);
m_hMenuDefault = m_dwMenuBarState == AFX_MBS_VISIBLE ? ::GetMenu(m_hWnd) : m_hMenu;
// load accelerator resource
LoadAccelTable(ATL_MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) // send initial update
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}