原文地址为: VC入门宝典 by 何志丹

這陣子從頭開始學習:---------------------

为了方便,也为了vb-->vc过渡成功!
VC入门宝典

何志丹

『针对对象』

想学VC,而不会VC的朋友.如果你刚学VC,可以看一下本系列的其他文章.

『摘要』

1,建立最简单的VC程序

2,Debug和release的区别及切换方式

3,如何备份VC代码

『正文』

万事开头来,首先我们编写一个最简单的VC程序.

1,进入VC.

2,主菜单File->New.

3,选择工程中的MFC AppWizard(exe),输入工程名(如Single)及路径.

4,MFC AppWizard -Step 1中,选择单文档,其它几步默认,直接Finish就行了.

5,Ctrl+F5运行.

我们可以看到一个最简单的程序了,没有添加一行代码.

我以此为原型,简单地讲解一下VC的常见问题.

1,在工作区(左边)选中类视图中的CSingleView类,右键,Add Member Varible,分别填CString和str.展开此类,双击SingleView(),在其中加入str="我会VC了!",注意用英文的引号.双击OnDraw(),在最后添加pDC->TextOut(100,110,str), 100是横座标,110是纵座标.

Ctrl+F5查看结果.

习题:打印九九乘法口决.提示:

int x1=1,x2=1;

CString str;

str.Format("%d*%d=%d",x1,x2,x1*x2);

2,菜单 在工作区(左边)选中资源,再展开菜单, 双击IDR_MAINFRAME,双击查看下面的空菜单项,输入ID ID_USER,标题 用户.Ctrl+w,在类名中选择CSingleView,在ID中选择ID_USER,双击消息中的COMMAND,确定.再双击我们刚才加的函数,加入如下代码:

str="I can use VC!";

Invalidate();

Ctrl+F5看结果.

习题:第一次单击菜单时显示英文,再单击菜单时显示中文.

提示:字符串(CString 类)可以用"=="比较.

MFC  AppWizard最重要的两步:

Step1:what type of application would you like to create?(生成那种类型的应用程序)

1,Single document单文档,如记事本,你无法同时打开两个文件.

2,Multiple document多文档,如Word.

3,Dialog based基于对话框,如扫雷,计算器.

Step 6:(基于对话框的程序没有此步骤)Base class基类:

1,CView:最基本的视图类.

2,CEditView:自动生成一个简单的记事本.

3,CFromView:类似于对话框,自带菜单工具栏状态条.

4,CHtmlView:加少量代码就可以浏览网页.

5,CRichEditView:便于处理图像.

6,CScrollView:自带滚动条.

Debug和release的区别及切换方式

Debug通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试。Release称为发布版本,它进行了各种优化,使得程序在大小和运行速度上都是最优的,以便用户很好地使用。实际上,Debug  和  Release  并没有本质的区别,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。我们可以通过主菜单->project->setting(Alt+F7)修改这些选项. Debug与Release的切换:主菜单->Build ->Set Active Configuaration

如何备份VC代码

删除Debug和Release文件夹,为了方便可以保留Release版的可执行程序.

删除文件:*.opt,*.ncb,*.plg.

可以删除的文件(不推荐): *.dsw,*.clw.

重新生成*.dsw:双击*.dsp.

重新生成*.clw:ctrl+w打开类向导,选择文件就行了.

vc入门宝典(一)(菜单) 
                           菜单

何志丹

菜单项属性说明:
ID 标识菜单的唯一常量。
Caption  菜单项标题,"&" 后面的字符为快捷键,在菜单项后的字符将加下划线。
Separator 水平线,其它属性无效。
Pop_up    有子菜单
Grayed   无效,标题以灰色显示
Inactive 无效,标题正常显示
Checked  在标题前加一个对钩
break   为None时,使它和它的兄弟们一行或一列显示。
Help    只对最上层菜单项有效,使它及后面的最上层菜单移到窗口的右上角。
Prompt  当鼠标指向它时的提示信息
多文档应用程序除了生成IDR_MAINFRAME外,还生成标识符为IDR_xxxxTYPE,其中xxxx为应用程序名。它们分别对应无文档和有文档时。
一个菜单id可以在多个类有响应函数,但只会有一个响应。
我实验得出的结果,CChildFrame,CCMenuApp,CCMenuDoc,CCMenuView,CMainFrame(我的应用程序名为CMenu)的响应顺序为:
在IDR_MAINFRAME中,CMainFrame,CCMenuApp其它三个不响应.
在IDR_XXXXTYPE 中,CCMenuView,CCMenuDoc,CChildFrame,CCMenuApp,CMainFrame.
ctrl+w打开ClassWizard,选好工程,类(最常选的是xxxView),在id中选择我们要修改的菜单项。
双击COMMAND(或UPDATE_COMMAND_UI)点确定就可以了。再在成员函数中双击我们刚刚加的函数,就可以编辑函数了。
当用户单击菜单时,我们刚刚编辑的函数会执行。
如果我们双击的是UPDATA_COMMAND_UI,则响应形式类似如下:
void ... OnUpdate...(CCmdUI * pCmdUI)
{
  pCmdUI->SetCheck(true);//在菜单项前加一个对钩
  pCmdUI->Enable(true);// 使菜单项能够使用
}
因为此函数往往影响到它的外形,故在它的“父亲”或“祖父”被选中时就会执行。

CWnd类中与菜单有关的几个函数。
SetMeun(CMenu *pMenu);
修改窗口的菜单,为NULL,则表示删除。
常用的还有
GetMenu();
GetSystemMenu();

CMenu的一些函数。
AppendMenu()函数指定的菜单最后附加一个新菜单项,同时可以指定菜单项的相关情况,它有两个语法。
nFlag指定状态,可以是以下四组之一或相组合而成,还可以与MF_POPUP组合表示添加的是弹出式菜单。
MF_CHECKED,MF_CHECKED
MF_DISABLED,MF_ENABLED,MF_GRAYED
MF_STRING,MF_OWNERDRAW,MF_SEPARATOR,MF_BITMAP菜单项是字符串,自画型,分隔线,位图。
MF_MENUBARBREAK,MF_MENUBREAK
nIDNewItem 指定菜单项的id.
lpszNewItem指定菜单项的内容,与nFlag有关。为MF_OWNERDRAW时,该参数为数据指针,用来传送数据,系统在发送消息WM_MEASUREITEM和WM_DRAWITEM时将该数据存入参数
的(DRAWITEMSTRUCT结构)itemData域;nFlag为MF_STRING时该参数为菜单标题。
InsertMenu
nFlags指定菜单项位置和状态,状态选项参见AppendMenu()函数,位置选项为MF_BYCOMMAND,MF_BYPOSITION.
nPositin若为MF_BYCOMMAND,新菜单项插在指定菜单项之前;或为MF_BYPOSITION,该参数指定新菜单项的位置,为-1插到最后。
ModifyMenu()参数与InsertMenu类似。
DeleteMenu删除菜单项
RemoveMenu移去菜单项

设置和显示浮动菜单
BOOL TrackPopupMenu(UINT nFlags,int x,int y,
                    CWnd *pWnd,LPCRECT = NULL);
nFlag浮动式菜单坐标设定方式及鼠标操作方式,有效值如下:
TPM_CENTERALIGN   TPM_LEFTALIGN  TPM_RIGHTALIGN
TPM_LEFTBUTTON    TPM_RIGHTBUTTON
x,y浮动式菜单坐标
pWnd指定操作菜单的窗口
lpRect指定鼠标操作范围
在客户区单击左键就会弹出快捷菜单,方法二需要在资源编辑器中编辑一个新菜单,方法三必须有主菜单。
方法一:
void CHeView::OnLButtonDown(UINT nFlags, CPoint point) 
{
 CMenu PopupMenu;
 PopupMenu.CreatePopupMenu();
PopupMenu.AppendMenu(MF_STRING,ID_FILE_NEW,"NEW..");
//...

ClientToScreen(&point);
PopupMenu.TrackPopupMenu(TPM_CENTERALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);

CView::OnLButtonDown(nFlags, point);
}

