小言_互联网的博客

窗口程序学习笔记No.2

242人阅读  评论(0)

MFC窗口建立运行机制

在 MFC 程序中,一个窗口的建立和运行同样是和笔记No.1中一样的:

  1. 设计一个窗口类
  2. 注册窗口类
  3. 创建窗口
  4. 显示及更新窗口
  5. 消息循环机制

有了一个窗口,有了消息循环机制,然后完成窗口过程函数就可以让一个窗口跑起来了
不过在 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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场