C++(底层窗口实现)

win32

Windows消息机制

1.SDK和API

SDK:
软件开发工具包 (Software Development Kit) ,一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。

API函数:
Windows 操作系统提供给应用程序编程的接口(Application Programming Interface)。Windows应用程序API函数是通过C语言实现的,所有主要的Wi ndows函数都在Windows. h头文件中进行了声明。Windows 操作系统提供了1000多种API函数。

2.窗口和句柄

窗口是Windows应用程序中一个非常重要的元素,一个Windows 应用程序至少要有一个窗口,称为主窗口。
窗口是屏幕上的一块矩形区域,是Windows应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。如下图:
应用程序窗口
窗口可以分为客户区和非客户区,如上图。客户区是窗口的一部分,应用程序通常在客户区中显示文字或者绘制图形。

标题栏、菜单栏、系统菜单、 最小化框和最大化框、可调边框统称为窗口的非客户区,它们由Windows系统来管理,而应用程序则主要管理客户区的外观及操作。

窗口可以有一个父窗口,有父窗口的窗口称为子窗口。除了上图所示类型的窗口外,对话框和消息框也是一-种窗口。在对话框上通常还包含许多子窗口,这些子窗口的形式有按钮、单选按钮、复选框、组框、文本编辑框等。

在Windows应用程序中,窗口是通过窗口句柄( HIND)来标识的。我们要对某个窗口进行操作,首先就要 得到这个窗口的句柄。

句柄( HANDLE)是Windows程序中一个重要的概念,使用也非常频繁。在Windows程序中,有各种各样的资源 (窗口、图标、光标,画刷等),系统在创建这些资源时 会为它们分配内存,并返回标识这些资源的标识号,即句柄。 在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR)和画刷句柄( HBRUSH) 。

3.消息与消息队列

Windows程序设计是一种完全 不同于传统的DOS方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。
每一个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。

例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件, 于是将这个事件包装成一一个消息,投递到应用程序的消息队列中,等待应用程序的处理。

然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。

在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门负责处理消
息的函数,这个函数称为窗口过程。
在这里插入图片描述

4.WinMain函数

当Windows 操作系统启动一个程序时,它调用的就是该程序的WinMain函数(实际是由插入到可执行文件中的启动代码调用的)。WinMain是Windows 程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain函数结束或返回时,Windows 应用程序结束。

Windows 编程模型

一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建-一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

  1. winMain函数的定义
  2. 创建一个窗口
  3. 进行消息循环
  4. 编写窗口过程函数
  5. 通过循环取消息
  6. 处理消息(窗口过程)

代码如下:

 #include <windows.h>//底层实现窗口的头文件



//6.处理消息(窗口过程)这是最后一步,但是把它写到了上面,起始是从程序入口函数开始

//CALLBACK 代表__stdcall:参数的传递顺序:从右至左依次入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
	HWND hwnd,  //消息所属的窗口句柄
	UINT uMsg,  //具体的消息名称  WM_xxxx消息名
	WPARAM wParam,//键盘附加消息
	LPARAM lParam//鼠标附加消息
	
	)

{
	//switch根据不同的消息做不同的处理
	switch (uMsg)
	{
	case WM_CLOSE:
		//所有xxxxWindow为结尾的方法,都不会进入消息队列中,而是直接执行
		DestroyWindow(hwnd);  //DestroyWindow发送另一个消息 WM_DESTROY
		break;

	case WM_DESTROY:
		PostQuitMessage(0); //发送正常的退出
		break;

	case WM_LBUTTONDOWN://鼠标左键按下

		{

		
		int xPos = LOWORD(lParam);//Xposition,x位置,打印鼠标位置
		int yPos = HIWORD(lParam);

		char buf[1024];//定义一个字符数组
		wsprintf(buf,TEXT("X=%d,Y=%d"),xPos,yPos);//拼接字符串1.buf你要把字符串拼接到哪里,2.你要拼接的字符串具体信息

		MessageBox(hwnd,buf,TEXT("鼠标左键按下"),MB_OK);

		break;
	}
	case WM_KEYDOWN://键盘按下

		MessageBox(hwnd,TEXT("键盘按下"),TEXT("键盘按下"),MB_OK);

		break;
	case WM_PAINT://绘图
		
		PAINTSTRUCT ps;//绘图结构体
		HDC hdc = BeginPaint(hwnd,&ps);

		TextOut(hdc,100,100,TEXT("hello"),strlen("hello"));

		EndPaint(hwnd,&ps);
		break;

	}

	//返回值用默认处理方式
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}