方法二:
void CHeView::OnLButtonDown(UINT nFlags, CPoint point) 
{

CMenu menu;
 menu.LoadMenu(IDR_DUMMY);
 CMenu *pMenu=menu.GetSubMenu(0);
 ASSERT(pMenu!=NULL);

ClientToScreen(&point);
        pMenu->TrackPopupMenu(TPM_CENTERALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
 CView::OnLButtonDown(nFlags, point);
}

方法三:
void CHeView::OnLButtonDown(UINT nFlags, CPoint point) 
{
 CWnd *pWnd=AfxGetApp()->GetMainWnd();
 CMenu * pMenu=pWnd->GetMenu();
 pMenu=pMenu->GetSubMenu(0);
    ASSERT(pMenu!=NULL);

ClientToScreen(&point);
 pMenu->TrackPopupMenu(TPM_CENTERALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);

}
习题:
动态菜单,用户点击“更多菜单”,增加一些菜单项。
其实,自画菜单原理不难理解.AppendMenu的风格选自画,将自画用的信息(指针)强制转化成LPCTSTR,再重

载DrawItem就行了,注意自画用的信息不要提前delete了.
示例如下:
COwnerMenu.h中
class CMenuItem
{
public:
 CString m_szText;
 COLORREF m_color;
 CMenuItem(CString szText,COLORREF color)
 {
  m_szText = szText;
  m_color  = color;
 }

};

#include <afxtempl.h>

class COwnerMenu : public CMenu  
{
public:
 void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
 bool AppendMenu(UINT nIDNewItem,CString caption,COLORREF color);
 COwnerMenu();

CTypedPtrList<CPtrList,CMenuItem *> m_MenuList;
 virtual ~COwnerMenu();

};

COwnerMenu.cpp中
COwnerMenu::~COwnerMenu()
{
 while(m_MenuList.GetCount())
 {
  CMenuItem *pMenuItem = m_MenuList.GetHead();
  delete pMenuItem;
  m_MenuList.RemoveHead();
 }
}

bool COwnerMenu::AppendMenu(UINT nIDNewItem, CString caption, COLORREF color)
{
 CMenuItem * pMenuItem = new CMenuItem(caption,color);
 m_MenuList.AddTail(pMenuItem);
 
 return CMenu::AppendMenu(MF_OWNERDRAW,nIDNewItem,(LPCTSTR)pMenuItem);
}

void COwnerMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
 pDC->SetTextColor(((CMenuItem*)lpDrawItemStruct->itemData)->m_color);
 pDC->TextOut(0,0,((CMenuItem*)lpDrawItemStruct->itemData)->m_szText);
 
}

在使用菜单的地方(不要忘记了加头文件):
void COwnerMenuView::OnRButtonDown(UINT nFlags, CPoint point) 
{
 COwnerMenu menu;
 menu.CreatePopupMenu();
 
 menu.AppendMenu(ID_1,"1",RGB(0,0,128));
 ClientToScreen(&point);
 
 menu.TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN,point.x,point.y,this);
 CView::OnRButtonDown(nFlags, point);
}

VC入门宝典三(String) 
CString

何志丹

主要内容:

1,主要函数的实现

2,常用函数

3.CString与char []的相互转换

4,将NULL字节放入CString中

vc中最主要函数不易理解。

CString::CString(char *p)

{

int n=strlen(p);

m_data = new char[n+1];

strcpy(m_data,p);

}

CString::CString(CString &other)

{

int n=strlen(other.m_data);

m_data = new char[n+1];

strcpy(m_data,other.m_data);

}

CString& CString::operator = (CString& other)

{

delete[] m_data;

int n=strlen(other.m_data);

m_data = new char[n+1];

strcpy(m_data,other.m_data);

return *this;

}

String::~String()

{

delete [] m_data;

}

Collate,Compare       与一个字符长指针所指的字符串进行比较,与strcmp相同,它们的区别是,分别调用_tcscoll,_tcsicmp。

Delete

int Delete( int nIndex, int nCount = 1 )

返回值是被删除前的字符串的长度,nIndex是第一个被删除的字符,nCount是一次删除几个字符。根据我实验得出的结果:当nCount>字符串的长度时会出错,当nCount过大,没有足够的字符删除时,此函数不执行。

FindOneOf

int FindOneOf( LPCTSTR lpszCharSet ) const;

此函数的功能是在查找lpszCharSet中的任意一个字符,查到一个就把位置返回,没有查到返回0。如:

CString str = "0123456789";

int x = str.FindOneOf("31");

x的值是1。

Find

int Find( TCHAR ch ) const;

int Find( LPCTSTR lpszSub ) const;

int Find( TCHAR ch, int nStart ) const;

int Find( LPCTSTR pstr, int nStart ) const;

返回值查找到的序号,ch待搜索的字符,lpszSub待搜索的字符子串,nStart 从那里开始搜索。如:

CString str = "0123456789";

int x = str.Find("34",4);

返回的值是-1.

GetAt

TCHAR GetAt( int nIndex ) const;

返回标号为nIndex的字符,你可以把字符串理解为一个数组,GetAt类似于[].注意nIndex的范围,如果不合适会有调试错误。

Insert

int Insert( int nIndex, TCHAR ch )
int Insert( int nIndex, LPCTSTR pstr )
返回修改后的长度,nIndex字符(或字符串)插入后的标号。

Left

CString Left( int nCount ) const;

返回的字符串的前nCount个字符。

Right与Left类似

MakeLower ,MakeUpper改变字符的大小写

MakeReverse字符倒置,如:

CString str = "X0123456789";

str.MakeReverse();

str变为"9876543210X"

+=

const CString& operator +=( const CString& string );
const CString& operator +=( TCHAR ch );
const CString& operator +=( LPCTSTR lpsz );

将参数合并到自己身上。

如:       CString str = "0123456789";

str+="ha";

str为"0123456789ha";

str[]

TCHAR operator []( int nIndex ) const;

象处理字符数组一样处理字符串。

注意是只读的。

CString str = "0123456789";

str[0]='x';

是错误的。

TrimLeft,TrimRight

void TrimLeft( );

void CString::TrimLeft( TCHAR chTarget );

void CString::TrimLeft( LPCTSTR lpszTargets );

void TrimRight( );

void CString::TrimRight( TCHAR chTarget );

void CString::TrimRight( LPCTSTR lpszTargets );

CString str = "/n/t a";

str.TrimLeft();

str为“a”;

如果没有参数,从左删除字符(/n/t空格等),至到遇到一个非此类字符.

当然你也可以指定删除那些字符.

如果指定的参数是字符串,那么遇上其中的一个字符就删除.

CString str = "abbcadbabcadb ";

str.TrimLeft("ab");

结果"cadbabcadb "

int CString::Remove( TCHAR ch );

ch删除的字符.

返回删除字符的个数,有多个时都会删除.

CString 与char []之间的转换.

char str[100] = ”str”;

CString sstr = “sstr”;

str.Format(“%s”,str);

str = LPCTSTR sstr;

strcpy(str,(LPCTSTR)sstr);

如果是赋值,则要:

CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在这里添加使用p的代码
if(p != NULL) *p = _T('/0');
s.ReleaseBuffer(); 
// 使用完后及时释放,以便能使用其它的CString成员函数

str的值变了.

将NULL字节放入CString中
1,CString str("abc/0""def", 7);
  str +="g";
  int nLength = str.GetLength();
  nLength为8.
2,CString str("My name is hedan!"); 
  str.SetAt(5, 0);
  int nLength = str.GetLength();
注意:不是所有的CString成员函数都可以,在使用时一定要小心。

实例:动态配置数据源
CString strDsn,strDBQ;
strDsn = "DSN=test";
strDBQ.Format("DBQ=%s",strSourceMDBName);
CString strConnect = strDsn + " " + strDBQ ;
strConnect.SetAt(strDsn.GetLength(),'/0'); 
SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, "Microsoft Access Driver (*.mdb)", strConnect);

vc入门宝典四(常用控件) 
常用控件

何志丹

主要内容:

1,  按钮

(1),位图按钮及动态按钮

(2),自画按钮

2,列表框

3,编辑控件和CRichEdit

4,CSliderCtrl

按钮的使用十分简单,拖一个到对话框,双击它就可以编辑代码了。利用程序向导生成一个基于对话框的程序Controls,拖一个按钮在对话框上,ID为IDC_OWNER,双击控件增加响应函数。为IDOK设置关联变量m_ok,将下列代码加到响应函数。m_ok.EnableWindow(false); 它的作用是使OK禁用。

将刚刚加的代码换成下面的,Ctrl+F5,点我们加的按钮就可以看到确定按钮变成了复选框,我们单击它,它还是执行以前的代码。

UINT Style = m_ok.GetButtonStyle();

Style |= BS_3STATE;

m_ok.SetButtonStyle(Style);

