《孙鑫vc++视频20集》【最后更新日期:16/04/20

记录的都是我个人比较关注的内容~


第1课 windows程序内部运行机制


句柄(handle)

图标句柄(HICON)、光标句柄(HCURSOR)、窗口句柄(HWND)、应用程序实例句柄(HINSTANCE)。

操作系统给没一个窗口指定的一个唯一的标识号即窗口句柄。


WPARAM、LPARAM

一级定义:

typedef UINT_PTR       WPARAM;
typedef LONG_PTR       LPARAM;
typedef LONG_PTR       LRESULT;

二级定义:

typedef _W64 int INT_PTR , *PINT_PTR;
typedef _W64 unsigned int UINT_PTR , *PUINT_PTR;
typedef _W64 long LONG_PTR , *PLONG_PTR;
typedef _W64 unsigned long ULONG_PTR , *PULONG_PTR;

含义:关于消息的附加信息。例:按下一个按键,产生一个WM_CHAR消息,但并不知道按下哪个按键。

要通过这个附加消息,才知道按下了哪个按键。


从变量类型区分变量的用途

int x,y;                     typedef int WIDTH

 x = 30;                      typedef int HEIGHT

 y = 30;                      WIDTH x;

                AND           HEIGHT y;


加特征直接或运算,减特征跟一个取反的特征求与

如果我们希望在某一变量原有的几个特征上去掉其中一个特征,用取反(~)之后再进行与(&)运算,

就能够实现,如在刚才的style的基础上去掉CS_NOCLOSE特征,可以用style&~CS_NOCLOSE实现。


LPCTSTR

L----long;

P----point;

CT----const;

STR----string;


成对儿的函数

BeginPaint()和EndPaint();

GetDC()和ReleaseDC();

【不能混用】


条件等价判断时的写法

常量写在左,变量写在右。


DestroyWindow()只销毁窗口,不退出程序。


条件分支结构,一定不能忘记对缺省的处理。【default


一些宏

#define CALLBACK     __stdcall
#define WINAPI        __stdcall
#define WINAPIV      __cdecl
#define APIENTRY     WINAPI
#define APIPRIVATE   __stdcall
#define PASCAL        __stdcall

-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/2/24 18:14

第2课 掌握C++


缺省形参写法:

void output(int a , int b=5);


类的三种权限说明:

pubilc:哪都能访问

protected:外部不能调用,只能本类内或者子类调用

private:只能本类内调用


类的继承访问特性:

基类的访问特性         类的继承特性        子类的访问特性
    Public                 Public                 Public
    Protected                                     Protected
    Private                                        No access    
    Public                 Protected                  Protected
    Protected                                      Protected
    Private                                        No access    
    Public                  Private                 Private
    Protected                                        Private
    Private                                        No access    

继承的一些初始化:

class Fish : public Animal                //继承Animal类

{

   public:

      Fish():Animal(400,300),a(1)        //初始化Animal类的带参构造方法,和初始化类变量a

      {

         cout<<"fish construct"<<endl;

      }

      ~Fish()

      {

         cout<<"fish deconstruct"<<endl;

      }

   private:

      const int a;

};


函数的覆盖与重载

覆盖是发生在父类和子类之间的【函数名、参数等都一样】,

重载是发生在一个类里面的【函数名一样,但参数个数或者类型不一样】。


类型转换

转换的双方内存模型要匹配,才能转换。


多态性

为了实现一个接口多个方法。即:
声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,
可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,
即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,
而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,
而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。

虚函数和纯虚函数

虚函数:
virtual void breathe()
{
   cout<<"animal breathe"<<endl;
}

头文件中声明时,加virtual;但在实现的时候,就不要加virtual了。

纯虚函数:
virtual void breathe()=0;    //基类先声明出一个方法,但还不确定具体干嘛。
                                 //留着子类实现各自对应的功能。
PS:带有纯虚函数的类不能实例化对象。

引用:

MFC中函数的调用,传参最好使用引用,而不是指针。这样可以避免内存的拷贝,
因为引用使用的是同一块内存地址。
int change(int* pA, int* pB)
{

}
void main()
{
   int x=3;
   int y=4;
   change(&x,&y);
}
这种指针的参数调用,容易产生语义上的混淆。使参数的类型不是那么明晰。

int change(int &a, int &b)
{

}
void main()
{
   int x=3;
   int y=4;
   change(x,y);
}
这种引用的参数调用,改变a、b的值,也就改变了x、y的值,因为用的是同一块内存地址,
传参时语义上更加清晰一些。


