vc++学习笔记—11月14日

本文深入探讨Windows编程的基础知识,包括应用程序框架、句柄、消息处理机制等核心内容,并详细介绍了MFC类库的重要组成部分及使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第三章 应用程序框架

句柄
HWND 窗口句柄
HBITMAP 位图句柄
HICON 图标句柄
HMENU 菜单句柄
HFILE 文件句柄
HINSTANCE 当前实例句柄
HGLOBAL 全局内存对象句柄
HDC 设备环境句柄
HCURSOR 光标句柄
HFONT 字体句柄
HPEN 画笔句柄
HBRUSH 画刷句柄
HLOCAL 局部内存对象句柄

旁注:
char是char[]的首地址
同样 main是main()的首地址

消息
  消息号: 事先定义好的消息标识
  wParam: 字参数 消息附加信息
  lParam:长字节参数 消息附加信息
消息循环:
常见的:
 while(GetMessage(&Msg,NULL,0,))
{
TranslatMessage(&Msg);//将消息的虚拟键转换为字符信息 例如把

wm_keyup/wm_keydown 转换为wm_char消息,它不会消灭以前的旧消息而是产生一

个新消息

DispatchMessage(&Msg);//将消息传送到指定窗口,即把消息传递给窗口类中的

lpfnWndProc所指向的函数名
}

窗口函数WinProc()
定义了程序对于接收到的不同消息的响应,包含了对各种可能接受到的消息的处

理过程。
每一个case处理一个消息
      
当你不感兴趣的消息也不能不管,在一般的消息回调函数中default 都会return

defwindowproc(...)交由系统处理,否则窗口会不显示
回调函数的callback是用来区分_stdcall(delphi语系以及其他api的语言约定)与

_cdle(c语言的语言约定)的 不同函数 的。

初始化
 1 定义窗口类
 2 注册窗口  RegisterClass();
 3 创建窗口  CreateWindow();
 4 窗口显示  ShowWindow();

MFC类库

包括CWinApp CDoucument CView CFrameWnd CDocTemplate 五大类

命令相关类 CCmdTarget  是消息映射属性的基类,消息映射规定了当一个对象接

收到消息命令时,调用哪个函数进行处理。

线程基类 CWinThread 可直接使用

应用程序类 CWinApp

窗口类 CWnd

框架窗口类 CFrameWnd

文档视窗类 CDocTemplate

winmain中lCmdline参数为 系统参数之意

窗口重画cs_vredraw..为单独位为1的意思如0x00001
如要去掉,可以采用style&~cs_vredraw

窗口类wndClass

旁注:HDC
HDC hdc1 创建一个hdc的变量(hdc是指跟显示设备相关的中间层变量,只要复制

给hdc就可以被显示)
hdc1.getDC(指定要显示窗口的句柄如hwnd);
可以用TextOut(hdc1,...)来显示文字
用完要释放  ReleaseDC(hwnd,hdc1)

 Class :

构造函数
它的名字就是类的名字,一般会在public中,它会在类创建的时候被调用,本来

用于自动给参数赋初值的函数,是类创建所必须的如果不写,系统会默认一个

例子:
class Point
{
public:
 int x;
 int y;
/* void init()       ///////////////////////此处用于 手工赋初值的

方法,如Point s1; s1.init();//即为初始化
 {
  x=0;
  y=0;
 }*/
 Point()//////////////此就是构造函数
 {
  x=0;
  y=0;
 }
---------------
析构函数:

它的名字就是~类名字,它会在类使用完的时候调用,本来用于释放类占据的空

间的,一般也会出现在public中

例子:

class Point
{
public:
 int x;
 int y;

 
 ~Point()/// 此即为析构函数
 {
 }

---------
函数的重载

有多个名字相同 参数个数或者类型不同的函数

例如:
Point()
 {
  x=0;
  y=0;
 }
Point(int a,int b)
 {
  x=a;
  y=b;
 }
到时候那个符合参数就用那个。。自适应的。

----------------------
this指针用于指向对象,

例如:
Class Point
{
...
void output(int x,int y)
 {
  this->x=x;
  this->y=y;
 }
}
...
Point ist;

此时类中的this就是指ist
----------------
函数的继承和派生

例如class a;
再定义b时,可采用
class b :public a
{

}
即b继承了a类,b是a的派生
====摘自csdn
继承和派生两个术语的区别在于它们的主宾关系不同。  
  继承是对于父类来说是被动的,可以描述为:父类XXX被子类XXX继承  
   