风格有:BS_AUTOCHECKBOX    BS_AUTORADIOBUTTON  BS_AUTO3STATE    BS_CHECKBOX    BS_DEFPUSHBUTTON  BS_GROUPBOX  BS_LEFTTEXT  BS_OWNERDRAW    BS_PUSHBUTTON    BS_RADIOBUTTON BS_3STATE

将刚刚加的代码换成下面的:

CWnd *pWnd = GetDlgItem(IDOK);

pWnd->EnableWindow(false);

它的效果是也是使确定按钮禁用,第一行的作用是根据ID找到CWnd指针,注意有些函数是CButton类特有的,那么我必须把pWnd强制转换成CButton类指针。

CButton常用的函数还有:

.GetFocus();获得拥有焦点的窗口,SetFocus();获得焦点。如果一个按钮拥有焦点,空格可以让它执行。

GetFont();SetFont();获得和设置字体。

位图按钮。

将确定的按钮的自画风格钩上,将确定按钮的标题改为OK,加四幅位图, “OKU”,”OKD”,”OKF”,”OKX”,分别对就按钮弹起来,被按下去,获得焦点,禁用情况,注意位图名有引号。

定义一个成员变量CBitmapButton bb,在OnInitDialog()加

bb.AutoLoad(IDOK,this);

有一个问题要注意,当点上自画时,默认按钮会被取消,所以你必须重新设定一个默认按钮。

将上面的一句改成:

bb.LoadBitmaps("OKU");//最多可以加载4幅,至少加载一幅。

bb.SubclassDlgItem(IDOK,this);//与控件建立关联。

bb.SizeToContent();//改变控件的大小来适应位图

自画按钮:

将取消按钮的自画钩上,Ctrl+w打开类向导,双击加CControlDlg的消息WM_DRAWITEM的响应函数。

void CControlsDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

{

if(IDCANCEL ==nIDCtl)

{

CDC *pDC = new CDC();

pDC->Attach(lpDrawItemStruct->hDC);

pDC->TextOut(10,10,"haha");

}

CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);

}

备用函数

CRect r;

GetClientRect(&r);

r存储了取消按钮的边界值。

列表框

建立一个基于对话框的程序Controls,加一个列表框,ID: IDC_LIST,设立一个控制类型的变量m_ctrl,再增加三个按钮,ID分别为:Append,Insert,Delete;

void CControlsDlg::OnAPPEND()

{

UpdateData();

if(m_input.IsEmpty()) return;

int i = m_ctrl.GetCount();

m_ctrl.SetCurSel(i-1);//选取最后一个;

m_ctrl.AddString(m_input);

}

void CControlsDlg::OnINSERT()

{

int i = m_ctrl.GetCurSel();

if(-1 == i)

MessageBox("请在列表框中选择一项,新加的项将在此项的后面","注意");

else

{

UpdateData();

m_ctrl.InsertString(i+1,m_input);

}

}

void CControlsDlg::OnREMOVE()

{

int i = m_ctrl.GetCurSel();

if(-1 != i)

m_ctrl.DeleteString(i);

}

常用函数:

ResetContent  清空。

int FindString( int nStartAfter, LPCTSTR lpszItem ) const;

从第nStartAfter开始查找lpszItem所指的字符串,如果没有找到返回-1,否则返回序号。

int SelectString( int nStartAfter, LPCTSTR lpszItem );

与FindString类似,找到后会反色显示被找到的字符串。

编辑控件:

生成一个基于对话框的程序Controls,加一个编辑控件,设置一个控制类型的关联变量m_ctrl.增加一按钮,双击加代码:

m_ctrl.SetSel(0,3);//选择前4个字符。

m_ctrl.Cut();//剪切

m_ctrl.Paste();//粘贴

m_ctrl.Paste();//粘贴

类似的函数还有Undo,Copy,ReplaceSel。

void MoveWindow( int x, int y, int nWidth, int nHeight, BOOL bRepaint = TRUE );

void MoveWindow( LPCRECT lpRect, BOOL bRepaint = TRUE );

移动窗口(如控件)。

最后一个参数是否重画,前面的参数表明四个角的位置,注意大小及比例可能改变。

建立一个基于对话框的应用程序Control,加一个CRichEdit Ctrl+F5,应该一点反应都没有。因为我们没有加:

BOOL CControlsApp::InitInstance()

{

AfxInitRichEdit();

这样就行了。

CSliderCtrl

生成一个基于对话框的应用程序Controls,加一个Slider控件,让它与一个整形变量m_value相关,再让它与一个控制类型的变量m_ctrl相关,增加此控件的NM_RELEASEDCAPTURE的响应函数,在那里加:

void CControlsDlg::OnReleasedcaptureSlider1(NMHDR* pNMHDR, LRESULT* pResult)

{

UpdateData(true);

CString str;

str.Format("%d",m_value);

MessageBox(str);

*pResult = 0;

}

再加上:

m_ctrl.SetRange(20,120);// 设置最小,最大值

m_ctrl.SetPageSize(30);//设置一次改变多少

m_ctrl.SetPos(30);//设置位置

vc入门宝典五(对话框) 
对话框

何志丹

主要内容:

1,  建立有模式对话框和无模式对话框

2,  控件的对齐及焦点设置

3,  实例

4,  通用对话框

5,  常用函数

对话框可按其动作模式分为“有模式”和“无模式”两大类。对于有模式对话框,在对话框被关闭之前,用户无法进行其它工作。而无模式的对话框,而它仍然保留在屏幕上的同时,用户可以在应用程序的其它窗口进行工作。

建立一个基于对话框的程序Dialog.

在资源管理器中插入一个对话框,Ctrl+w新建一个类COwnerDiaog;在IDD_DIALOG_DIALOG中加一个按钮,双击它编辑代码。

void CDialogDlg::OnButton1()

{

COwnerDialog dlg;

dlg.DoModal();

}

不要忘了#include "OwnerDialog.h"。你不关闭它,无法对主对话框下达命令,但你仍然可以打开其它程序。我们删除刚刚添加的代码。

void CDialogDlg::OnButton1()

{

COwnerDialog *pDlg=new COwnerDialog();

pDlg->Create(IDD_DIALOG1);

pDlg->ShowWindow(SW_RESTORE);

}

这是一个无模式对话框,你可以在处理子对话框之前,对主对话框下达命令。注意如果你关闭了主对话框,则子对话框也被关闭了。

在Layout中有四个功能是十分有用的,Tab Order(快捷键Ctrl+D):依次单击按钮决定它们的焦点顺序。

这样当用户,按Tab键切换焦点时,控件获得焦点的顺序就是我们设定好的。例如一个对话框要我们输入用户名,口今,再按确定。我们将它们的焦点顺序分别设为1,2,3,这样用户输入了用户名,再按Tab,输入口今,回车就可以了。

Layout  Align                            将选择的控件按某种方式对齐

Layout  Space evenly      平均分配选择的控件的间隔

Layout  Make same size    使选择的控件大小相同

我们来编一个简单程序,程序随机产生一个x,用户输入y=x*x,的值,程序检查对错,如果错了,还要改正。

生成一个基于对话框的应用程序,去掉”TODO: 在这里设置对话控制”,这个静态控件没什么用。加入两编辑控件(如果控件多的话最好改成一个容易理解的ID),Ctrl+W将两个控件

与两个整形变量m_x,m_y(命名要容易理解)相关联。加一个按钮,ID改为IDC_CHECK,双击它编辑代码。

void CCheckDlg::OnCheck()

{

UpdateData();

if(m_y == m_x * m_x)

MessageBox("你对了");

else

{

m_y = m_x * m_x;

UpdateData(false);

MessageBox("根据结果想想");

}

}

找到构造函数(最好在中OnInitDialog()处理),找到m_x = 0;改成

CTime t=CTime::GetCurrentTime();

int n=t.GetSecond();

for(int i=0;i<n;i++)

m_x = rand()%10;

其实rand并不随机,第一次调用返回值总是相同的,我们可以取当前时间的秒数,来决定调用次数。设置各个控件的Caption,并按上述方法设置焦点,并调整各控件的大小。

控件显示的值与控件相关联的数(成员变量)的值不是同步的,我们必须调用UpDateData();当我们输入了数据,就调用UpdateData(true)来更新成员变量;UpdateData(false)

将成员变量的值显示在屏幕上。CDialog的UpDateData()更新所有的控件,如果只想更新一个控件,可以调用控件类的UpDateData().

通用对话框,经常用的是CColorDialog,CFontDialog,CFileDialog,类似于

CColorDialog dlg;

if(IDOK==dlg.DoModal())

{

…dlg.GetColor();

}

注意CFileDialog dlg(false),表示是另存为对话框,为true表示是打开对话框,第一个参数没有默认值。

常用函数:

CDialog::CloseWindow();最小化对话框。

CDialog::DestroyWindow();关闭对话框,OnOk,OnCancel也可以关闭对话框。

CDialog::GetClientRect();获得客户区范围;

CDialog::GetFocus();      获得焦点;

CDialog::GetFont()      获得字体;

CDialog::SetWindowText);设置对话框标题;