包含的标点:

双引号定义从当前目录下进行查找,双尖括号定义从系统目录下开始查找。
基本上:如果不是自己的头文件,就用尖括号,这样可以加快搜索的速度;
如果是自己的头文件,就用双引号,从当前目录下开始搜索。

重复定义的问题:

第一:
#ifndef XXXXXX
#define XXXXXX   1
class Point
{

};
#endif

#ifndef XXXXXX
#define XXXXXX   1
class Point
{

};
#endif

void main()
{
   Point pt;
}
通过这种方式,并不是要用XXXXXX来定义什么,而是通过用这个结构来防止重复定义。

第二:
#ifndef XXXXXX
#define XXXXXX
class Point
{

};
#endif

#ifndef XXXXXX
#define XXXXXX
class Point
{

};
#endif

void main()
{
   Point pt;
}
#define XXXXXX后面并没有定义为某个具体的值,但是这样操作后是定义了,定义为空。

第三:
#ifndef POINT_H_H_H
#define POINT_H_H_H
class Point
{

};
#endif

#ifndef POINT_H_H_H
#define POINT_H_H_H
class Point
{

};
#endif

void main()
{
   Point pt;
}
通常,我们不会写成X,因为我们的代码很有可能要和其他人的代码去集成。
如果写一个很常用的变量,很可能其他人已经在它的代码中定义过了这样一个宏,
编译时就会报错。
所以用POINT_H_H_H,有一定实际意义,且能和别的变量或者宏区别开。

通常的模式为,在头文件中声明类,在源文件中实现类,在头文件中使用这种防止重定义的措施。

VC++编译链接过程:



错误会产生两个地方:
1.编译过程
2.链接过程
-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/2/26 15:55

第3课 MFC框架程序剖析


win32窗口程序的主线:

先进入winmain函数,设计窗口类,注册窗口类,创建窗口、显示窗口、更新窗口,最后作消息循环。

将消息路由到窗口过程当中去处理。


全局对象、对象对应类的构造函数、WinMain函数】执行顺序

全局对象→→→对象对应类的构造函数→→→WinMain函数

【通过设置断点,可逐步推测出程序各部分初始化顺序。】


子类用不传参的方式,调用基类带参数的构造函数:

将基类构造函数设置好缺省,就妥啦~


::前面没有类名:

说明::后面的函数或变量是全局的,不属于任何命名空间


getparent()获取父窗口句柄


第4课 简单绘图


画线:

先建俩消息响应函数,一个是鼠标左键按下、另一个是鼠标左键弹起。

然后分别在里面敲如下代码:【提前建一个CPoint类的对象m_point】

左键按下→函数传入两个参数:1. UINT nFlags   2.CPoint point

m_point=point;


左键弹起→函数传入两个参数:1. UINT nFlags   2.CPoint point

【平台SDK函数返回的是句柄,CWnd函数返回的是指针】

HDC到CDC的转换:

法一:CDC *pDC = CDC::FromHandle(hDC);//此方法在设备结束时,不会销毁原来的资源

法二:CDC dc;  dc.Attach(hDC);       //此方法在设备结束时,会销毁原来的资源

CDC到HDC的转换:

CDC dc;
HDC hDC;
hDC = dc.GetSafeHdc();


第一种:

HDC hdc;

hdc = ::GetDC(m_hWnd);

MoveToEx( hdc, m_point.x, m_point.y, NULL);

LineTo( hdc, point.x, point.y);

::ReleaseDC(m_hWnd,hdc);

第二种:

CDC *pDC = GetDC();

pDC ->MoveTo(m_point);

pDC ->LineTo(point);

ReleaseDC(pDC);

第三种:

CClientDC dc(this);      //CClientDC dc(GetParent());算上工具窗口   
//CWindowDC dc(this);整个程序窗口     至于区别,来这里看吧~还有这里
     //CWindowDC dc(GetDesktopWindow());整个电脑屏幕

dc.MoveTo(m_point);

dc.LineTo(point);

-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/3/16 20:55

创建画笔:

CPen pen(PS_SOLID, 10, RGB(0, 255, 0));   //画笔类型、笔画粗细、颜色

CClientDC dc(this);

CPen *pOldPen = dc.SelectObject(&pen);     //SelectObject返回被替换的那个画笔

dc.MoveTo(m_point);

dc.LineTo(point);

dc.SelectObject(pOldPen);                     //恢复旧的画笔


创建画刷:


