MFC窗口建立运行机制
在 MFC 程序中,一个窗口的建立和运行同样是和笔记No.1中一样的:
- 设计一个窗口类
- 注册窗口类
- 创建窗口
- 显示及更新窗口
- 消息循环机制
有了一个窗口,有了消息循环机制,然后完成窗口过程函数就可以让一个窗口跑起来了
不过在 MFC 中,系统已经完成并隐藏了这些,不用我们自己去写
我们只需要填充我们想完成的功能
在MFC窗口中设计一个按钮
创建工程
在 VS2019 中(孙鑫老师视频中是VC++)建立一个工程
选择 【创建新项目】->【MFC应用】->【创建】
然后应用程序类型勾选 单个文档完成即可
单个文档下面的类型选项都不用选(主要是我不知道选了有啥用。。。也许以后会知道。。。嘘)
————————————————————>
完成后点击 【视图】->【类视图】,会看到这样的几个类:
其中 C Draw App中间的 Draw 是根据你的工程名
(VC++下会多一个 CDrawDoc类,暂时不知道是啥,啥也不知道啥也不敢问。。。)
添加按钮
先看看创建按钮的类 CButton 的创建按钮的函数
在窗口框架创建完成之后,我们进行创建按钮:
再MainFrame.h里面类成员里加上一个按钮,定义为私有:
private:
CButton m_btn;
在 MainFrame.cpp里面的 CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)函数最后,即框架创建完成之后再加上按钮并使之显示(return 0之前两句)
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
m_btn.Create("有趣",WS_CHILD | BS_DEFPUSHBUTTON,CRect(0,0,100,100),this,123);
m_btn.ShowWindow(SW_SHOWNORMAL);
return 0;
}
也可以右键点击类视图CMainFrame【添加】->【类成员】
点击运行会发现按钮覆盖了菜单栏,是因为我们是在框架中添加的,如果是在 view 类中就不会
同样的方法在 view中添加成员,但是没有OnCreate函数啊?不慌,我们可以添加一个消息命令,右键单击 view 类,选择【类向导】,选择消息,找到WM_CREATE,添加,编辑,把之前的剪切过来
(图中已经添加了,所以在右边)
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
m_btn.Create("有趣", WS_CHILD | BS_DEFPUSHBUTTON, CRect(0, 0, 100, 100), this, 123);
m_btn.ShowWindow(SW_SHOWNORMAL);
return 0;
}
效果:
可以自己改变m_btn.Create()里面第二个参数让按钮改变类型(大家可以自己试下)
在MFC窗口中写写画画
画直线
建立一个工程(这个时候突然发现MFC工程好大,100多M)
我们知道,画一条直线需要两个点,我们鼠标左键点击下来是一个,放开又是一个
还是那个添加消息命令:【类向导】->【消息】找到 WM_LButtonDown,添加
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CWnd::OnLButtonDown(nFlags, point);
}
先在头文件里添加一个成员 m_ptOrigin:
private:
CPoint m_ptOrigin;
我们发现函数OnLButtonDown()参数中有 CPoint point,这就是那个点,用m_ptOrigin记录:
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptOrigin = point;
CWnd::OnLButtonDown(nFlags, point);
}
接着添加鼠标左键弹起的那个点,同样添加消息命令【类向导】,【消息】找到 WM_LButtonUP
完成后:
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CWnd::OnLButtonUp(nFlags, point);
}
修改:
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
HDC hdc;
hdc = ::GetDC(m_hWnd);
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);//两点间移动
LineTo(hdc,point.x, point.y); //两点间画线
::ReleaseDC(m_hWnd,hdc);
CWnd::OnLButtonUp(nFlags, point);
}
我们还可以用CObject派生出来的CDC,或者CClientDC,还能用CWindowDC画到程序框外面:,其中,CClientDC,CWindowDC不用 ReleaseDC();
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDC *pDC = GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
//CClientDC dc(GetParent());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CWindowDC dc(this);
CWindowDC dc(GetDesktopWindow());
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CWnd::OnLButtonUp(nFlags, point);
}
画笔改变颜色
改变画笔颜色,我们首先要知道画笔这个东西,之前由于是直接缺损的,故就是黑色
画笔 CPen:
其中,第三个参数是颜色,我们用函数 RGB() 来实现:
三个参数都在0~255之间
Selectobject() 用于返回之前的画笔,因为我们可能用完了这个颜色的想换回来之前的
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CPen pen(PS_SOLID,2,RGB(255,0,0));
CClientDC dc(this);
CPen* pOldpen = dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(&pOldpen);
CWnd::OnLButtonUp(nFlags, point);
}
可以自己改变线型和颜色:
CPen pen(PS_DASH,1,RGB(0,255,0));//阴影线,这时线宽只能为一
CPen pen(PS_DOT,1,RGB(0,0,255));//点线,这时线宽只能为一
画刷
画刷一般用于填充某一块区域的颜色:
填充一块区域用 FillRect(),它需要两个参数,一个CRect型,一个画刷
**CRect:**用我们的两个点确定区域:
完成函数:
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CBrush brh(RGB(255,0,0));
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin, point),&brh);
CWnd::OnLButtonUp(nFlags, point);
}
图:
位图画刷
有时候我们并不用满足用单一颜色的画刷,我们可能需要使用一种位图画刷,那么我们看一下,发现画刷中有一个位图指针的重载:
CBitmap();初始化的时候必须用一个初始化的成员函数来初始化:
我们使用LoadBitmap():
需要一个资源 ID作为参数,那么我们先创建一个资源:
解决方案资源管理器 - > 资源文件右键单击 - > 添加 - > 资源 - > 位图 - > 新建,然后自己画下
然后双击 你的工程名.rc文件,找到位图对应的资源ID号,复制:
资源创建完成,完成代码:
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CBitmap bitmap;
bitmap.LoadBitmapA(IDB_BITMAP1);
CBrush brh(&bitmap);
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin, point), &brh);
CWnd::OnLButtonUp(nFlags, point);
}
效果:
透明画刷
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CBrush* pbrh = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush* pOldbrh = dc.SelectObject(pbrh);
dc.Rectangle(CRect(m_ptOrigin, point));
dc.SelectObject(pOldbrh);
CWnd::OnLButtonUp(nFlags, point);
}
画连续的曲线
想要画曲线,我们需要添加一个用来标识鼠标按下和弹起:
右键单击 view 类添加成员:
private:
bool m_bDraw;
在构造函数中初始化为假:
CChildView::CChildView()
{
m_ptOrigin = 0;
m_bDraw = FALSE;
}
在鼠标左键按下时改为真:
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//MessageBox("view 点击");
m_ptOrigin = point;
m_bDraw = TRUE;
CWnd::OnLButtonDown(nFlags, point);
}
在弹起时又变为假:
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bDraw = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
再右键单击 view类 ,类向导,添加一个消息响应函数 WM_MOUSEMOVE:
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
if (m_bDraw == TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin = point;
}
CWnd::OnMouseMove(nFlags, point);
}
如果想改变画笔颜色:
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CPen pen(PS_SOLID,2,RGB(255,0,0));
CPen* pOldpen = dc.SelectObject(&pen);
if (m_bDraw == TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin = point;
}
dc.SelectObject(&pOldpen);
CWnd::OnMouseMove(nFlags, point);
}
画射线簇
在画曲线的基础上稍作修改
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CPen pen(PS_SOLID,2,RGB(255,0,0));
CPen* pOldpen = dc.SelectObject(&pen);
if (m_bDraw == TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOld = point;
}
dc.SelectObject(&pOldpen);
CWnd::OnMouseMove(nFlags, point);
}
加上边界,改一个位置就可以:
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CPen pen(PS_SOLID,2,RGB(255,0,0));
CPen* pOldpen = dc.SelectObject(&pen);
if (m_bDraw == TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOld);
dc.LineTo(point);
m_ptOld = point;
}
dc.SelectObject(&pOldpen);
CWnd::OnMouseMove(nFlags, point);
}
除了定义画笔,话可以用 SetROP2();来设置绘画模式:
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
if (m_bDraw == TRUE)
{
dc.SetROP2(R2_BLACK);
dc.MoveTo(m_ptOrigin);
dc.LineTo(m_ptOld);
dc.MoveTo(m_ptOld);
dc.LineTo(point);
m_ptOld = point;
}
CWnd::OnMouseMove(nFlags, point);
}
转载:https://blog.csdn.net/weixin_43154583/article/details/104976043