CDialog::SetMenu();     设置菜单;

CDialog::SetFocus();     设置焦点;

CDialog::SetFont();      设置字体;

有些东西我们无法在构造函数中进行,如SetTimer,我们可以在OnInitDialog()中进行,或者在WM_SHOWWINDOW的响应函数中进行。

ShowWindow(SW_HIDE);它的参数还可以是:

SW_HIDE    SW_MINIMIZE    SW_RESTORE       SW_SHOWMAXIMIZED    SW_SHOWMINIMIZED    SW_SHOWMINNOACTIVE  SW_SHOWNA    SW_SHOWNOACTIVATE  SW_SHOWNORMAL

vc入门宝典六(多线程) 
多线程

何志丹

主要内容:

1,  工作者线程

2,  用户界面线程

3,  同步

线程被分为工作者线程和用户用户界面线程。用户界面的线程的特点是拥有单独的消息队列,可以具有自己的窗口界面,能够对用户输入和事件作出反应。

可以用以下方法建立一个工作者线程。

UINT MyThreadProc(LPVOID pParam)

{

}

AfxBeginThread(MyThread,..);

它有六个参数,第一个为控制函数,第二个为启动线程时传给控制函数的入口参数,当前线程的优先级,当前线程的栈的大小,当前线程的创建状态,安全属性,后四个有默认值。

用户界面线程:

首先利用应用程序向导建立单文档程序Thread,再建立Thread1 : public CWinThread,

Frame1 : public CFrameWnd,可以用Ctrl+w建立这两个新类。

在CThreadApp中加一个指针Thread1* pThread1,在BOOL CThreadApp::InitInstance()

中进行初始化:

pThread1 = new Thread1();

pThread1->CreateThread();

将Thread1的构造函数改成公有。

在Thread1中加一个指针Frame1* m_pWnd,然后初始化。

BOOL Thread1::InitInstance()

{

m_pWnd = new Frame1();

return TRUE;

}

把Frame1的构造函数改成公有,在Thread.h中包含#include "Frame1.h"。

在资源编辑器中编辑一个菜单IDR_MENU,它有一个菜单项ID_BEGIN。

Frame1::Frame1()

{

Create(NULL,"Demo");

ShowWindow(SW_SHOW);

UpdateWindow();

CMenu menu;//可以用局部变量,因为以后不会用到它了,加菜单。

menu.LoadMenu(IDR_MENU);

SetMenu(&menu);

}

同步

多线程的一个难点是各线程间的协调。同样的方法在CThreadApp中再开一个线程。

BOOL CThreadApp::InitInstance()

{

。。。。。。

pThread1 = new Thread1();

pThread1->CreateThread();

pThread2 = new Thread1();

pThread2->CreateThread();

。。。。。。

}

为IDR_MENU中的菜单在Frame1中设立响应函数,方法也是Ctrl+w打开类向导。并在Frame1中定义一个全局整形变量n,初始值为0.

HANDLE handle=CreateSemaphore(NULL,0,1,"he");

WaitForSingleObject(handle,10000);

CString str;

n++;

str.Format("第%d次工作",n);

MessageBox(str);

ReleaseSemaphore(handle,1,NULL);

当你点击Frame1的菜单时,会弹出一个对话框,暂时不要点 确定,点击另一个线程的菜单,暂不会弹出对话框,确定刚才的对话框,另一个线程的对话框也弹出来了。

这个同步的方法称为信号量。它允许有限的线程存取某个共享的系统资源,采用计数器来实现信号量。

HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES  lpa,LONG cSemInitial,LONG cSemMax,LPTSR  lpszSemName);

第一个参数来指明所创建的对象是否可以被其子进程继承。如果你希望在所有的子进程之间共享这个信号量,可以把它的成员bInheritHandle设为true,也可以直接设为NULL来使用默认的安全设置第二个参数是还可以让几个线程使用,第三个参数是最多可以让几个线程使用。

最后参数是信号量的名字,在其它的进程中调用CreateSemapphore()或OpenSemaphore()时使用这个字符串作为参数之一就可以得到信号量的句柄。

ReleaseSemaphore(HANDLE  hSemaphore, LONG cRelease,LPLONG plPrev)

第二个表示一次释放几,

vc入门宝典七(工具栏) 
工具栏

何志丹

主要内容:

1,  概要。

2,  常用函数

3,  实例。

4,  动态建立工具条

5,  在工具栏中嵌控件

6,  用对话框加位图按钮作工具条

我们可以在资源编辑器的ToolBar上单击右键,选择Insert ToolBar,选中一个工具栏后,在右边双击它的一项就可以编辑了。我们可以用图形工具条及颜色盒画它的外表,它的属性有ID,长,宽及鼠标指向它时的说明。

一般CToolBar定义在CMainFrame中,其实现在CMainFrame的OnCreate函数中完成。

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

}

m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_wndToolBar);

Bool Create(CWnd *pParentWnd,

DWORD dwStu;e =  WS_CHILD | WS_VISIBLE |CBRS_TOP,

UINT      nID = AFX_IDW_TOOLBAR);

pParentWnd指定所属窗口。

dwStyle 指定工具栏风格

CBRS_TOP                                        允许工具栏位于框架窗口顶端。

CBRS_BOTTOM                                允许工具栏位于框架窗口底端

CBRS_NOALIGN                                父窗口改变尺寸后工具栏位置不变

CBRS_TOOLTIPS                              工具栏显示提示条

CBRS_SIZE_DYNAMIC               工具幸是动态的

CBRS_SIZE_FIXED                            工具栏是固定的

CBRS_FLOATING                         工具栏是浮动的

CBRS_FLYBY                               当鼠标从命令按钮上掠过时显示提示信息

CBRS_HIDE_INPLACE                 工具栏对用户不可见

SetButtonStyle()函数用来设定命令按钮的风格或间隔区,或设为一组,按钮的风格决定了按钮的外貌和对用户的反应方式.

Void SetButtonStyle(int nIndex,UINT nStyle);

nIndex       指定工具栏中按钮或间隔的索引号.

nStyle       TBBS_BUTTON                                   标准按钮,此为默认值

TBBS_SEPARATOR                      间隔区

TBBS_CHECKBOX                        自动确认区

TBBS_GROUP                                   标记为一组按钮的开始

TBBS_CHECKGROUP                          标记为一组确认框的开始

ControlBar类的EnableDocking函数和CFrameWnd类的DockControlBar函数配合,设定工具栏的可活动性.

Void        EanbleDocking(DWORD       dwStyle)

CBRS_ALIGN_TOP                             允许工具栏位于客户区上侧

CBRS_ALIGN_BOTTOM                            允许工具栏位于客房区下侧

CBRS_ALIGN_LEFT                                  允许工具栏位于客户区左侧

CBRS_ALIGN_RIGHT                                允许工具栏位于客户区右侧

CBRS_ALIGN_ANY                                   允许工具栏位于客户区的任意位置

CBRS_FLOAT_MULTI                                 允许多个控制栏在一个迷你框架窗口中浮动

Void DockControlBar(….)

pBar       要浮动的控制栏指针.

nDockBarID指定允许浮动的位置,或为0则不允许浮动,可以由下列值组合而成:

AFX_IDW_DOCKBAR_TOP                               控制栏置于框架窗口上侧;

AFX_IDW_DOCKBAR_BOTTOM                         控制栏置于框架窗口下侧

AFX_IDW_DOCKBAR_LEFT                               控制栏置于框架窗口左侧

AFX_IDW_DOCKBAR_RIGHT                                   控制栏置于框架窗口右侧

改变工具栏的命令按钮风格,工具栏的按钮一般默认为命令按钮,当放开标鼠标,命令按钮就”弹出来”,如果我们希望命令按钮能留在被按上的状态,就可以把命令按钮的风格设为确认框。在ON_UPDATE_COMMAND_UI消息处理函数中,使用SetCheck()成员函数和SetRadio()成员函数改变按钮状态。

SetCheck()的参数0表示删除状态,1表示确认状态,2表示不确认状态