颜色的画刷:
CBrush brush(RGB(255, 0, 0));    //创建了一个红色的画刷

CClientDC dc(this);               //设定可操作的窗口范围

dc.FillRect(CRect(m_point,point),&brush);


带图形的画刷:

CBitmap bitmap;

bitmap.LoadBitmap(ID_Bit);        //建个ID号为ID_Bit的位图

CBrush brush(&bitmap);            //相当于把输入,从之前的颜色换成了一张图~

CClientDC dc(this);

dc.FillRect(CRect(m_point,point),&brush);


画矩形框:

矩形框之间有被白色背景覆盖:    //因为缺省的画刷是白色

CClientDC dc(this);

dc.Rectangle(CRect(m_point,point));

矩形框之间无白色背景覆盖:    //即画刷是透明的

CClientDC dc(this);

CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));   

                        //FromHandle()是输入一个HBRUSH类型的句柄,返回一个CBrush指针;

                        //GetStockObject()是输入一个画刷种类的名称,返回该画刷名的句柄。

CBrush *pOldBrush = dc.SelectObject(pBrush);

dc.Rectangle(CRect(m_point,point));

dc.SelectObject(pOldBrush);


静态函数和静态变量:

#include<iostream.h>

class Piont

{

   public:

   void output()

   { //init();

   }

   static void init()

   { x = 0; y = 0;}

   private:

   static int x,y;

};


   int Point::x = 0;

   int Point::y = 0;


void main()

{

   Point pt;

   pt.init();

   pt.output();


   Point::init();          //可以直接调用,初始化的时候,已经为该函数分配了内存单元

   Point::output();       //不可以直接调用,需要用对象来承载

}

总结:我们只能调用内存中已经存在的东西,静态函数或者静态变量在类的初始化的时候,

就已经被分配了内存单元。所以可以脱离对象直接调用。静态变量在声明的时候,要初始化,

其实不初始化也行,只要全程不调用它就OK。但如果不调用,这静态变量也就没有存在的意义了。

同时静态函数是不能引用非静态函数或变量的。非静态函数可以调用静态函数,

因为此时静态函数已经在初始化的时候,被分配的内存单元,是已经存在的。

总之就是只能调用内存中已经存在的东东!!!


说这些,就是为了解释CBrush::FromHandle()这个函数,因为这个函数就是一个静态函数,

所以不依赖于对象就可以使用。


在指定的客户区域写字:

建一个布尔变量m_Flag,初始化为FALSE。

在按下鼠标左键的消息响应函数中,将该布尔变量赋值为TRUE;

在弹起鼠标左键的消息响应函数中,将该布尔变量赋值为FALSE。

在鼠标移动的消息响应函数中实现写字。

代码如下:

CClientDC dc(this);

CPen pen(PS_SOLID, 1, RGB(255, 0, 0));

CPen *pOldPen = dc.SelectObject(&pen);

if(TRUE ==m_Flag)

{

dc.MoveTo(m_point);

dc.LineTo(point);

m_point = point;

}

dc.SelectObject(pOldPen);


绘画模式设置:dc.SetROP2(R2_BLACK);


那么问题来了,Ondraw和Onpaint有啥区别啊!!!

-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/3/17 19:55

第5课 文本编程


创建插入符:OnCreate消息响应函数内的代码

创建普通光标的插入符:

CClientDC dc(this);

TEXTMETRIC tm;

dc.GetTextMetrics(&tm);

CreateSolidCaret( tm.tmAveCharWidth/8, tm.tmHeight);

ShowCaret();


创建位图的插入符:CBitmap bitmap;在头文件中声明

CClientDC dc(this);

TEXTMETRIC tm;

dc.GetTextMetrics(&tm);

bitmap.LoadBitmap(IDC_BITMAP);

CreateCaret(&bitmap);

ShowCaret();


VS代码自动缩进快捷键:

法一:ALT+F8

法二:ctrl+K,ctrl+F


重绘显示文字:

CClientDC dc(this);            //获取客户区dc
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);          //载入字体,这个文字的ID号在资源视图的String Table里面设置 
dc.DrawText(str,rect,DT_LEFT);      //输出到屏幕

-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/3/27 21:05

第6课 菜单编程---无



第7课 对话框编程(一)


弹出自建Dialog:

模态:

CTestDlg dlg;           //当前代码页面要包含该Dialog类的头文件

dlg.DoModal();          //虽然dlg是局部变量,但程序执行到此处,会暂停,

        //直到模态对话框关闭,才继续向下执行


