记录的都是我个人比较关注的内容~
第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:只能本类内调用
类的继承访问特性:
继承的一些初始化:
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;
};
函数的覆盖与重载:
覆盖是发生在父类和子类之间的【函数名、参数等都一样】,
重载是发生在一个类里面的【函数名一样,但参数个数或者类型不一样】。
类型转换:
转换的双方内存模型要匹配,才能转换。
多态性:
虚函数和纯虚函数:
引用:
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);
}
包含的标点:
重复定义的问题:
#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;
}
#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;
}
VC++编译链接过程:
第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);
第三种:
dc.MoveTo(m_point);
dc.LineTo(point);
-----------------------------------------------------------------------------------------------------------------------------------------------------------2016/3/16 20:55
创建画笔:
CClientDC dc(this);
CPen *pOldPen = dc.SelectObject(&pen); //SelectObject返回被替换的那个画笔
dc.MoveTo(m_point);
dc.LineTo(point);
dc.SelectObject(pOldPen); //恢复旧的画笔
创建画刷:
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);
-----------------------------------------------------------------------------------------------------------------------------------------------------------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号) -> 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;
{
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课 对话框编程(二)
逃跑按钮:
m_btn2.m_pBtn = &m_btn1;
m_pBtn -> ShowWindow(SW_SHOW);
CRect rectDialog; //获取按钮和对话框的尺寸坐标
GetParent()->GetClientRect(&rectDialog);
int x = rand() % rectDialog.right;
//保证整个按钮完整的显示在对话框内部
if(x > rectDialog.right - rectBtn.right)
int y = rand() % rectDialog.bottom;
if(y > rectDialog.bottom - rectBtn.bottom)
//不改变尺寸,不改变Z次序
SetWindowPos(NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
第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 ->插入
//显示时间由设置的定时器控制