SetRadio()的参数0表示删除状态,非0表示确认状态。

我们用应用程序向导建立一个单文档程序,在工具栏中添加按钮,ID设定为ID_TIME.在CMainFrame类添加一个布尔数据类型m_bTime,初始值为false.

Ctrl+w添加ID_TIME的ON_COMMANDT和ON_UPDATE_COMMAND_U消息响应函数。

void CMainFrame::OnShowTime()

{

m_bTime = ! m_bTime;

}

void CMainFrame::OnUpdateShowTime(CCmdUI * pCmdUI)

{

pCmdUI ->SetCheck(m_bTime);

}

注意如果有一个同ID的菜单,它会自动根据按钮的情况打上钩钩。

事实上我们可以不用toolbar资源建立一个工具条。代码如下:

UINT nID[]=

{ID_FILE_NEW,

ID_FILE_OPEN,

ID_TIME

};

m_wndToolBar.Create(this);

m_wndToolBar.LoadBitmap(IDB_BITMAP1);

m_wndToolBar.SetButtons(nID,sizeof(nID)/sizeof(UINT));

其中位图的大小要合适,否则会影响美观,最后一行让几个ID与工具栏的按钮和相关。

如果想设置每个按钮的风格,可以将最后一行后面加:

m_wndToolBar.SetButtonStyle(1,TBBS_SEPARATOR);

也可m_wndToolBar.Create(this);

m_wndToolBar.LoadBitmap(IDB_BITMAP1);

m_wndToolBar.SetButtons(NULL,3);

m_wndToolBar.SetButtonInfo(0,ID_FILE_NEW,TBBS_BUTTON,0);

m_wndToolBar.SetButtonInfo(1,ID_FILE_OPEN,TBBS_BUTTON,2);

在工具栏中嵌入控件,如编辑框

1,  定义一个编辑控件对象,不能是局部变量,否则会被释放掉。

2,  调用Create,唯一要注意的是位置要在工具条的地盘上。

CRect rect;

m_wndToolBar.GetItemRect(1,&rect);

edit.Create(WS_CHILD|WS_VISIBLE,rect,&m_wndToolBar,ID_EDIT);

用对话框加位图按钮作工具栏。

插入一个对话框,Styles的style设为child,border设为none.

在CMainFrame中m_wndToolBar的改成CDialogBar,并加一个CBitmapButton bb;

把建立工具条的那一句改为:

m_wndToolBar.Create(this,IDD_DIALOG1,WS_CHILD|WS_VISIBLE|CBRS_TOP,AFX_IDW_STATUS_BAR);

最后一上ID 同自己随便确定。Ctrl+F5,一个极不美观的工具条就出来了。

对按钮进行整理,它们的处理函数仍然上Ctrl+w加。将按钮Styles的Owner drawer和bitmap钩上。在刚才的地方加一句。

bb.AutoLoad(IDC_BUTTON1,&m_wndToolBar);

注意你需要加三幅位图(一幅也可以)。如你的按钮的名字为X,刚三幅位图的名字分别为”XUP”,”XDOWN”,”XFOCUS”,简写为”XU”,”XD”,”XF”.

vc入门宝典八(基本操作) 
    基本操作

何志丹

主要内容:

Workspace(ClassView,ResoreceView,FileView)

菜单

App Wizard(应用程序向导)

Class Wizard(类向导)

标准控件

常用调试方法

VC的窗口分为三部分,正文窗口(右上角),工作窗口(左侧),输出窗口(下侧)。

工作窗口有三个标签,ClassView,ResoreceView,FileView;单击“+”,“—”打开文件夹;对没有打开的文件夹或文件,双击打开;对于打开的文件夹双击关闭。在ClassView中双击类名,

正文窗口显示类定义,双击类的成员变量查看定义,双击函数进入函数实现。对函数名右键,

有两个功能比较有实用价值:calls,called by.对类名进行右键,有两个功能十分有价值:

增加成员变量,增加成员函数。

常见菜单:

Edit->Advanced/Format Selection  Alt+F8           对选中对象进行缩排

Edit->Advanced/Make Selection Uppercase Ctrl+Shift+U  把选中部分改成大写

Edit->Advanced/Make Selection Lowercase Ctrl+U            把选中部分改成小写

Edit最后的三个菜单没有多大实用价值,因为如果要查看一个类的成员,可以用ClassName::的形式看,自动会列出成员,你只需打个开头再空格(或其它非标识符字符)就可以了,自动会匹配第一个符合条件的成员。当你打完函数名,再打正括号时,就会显示有关信息,包括在函数定义同一行的注释。

View->ClassWizard   Ctrl+w               编辑应用程序中的类

View->DebugWindow  Ctrl+F10,运行到光标处,它的子项就可以使用了。

Debug菜单基本上都会使用,Set Active Configuration,设置Debug方式或Release方式。

#ifdef _DEBUG

#endif

这个宏定义之间的语句,在Release方式下不会被执行。

Tool->Customize->Toolbars定义工具条

AppWizard有几步,只有第一,第二,最后一步比较重要。

第一步选择:MFC A ppWizard(exe);

第二步:Single document单文档

Multiple document多文档

Dialog basede  基于对话框

最后一步(基于对话框没有):

Base Class:

选择视图类的基类,各基类差别比较明显,大家试一下就行了。应用程序向导会自动生成应用程序类,文档模块类,框架类,文档类,视图类。简单程序绝大部分处理都在视图类。当数据较复杂时,会用到文档类。

Ctrl+W打开ClassWizard

该对话框包含以下选项卡。

1,  Message Maps选项卡:管理消息和成员函数之间的连接。

2,  Member Variables选项卡:使用户加入或删除成员变量(与控件关联的)。

3,  Automation选项卡:提供各种特性来支持Automation,使用户方便地增删Automation的属性和方法。

4,  Active Events选项卡:提供各种特性来支持ActiveX,使用户方便地增删属性和响应函数。

5,  Class Info选项卡:显示类的信息,允许用户创建新类,以便支持对话框和有格式的视图。

Message Maps

1 Projcect 工程,一般不必修改,因为一般只有一个。

2,Class name  类名

3,Object IDs列出了当前所选中对象的ID号,包括能产生消息的菜单项,对话框控件等。

4,message列出了Object IDs框中所选中的当前项可处理的消息及可以被重写的MFC函数。双击消息相当于AddFunction.

5,Member functions列表框列出了Class name框当前类包含的所有成员函数。标注V的是虚函数,标注W的是Windows消息。

Member Variables选项卡:

双击ID,弹出增加成员变量对话框:

Category有两种选择,值,控制,每个控件可以和一个值类型数据相关联,同时还可以和一个控制类型数据相关联。

当你编辑一个对话框时,会多一个工具条,上面有许多标准控件。如果你不小心把它关掉了,在标准工具条附近的空白处右键,如菜单右边,将Controls勾上。将一个控件加到对话框有两种方法:

1,  直接拖到对话框上。

2,  单击一个控件,然后在对话框上画。

调试的最常用的三种方法,假如我们怀疑一个整形变量x有问题的话,可以:

1,  CString str;

str.Format(“%d”,x);//和printf非常相似

MessageBox(str);

优点:点确定后程序才会继续运行。

缺点:如果次数太多,过于浪费时间和键盘。

2,Ctrl+F10运行到光标处,在Watch窗口中name项输入x,,后面会显示值。

优点:简单,可以查看所有的值。

缺点:无法看到第二次运行到此处的情况。

3,  #ifdef _DEBUG

afxDump<<x;

#endif

将结果显示在OutPut,不能在Release状态下。Ctrl+F5似乎无效,F5可以。

afxDump.SetDepth(1);
设置深度,如maps,arrays,它只打出有几个可元素,我们用上面的这个函数,它会将所有的内容打出来.
#ifdef _DEBUG
 char test[] = "0123456789/n";
 afxDump.HexDump( "--", (BYTE*) test, 11, 6 );
#endif
结果为:
-- 30 31 32 33 34 35
-- 36 37 38 39 0A
第一个参数,行首的打头字符.
第二个参数,要打的内容.
第三个参数,要打的元素个数.
第四个参数,每行的个数.

4,TRACE(...), TRACE0, TRACE1, TRACE2, TRACE3 也只能在调试时用注意打字符串时有长度限制,包括结束符在内,不超过512个字符.