非模态:

CTestDlg dlg;

dlg.Create(IDD_DIALOG,this);

dlg.ShowWindow(SW_SHOW);       //此处由于dlg为局部变量,

                                    //故不会弹出对话框


CTestDlg *pDlg = new CTestDlg();

pDlg -> Create(IDD_DIALOG,this);

pDlg -> ShowWindow(SW_SHOW);        //此时才会弹出对话框

                                         //还可以把dlg定义成当前类的成员变量

                                        //放到析构函数中delete掉

//系统创建的对话框窗口上的OK和CANCEL按钮,点击OK按钮时,

//是OnOK()这个函数响应的,基类OnOK()是虚函数


BUTTON控件:

动态创建按钮:

先在头文件声明个变量:CButton m_btn;

然后在适当的地方添加如下代码:

m_btn.Create("按钮名",BS_DEFPUSHBUTTON|WS_VISIBLE|

               WS_CHILD,CRect(0,0,100,100),this,123);


销毁时使用:DestroyWindow();

例:m_btn.DestroyWindow();

-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/3/28 17:05

通过判断句柄是否有值,来判断控件是否存在:

m_btn.m_hWnd句柄,返回按钮的句柄,存在即为TRUE,不存在为0.


STATIC静态文本框:

","逗号表达式:表达式1,表达式2,表达式3,……,表达式n

最后结果为表达式n的值


为改控件添加消息响应函数的时候,要修改其属性Notify为TRUE

GetDlgItem(ID号);       //获取控件的CWnd指针

GetWindowText(CString str);  //获取文本


成对儿的组合使用:

GetDlgItem(ID号) -> GetWindowText(CString str); //获取文本

GetDlgItem(ID号) -> SetWindowText(CString str);  //设置文本


GetDlgItemText(ID号,CString str,int n);    //参数n为接收字符串的长度

SetDlgItemText(ID号,CString str);


GetDlgItemInt(ID号);         //返回值就是获取到的值

SetDlgItemInt(ID号,UINT nValue);


::SendMessage(与控件关联的变量.m_hWnd, WM_GETTEXT, n, (LPARAM)ch1);   

               前面有::的函数为win32平台SDK函数    //n为获取文本的的长度,

                                                          //ch1为buffer首地址

::SendMessage(与控件关联的变量.m_hWnd, WM_SETTEXT,(WPARAM)n, (LPARAM)ch1);


与控件关联的变量.SendMessage( WM_GETTEXT,(WPARAM)n, (LPARAM)ch1);

与控件关联的变量.SendMessage( WM_SETTEXT,(WPARAM)0, (LPARAM)ch1); 

                                                          //参数二没使用,必须为0


SendDlgItemMessage(控件ID,WM_GETTEXT, (WPARAM)n, (LPARAM)ch1);

SendDlgItemMessage(控件ID,WM_SETTEXT, (WPARAM)0, (LPARAM)ch1);


UpdateData(BOOL bSaveAndValidate=TRUE);     //TRUE为从控件传到变量;

                                                    //FALSE为从变量传到控件


设置选中edit编辑框中的文本:

SendDlgItemMessage(控件ID,EM_SETSEL,0,-1);     //后两个参数设置为0,-1为全选中

例:

与控件关联的变量.SetFocus();

限定编辑框输入数字的位数:

与控件关联的变量.SetLimitText(UINTn);   //设置编辑框允许输入的长度


DoDataExchange函数:

控件和成员变量的关联是在DoDataExchange中完成的 -> DDX_xxx()

对话框的数据校验:DDV_MinMaxInt( CDataExchange*pDX, intvalue, intminVal, intmaxVal );

value:与控件关联的变量,min,max );

minVal、maxVal:需要设置的最小值和最大值


数据类型转换:

字符串→整型:atoi(CString str);

整型→字符串:itoa(int a,CString str,int n);//最后一个参数为按n进制转换


获取控件句柄:

方式一:GetDlgItem(ID号) -> m_hWnd

方式二:与控件关联的变量.m_hWnd


EndDialog函数:

EndDialog(int nResult);    //nResult为指定由DoModal返回的参数,

                               //就是DoModal返回时,返回这个变量


改变按钮文字:

CString str;

if(GetDlgItemText(IDC_BUTTON2,str),str=="收缩<<")
{
SetDlgItemText(IDC_BUTTON2,"扩展>>");
}
else
{
SetDlgItemText(IDC_BUTTON2,"收缩<<");
}