  而派生对于父类来说是主动的。描述为:父类XXX派生子类XXX。  
   
  关于派生类和子类的区别:应该是继承关系的层次结构的概念区别。  
  派生类可以是多余一级的继承关系,  
  子类是一级关系。  
  但同时也有这样的概念:子类属于派生类。  
   
  例如:基类A,  
              类B直接继承于A  
              类C直接继承于B;  
   
          那么依据上面的说法则有:  
   
              类A派生类B,类A被类B继承;类B派生类C,   类B被类C继承。  
              类B是类A的子类,类C是类B的子类;  
              类B和类C都是类A的派生类。  
------------------------
多态性

就是父类的同名函数若设置为虚函数,则放弃父虚函数的类型,主要看子类。子

类有的调用子的,没有的调用父类。
----------------------
虚函数

见上述函数的多态性 ,
例子:
class animal
{
public:
....
..
virtual viod breathe()//此即为虚函数,
 {
 }

}

若为virtual viod breathe()=0;则为纯虚函数纯虚函数是父类用来“留白”的

,即,子类必须定义自己的这个函数
--------------
引用

就是一种别名
例子:
int a=6;
int &b=a;
则b就是a的引用,而且b变换,a也会跟着变化,
注意引用只能在定义时候定义一次,之后不会被重复定义
用法
如果b=5,则a也会变成5

一般用法 定义函数

change(int &a,int &b0)
{...}
使用的时候change(x,y)即使把参数x和y的 本身 进行交换。。。

======================
类的一般 用法
把文件分为cpp和h文件
h文件中只是声明类的函数,不做具体定义
如 animal.h就只用写
class animal
{
public:
animal(int heght , int weght);
viod eat();
viod sleep();
virtual viod breathe();
}
在animal.cpp中写

animal:: animal()//注意此处不必写函数返回值,因为构造函数没有返回值
{
//构造函数
}
void Animal::eat()
{
}
.....

继承animail类的fish类 定义的fish构建函数
Fish::Fish():Animal(300,400)
{
}
---------注意头文件不参与编译
--------------
::shownwindow() 表示调用全局或者平台的函数
AFX类是框架类的函数,系统把众多类联系起来的全局函数
AfxGetApp()可以获得一个CWinApp类的指针即this
CWinApp是应用程序类

先构建 CWinApp 先构建全局变量
然后构建winmain
afxwinmain是winmain的调用函数,用来完成winmain函数的功能
AfxRegisterClass注册窗口类函数,用来使用win32风格的几种窗口
Initapplication()是用来初始化管理用函数
InitInstance()调用子类的初始化函数

this 指向是CxxxApp xxxApp 定义中的xxxApp 是应用程序类

PreCreatWindows()函数中先注册窗口AfxDeferRegisterClass

()//AfxEndDeferRegisterClass判断有没有注册,如果没有就注册参数
可以通过其参数 CREATESTRUCT& cs改变有无最大化等窗口类型
主窗口的创建,是在ProcessShellComand(cmdinfo)实现的
::CreatWindowEx(...)创建窗口,其返回值是个句柄
m_pMainWnd是指向cMainFrame的指针
CWinThread::Run()完成了消息循环

注意wndcls.lpfnWndProc=DefWindowProc并非单纯把消息交给消息处理函数,所

谓的Defxxxx而是做了消息映射,所以此处该处理函数是没有相应的。--leon注解

单文档程序的子窗口是cxxxxview类
LPCTSTR 常量字符串

CxxxDOC 文档类
在C++中,结构体也是一种特殊的类

MFC和WIN32 创建窗口方法的区别和联系