5.在Debug状态下
F9设置断点后,F5到下一个断点,F10下一行,F11进入函数(包括系统函数)内部,Shift + F11出来.
F5后,Debug菜单有相应的菜单项.
F5后,View->Debug Window的子菜单项比较有用.
Watch    查看你指定的变量
variables 显示auot变量,local变量,this的值
memory   显示指定内存地址存储的值
call stack 显示函数调用关系
registers 寄存器的值
Disabblemble    汇编代码

其实Release下也可调试F5
Alt + f7 工程设置
c/c++  Generate Browse info 选上.
       Debug info 选 Progame database for edit and continue
Link   Generate debug info 选上
       Link incrementally 选上

vc入门宝典(九)

集合类使用心得

何志丹

MFC提供集合类(Collect)专门负责数据对象的存储和管理,MFC的集合类分为三类,分别用于处理三类不同性质的数据结构:表(List,类似于数据结构的双链表),数组(Array)和映射(Map,具有类似字典的功能).

一,数组使用心得

原型: template< class TYPE, class ARG_TYPE > class CArray : public Cobject

简单地说是你输入的时候用ARG_TYPE类,输出的时候用TYPE,自动实现转换.

具体实现可以看c:/program files/microsoft visual studio/vc98/mfc/include/afxtempl.h.

如:

#include "afxtempl.h"//那个类需要那些头文件可以查看msdn,在类总括的最后

CArray<int,  char>   Vars;

Vars.SetSize(3,1);

Vars.SetAt(0,'a');

int x= Vars.GetAt(0);

这种性质对于自定义类更有效,因为我可以通过重载”=”,来控制改化过程.

设置断点,我们会发现这个类有三个类成员:m_nSize,m_nMaxSize,m_nGrowBy,分别对应元素个数,已经开辟的空间,空间不足时,每次开辟的多少个元素的空间.

常见函数:

int GetSize( ) const得到m_nSize的值.

int GetUpperBound( ) const;数组的上界,m_nSize-1.

void SetSize( int nNewSize, int nGrowBy = -1 );三个类成员都会变,以前加的内容不一定丢失.

void FreeExtra( );整理多余的空间,使m_nMaxSize = m_nSize.

void RemoveAll( );删除全部元素.

TYPE GetAt( int nIndex ) const;得到第nIndex(从0开始)元素的值.

void SetAt( int nIndex, ARG_TYPE newElement ); nIndex不能越界.

const TYPE* GetData( ) const;将数据指针返回.

void SetAtGrow( int nIndex, ARG_TYPE newElement );和SetAt类似,如果过大,会开辟新空间.

int Add( ARG_TYPE newElement );加一个元素,m_nSize加一.

int Append( const CArray& src );//加上一个同类型的数组.

void InsertAt( int nIndex, ARG_TYPE newElement, int nCount = 1 );
void InsertAt( int nStartIndex, CArray* pNewArray );

TYPE& operator []( int nIndex );以c风格操作数组.

TYPE operator []( int nIndex ) const;

其它数组有:

CByteArray     支持字节数组.

CWordArray      支持字数组.

CDWordArray     支持双字节数组.

CObArray      支持COject类型指针数组.

CPtrArray       支持Void类型指针数组.

CUIntArray      支持无符号整形数组.

CStringArray    支持CString数组.

用法与上面基本一致.

二,  表使用心得

我以CStringList为例,谈一下使用表的心得.注意:查看MSDN,实际上看的是CObList,注意相应的类型改成CString类,当然还有一些小差别,具体看vc的提示,最好安装vc_assist6.下面这个例子几乎用到这个类所有的函数.

CStringList var(15);

POSITION position;

position =         var.InsertAfter(NULL,"item1");

position =  var.InsertAfter(position,"item3");

position =  var.InsertBefore(position,"item2");

for( position = var.GetHeadPosition(); NULL != position ; )

AfxMessageBox(var.GetNext(position));

for( position = var.GetTailPosition(); NULL != position ;var.GetPrev(position))

{

CString str;

str = var.GetAt(position);

if("item3"==str)

{

var.RemoveAt(position);

}

else

{

str.MakeUpper();

var.SetAt(position,str);

}

}

var.RemoveHead();

var.RemoveTail();

var.RemoveAll();

var.AddHead("he");

var.AddTail("dan");

position = var.Find("he");

var.SetAt(position,"He");

position = var.FindIndex(1);

var.SetAt(position,"Dan");

//end

下面是该类函数的简介.

POSITION InsertBefore( POSITION position, CObject* newElement );

POSITION InsertAfter( POSITION position, CObject* newElement );

在一个位置前或后插入一个新元素.

POSITION GetHeadPosition( ) const;

POSITION GetTailPosition( ) const;

获得头位置和尾位置.

CObject*& GetNext( POSITION& rPosition );

CObject* GetNext( POSITION& rPosition ) const;

CObject*& GetPrev( POSITION& rPosition );

CObject* GetPrev( POSITION& rPosition ) const;

获得后一元素或前一元素,注意rPosition会变.

CObject*& GetAt( POSITION position );

CObject* GetAt( POSITION position ) const;

根据位置得到元素.

void SetAt( POSITION pos, CObject* newElement );

根据位置设置元素.

void RemoveAt( POSITION position );

根据位置删除元素.

CObject* RemoveHead( );删除并返回头元素

CObject* RemoveTail( ); 删除并返回尾元素

POSITION AddHead( CObject* newElement );增加头元素
void AddHead( CObList* pNewList );在前面加一个表
POSITION AddTail( CObject* newElement );增加尾元素
void AddTail( CObList* pNewList );在后面加一个表
POSITION Find( CObject* searchValue, POSITION startAfter = NULL ) const根据元素值找位置.
POSITION FindIndex( int nIndex ) const根据索引找位置.

vc入门宝典(十) 
消息

何志丹

PreTranslateMessage函数顾名思义,就是在消息被翻译之前,做的一些事.我们可以屏蔽一个键或一个命令.
下面是一些常用消息的相关信息.这些信息放pMsg中.
WM_KEYDOWN 
nVirtKey = (int) wParam;  /*虚键值,和ascll码有许多相同的地方 */ 
lKeyData = lParam;        /*和硬件有关 */    
WM_CHAR 
chCharCode = (TCHAR) wParam;    
lKeyData = lParam;              
WM_COMMAND 
wNotifyCode = HIWORD(wParam); 
wID = LOWORD(wParam);         
hwndCtl = (HWND) lParam;      
WM_LBUTTONDOWN 
fwKeys = wParam;        // 
xPos = LOWORD(lParam);  //  鼠标横坐标
yPos = HIWORD(lParam);  //  鼠标纵坐标
 fwKeys 
MK_CONTROL MK_LBUTTON MK_MBUTTON MK_RBUTTON  MK_SHIFT 
WM_MOUSEMOVE 
fwKeys = wParam;        
xPos = LOWORD(lParam);   
yPos = HIWORD(lParam);  
 
下面这个例子演示了,PreTranslateMessage的常用用法.
BOOL CPreTranslateDlg::PreTranslateMessage(MSG* pMsg) 
{
 if(WM_KEYDOWN == pMsg->message )
  if(0x30 == (int) pMsg->wParam)
  {
   return true;               /*禁止在编辑框中输入0(ascll 0x30)*/
  }

if(WM_CHAR == pMsg->message )
  if('A' == (TCHAR) pMsg->wParam)
  {
   return true;               /*禁止在编辑框中输入'A'*/
  }
  
 if(WM_MOUSEMOVE == pMsg->message)  
  if(MK_CONTROL & pMsg->wParam)  /*当ctrl被按下鼠标移动时,显示相关信息*/
  {
   int xPos = LOWORD(pMsg->lParam);  
   int yPos = HIWORD(pMsg->lParam); 
   CString str ;
   str.Format("鼠标的坐标%d %d",xPos,yPos);
   AfxMessageBox(str);
  }

if(WM_COMMAND == pMsg->message)
  if(ID_1 == LOWORD(pMsg->wParam))//禁止菜单项ID_1,注意按钮发送的是BN_CLICKED
  {
   return true;
  }
 return CDialog::PreTranslateMessage(pMsg);
}

VC入门宝典十一(xml) 
                                         xml

何志丹

我们建立一个xml文件,内容如图所示:

一,建立一个基于对话框的程序,工程名为xml;

二, 初始化OLE.

BOOL CXmlApp::InitInstance()

{

AfxOleInit();

…….

}

三, 在对话框中增加一个按钮,ID为IDC_CREATE,我们在这个按钮的响应函数中生成一个xml文件.

void CXmlDlg::OnCreate()