用于标示在界面上的分隔符可用picture control拉成一条线,设置风格中

将Sunken设置为TRUE,使picture control成为下陷的形态


IsRectEmpty()和IsRectNull():

IsRectEmpty()判断四个值是否能构成矩形;

IsRectNull()判断四个值是否都为0


按钮控制窗口伸缩:

先用分割线在要切割的位置画个picture控件,ID号为IDC_PIC


static CRect rectLarge;  //保存还原后的对话框的尺寸【要求不重复定义,设置为静态
static CRect rectSmall;  //保存切割后的对话框的尺寸【要求不重复定义,设置为静态

if(rectLarge.IsRectNull())
{
   CRect rectSeparator;           //存IDC_PIC的两点坐标【左上角和右下角
   GetWindowRect(&rectLarge);
   GetDlgItem(IDC_PIC)->GetWindowRect(&rectSeparator); 


   rectSmall.left=rectLarge.left;            //左上角横坐标
   rectSmall.top=rectLarge.top;              //左上角纵坐标
   rectSmall.right=rectLarge.right;         //右下角横坐标
   rectSmall.bottom=rectSeparator.top;  //右下角纵坐标
}

if(str=="收缩<<")
{
   SetWindowPos(NULL,0,0,rectSmall.Width(),rectSmall.Height(),
   SWP_NOMOVE | SWP_NOZORDER);     //保留当前位置不移动 | 保留当前Z字序,即窗口层叠次序
}
else
{
   SetWindowPos(NULL,0,0,rectLarge.Width(),rectLarge.Height(),
   SWP_NOMOVE | SWP_NOZORDER);
}


TAB STOP的顺序:(在控件中按TAB时,移动的顺序)

ctrl+D


焦点移动到下一个控件:

GetNextDlgTabItem(GetFocus()) -> SetFocus();


关于OnOK()的重载:

在类视图里,找到CxxxDlg,右键点属性,点重写,找到OnOK这个虚函数,点右侧空白条的下拉箭头,

选 <Add> OnOK,然后编辑该函数。

代码如下:

void CxxxDlg::OnOK()
{

   CWnd *wnd = GetFocus ();

   SendDlgItemMessage(wnd->GetDlgCtrlID (),EM_SETSEL,0,-1);   

                                                //此处把各个编辑框都设置成了全选状态

   GetNextDlgTabItem (GetFocus()) -> SetFocus();     //切换到tab stop序的下一个控件


   //CDialogEx::OnOK();                                   //此处注释掉默认调用的基类OnOK()
}

但此处有个小问题,切换到按钮时,再按回车,直接切换到tab stop序的下一个控件;

而我们希望它先执行一下按钮的响应函数,再切换到tab stop序的下一个控件。


so,又作了如下修改,代码扒自这里

首先,要同上一步一样,重载一个虚函数。

在类视图里,找到CxxxDlg,右键点属性,点重写,找到PreTranslateMessage这个虚函数,

点右侧空白条的下拉箭头,选 <Add> OnOK,然后编辑该函数。


BOOL CfakerDlg::PreTranslateMessage(MSG* pMsg)
{
   if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
   {
      CWnd *wnd = GetFocus ();
      if (wnd != NULL)
      {

         char str[256];
         CString ClassName = _T("Button");
         GetClassName (wnd->m_hWnd, str, 256);
         if (ClassName == str)
         {
            UINT i = wnd->GetDlgCtrlID ();

            SendMessage (WM_COMMAND, i, (LPARAM)wnd->m_hWnd);
            return TRUE;
         }
      }
      SendDlgItemMessage(wnd->GetDlgCtrlID (),EM_SETSEL,0,-1);
      GetNextDlgTabItem (wnd)-> SetFocus();
      return TRUE;
   }
   return CDialogEx::PreTranslateMessage(pMsg);
}


第8课 对话框编程(二)


逃跑按钮:

1.把dialog上自带那些东西删掉,往上放俩按钮,然后添加变量。
添加成CButton类型,一个是m_btn1,一个是m_btn2。

2.自己建个类,叫Cbtn,继承CButton类。

3.在自己建的类的头文件里,声明个指针。      Cbtn* m_pBtn;

4.在主dialog的头文件里,包含#include "Cbtn.h",
然后再把之前生成的俩CButton变量,改成Cbtn类型,如下:
                     Cbtn m_btn1;
                     Cbtn m_btn2;

5.在主dialog的初始化函数中,添加如下代码:
               m_btn1.m_pBtn = &m_btn2;
               m_btn2.m_pBtn = &m_btn1;

