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 Deleteint 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 chint 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,具有類似字典的功能).

一,數組使用心得

原型: templateclass 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:[email protected]","","", 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));
}
後兩行不只是賦初值,同時還使得控件使用者可以用顏色對話框選擇顏色。

發佈了80 篇原創文章 · 獲贊 0 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章