{

MSXML2::IXMLDOMDocumentPtr pDoc;

MSXML2::IXMLDOMElementPtr  xmlRoot ;

//创建DOMDocument对象

HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));

if(!SUCCEEDED(hr))

{

MessageBox("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");

}

//根节点的名称为china

pDoc->raw_createElement((_bstr_t)(char*)"china", &xmlRoot);

pDoc->raw_appendChild(xmlRoot, NULL);

MSXML2::IXMLDOMElementPtr  childNode ;

pDoc->raw_createElement((_bstr_t)(char*)"City", &childNode);

childNode->Puttext("WuHan");//节点值

childNode->setAttribute("population","8,000,000");//属性名,属性值

childNode->setAttribute("area","10000");

xmlRoot->appendChild(childNode);

pDoc->raw_createElement((_bstr_t)(char*)"City", &childNode);

childNode->Puttext("ShangHai");

childNode->setAttribute("population","12,000,000");

childNode->setAttribute("area","12000");

xmlRoot->appendChild(childNode);

//保存到文件

//如果不存在就建立,存在就覆盖

pDoc->save("f://he.xml");

}

不要忘了#import "msxml4.dll" //引入类型库

四, 再增加一个按钮,ID为IDC_GET,在这个按钮的响应函数中读取xml文件.

void CXmlDlg::OnGet()

{

//创建DOMDocument对象

MSXML2::IXMLDOMDocumentPtr pDoc;

HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));

if(!SUCCEEDED(hr))

{

MessageBox("无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!");

}

//加载文件

pDoc->load("f://he.xml");

//在树中查找名为City的节点,"//"表示在任意一层查找

MSXML2::IXMLDOMElementPtr  childNode ;

childNode = (MSXML2::IXMLDOMElementPtr)(pDoc->selectSingleNode("//City"));

//得到节点类型

MSXML2::DOMNodeType nodeType;

childNode->get_nodeType(&nodeType);

//节点名称

BSTR var;

CString name;

childNode->get_nodeName(&var);

name = (char*)(_bstr_t)var;

//节点值

VARIANT varVal;

childNode->get_nodeTypedValue(&varVal);

CString strValue = (char*)(_bstr_t)varVal;

//节点属性,放在链表中

MSXML2::IXMLDOMNamedNodeMapPtr pAttrs = NULL;

MSXML2::IXMLDOMNodePtr pAttrItem;

childNode->get_attributes(&pAttrs);

long nCount ;

pAttrs->get_length(&nCount);

for(int i = 0 ; i < nCount ; i++)

{

pAttrs->get_item(i,&pAttrItem);

//我们可以通过函数get_nodeName,get_nodeTypedValue得到属性名和属性值

//也可以直接得到

CString strAttrName   = (char*)(_bstr_t)pAttrItem->nodeName;

CString strAttrValue  = (char*)(_bstr_t)pAttrItem->nodeTypedValue;

}

}

vc入门宝典十二(调用其它程序) 
                                       调用其它程序

何志丹

WinExec
原型:
UINT WinExec(
  LPCSTR lpCmdLine,  // address of command line
  UINT uCmdShow      // window style for new application
);
用于十六位操作系统及兼容系统.
例如:
WinExec("notepad.exe f://调用程序.txt",SW_SHOW);
WinExec("notepad.exe ",SW_SHOW);
不同的参数用空格分开,故路径中不能有空格,而大部分程序默认是安装在".../Program Files/...",如word,这极大的限制了WinExec的应用范围.
以上可不带路径:
1,程序所在目录.
2,当前路径.
3,系统目录,可以用GetSystemDirectory得到.
4,Windows 目录. 可以用TheGetWindowsDirectory得到.  
5,在环境变量中设置的目录.

ShellExecute
原型:
HINSTANCE ShellExecute(
    HWND hwnd,                   //父窗口句柄
    LPCTSTR lpOperation,         //操作,"open","print","explore"
    LPCTSTR lpFile,              //文件名,前面可加路径
    LPCTSTR lpParameters,        //参数
    LPCTSTR lpDirectory,         //默认文件夹
    INT nShowCmd                 //显示方式
);

打开一个应用程序
ShellExecute(this->m_hWnd,"open","calc.exe","","", SW_SHOW );

ShellExecute(this->m_hWnd,"open","notepad.exe","c:/MyLog.log","",SW_SHOW );

打开一个同系统程序相关连的文档
ShellExecute(this->m_hWnd,"open","c:/abc.txt","","",SW_SHOW );

激活相关程序,发送EMAIL
ShellExecute(this->m_hWnd,"open","mailto:nishinapp@yahoo.com","","", SW_SHOW );

用系统打印机打印文档
ShellExecute(this->m_hWnd,"print","c:/abc.txt","","", SW_HIDE);

lpParameters的用法示例:
一,建立一个可以接受参数的程序call.exe,添加如下代码:
BOOL CCallApp::InitInstance()
{
 int n = __argc;
 for(int i = 1 ; i < n ; i++)
  AfxMessageBox(__targv[i]);
       //__targv[0]存储的是程序的文件名
...
}
二,Alt + F7的进行Project setting, Debug -> program argurments ->"1 2 3 4 5".
如果有多个参数,用空格分开.
三,运行.
四,执行ShellExecute(NULL,NULL,"f://call.exe","1 2 3 4 5",NULL,SW_SHOW);

BOOL CreateProcess(
  LPCTSTR lpApplicationName,
                         
  LPTSTR lpCommandLine,  
  LPSECURITY_ATTRIBUTES lpProcessAttributes,  
  LPSECURITY_ATTRIBUTES lpThreadAttributes,   
  BOOL bInheritHandles,  
  DWORD dwCreationFlags, 
  LPVOID lpEnvironment,  
  LPCTSTR lpCurrentDirectory,   
  LPSTARTUPINFO lpStartupInfo,  
  LPPROCESS_INFORMATION lpProcessInformation  
);

STARTUPINFO   startupInfo;
memset(&startupInfo,0,sizeof(STARTUPINFO));
startupInfo.cb = sizeof(STARTUPINFO);

示例:
//程序最启动时最大化 
startupInfo.dwFlags |= STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_SHOWMAXIMIZED;
 
//运行....exe
 PROCESS_INFORMATION ProcessInfo;
  BOOL bCreate = ::CreateProcess
        (
        "f://call.exe",// 1 2 3 4",
  NULL,
  NULL,
        NULL,
        FALSE,
        0,
        NULL,
        NULL,
        &startupInfo,
        &ProcessInfo);

//等到call.exe执行完毕
WaitForSingleObject(ProcessInfo.hProcess,1000000);
MessageBox("调用程序结束!");

控件 
控件

何志丹
1,File=>New=>Project=>MFC ActiveX ControlWizard创建一个名为Owner的工程,所有的设置都默认,直接Finish就可以了。
4,Ctrl+F5运行。Executable For Debug Session,选取消就可以了。
5,Tool=>ActiveX Control Test Container中进行测试。
6,注册,将控件的ocx文件拷到Windows系统目录下,如:win95/system.开始菜单,运行Regsvr32 Owner.ocx.
   Regsvr32 [/u][/s][/c][/i[:cmdline]] dllname
  其中:
  /u 注销动态库
  /s 不显示提示信息
  /c 输出控制台
  /i  调用Dllinstall并传递cmdline,与/u一起使用时调用注销程序
  /n 不调用DllRegisterSever,必须与/i一起使用。
7,创建一个基于对话框的可执行程序OwnerExe,注意AppWizard-Step 2 of 6将ActiveX controls复选框选中。
  应用程序向导会为我们添加