 WNDCLASS wndcls;
 wndcls.cbClsExtra=0;
 wndcls.cbWndExtra=0;
 ......
 RegisterClass(&wndcls);

 CWnd wnd;//wnd并不是窗口,窗口销毁时之销毁了句柄为空,但是成员

函数仍可以用,但是如果wnd销毁,则窗口销毁
 wnd.CreateEx(...);//hwnd 内部传递并没有外漏
 wnd.ShowWindow(SW_SHOWNORMAL);
 wnd.UpdateWindow();
|WIN32----------------------------------------------------------------

--个MFC
v HWND hwnd;
 hwnd=CreateWindowEx();
 ::ShowWindow(hwnd,SW_SHOWNORMAL);
 ::UpdateWindow(hwnd);

 ......

CButton::Create(LPSTSTR按键的文字,风格,大小和位置,父窗口,ID)
例子 : CButton btn;//加到class中的private中
调用
        btn.Create("test",WS_Child|BS_PUSHBUTTON,CRect(0,0,1,1),this,

ID123);
        btn.ShowWindow。。。
小锁 private ,钥匙protect ,什么都没有就是public
得到父窗口指针HWND GetParent();


----------------------------------------------------------------------

--------------------
----------------------------------------------------------------------

--------------------
文本编辑
创建插入符
CreateSolidCaret(20宽度,100高度);
ShowCaret();
//Ascent 升序高度,即h角到头的高度
//Descent 降序高度 ,即G从头到脚的高度
获得字体高度
CCilentDC dc(this);
TEXTMETRIC tm;//注意此处的tm为随意命名
dc.GetTextMetrics(&tm);
tm.tmhight 就是他的高度
这个用法很有用!

位图插入符

CBitmap bitmap;//如果要用,最好放到类的private中,以免析构的时候被干掉
bitmap.LoadBitmap(IDC_XXX);//CString也有类似的读取资源的方法就是

LoadString//可以在资源的String Table中添加
CreateCaret(&bitmap);
ShowCaret();


View 类, 中的OnDraw 窗口重绘时经历

CDC类定义的*pDC
CString str("Hello World!");
文本输出:
pDC->TextOut(50,50,str);//50,50就是文字的左上角的坐标

CSize 中的成员x y 分别是长度和高度

获得字符串的高度
CSize sz=pDC->GetTextExtent(str);

画矩形 pDC->Rectangle(x0,y0,x1,y1);
cstring.GetLength()取长度
 //////////////////////////////
此函数实在CxxxView类中右击选择 Add Windowsmessage Hander 从而增添的消息

截获WM_CHAR消息做的响应
void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
 CClientDC dc(this);
 CFont font;
 font.CreatePointFont(300,"华文行楷",NULL);
 CFont *pOldFont=dc.SelectObject(&font);
 TEXTMETRIC tm;
 dc.GetTextMetrics(&tm);
 if(0x0d==nChar)//回车
 {
  m_strLine.Empty();
  m_ptOrigin.y+=tm.tmHeight;
 }
 else if(0x08==nChar)// 退格
 {
  COLORREF clr=dc.SetTextColor(dc.GetBkColor());
  dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);
  m_strLine=m_strLine.Left(m_strLine.GetLength()-1);
  dc.SetTextColor(clr);
 }
 else
 {
  m_strLine+=nChar;
 }
 CSize sz=dc.GetTextExtent(m_strLine);

 CPoint pt;
 pt.x=m_ptOrigin.x+sz.cx;
 pt.y=m_ptOrigin.y;

 SetCaretPos(pt);
 dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);

 dc.SelectObject(pOldFont);

 CView::OnChar(nChar, nRepCnt, nFlags);
}