//程序入口函数

//WINAPI宏 代表__stdcall:参数的传递顺序:从右至左依次入栈,并且在函数返回前清空堆栈

int WINAPI WinMain( 
	HINSTANCE hInstance,  //应用程序实例句柄
	HINSTANCE hPrevInstance,//上一个应用程序句柄,在win32环境下参数一般为null,不起作用了
	LPSTR lpCmdLine,   //char*argv[]
	int nShowCmd )//显示命令  最大化、最小化、正常
{
	//1.设计窗口
	//2.注册窗口
	//3.创建窗口
	//4.显示和更新
	//5.通过循环取消息
	//6.处理消息(窗口过程)


	//1.设计窗口
	WNDCLASS wc;  //WNDCLASS窗口的类
	wc.cbClsExtra = 0; //类的额外的内存
	wc.cbWndExtra = 0; //窗口的额外的内存
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景GetStockObject()是个API  
	wc.hCursor = LoadCursor(NULL,IDC_HAND);//设置光标  第一个是null代表使用系统提供的光标,
	wc.hIcon = LoadIcon(NULL,IDI_ERROR);//图标
	wc.hInstance = hInstance;  //应用程序的实例句柄,传入winmain中的形参即可
	wc.lpfnWndProc = WindowProc; //窗口过程函数,即回调函数,回调函数名可随意更改
	wc.lpszClassName = TEXT("WIN");//指定窗口类名称
	wc.lpszMenuName = NULL;//菜单名称
	wc.style = 0;//显示风格,0代表默认风格


	//2.注册窗口类
	RegisterClass(&wc);//带地址wc


	//3.创建窗口
	/*
	lpClassName,  //类名
	lpWindowName,  标题名
	dwStyle,   风格
	x,         坐标
	y,
	nWidth, 
	nHeight,
	hWndParent,//父窗口
	hMenu,//菜单
	hInstance, //实例句柄
	lpParam   //附加值  鼠标的附加值
	*/
	HWND hwnd = CreateWindow(
		wc.lpszClassName,
		TEXT("WINDOWS"),
		WS_OVERLAPPEDWINDOW,  //混合风格
		CW_USEDEFAULT,    //坐标默认值
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		NULL,
		NULL,
		hInstance,
		NULL
		);


	//4.显示和更新
	ShowWindow(hwnd,SW_SHOWNORMAL);//SW_SHOWNORMAL 正常方式展示窗口
	UpdateWindow(hwnd);

	//5.通过循环取消息

	/*
	HWND        hwnd;主窗口句柄,代表哪一个窗口传过来的消息
	UINT        message;具体的消息名称
	WPARAM      wParam;附加消息 键盘消息
	LPARAM      lParam;附加消息 鼠标消息 左右键
	DWORD       time;消息产生的时间
	POINT       pt;附加消息 鼠标消息 点击返回该点坐标点信息
	*/
	MSG msg;//每个消息都是一个结构体

	while (1)
	{
		/*
		__out LPMSG lpMsg,封装好的消息,带lp表示指针,所以要在前面加&
		__in_opt HWND hWnd,  捕获窗口  填NULL代表捕获所有的窗口
		__in UINT wMsgFilterMin,  //最小和最大的过滤的消息 一般填0,代表捕获所有消息
		__in UINT wMsgFilterMax);
		*/


		if (GetMessage(&msg,NULL,0,0)==FALSE)
		{
			break;//退出消息
		}
		
		//翻译消息(比如组合键,就需要获取到消息,翻译消息,再排队,再获取,再分发)
		TranslateMessage(&msg);

		//不为false,分发消息
		DispatchMessage(&msg);

	}

	//6.处理消息(窗口过程)



	return 0;
}
  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++写的一个简单的界面演示系统 void CMiniDrawDoc::AddFigure (CFigure *PFigure) { m_FigArray.Add (PFigure); SetModifiedFlag (); } CFigure *CMiniDrawDoc::GetFigure (int Index) { if (Index m_FigArray.GetUpperBound ()) return 0; return (CFigure *)m_FigArray.GetAt (Index); } int CMiniDrawDoc::GetNumFigs () { return m_FigArray.GetSize (); } void CMiniDrawDoc::DeleteContents() { // TODO: Add your specialized code here and/or call the base class int Index = m_FigArray.GetSize (); while (Index--) delete m_FigArray.GetAt (Index); m_FigArray.RemoveAll (); CDocument::DeleteContents(); } void CMiniDrawDoc::OnEditClearAll() { // TODO: Add your command handler code here DeleteContents (); UpdateAllViews (0); SetModifiedFlag (); } void CMiniDrawDoc::OnUpdateEditClearAll(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable (m_FigArray.GetSize ()); } void CMiniDrawDoc::OnEditUndo() { // TODO: Add your command handler code here int Index = m_FigArray.GetUpperBound (); if (Index > -1) { delete m_FigArray.GetAt (Index); m_FigArray.RemoveAt (Index); } UpdateAllViews (0); SetModifiedFlag (); } void CMiniDrawDoc::OnUpdateEditUndo(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable (m_FigArray.GetSize ()); } // implementation of figure classes: IMPLEMENT_SERIAL (CFigure, CObject, 3) CRect CFigure::GetDimRect () { return CRect (min (m_X1, m_X2), min (m_Y1, m_Y2), max (m_X1, m_X2) + 1, max (m_Y1, m_Y2) + 1); } void CFigure::Serialize (CArchive& ar) { if (ar.IsStoring ()) ar << m_X1 << m_Y1 << m_X2 << m_Y2 <> m_X1 >> m_Y1 >> m_X2 >> m_Y2 >> m_Color; } IMPLEMENT_SERIAL (CLine, CFigure, 3) CLine::CLine (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = X1; m_Y1 = Y1; m_X2 = X2; m_Y2 = Y2; m_Color = Color; m_Thickness = Thickness; } void CLine::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CLine::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_SOLID, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); // draw figure: PDC->MoveTo (m_X1, m_Y1); PDC->LineTo (m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectangle, CFigure, 3) CRectangle::CRectangle (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = X1; m_Y1 = Y1; m_X2 = X2; m_Y2 = Y2; m_Color = Color; m_Thickness = Thickness; } void CRectangle::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CRectangle::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: PDC->Rectangle (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectFill, CFigure, 3) CRectFill::CRectFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CRectFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: PDC->Rectangle (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); } IMPLEMENT_SERIAL (CRectRound, CFigure, 3) CRectRound::CRectRound (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; m_Thickness = Thickness; } void CRectRound::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CRectRound::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: int SizeRound = (m_X2 - m_X1 + m_Y2 - m_Y1) / 6; PDC->RoundRect (m_X1, m_Y1, m_X2, m_Y2, SizeRound, SizeRound); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CRectRoundFill, CFigure, 3) CRectRoundFill::CRectRoundFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CRectRoundFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: int SizeRound = (m_X2 - m_X1 + m_Y2 - m_Y1) / 6; PDC->RoundRect (m_X1, m_Y1, m_X2, m_Y2, SizeRound, SizeRound); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); } IMPLEMENT_SERIAL (CCircle, CFigure, 3) CCircle::CCircle (int X1, int Y1, int X2, int Y2, COLORREF Color, int Thickness) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; m_Thickness = Thickness; } void CCircle::Serialize (CArchive& ar) { CFigure::Serialize (ar); if (ar.IsStoring ()) ar <> m_Thickness; } void CCircle::Draw (CDC *PDC) { CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, m_Thickness, m_Color); POldPen = PDC->SelectObject (&Pen); PDC->SelectStockObject (NULL_BRUSH); // draw figure: PDC->Ellipse (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); } IMPLEMENT_SERIAL (CCircleFill, CFigure, 3) CCircleFill::CCircleFill (int X1, int Y1, int X2, int Y2, COLORREF Color) { m_X1 = min (X1, X2); m_Y1 = min (Y1, Y2); m_X2 = max (X1, X2); m_Y2 = max (Y1, Y2); m_Color = Color; } void CCircleFill::Draw (CDC *PDC) { CBrush Brush, *POldBrush; CPen Pen, *POldPen; // select pen/brush: Pen.CreatePen (PS_INSIDEFRAME, 1, m_Color); POldPen = PDC->SelectObject (&Pen); Brush.CreateSolidBrush (m_Color); POldBrush = PDC->SelectObject (&Brush); // draw figure: PDC->Ellipse (m_X1, m_Y1, m_X2, m_Y2); // remove pen/brush: PDC->SelectObject (POldPen); PDC->SelectObject (POldBrush); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值