6.在类视图下,右键Cbtn类,→属性→消息→ WM_MOUSEMOVE → <Add> OnMouseMove
添加如下代码:
                       ShowWindow(SW_HIDE);
                       m_pBtn -> ShowWindow(SW_SHOW);


7.把其中一个按钮的visible选项改成FALSE

8.编译、、、

Tips:之所以要额外建个类,是因为如果使用主dialog的WM_MOUSEMOVE,
鼠标只要移动,就会触发,这当然不是我们想要的。
我们想要的是鼠标碰到按钮才会触发,所以,我们把两个按钮打包成一个类。
使用这个打包的类来响应WM_MOUSEMOVE,即鼠标焦点只要进入到这两个按钮的区域,
也就是Cbtn类在视图上的作用域,一移动就会触发WM_MOUSEMOVE来完成我们想要的操作。

1.把dialog上自带那些东西删掉,往上放一个按钮,然后添加变量。
添加成CButton类型,m_btn1。

2.自己建个类,叫Cbtn,继承CButton类。

3.在主dialog的头文件里,包含#include "Cbtn.h",
然后再把之前生成的俩CButton变量,改成Cbtn类型,如下:
                     Cbtn m_btn1;

4.在类视图下,右键Cbtn类,→属性→消息→ WM_MOUSEMOVE → <Add> OnMouseMove
添加如下代码:
把WM_MOUSEMOVE的代码改成如下代码:【实现按钮在客户区域随机移动

   CRect rectBtn;  
   CRect rectDialog;
   //获取按钮和对话框的尺寸坐标  
   
   GetClientRect(&rectBtn);  
   GetParent()->GetClientRect(&rectDialog);

   //获取一个相对于对话框大小的一个随机坐标
   int x = rand() % rectDialog.right;  
   //保证整个按钮完整的显示在对话框内部
   if(x > rectDialog.right - rectBtn.right)
         x -= rectBtn.right;

   int y = rand() % rectDialog.bottom;  
   if(y > rectDialog.bottom - rectBtn.bottom)
         y -= rectBtn.bottom;

   //不改变尺寸,不改变Z次序  
   SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);


Tips:原作者代码有点儿小BUG,顺手给改了、【限制按钮不出界
      还有就是,现在这样,一个按钮就够用了。

增强版_plus:


工程文件:文件一文件二   【 级别不够,不能传大文件,只能拆开传、、、囧


-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/4/20 17:00


第9课 定制应用程序外观


view类在frame类的上层,改鼠标和背景在view类中改


CTime类获取时间:

CTime  t = CTime::GetCurrentTime();

CString str = t.Format("%H:%M:%S");


获取字符串在屏幕上显示的宽度和高度:

CClientDC dc(this);

CSize sz = dc.GetTextExtent(str);   //sz.cx为宽度;sz.cy为高度


用户自定义消息:

第一步:在头文件定义一个消息

#define  UM_PROGRESS  WM_USER+1


第二步:消息响应函数原型的声明,在头文件protected:下面

afx_msg void OnProgress();     //括号里可带两个附加参数,不写就不带了


第三步:消息映射,在此处添加      //对消息来说,用ON_MESSAGE;对命令消息来说,用ON_COMMAND;

BEGIN_MESSAGE_MAP()

ON_MESSAGE(UM_PROGRESS,OnProgress)

END_MESSAGE_MAP()


第四步:实现消息响应

void CDialog::OnProgress()

{

//TODO

}


用户重绘的东西一般都放在OnDraw()函数里


检测控件显\隐状态:

BOOL IsWindowVisible( ) const;    //检测控件当前为显示还是隐藏状态

例:

与控件关联的变量.IsWindowVisible( );   //可见返回TRUE,不可见返回FALSE


移动控件位置:

void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );    //移动控件到指定位置

例:

CRect rect;

与控件关联的变量.MoveWindow(rect);


人为发送消息:

LRESULT SendMessage( UINTmessage, WPARAMwParam = 0, LPARAMlParam = 0 );

BOOL PostMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 );

SendMessage函数发送消息之后,立即去执行消息响应函数

PostMessage函数将消息发送到消息队列中,按照消息摆放顺序,通过GetMessage一条一条消息取出来


软件启动画面:

工程 -> 增加到工程 -> Components and Controls... -> 

-> Visual C++ Components -> Splash screen ->插入


//显示时间由设置的定时器控制




发布了48 篇原创文章 · 获赞 43 · 访问量 13万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览