CTextView::OnTimer(UINT nIDEvent) //文字追随变色的Timer组件代码
{
 // TODO: Add your message handler code here and/or call default
 m_nWidth+=5;

 CClientDC dc(this);
 TEXTMETRIC tm;
 dc.GetTextMetrics(&tm);
 CRect rect;
 rect.left=0;
 rect.top=200;
 rect.right=m_nWidth;
 rect.bottom=rect.top+tm.tmHeight;

 dc.SetTextColor(RGB(255,0,0));
 CString str;
 str.LoadString(IDS_WEIXIN);
 dc.DrawText(str,rect,DT_LEFT);

 rect.top=150;
 rect.bottom=rect.top+tm.tmHeight;
 dc.DrawText(str,rect,DT_RIGHT);

 CSize sz=dc.GetTextExtent(str);
 if(m_nWidth>sz.cx)
 {
  m_nWidth=0;
  dc.SetTextColor(RGB(0,255,0));
  dc.TextOut(0,200,str);
 }
///////////////////////////////////////////////////////////////////////

/
 CView::OnTimer(nIDEvent);
}

///////////////////////////////////////
=======================================================================

====
关于消息的三点:

1.类的头文件中注释宏之间(//{{AFX_VIRTUAL(xxx)。。。//}}AFX_VIRTUAL)
2.源文件的
BEGIN_MESSAGE_MAP(CXXXView, CView)
 //{{AFX_MSG_MAP(CXXXView)
这个位置
//}}AFX_MSG_MAP
3.源文件的viod cXXxx::onXXX ()自定义的处理函数部分

MFC的消息映射(非WIN32的消息循环处理)

WIN32的编程中 消息处理是把所有的消息都做成虚函数,只要定了子类就可以进

行相应
这样会造成内存资源的浪费

后台有个句柄和c++类对象指针的映射表 ,有消息发生后,后台会把消息以及相

关的窗口对应起来,通过该窗口的句柄找到C++对象的指针,然后将指针传给基类

,基类通过消息循环调用了WindowProc,而WindowProc本身是虚函数,在具体子

类定义次函数时必然会调用了OnWinMsg(消息路由部分),OnWinMsg会查找 1和2

从而判断有没有该消息响应的生命,最后找到3 进行处理。--孙鑫先生原文

我理解MFC的消息映射过程是这样的:

消息产生了-》启用那个后台的映射表-》查找响应窗口的句柄-》WindowProc-》

OnWinMsg-》看看1,2部分有无定义,有的话就—》3 ;、、、、没有就算了(交

由基类处理) :)

view中无须用函数获得本窗口句柄,直接用m_hWnd就是本窗口句柄

画线函数及其用法:

win32用法

HDC hdc;
hdc=::GetDC(m_hWnd);//平台sdk的函数需要加::
MoveToEx(hdc,m_old.x,m_old.y,NULL);//先把鼠标移动到最初的点
LineTo(hdc,point.x,point.y);//画函数
::ReleaseDC(m_hWnd,hdc);//用完释放dc

MFC用法

CDC *pDC=GetDC();
pDC->MoveTo(m_old);
pDC->LineTo(point);
ReleaseDC(pDC);
注释同上


更快的MFC(自动会GetDC和ReleaseDC)

//CClientDC dc(GetParent());//若用此法,可以在工具栏上画,即目标是整个

框架,但不包括非客户区域即标题栏和菜单。
CClientDC dc(this);//注意此函数需要的是一个CWnd的指针,而不是hwnd,hwnd

只是cwnd的一个变量可以用cwnd->hwnd 来调用
dc.Moveto(m_old);
dc.LineTO(ponit);

第四种方法,CWindowDC(也自动会GetDC和ReleaseDC)

CWindowDC dc(this);//若用GetParent可以全窗画
dc.MoveTo(m_old);
dc.LineTo(ponit);

桌面本身就是窗口!
获取桌面窗口的句柄: GetDesktopWindow()可以获取一个CWnd;

注意,此处若用CWnd::的就是获取CWnd类的指针
若用sdk的即::类的就是获取这个窗口的句柄!