BOOL COwnerExeApp::InitInstance()
{
 AfxEnableControlContainer();
       ......
8,Project=>Add To Project- Components.找到刚才注册的控件,插入到控制工具栏中。像使用标准控件一样将它弄到对话框上。
9,Ctrl+F5,我们就可以看到一个什么都不干的控件。
下面我们来做一个检查一个数是不是2的几次幂(如1,2,4,8)的控件,我们来补充第二步和第三步。
2,在COwnerCtrl增加一个布尔变量Is2n,初值为false;将OnDraw改成:
void COwnerCtrl::OnDraw(
   CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 CBrush * pBrush;
 if(Is2n)
  pBrush = new CBrush(RGB(255,0,0));
     else
  pBrush = new CBrush(RGB(255,255,255));
 pdc->FillRect(rcBounds, pBrush);
 delete pBrush;
}
Ctrl+w打开类向导,Automation=>Add Method. name填IsPow2n,返回值void,一个长整形的参数x.注意有多个参数时,用向下光标键或PageDown移动。
修改此函数:void COwnerCtrl::IsPow2n(long x) 
{
 Is2n = ((x&-x)==x);
 InvalidateControl();
}
Ctrl+F5生成新的ocx,覆盖原来的ocx.注意当Windows系统目录下的ocx被修改以后,我们的程序中的oxc会自动更新控件。并不是控件所有的函
数都可以被控件使用者调用,只有方法才可以。
回到OwnerExe,加一个编辑控件(与一个长整形变量m_input相关联)和一个按钮,让控件与m_ctrl相关联,此按钮的响应函数为:
void COwnerExeDlg::OnIs2n() 
{
 UpdateData();
 m_ctrl.IsPow2n(m_input);
}
Ctrl+F5,查看效果,仔细一点就会发现当输入零时,结果是错的。显然0不可能是2的n次方。
3,我们为控件定义一个事件,事件很像自定义的消息,你必须决定它何时被调用,并用在调用时,必须设置好初值。
再回到我们的控件,ctrl+w=>ActiveX Events=>Add Events.名字Zero,参数为x,长整形。
将if(0 == x)FireZero(x);插到void COwnerCtrl::IsPow2n(long x)中,表示在IsPow2n执行过程过发现IsPow2n的参数为0,此方法被调用。且它的参数与IsPow2n相同。
void COwnerCtrl::IsPow2n(long x) 
{
 Is2n = ((x&-x)==x);
 if(0 == x)
 {
  FireZero(x);
  Is2n = false;
 }
 InvalidateControl();
}

回到OwnerExe,Ctrl+w=>MessageMaps. ID填我们的控件,在Messages中双击我们刚刚加的Zero,编辑函数:
void COwnerExeDlg::OnZeroOwnerctrl1(long x) 
{
 CString str;
 str.Format("请输入一个非%ld整数",x);
 AfxMessageBox(str);
}
Ctrl+F5。
3.5大家可能觉得颜色设置得太差,我们可以增加控件的属性。
回到我们的控件,Ctrl+w=>Automation=>Add Property;在External name中选择库存属性。
我们来自定义两个属性是2的n次方时的颜色和不是时的颜色,isColor,notColor;类型是OLE_COLOR;编辑代码。
void COwnerCtrl::OnIsColorChanged() 
{
 InvalidateControl();
 SetModifiedFlag();
}

void COwnerCtrl::OnNotColorChanged() 
{
 InvalidateControl();
 SetModifiedFlag();
}
void COwnerCtrl::OnDraw(
   CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
 CBrush * pBrush;
 if(Is2n)
  pBrush = new CBrush(m_isColor);
    else
  pBrush = new CBrush(m_notColor);
 pdc->FillRect(rcBounds, pBrush);
 delete pBrush;
}
void COwnerCtrl::DoPropExchange(CPropExchange* pPX)
{
 ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
 COleControl::DoPropExchange(pPX);
 PX_Color(pPX,"isColor",m_isColor,RGB(0,255,255));
 PX_Color(pPX,"notColor",m_notColor,RGB(0,255,0));
}
后两行不只是赋初值,同时还使得控件使用者可以用颜色对话框选择颜色。

转载请注明本文地址: VC入门宝典 by 何志丹

VC入门宝典 by 何志丹相关推荐

  1. python魔力手册-小白入门宝典:Python快速入门魔力手册 PDF 超清版

    给大家带来的一篇关于Python编程相关的电子书资源,介绍了关于小白入门.python入门.Python手册方面的内容,本书是由魔力手册出版,格式为PDF,资源大小11.8 MB,魔力手册编写,目前豆 ...

  2. 统计学习方法 pdf_机器学习的入门宝典!《统计学习方法》的代码实现

    李航:毕业于日本京都大学电气电子工程系,日本东京大学获得计算机科学博士学位.1990年至2001年就职于日本NEC 公司中央研究所,任研究员,2001年至2012年就职于微软亚洲研究院,任高级研究员与 ...

  3. Tungsten Fabric入门宝典丨8个典型故障及排查Tips

    Tungsten Fabric入门宝典系列文章,来自技术大牛倾囊相授的实践经验,由TF中文社区为您编译呈现,旨在帮助新手深入理解TF的运行.安装.集成.调试等全流程.如果您有相关经验或疑问,欢迎与我们 ...

  4. 嵌入式Linux系统开发入门宝典(第2版)

    距离<嵌入式Linux系统开发入门宝典>第1版已经有6年了,由于是第一次写作,对章节的划分,语言的组织,知识点的推敲,以及本人习惯用五笔输入法打字,有很多地方出现一些诡异的文字.另外,既然 ...

  5. 深度学习试题_初学者入门宝典-机器学习入门资料汇总及学习建议(2018版)

    机器学习初学者公众号自从2018年10月开设以来,发表了不少机器学习入门的宝贵资料,受到广大机器学习爱好者的好评,本文对2018年本站发过的文章进行分类和汇总,以便初学者更好地学习. 机器学习入门,初 ...

  6. 数据治理之元数据管理的利器——Atlas入门宝典

    随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程.作为Hadoop生态最紧密的元数据管理与发现工具,Atlas在其中扮演着重要的位置.但是其官方文档不是很丰富,也不够详细.所以整 ...

  7. 科研入门宝典(一):如何确定科研方向并合理展开工作

    文章目录 前言 你为啥要搞科研? 1 研究方向的确定 1.1 选题难在哪儿,我该怎么规划? 1.2 怎么确定研究方向? 1.选择成熟的.开源项目多的方向,草草跑跑混个毕业. 2.选择领域的热点问题,跟 ...

  8. 科研入门宝典(二):文献调研工作如何展开

    文章目录 前言 1 论文查找与甄别 1.1 检索词 1.2 文章年限 1.3 引用次数 1.4 高水平期刊 以机器人领域为例,顶级期刊与会议包括 2 怎么阅读文献 3 怎么总结归纳文献 3.1 文献调 ...

  9. 新手入门宝典:从零开始做微信小程序开发

    微信小程序联盟出品.jpg 开发前必读简要 基于大量无效开发,无法上线的案例,所以开发前部分知识十分重要:| 链接 微信小程序个人注册简单步骤 打开mp.weixin.qq.com,点击右上角立即注册 ...

最新文章

  1. java编写限制密码_java – 用户’root’@’localhost’拒绝访问(使用密码:YES)
  2. 【剑指offer-Java版】04替换空格
  3. JavaScript实现cartesianProduct笛卡尔乘积算法(附完整源码)
  4. 易飞扬宣布完成100G CWDM4PSM4光模块量产线建设
  5. spring aop 中@annotation()和自定义注解的使用
  6. Spring【DAO模块】就是这么简单
  7. Starting MySQL. ERROR! The server quit without updating PID file
  8. Sublime Text插件
  9. lisp型材库_基于Visual Lisp的面向对象零件库的开发
  10. 一米村长讲故事机器人_主持人李锐推出“村长讲故事”APP,已入驻喜马拉雅
  11. iOS 百思不得姐 项目
  12. 新一代“四型机场”,青岛胶东国际机场正式实施转场运营
  13. 飞机大战java_java版飞机大战实战项目详细步骤
  14. Numpy属性dtype的转换(数据类型转换):unit8和float32转换
  15. 10款NFT游戏邀请的“玩赚”
  16. 毕业后如何防止堕落(胡适说)
  17. 盐城北大青鸟东台基地手绘课程作品展
  18. Linux中创建python项目的虚拟环境virtual enviroment
  19. 商业计划书范文3000_商业计划书范文
  20. 网络协议 一 网络层( 版本、首部长度、区分服务、总长度、 标识、标志、片偏移生存时间、协议、首部校验和)

热门文章

  1. 机器学习:银行贷款违约预测模型
  2. 杠铃卧推:平板、上斜、下斜杠铃卧推动作图解教程
  3. python之__len__()
  4. 计算机启动时显示更改了硬件或软件吗,window未能启动,原因可能是最近更改了硬件或软件,解决此问题的步骤。...
  5. 2013年9月9日--9月21日(有效时间7天,每天5小时,共35小时,还有5065小时)
  6. FPGA纯Verilog实现任意尺寸图像缩放,串口指令控制切换,贴近真实项目,提供工程源码和技术支持
  7. 藏经阁导航-做你的全能小帮手
  8. 记录排查rocketMQ-broker-JVM进程消失问题
  9. 原生js实现吸顶效果
  10. 思博伦Spirent TestCenter _经典接入 (Access) 测试之PPPoX_双极未来