CPen画笔类
CPen pen(笔形,宽度,RGB颜色);
需要选入设备描述表中!!
应采用SelectObject可以选择pPen,pBrush,pFont,pBitmap(使用时需要加& 如

&pen,其返回值也是指针,需要用 *pen接)
其返回值是先前一个状态的设备,比如定义了新画笔,那么返回值就是旧画笔。

 

CBrush画刷类

颜色画刷
CBrush brush(RGB(255,0,0));
CClientDC dc(this);
dc.FillRect(CRect(m_old,point),&brush);//填充
//画红色矩形

位图画刷

CBitmap bitmap;
bitmap.LoadBitmap(IDB_XXXX);
CBrush brush(&bitmap);
CClientDC dc(this);
dc.FillRect(CRect(m_old,point),&brush);//填充


画矩形最快的方法:
dc.Rectangle(CRect(m_old,point));


透明画刷方法:

CBrush:*pB=CBrush::FromHandle((HBURSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pB);
dc.Rectangle....
---------------------
Class p
{
public:
       void a()
       {}
       static void b()
』//静态使用成员函数可以在任何地方写 
如, 静态环境不能调用非静态(没有static定义)的成员变量,

非静态的可以引用静态参数

静态的必须初始化!!即在定义前就要做好!

p point;
p:b();就可以


        {}
}
==============================================
ss菜单:

新增菜单命令响应函数的四大文件篇
 
MainFrame
第三优先级
App
第四优先级
Doc
第二优先级
View
最高优先级

个级别都是如果有函数,就不再允许别的类相应

-----------

消息分类

标准消息:
它是CWnd派生的类,它派生的类中都可以接受到这个消息
除了WM_COMMAND外,所有已WM开头的消息

命令消息
菜单,快捷键,工具栏按钮的消息
都是以WM_COMMAND呈现,要区分 需要菜单项的ID号码
CCmdTarget(CWnd的父类)派生的类都可以接受这类消息

通告消息
有控件产生的消息,按键的单击,区分需要ID。。。
也是以WM_COMMAND呈现
CCmdTarget(CWnd的父类)派生的类都可以接受这类消息

CWnd类可以接受所有的消息,但是CCmdTarget只能接受后两者

命令消息的路由:                                     
AfxWndProc->AfxCallWandProc->WindowProc->OnWndMsg  ->.1 OnNotify(通告消

息)  ->OnCmdMsg   
                                                     .2 OnCommand(命令

消息)

标记菜单——带对勾的那种
实现方法:
在相应函数处加入OnCreate中
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_按键,

MF_BYCOMMAND|MF_CHECKED);//MF_UNCHECKED
0 代表是第几个子菜单
GetMenu是CWnd的一个成员函数,它返回一个指向整个菜单栏的指针
而GetSubMenu只是返回子菜单的指针
CheckMenuItem是在菜单中放置或者取消一个标记

注意如果用索引法,一定能够要计算分割栏!

设置默认菜单(字体变粗)
GetMenu()->GetSubMenu(0)->SetDefaultItem(ID);
一个子菜单只能有一个缺省菜单,即最后一次命名的。

设置图片菜单
SetMenuItemBitmaps
可以有连个位图,选中一个位图,没选中一个位图。
CBitmap cc;
cc.loadbitmap(图片的ID);
SetMenuItemBitmaps(ID_FILE_OPEN,MF_BYCOMMAND,&m_cbp,&m_cbp);

按键变灰色的函数:GetMenu()->GetSubMenu(0)->EnableMenuItem(ID,

MF_BYCOMMAND/MF_DISABLE|MF_GRAYED);需要在mainframe的构造函数中加

m_bAutoMenuEnable=0;


GetSystemMetrics();//获得系统参数,详情请参考msdn可以查到很多有用的数据
移走菜单 : SetMenu(NULL);
回复菜单:
CMenu menu;
menu.LoadMenu(菜单的ID);
SetMenu(&menu);
1.10
CMenu类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值