• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            使用VC編程來操縱Office。你可以實現諸如:Word文件打印、傳送數據到Word文檔、發送E-MAIL、自動產生表格、Excel數據統計、圓餅圖,直方圖顯示、自動報表生成、播放幻燈、doc,txt,HTML,rtf文件轉換、中文簡繁體轉換、拼音或筆畫排序......只要是Office能夠實現的功能,都可以在你寫的程序中調用。仔細閱讀下面的說明,并下載源文件進行參考,你就可以一步一步地掌握這個技術。祝朋友們學習快樂。

            一、概念
              Microsoft 的 Office 產品中,都提供了OLE Automation 自動化程序的接口。如果你使用VB,VBA 和 Script 腳本調用 Office 功能的話,其實比使用 VC 調用要簡單的多。比如在 WORD 中,調出菜單“工具(T)\宏(M)\錄制新宏(R)”,這時候它開始記錄你在 WORD 中任何菜單和鍵盤的操作,把你的操作過程保存起來,以便再次重復調用。而保存這些操作的記錄,其實就是使用了 VBA 程序(Visual Basic for Application)。而我們下面要實現的功能,也同樣要參考 VBA 的方法。

            二、結構層次
              為了更有邏輯,更有層次地操作 Office,Microsoft 把應用(Application)按邏輯功能劃分為如下的樹形結構

            Application(WORD 為例,只列出一部分)
              Documents(所有的文檔)
                    Document(一個文檔)
                        ......
              Templates(所有模板)
                    Template(一個模板)
                        ......
              Windows(所有窗口)
                    Window
                    Selection
                    View
              Selection(編輯對象)
                    Font
                    Style
                    Range
                    ......
              ......

            只有了解了邏輯層次,我們才能正確的操縱 Office。舉例來講,如果給出一個VBScript語句是:
                  application.ActiveDocument.SaveAs "c:\abc.doc"
            那么,我們就知道了,這個操作的過程是:第一步,取得Application;第二步,從Application中取得ActiveDocument;第三步,調用 Document 的函數 SaveAs,參數是一個字符串型的文件名。

            三、基本步驟
            (1)創建(或打開已有的)一個 MFC 的程序工程
            (2)Ctrl+W 執行 ClassWizard(本文按照 VC6 操作,例子程序也是在VC6 下編寫測試的)
            (3)Add Class...\From a type Library... 在 Office 目錄中,找到你想使用的類型庫。(我使用的是 Office2000,其Word 的類型庫文件,保存在 C:\Program Files\Microsoft Office\Office\MSWORD9.OLB)根據你 Office 的版本,可以使用下表列出的類型庫文件

            Office 版本和類型

            類型庫文件

            Office 版本和類型

            類型庫文件

            Access 97 Msacc8.olb PowerPoint 2000 Msppt9.olb
            Jet Database 3.5 DAO350.dll Word 2000 Msword9.olb
            Binder 97 Msbdr8.olb Access 2002 Msacc.olb
            Excel 97 Excel8.olb Excel 2002 Excel.exe
            Graph 97 Graph8.olb Graph 2002 Graph.exe
            Office 97 Mso97.dll Office 2002 MSO.dll
            Outlook 97 Msoutl97.olb Outlook 2002 MSOutl.olb
            PowerPoint 97 Msppt8.olb PowerPoint 2002 MSPpt.olb
            Word 97 Msword8.olb Word 2002 MSWord.olb
            Access 2000 Msacc9.olb Office Access 2003 Msacc.olb
            Jet Database 3.51 DAO360.dll Office Excel 2003 Excel.exe
            Binder 2000 Msbdr9.olb Graph 2003 Graph.exe
            Excel 2000 Excel9.olb Office 2003 MSO.dll
            Graph 2000 Graph9.olb Office Outlook 2003 MSOutl.olb
            Office 2000 Mso9.dll Office PowerPoint 2003 MSPpt.olb
            Outlook 2000 Msoutl9.olb Office Word 2003 MSWord.olb

            (4)選擇類型庫文件后,在彈出的對話窗中繼續選擇要添加的類。具體選擇什么類,要看你將來在程序中打算調用什么功能。當然,你也可以不用考慮這么多,用鼠標和Shift鍵配合,全部選擇也可以。
            (5)初始化COM。方法一,找到App的InitInstance()函數,在其中添加 AfxOleInit()函數的調用;方法二,在需要調用COM功能的地方 CoInitialize(NULL),調用完畢后 CoUninitialize()。
            (6)在你需要調用 Office 功能函數的 cpp 文件中
                 #include <atlbase.h>  // 為了方便操作 VARIANT 類型變量,使用 CComVariant 模板類
                 #include "頭文件.h"   // 具體的頭文件名,是由裝載類型庫的文件名決定的。(鼠標雙點包裝類的文件,就可以看到)
                                       // 比如使用 msword9.olb類型庫,那么頭文件是 msword9.h
            (7)好了,現在開始寫程序吧。另外要說明的是,步驟3和4,其實也可以使用 #import 方式引入類型庫。

            四、實現技巧
                在書寫調用 Office 函數的過程中,最困難的是確定函數的參數,一般情況下,參數都是 VARIANT 類型的變量指針。那么到底具體我們應該怎么寫那?推薦兩個方法,其一是閱讀有關 VBA 的書籍;其二,是使用 Office 中自帶的“宏”功能。強烈推薦大家使用第二個方法,把你要完成的功能,在 Office 的操作環境中,用宏錄制下來,然后觀察分析錄制后的函數和參數,就可以在 VC 中使用了。舉一個例子:

                  ActiveDocument.SaveAs FileName:="Hello.doc", FileFormat:=wdFormatDocument _
            , LockComments:=False, Password:="", AddToRecentFiles:=True, _
            WritePassword:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
            SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
            False
            以上是在 Word 中錄制的一個保存文件的宏,而在 VC 中對應的函數原型為
                  void _Document::SaveAs(VARIANT* FileName, VARIANT* FileFormat, VARIANT* LockComments,
            VARIANT* Password, VARIANT* AddToRecentFiles, VARIANT* WritePassword,
            VARIANT* ReadOnlyRecommended, VARIANT* EmbedTrueTypeFonts, VARIANT* SaveNativePictureFormat,
            VARIANT* SaveFormsData, VARIANT* SaveAsAOCELetter)
            分析對照后,我們就能看出,參數 FileName 是字符串 VARIANT(VT_BSTR),參數 LockComments 是布爾VARIANT(VT_BOOL),等等。參數 FileFormat := wdFormatDocument 是什么類型那?其實這是一個表示保存的時候指定文件類型的常量,而且顯然是 DWORD 類型VARIANT(VT_I4)。那么常量的數值又是多少那?很簡單,寫一個宏,調用函數 MsgBox 顯示一下不就都知道啦?!

            五、步步為營
              特別提示一:編譯執行前,一定要先關閉 KV 實時監視病毒的功能(KV 的程序會干擾我們的調用,瑞星的則沒關系)。
               特別提示二:在例子程序中,為了表現程序的關鍵部分,沒有或很少使用了條件判斷。為了實現你程序的健壯性,請自己加上條件判斷和異常處理。

            Step1:如何啟動和關閉 WORD,及 VARIANT 的最基本的使用方法
            Step2:和 Step1 同樣功能,用 CComVariant 改進了 VARIANT 的使用方式
            Step3:在 Step2 的基礎上,新建一個 WORD 文檔,并從程序中傳送一些字符到 WORD
            Step4:在 Step3 的基礎上,保存 WORD 文檔
            Step5:一個小應用舉例,把輸入的漢字按照“筆畫”排序
            Step6:一個小應用舉例,盜竊正在使用的 WORD 文檔
              以上這6個小程序中,都有詳細的注釋。大家閱讀后慢慢體會并實驗,你就可以自由地操縱任何一個 Office 啦。
            posted @ 2008-04-27 15:28 wrh 閱讀(251) | 評論 (0)編輯 收藏
            在工業生產控制系統中,有許多需要定時完成的操作,如定時顯示當前時間,定時刷新屏幕上的進度條,上位 機定時向下位機發送命令和傳送數據等。特別是在對控制性能要求較高的實時控制系統和數據采集系統中,就更需要精確定時操作。
              眾所周知,Windows 是基于消息機制的系統,任何事件的執行都是通過發送和接收消息來完成的。 這樣就帶來了一些問題,如一旦計算機的CPU被某個進程占用,或系統資源緊張時,發送到消息隊列 中的消息就暫時被掛起,得不到實時處理。因此,不能簡單地通過Windows消息引發一個對定時要求 嚴格的事件。另外,由于在Windows中已經封裝了計算機底層硬件的訪問,所以,要想通過直接利用 訪問硬件來完成精確定時,也比較困難。所以在實際應用時,應針對具體定時精度的要求,采取相適 應的定時方法。
              VC中提供了很多關于時間操作的函數,利用它們控制程序能夠精確地完成定時和計時操作。本文詳細介紹了 VC中基于Windows的精確定時的七種方式,如下圖所示:


            圖一 圖像描述

              方式一:VC中的WM_TIMER消息映射能進行簡單的時間控制。首先調用函數SetTimer()設置定時 間隔,如SetTimer(0,200,NULL)即為設置200ms的時間間隔。然后在應用程序中增加定時響應函數 OnTimer(),并在該函數中添加響應的處理語句,用來完成到達定時時間的操作。這種定時方法非常 簡單,可以實現一定的定時功能,但其定時功能如同Sleep()函數的延時功能一樣,精度非常低,最小 計時精度僅為30ms,CPU占用低,且定時器消息在多任務操作系統中的優先級很低,不能得到及時響 應,往往不能滿足實時控制環境下的應用。只可以用來實現諸如位圖的動態顯示等對定時精度要求不高的情況。如示例工程中的Timer1。
              方式二:VC中使用sleep()函數實現延時,它的單位是ms,如延時2秒,用sleep(2000)。精度非常 低,最小計時精度僅為30ms,用sleep函數的不利處在于延時期間不能處理其他的消息,如果時間太 長,就好象死機一樣,CPU占用率非常高,只能用于要求不高的延時程序中。如示例工程中的Timer2。
              方式三:利用COleDateTime類和COleDateTimeSpan類結合WINDOWS的消息處理過程來實現秒級延時。如示例工程中的Timer3和Timer3_1。以下是實現2秒的延時代碼:
                  COleDateTime      start_time = COleDateTime::GetCurrentTime();
            COleDateTimeSpan  end_time= COleDateTime::GetCurrentTime()-start_time;
            while(end_time.GetTotalSeconds()< 2) //實現延時2秒
            {
            MSG   msg;
            GetMessage(&msg,NULL,0,0);
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            //以上四行是實現在延時或定時期間能處理其他的消息,
                   //雖然這樣可以降低CPU的占有率,
            //但降低了延時或定時精度,實際應用中可以去掉。
            end_time = COleDateTime::GetCurrentTime()-start_time;
            }//這樣在延時的時候我們也能夠處理其他的消息。      
              方式四:在精度要求較高的情況下,VC中可以利用GetTickCount()函數,該函數的返回值是  DWORD型,表示以ms為單位的計算機啟動后經歷的時間間隔。精度比WM_TIMER消息映射高,在較 短的定時中其計時誤差為15ms,在較長的定時中其計時誤差較低,如果定時時間太長,就好象死機一樣,CPU占用率非常高,只能用于要求不高的延時程序中。如示例工程中的Timer4和Timer4_1。下列代碼可以實現50ms的精確定時:
                   DWORD dwStart = GetTickCount();
            DWORD dwEnd   = dwStart;
            do
            {
            dwEnd = GetTickCount()-dwStart;
            }while(dwEnd <50);
            為使GetTickCount()函數在延時或定時期間能處理其他的消息,可以把代碼改為:
                   DWORD dwStart = GetTickCount();
            DWORD dwEnd   = dwStart;
            do
            {
            MSG   msg;
            GetMessage(&msg,NULL,0,0);
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            dwEnd = GetTickCount()-dwStart;
            }while(dwEnd <50);
            雖然這樣可以降低CPU的占有率,并在延時或定時期間也能處理其他的消息,但降低了延時或定時精度。
              方式五:與GetTickCount()函數類似的多媒體定時器函數DWORD timeGetTime(void),該函數定時精 度為ms級,返回從Windows啟動開始經過的毫秒數。微軟公司在其多媒體Windows中提供了精確定時器的底 層API持,利用多媒體定時器可以很精確地讀出系統的當前時間,并且能在非常精確的時間間隔內完成一 個事件、函數或過程的調用。不同之處在于調用DWORD timeGetTime(void) 函數之前必須將 Winmm.lib  和 Mmsystem.h 添加到工程中,否則在編譯時提示DWORD timeGetTime(void)函數未定義。由于使用該 函數是通過查詢的方式進行定時控制的,所以,應該建立定時循環來進行定時事件的控制。如示例工程中的Timer5和Timer5_1。
              方式六:使用多媒體定時器timeSetEvent()函數,該函數定時精度為ms級。利用該函數可以實現周期性的函數調用。如示例工程中的Timer6和Timer6_1。函數的原型如下:
                   MMRESULT timeSetEvent( UINT uDelay,
            UINT uResolution,
            LPTIMECALLBACK lpTimeProc,
            WORD dwUser,
            UINT fuEvent )
              該函數設置一個定時回調事件,此事件可以是一個一次性事件或周期性事件。事件一旦被激活,便調用指定的回調函數, 成功后返回事件的標識符代碼,否則返回NULL。函數的參數說明如下:
                   uDelay:以毫秒指定事件的周期。
            Uresolution:以毫秒指定延時的精度,數值越小定時器事件分辨率越高。缺省值為1ms。
            LpTimeProc:指向一個回調函數。
            DwUser:存放用戶提供的回調數據。
            FuEvent:指定定時器事件類型:
            TIME_ONESHOT:uDelay毫秒后只產生一次事件
            TIME_PERIODIC :每隔uDelay毫秒周期性地產生事件。      
              具體應用時,可以通過調用timeSetEvent()函數,將需要周期性執行的任務定義在LpTimeProc回調函數 中(如:定時采樣、控制等),從而完成所需處理的事件。需要注意的是,任務處理的時間不能大于周期間隔時間。另外,在定時器使用完畢后, 應及時調用timeKillEvent()將之釋放。
              方式七:對于精確度要求更高的定時操作,則應該使用QueryPerformanceFrequency()和 QueryPerformanceCounter()函數。這兩個函數是VC提供的僅供Windows 95及其后續版本使用的精確時間函數,并要求計算機從硬件上支持精確定時器。如示例工程中的Timer7、Timer7_1、Timer7_2、Timer7_3。
            QueryPerformanceFrequency()函數和QueryPerformanceCounter()函數的原型如下:
                   BOOL  QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
            BOOL  QueryPerformanceCounter(LARGE_INTEGER *lpCount);
              數據類型ARGE_INTEGER既可以是一個8字節長的整型數,也可以是兩個4字節長的整型數的聯合結構, 其具體用法根據編譯器是否支持64位而定。該類型的定義如下:
                   typedef union _LARGE_INTEGER
            {
            struct
            {
            DWORD LowPart ;// 4字節整型數
            LONG  HighPart;// 4字節整型數
            };
            LONGLONG QuadPart ;// 8字節整型數
            }LARGE_INTEGER ;
              在進行定時之前,先調用QueryPerformanceFrequency()函數獲得機器內部定時器的時鐘頻率, 然后在需要嚴格定時的事件發生之前和發生之后分別調用QueryPerformanceCounter()函數,利用兩次獲得的計數之差及時鐘頻率,計算出事件經 歷的精確時間。下列代碼實現1ms的精確定時:
                   LARGE_INTEGER litmp;
            LONGLONG QPart1,QPart2;
            double dfMinus, dfFreq, dfTim;
            QueryPerformanceFrequency(&litmp);
            dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
            QueryPerformanceCounter(&litmp);
            QPart1 = litmp.QuadPart;// 獲得初始值
            do
            {
            QueryPerformanceCounter(&litmp);
            QPart2 = litmp.QuadPart;//獲得中止值
            dfMinus = (double)(QPart2-QPart1);
            dfTim = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒
            }while(dfTim<0.001);
              其定時誤差不超過1微秒,精度與CPU等機器配置有關。 下面的程序用來測試函數Sleep(100)的精確持續時間:
                   LARGE_INTEGER litmp;
            LONGLONG QPart1,QPart2;
            double dfMinus, dfFreq, dfTim;
            QueryPerformanceFrequency(&litmp);
            dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
            QueryPerformanceCounter(&litmp);
            QPart1 = litmp.QuadPart;// 獲得初始值
            Sleep(100);
            QueryPerformanceCounter(&litmp);
            QPart2 = litmp.QuadPart;//獲得中止值
            dfMinus = (double)(QPart2-QPart1);
            dfTim = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒     
              由于Sleep()函數自身的誤差,上述程序每次執行的結果都會有微小誤差。下列代碼實現1微秒的精確定時:
                   LARGE_INTEGER litmp;
            LONGLONG QPart1,QPart2;
            double dfMinus, dfFreq, dfTim;
            QueryPerformanceFrequency(&litmp);
            dfFreq = (double)litmp.QuadPart;// 獲得計數器的時鐘頻率
            QueryPerformanceCounter(&litmp);
            QPart1 = litmp.QuadPart;// 獲得初始值
            do
            {
            QueryPerformanceCounter(&litmp);
            QPart2 = litmp.QuadPart;//獲得中止值
            dfMinus = (double)(QPart2-QPart1);
            dfTim = dfMinus / dfFreq;// 獲得對應的時間值,單位為秒
            }while(dfTim<0.000001);
            其定時誤差一般不超過0.5微秒,精度與CPU等機器配置有關。(完)
            posted @ 2008-04-27 15:19 wrh 閱讀(230) | 評論 (0)編輯 收藏
            有三個API函數可以運行可執行文件WinExec、ShellExecute和CreateProcess。CreateProcess因為使用復雜,比較少用。 
            WinExec主要運行EXE文件。如:WinExec(’Notepad.exe Readme.txt’, SW_SHOW); 

            ShellExecute不僅可以運行EXE文件,也可以運行已經關聯的文件。

            首先必須引用shellapi.pas單元:uses ShellAPI; 

            1.標準用法 

              ShellExecute函數原型及參數含義如下: 

              function ShellExecute(hWnd: HWND; Operation, FileName, Parameters,Directory: PChar; ShowCmd: Integer): HINST; stdcall; 

              ●hWnd:用于指定父窗口句柄。當函數調用過程出現錯誤時,它將作為Windows消息窗口的父窗口。例如,可以將其設置為應用程序主窗口句柄,即Application.Handle,也可以將其設置為桌面窗口句柄(用GetDesktopWindow函數獲得)。 

              ●Operation:用于指定要進行的操作。其中“open”操作表示執行由FileName參數指定的程序,或打開由FileName參數指定的文件或文件夾;“print”操作表示打印由FileName參數指定的文件;“explore”操作表示瀏覽由FileName參數指定的文件夾。當參數設為nil時,表示執行默認操作“open”。 

              ●FileName:用于指定要打開的文件名、要執行的程序文件名或要瀏覽的文件夾名。 

              ●Parameters:若FileName參數是一個可執行程序,則此參數指定命令行參數,否則此參數應為nil或PChar(0)。 

              ●Directory:用于指定默認目錄。 

              ●ShowCmd:若FileName參數是一個可執行程序,則此參數指定程序窗口的初始顯示方式,否則此參數應設置為0。 

              若ShellExecute函數調用成功,則返回值為被執行程序的實例句柄。若返回值小于32,則表示出現錯誤。 

              上述僅僅是ShellExecute函數的標準用法,下面將介紹它的特殊用法。 

            2.特殊用法 

              如果將FileName參數設置為“http:”協議格式,那么該函數將打開默認瀏覽器并鏈接到指定的URL地址。若用戶機器中安裝了多個瀏覽器,則該函數將根據Windows 9x/NT注冊表中http協議處理程序(Protocols Handler)的設置確定啟動哪個瀏覽器。 

              格式一:http://網站域名。 

              如:ShellExecute(handle, ‘open’, http:// ; 

            www.neu.edu.cn’, nil, nil, SW_SHOWNORMAL); 

              格式二:http://網站域名/網頁文件名。 

              如:ShellExecute(handle, ‘open’, http:// ; 

            www.neu.edu.cn/default.htm’,nil,nil, 

            SW_SHOWNORMAL); 

              如果將FileName參數設置為“mailto:”協議格式,那么該函數將啟動默認郵件客戶程序,如Microsoft Outlook(也包括Microsoft Outlook Express)或Netscape Messanger。若用戶機器中安裝了多個郵件客戶程序,則該函數將根據Windows 9x/NT注冊表中mailto協議處理程序的設置確定啟動哪個郵件客戶程序。 

              格式一:mailto: 

              如:ShellExecute(handle,‘open’, ‘mailto:’, nil, nil, SW_SHOWNORMAL);打開新郵件窗口。 

              格式二:mailto:用戶賬號@郵件服務器地址 

              如:ShellExecute(handle, ‘open’,‘ mailto:who@mail.neu.edu.cn’, nil, nil, SW_SHOWNORMAL);打開新郵件窗口,并自動填入收件人地址。若指定多個收件人地址,則收件人地址之間必須用分號或逗號分隔開(下同)。 

              格式三:mailto:用戶賬號@郵件服務器地址?subject=郵件主題&body=郵件正文 

              如:ShellExecute(handle, ‘open’, ‘ mailto:who@mail.neu.edu.cn?subject=Hello&Body=This is a test’, nil, nil, SW_SHOWNORMAL);打開新郵件窗口,并自動填入收件人地址、郵件主題和郵件正文。若郵件正文包括多行文本,則必須在每行文本之間加入換行轉義字符%0a。 

            例子(delphi): 

            在一個應用程序調用c:\Project1.exe; 

            ShellExecute(handle, ’open’,’c:\Project1.exe’,’字串內容’,nil, SW_SHOWNORMAL); 

            在Project1.exe里可以調用: 

            procedure TForm1.FormCreate(Sender: TObject); 

            var i:integer; 

            begin 

            for i:=1 to paramcount do 

            if ParamStr(i)<>’’ then showmessage(ParamStr(i)); 

            end;

             

            最后的那個參數,為窗口指定可視性方面的一個命令。 

            請用下述任何一個常數 

            SW_HIDE 隱藏窗口,活動狀態給令一個窗口 

            SW_MINIMIZE 最小化窗口,活動狀態給令一個窗口 

            SW_RESTORE 用原來的大小和位置顯示一個窗口,同時令其進入活動狀態 

            SW_SHOW 用當前的大小和位置顯示一個窗口,同時令其進入活動狀態 

            SW_SHOWMAXIMIZED 最大化窗口,并將其激活 

            SW_SHOWMINIMIZED 最小化窗口,并將其激活 

            SW_SHOWMINNOACTIVE 最小化一個窗口,同時不改變活動窗口 

            SW_SHOWNA 用當前的大小和位置顯示一個窗口,不改變活動窗口 

            SW_SHOWNOACTIVATE 用最近的大小和位置顯示一個窗口,同時不改變活動窗口 

            SW_SHOWNORMAL 與SW_RESTORE相同
            posted @ 2008-04-26 15:46 wrh 閱讀(1212) | 評論 (0)編輯 收藏
            如果你是一個使用VB編程的程序員,要在程序中顯示JPG或者GIF圖像簡直易如反掌,將圖像控件拖到Form中,分分鐘即可搞掂。但是C++程序員要顯示同樣的圖形卻沒有那么輕松,那么是不是要自己編寫JPG解壓縮代碼呢?當然不用那么復雜啦!本文將針對這個問題討論如何在MFC中顯示JPG或者GIF圖像。
                用VB寫圖像顯示程序之所以如此輕松,完全是利用了琳瑯滿目的圖像處理控件,把你想要做的事情都一一搞掂。而C++程序員為了實現相同的功能必須忙乎半天。其實,C/C++程序員也能使用那些VB程序員所用的(或者說幾乎一樣的)圖像控件。VB用的圖像控件實際上都基于一個系統級COM類——IPicture。下面是有關 IPicture 的方法描述:
            方法 描述
            get_Handle  返回圖像對象的Windows GDI句柄 
            get_Hpal  返回圖像對象當前使用的調色板拷貝
            get_Type 返回當前圖像對象的的圖像類型
            get_Width  返回當前圖像對象的圖像寬度
            get_Height  返回當前圖像對象的圖像高度
            Render  在指定的位置、指定的設備上下文上繪制指定的圖像部分
            set_Hpal  設置當前圖像的調色板
            get_CurDC  返回當前選中這個圖像的設備上下文
            SelectPicture  將一個位圖圖像選入給定的設備上下文,返回選中圖像的設備上下文和圖像的GDI句柄
            get_KeepOriginalForma  返回圖像對象KeepOriginalFormat 屬性的當前值
            put_KeepOriginalFormat  設置圖像對象的KeepOriginalFormat 屬性
            PictureChanged  通知圖像對象它的圖像資源改變了
            SaveAsFile  將圖像數據存儲到流中,格式與存成文件格式相同
            get_Attributes  返回圖像位屬性當前的設置

                從上面這個表可以看出,IPicture操縱著圖像對象及其屬性。圖像對象提供對位圖的抽象,而Windows負責BMP、JPG和GIF位圖的標準實現。程序員要做的只是實例化IPicture,然后調用其Render函數。與通常使用接口的方式不同,這里實例的創建我們不用CoCreateInstance函數,而是用一個專門的函數OleLoadPicture。

            IStream* pstm = // 需要一個流(stream)
            IPicture* pIPicture;
            hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&pIPicture);      
            OleLoadPicture從流中加載圖像并創建一個可用來顯示圖像的新IPicture對象。
            rc = // 顯示圖像的矩形
            // 將rc 轉換為 HIMETRIC
            spIPicture->Render(pDC, rc);      
                IPicture 負責處理所有瑣事,以便確定圖形之格式,如 Windows 位圖、JPEG或者GIF文件——甚至是圖標和元文件(metafiles)。當然啦,所有這些的實現細節是需要技巧的,為此我寫了一個Demo程序Myimgapp(如圖二)來示范這些IPicture的使用方法。


            圖一 Myimgapp的運行畫面

                Myimgapp是個典型的MFC文檔/視圖程序,在編寫這個程序之前,我首先對 IPicture COM接口進行封裝,之所以要這么做,主要是考慮到并不是每一個程序員都能熟練運用COM接口進行編程,另外將IPicture的主要功能封裝在C++類中可以使我們的問題更容易解決,我封裝的這個C++類名字叫做CPicture。它的定義和實現細節請參考本文提供的源代碼。
                我在這個類中將復雜而陌生的COM風格的參數映射成MFC程序員更為熟悉的類型。例如,CPicture可以讓你直接從文件名加載一幅圖像,CFile或者CArchive,而不用去處理流,CPicture::Render替你完成了IPicture中所有令人討厭的但又是必須的HIMETRIC平滑轉換工作。CPicture甚至具備了一個Load函數,它可以從資源數據中加載圖像,所以你只要用下面的代碼就可以顯示資源中的圖像:
               CPicture pic(ID_MYPIC); // 加載圖像
            CRect rc(0,0,0,0);      // 使用缺省的rc
            pic.Render(pDC, rc);    // 顯示圖像      
            CPicture::Render提供一個顯示圖片的矩形。IPicture 對圖像進行延伸處理。如果傳遞一個空矩形,則CPicture用圖像本身的大小--不進行延伸處理。對于圖像本身而言,CPicture查找"IMAGE"類型的資源,所以在資源文件中你必須要加入下面的代碼:
               IDR_MYPIC IMAGE MOVEABLE PURE "res\\MyPic.jpg"      
                CPicture是個很棒的傻瓜類,它具備一個 ATL 智能指針CComQIPtr指向IPicture接口,通過調用OleLoadPicture來初始化不同的Load函數。CPicture提供了常用的打包函數來調用底層的IPicture。CPicture只封裝了那些在Demo例子程序中要用到的方法。如果你需要調用IPicture::get_Handle或其它一些很少用到的IPicture方法,你可以自己嘗試編寫相應的打包代碼。 另外,在編寫完CPicture之后,我發現了一個現成的MFC類——CPictureHolder,這個類的功能幾乎與CPicture完全一樣,你可以在afxctl.h文件中找到它的定義。 前面說過,Demo例子是個典型的MFC文檔/視圖應用程序,因此它肯定少不了與文檔和視圖類相對應的CPictureDoc 和CPictureView:
            CPictureDoc類沒有什么特別的處理代碼,它用CPicture對象存儲圖像:
            class CPictureDoc : public CDocument {
            protected:
            CPicture m_pict; // the picture
            };      
            并且CPictureDoc::Serialize 調用CPicture::Load 從MFC存檔的數據中讀取圖像。
            void CPictureDoc::Serialize(CArchive& ar)
            {
            if (ar.IsLoading()) {
            m_pict.Load(ar);
            }
            }      
            為了使Myimgapp程序更實用,CPictureDoc::OnNewDocument從程序資源數據加載了一幅圖像。為了顯示這幅圖像,CPictureView::OnDraw要調用CPicture::Render。這樣程序一啟動便會顯示一幅默認的圖像。
            void CPictureView::OnDraw(CDC* pDC)
            {
            CPictureDoc* pDoc = GetDocument();
            CPicture* ppic = pDoc->GetPicture();
            CRect rc;
            GetImageRect(rc);
            ppic->Render(pDC,rc);
            }
                GetImageRect是CPictureView類的一個成員函數,作用是根據當前Myimgapp的縮放比率(可用25%、33%、50%、75%、100%或自適應方式)獲取圖像矩形。GetImageRect調用CPicture::GetImageSize來獲得真正的圖像大小,然后根據比率顯示。 CPictureView其余的部分完全和CScrollView的做法差不多,初始化視圖并設置滾動大小,處理命令等等。唯一讓人操心的是IPicture::Render中HIMETRIC的處理問題,因為標準的MFC應用程序都使用MM_TEXT映射模型。不用擔心,CPicture::Render和CPicture::GetImageSize會將這一切轉換過來,所以你不必為這些事情傷神。 CPictureView有一個消息處理器值得一提:它就是OnEraseBkgnd,當要顯示的圖像比客戶區小的時候,這個函數必須繪制空白區域,如圖二,OnEraseBkgnd創建一個與圖像大小相等的切邊(clip)矩形,然后將客戶區填成黑色。之所以要創建切邊矩形,主要是避免當改變窗口大小時出現的抖動——FillRect不繪制切邊矩形內的區域,此乃Windows圖形處理的常識。


            圖二 OnEraseBkgnd 填充修剪的圖像

                IPicture/CPicture簡化了圖像的顯示。它甚至可以實現調色板的識別這樣復雜的處理。你完全可以拋開老式DIB 圖像繪制方法,如加載調色板、BitBlts、StretchBlts等等——這一切IPicture全都可以搞掂。如果你未曾用IPicture顯示過圖像,那么現在試試吧。 CPictureView完成圖像瀏覽的任務看來不是什么難事了。但是如果要把一幅圖像添加到一個對話框或者其它的什么窗口中怎么辦呢?為此我創建了另外一個類——CPictureCtrl。
            CPictureCtrl 使你可以在任何對話框或窗口中把圖像作為子窗口顯示。例如:
            class CAboutDialog : public CDialog {
            protected:
            CPictureCtrl m_wndPict;
            virtual BOOL OnInitDialog();
            };
            BOOL CAboutDialog::OnInitDialog()
            {
            m_wndPict.SubclassDlgItem(IDC_MYIMAGE,this);
            return CDialog::OnInitDialog();
            }      
                假設你的對話框中有一個靜態控制,它的ID=IDC_IMAGE,并且有一幅IMAGE資源的ID與之相同。則從CStaticLink派生出的CPictureCtrl還可以指定一個URL超鏈接(或者創建一個ID與此控制或圖像的ID相同的串資源)。如果你指定了一個URL,則在圖像上單擊鼠標將啟動默認瀏覽器訪問URL。真是酷呆了。CPicture控制著CPicture對象并改寫WM_PAINT消息處理例程,調用CPicture::Render代替通常的靜態控制處理例程。處理細節請參見代碼。打開Myimgapp程序的“關于”對話框就知道了。
            posted @ 2008-04-26 11:10 wrh 閱讀(1199) | 評論 (0)編輯 收藏
            很多程序員都喜歡讓自己的代碼運行效果與眾不同。Windows系統的應用程序打開某個文件一般使用的都是默認的CFileDialog。但是這個默認的CFileDialog往往滿足不了用戶的要求。我就碰到一個這樣的用戶,他的要求如下:
            • 1、在默認的CFileDialog對話框中加一個預覽窗格,以便在選中ASCII文件時能看到所選文件的內容,也就是用*.txt作為文件過濾條件。
            • 2、在默認的CFileDialog對話框中加一個"全部"按鈕來選擇某個目錄中所有的.txt文件。
            • 3、如果選擇的目錄中沒有.txt文件時,要將"全部"按鈕disable,也就是置灰這個按鈕。
               實現上面這些需求必須要改裝CFileDialog對話框。當最后寫完程序時,功能到是全都實現了,但在Windows 2000環境測試中,用戶發現了這樣一個問題:如果先選中某個文件,然后再去選某個文件夾,預覽窗格仍然顯示的那個文件的內容。盡管在OnFileNameChange中對CDN_SELCHANGE進行了處理,為了獲取所選的文件/路徑名,也調用了CFileDialog::GetPathName。但是即使是選中了文件夾,GetPathName仍然返回的是文件的名字。即便嘗試用其它的通知消息和函數,比如 CDN_FOLDERCHANGE 和 GetFileName,但仍舊存在同樣的問題。必須承認在Windows 2000中,CFileDialog是個不完美的對話框,確實存在上述問題。正是有這些不完美,程序員們才忙得個不亦樂乎......那么到底如何判斷用戶選中的是文件還是文件夾呢?下面就讓我們從用戶需求開始,一個一個解決所碰到的問題。
                首先簡單介紹下本文引入的三個輔助類:CFileDialogHook;CFileDialogOwnerHook和CFileDlgHelper,這三個類很簡單,其功能分別是:子類化文件對話框;子類化文件對話框的父窗口或宿主窗口,這兩個類只在CFileDlgHelper類中使用,一些重要的處理都在CFileDlgHelper中。它的使用方法很簡單,實例化CFileDlgHelper以后調用Init即可。
            class CMyOpenDlg ... {
            protected:
            CFileDlgHelper m_dlghelper;//實例化
            };
            BOOL CMyOpenDlg::OnInitDialog()
            {
            m_dlghelper.Init(this)//初始化
            ……
            }     
                初始化CFileDlgHelper以后,便可以用它來獲取列表控制以及判斷選項是否有文件夾屬性,例如:
            CListCtrl* plc = m_dlghelper.GetListCtrl();
            POSITION pos = plc->GetFirstSelectedItemPosition();
            while (pos) {
            int i = plc->GetNextSelectedItem(pos);
            if (fdh.IsItemFolder(i)) {
            // 顯示"(FOLDER)"……
            } else {
            // 顯示其它內容
            }
            }

                毫無疑問,要改裝CFileDialog對話框,必須建立一個它的派生類以及一個新的對話框資源。“全部”按鈕的實現代碼是這樣的:

            void CMyOpenDlg::OnSelectAll()
            {
            CListCtrl* plc = m_dlghelper.GetListCtrl();
            for (int i=0; i<plc->GetItemCount(); i++) {
            CString fn = plc->GetItemText(i,0);
            if (IsTextFileName(fn)) {
            plc->SetItemState(i,LVIS_SELECTED,
            LVIS_SELECTED);
            }
            }
            plc->SetFocus();
            }
                當所選目錄中沒有.txt文件時,要disable“全部”按鈕的處理稍微麻煩一些,要用到ON_UPDATE_COMMAND_UI消息。回顧一下MFC有關UI更新的基本方法,通常是在主消息循環處于空閑狀態時候——也就是說在消息隊列中沒有待處理的消息。但對話框則有所不同,尤其是運行模式對話框時,MFC啟動另外一個消息循環。當沒有消息等待處理的時候,CWnd::DoModal向對話框發送一個WM_KICKIDLE消息。所以要想讓對話框處理UI,常用的方式是這樣的:
            LRESULT CMyDialog::OnKickIdle(WPARAM wp, LPARAM lp)
            {
            UpdateDialogControls(this, TRUE);
            return 0;
            }      
                CWnd::UpdateDialogControls將神奇的CN_UPDATE_COMMAND_UI消息發送到對話框,觸發ON_UPDATE_COMMAND_UI處理例程。可惜這個方法對CFileDialog對話框不靈。原因是CFileDialog重寫了DoModal,它不會以正常方式運行某個消息循環,而是調用::GetOpenFileName (或::GetSaveFileName)。這些API函數都有自己消息循環,并且你無法鉆進去進行消息空閑處理。無論什么時候,每當模式對話框處于等待消息狀態時,對話框發送自己的WM_ENTERIDLE消息。從這里進去才可以處理UI更新事宜。但有幾個細節需要注意。首先,Windows只發送WM_ENTERIDLE消息到對話框的所有者——此處為主框架——所以必須在那里捕獲這個消息。然后,只要對話框仍然處于空閑狀態,則Windows繼續發送WM_ENTERIDLE,但只需要調用UpdateDialogControls一次,此間可以進行常規的標志設置。那到底什么時候設置標志呢?無論何時,UI狀態的改變,都是在對話框獲得到WM_COMMAND 或 WM_NOTIFY消息之后。所以還必須在CFileDialog派生的對話框中截獲這些消息。 因為這些都是一些繁瑣的細節,所以最好將它們封裝到在一個新類中,這就是CFileDlgHelper的來由。只要從CFileDialog派生的對話框OnInitDialog函數中調用CFileDlgHelper的Init,便不用操心ON_UPDATE_COMMAND_UI的處理細節。CFileDlgHelper是如何實現的呢?告訴你吧,利用萬能類CSubclassWnd,這個類可以用Windows的方式子類化任何窗口,通過在某個窗口過程之前安裝一個新的窗口過程來實現消息的捕獲。實際上,CFileDlgHelper 用了兩個CSubclassWnds派生類:一個用來截獲發送到對話框父窗口的WM_ENTERIDLE消息,另一個用來截獲發送到對話框本身的WM_COMMAND 或 WM_NOTIFY。當主窗口得到WM_ENTERIDLE消息時,CFileDialogOwnerHook解釋它并更新對話框控制:
            LRESULT CFileDialogOwnerHook::WindowProc(...)
            {
            if (msg==WM_ENTERIDLE) {
            if (m_pHelper->m_bUpdateUI) {
            m_pDlg->UpdateDialogControls(m_pDlg, FALSE);
            m_pHelper->m_bUpdateUI=FALSE;
            }
            }
            return CSubclassWnd::WindowProc(msg, wp, lp);
            }
            當對話框得到WM_NOTIFY 或者WM_COMMAND消息時,CFileDialogHook重置標志。
            LRESULT CFileDialogHook::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
            {
            if (msg==WM_COMMAND || msg==WM_NOTIFY) {
            m_pHelper->m_bUpdateUI = TRUE;
            }
            return CSubclassWnd::WindowProc(msg, wp, lp);
            }     
            一旦知道了其中的奧秘,一切就這么簡單。注意從CSubclassWnd派生了兩個類——CFileDialogOwnerHook和CFileDialogHook,一個用來對付主框架,另一個用來對付對話框本身,它們都在隱含在CFileDlgHelper類中。有了它,“按鈕”的UI更新就會象你所期望的那樣:
            void CMyOpenDlg::OnUpdateSelectAll(CCmdUI* pCmdUI)
            {
            CFileDlgHelper& fdh = m_dlghelper;
            CListCtrl* plc = fdh.GetListCtrl();
            for (int i=0; i<plc->GetItemCount(); i++) {
            if (IsTextFileName(fdh.GetItemName(i))) {
            pCmdUI->Enable(TRUE);
            return;
            }
            }
            pCmdUI->Enable(FALSE);
            }      
               以上是用戶需求的實現,下面來解決Window 2000環境測試出現的問題:如何確定在列表框中選擇的是文件還是文件夾。
                要想解決這個問題,就必須關注對話框中的列表控制(ListCtrl/ListView),許多普通的對話框里的控制都有明確的IDs,如靜態文本控制有stc1,以及列表框有lst1,這些符號都定義在文件中。你可以把列表控制看成是lst1,但用Spy++察看后,如圖一所示:


            圖一 Spy++

            你會發現列表控制實際上被包含在另一個窗口類SHELLDLL_DefView中。SHELLDLL_DefView窗口的ID為lst2,其項下的列表控制(SysListView32)的子ID為1。所以,為了要得到這個列表控制,可以這樣編碼:

            // 在自己的CFileDialog 派生類中
            CListCtrl* plc = (CListCtrl*)GetParent()->GetDlgItem(lst2)->GetDlgItem(1);      
                記住,在定制CFileDialog時,它實際上是一個實際對話框的子對話框,這就是必須用GetParent的原因。更多的細節請參考MSDN中的相關文章。強制類型轉換 CListCtrl* 與每一個常見的MFC訣竅一樣,因為CListCtrl既沒有數據成員也沒有虛擬函數成員,它是一個純粹的包裝類(因為GetDlgItem返回一個臨時的CWnd指針,而不是CListCtrl,每次碰到這種情況,常常都會讓人感到沮喪,其實這很正常)。 一旦你有了列表控制的指針,便可以做任何想做事情——例如獲取選中的路徑名,調用CListCtrl::GetItemText并添加結果到當前打開的文件夾(GetFolderPath/CDM_GETFOLDERPATH)。有了路徑名,如何知道它到底時文件還是文件夾呢?方法如下:
            #include 
            // 檢查路徑名是不是文件夾
            static BOOL IsFolder(LPCTSTR pathname)
            {
            struct stat st;
            return stat(pathname, &st)==0 && (st.st_mode & _S_IFDIR);
            }
                這里需要注意的是:不管怎樣,如果路徑名不是文件夾,你也不能因此就斷定它就是一個文件!因為它還可能是其它的外殼對象,如"網上鄰居"或者"我的電腦"之類的東西。 詳細做法可以參考本文的例子程序 OpenFileDlg,它還示范了如何建立預覽對話框。這個程序可以進行多項選擇,如果只選中一個.txt文件,則預覽窗格顯示文件的開始幾行。程序還帶一個調試窗口,窗口中列出選中的條目,如果選中的是文件夾,則在它的旁邊會有“FOLDER”說明。如圖二所示。


            圖二運行中的OpenFileDlg

                如果選中的是文件夾,則OpenFileDlg會清空預覽格,這樣就解決了本文所提出的預覽問題。當然,如果運行環境是Windows XP,而非Windows 2000,那么就不會碰上這個問題!在Windows XP中,OnFileNameChange/CDN_SELCHANGE會返回正確的文件名和文件夾名字。但仍然可以用CFileDlgHelper類獲取列表控制,選項名稱等。并且仍然需要IsFolder來檢查路徑名是不是文件夾。
                其實,在OnSelectAll處理代碼中,IsTextFileName的功能是查找以.txt結尾文件名字。這個函數真的能實現這個功能嗎?其實,在程序中有個致命的問題——如果用戶定制了資源管理器來隱藏已知文件類型的擴展名。那么,.txt就不會出現在列表框中。也就是說CFileDlgHelper::GetItemName返回foo,而不是foo.txt。實際上,如果擴展名被隱藏,那么象foo.txt、foo.jpg和foo.doc等等這樣的文件都以名字foo出現(試一下就知道了)。如此一來,怎么知道這個foo文件到底是此foo,還是彼foo呢?問題真是解決不完啊,搞掂這個問題,又出那個問題。唉,好累啊,下次再說吧......

            posted @ 2008-04-26 08:10 wrh 閱讀(894) | 評論 (0)編輯 收藏
            使用rand函數獲得隨機數。rand函數返回的隨機數在0-RAND_MAX(32767)之間。
                例子:
                /* RAND.C: This program seeds the random-number generator
                
            * with the time, then displays 10 random integers.
                
            */
                
                
            #include <stdlib.h>
                
            #include <stdio.h>
                
            #include <time.h>
                
                
            void main( void )
                
            {
                
            int i;
                
                
            /* Seed the random-number generator with current time so that
                
            * the numbers will be different every time we run.
                
            */
                
            srand( (unsigned)time( NULL ) );
                
                
            /* Display 10 numbers. */
                
            for( i = 0; i < 10;i++ )
                
            printf( " %6d\n", rand() );
                
            }
                
                

                在調用這個函數前,最好先調用srand函數,如srand( (unsigned)time( NULL ) ),這樣可以每次產生的隨機數序列不同。
                如果要實現類似0-1之間的函數,可以如下:
                double randf()
                
            {
                
            return (double)(rand()/(double)RAND_MAX);
                
            }
                
                

                如果要實現類似Turbo C的random函數,可以如下:
                int random(int number)
                
            {
                
            return (int)(number/(float)RAND_MAX * rand());
                
            }
            posted @ 2008-04-15 13:56 wrh 閱讀(1668) | 評論 (0)編輯 收藏

            1.檢測程序中的括號是否匹配
            把光標移動到需要檢測的括號(如大括號{}、方括號[]、圓括號()和尖括號<>)前面,鍵入快捷鍵“Ctrl+]”。如果括號匹配正確,光標就跳到匹配的括號處,否則光標不移動,并且機箱喇叭還會發出一聲警告聲。

            bbs.bitsCN.com

             

            2.查看一個宏(或變量、函數)的宏定義
            把光標移動到你想知道的一個宏上,就比如說最常見的DECLARE_MAP_MESSAGE上按一下F12(或右鍵菜單中的Go To Defition Of …),如果沒有建立Browse files,會出現提示對話框,確定,然后就會跳到定義那些東西的地方。
            相當可喜的是,它也可以看到Microsoft定義的系統宏,非常good.

            BBS.bitsCN.com網管論壇


            3.格式化一段亂七八糟的源代碼
            選中那段源代碼,按ATL+F8。 [bitsCN_com]


            4.在編輯狀態下發現成員變量或函數不能顯示
            刪除該項目擴展名為.ncb文件,重新打開該項目。 bitsCN.nET*中國網管博客


            5.如何整理ClassView視圖中大量的類
            可以在classview 視圖中右鍵新建文件夾(new folder),再把具有相近性質的類拖到對應的文件夾中,使整個視圖看上去清晰明了. bbs.bitsCN.com


            6.定位預處理指定
            在源文件中定位光標到對稱的#if, #endif,使用Ctrl+K.

            bbs.bitsCN.com中國網管論壇

             

            7.如何添加系統中Lib到當前項目
            在Project | Settings | Link | Object/library modules:輸入Lib名稱,不同的Lib之間用空格格開. bbs.bitsCN.com


            8.如何添加系統中的頭文件(.h)到當前項目.
            #include <FileName.h>,告訴編譯到VC系統目錄去找;使用#include "FileName.h",告訴編譯在當前
            目錄找.

            bbs.bitsCN.com

             

            9.如何在Studio使用匯編調試
            在WorkBench的Debugger狀態下按CTRL+F7. www@bitscn@com


            10.怎樣處理ClassZiard找不到的系統消息
            如果要在ClassWizard中處理WM_NCHITTEST等系統消息,請在ClassWizard中Class Info頁中將
            Message filter改為Window就有了.

            bitsCN~com


            11.如何干凈的刪除一個類
            先從Workspace中的FileView中刪除對應的.h和.cpp文件,再關閉項目,從實際的文件夾中刪除對應的.h和.cpp文件與.clw文件。

            bbs.bitsCN.com中國網管論壇


            12.在Studio中快速切換兩個文件
            有時,我們需要在最近使用的兩個文件中快速切換,換Ctrl+F6。這在兩個文件不相今的時候就有用的. bitsCN.nET*中國網管博客

            13.取得源程序預處理后的結果:
            在Studio里,可以在->PROJECT->SETTINGS->C/C++->Project Options中,在最后加上 /P /EP這兩個編譯開關即可做到"只進行預處理".就可以了。編譯以后就可以在源程序目錄中發現“文件名.I ”的文本文件。這就是預處理后的結果。
            (注意注:區分大小定,請用大定/P)

            [bitsCN.Com]


            14.在Debug模式中查看WINAPI調用后的返回值:
            很簡單,且實用:在watch中加入@hr,err。在CSDN的文檔中心有一篇講得更細,請參考。

            www@bitscn@com


            15.產生指定源程序文件的匯編代碼:
            從IDE菜單的Project->Setting打開項目設置,按如下文件做:
            1.先在左邊選擇指定文件,可以多選。
            2. 在右邊的C++屬性頁中,在category中選擇List Files,接著在下面的List Files Type中選擇Assembly and source code(或選擇其它),最后在List File Name中輸入在個C/C++源文件產生的相應的匯編代碼的文件。
            3.編譯整個工程。

            DL@bitsCN_com網管軟件下載

             

            16.手工編譯純資源成dll:
            Rc.exe /v data.rc
            Cvtres.exe /machine:ix86 data.res
            Link /SUBSYSTEM:WINDOWS /DLL /NOENTRY data.res ;編譯成DLL文件
            這種方式創建的DLL是最小的,比起你用Win 32 Dynamic Libray等產生的更小。 [bitsCN.Com]

            17:怎樣快速生成一個與現有項目除了項目名外完全相同的新項目? bitsCN.nET*中國網管博客

            利用File菜單下生成新項目中的Custom AppWizard ,選擇 An existing Project ,然后選擇現有項目的項目文件名(*.dsp)Finish,編譯后就生成一個可以生成與現有項目相同但可以重新取名的項目的AppWizard。你可以象用MFC AppWizard一樣用它。如果不想用了,可以在VC 安裝目錄下Common\MSDev98\Template目錄中刪除該Wizard中.awx和 .pdb文件。    bbs.bitsCN.com

            18:如果想把整個項目拷貝到軟盤,那些文件可以刪掉?   bbs.bitsCN.com

              除了項目文件夾中debug文件夾可以刪除外,.ncb,.clw,.opt 等文件也可以刪除,這些文件Rebuilt all后可以重新生成。   

            19.如果讓控制臺應用程序支持mfc類庫
                可以在控制臺應用程序中include 來引入mfc庫,但是控制臺應用程序缺省是單線程的,mfc是多線程的,為解決該矛盾,在project setting->c/c++ 選項,選擇code generation,在use run-time library 下拉框中選擇debug multithread。
             
            20.如何漢化只有可執行代碼的.exe 文件
                在nt下利用vc open file 以resources方式打開*.exe 文件,直接修改資源文件,然后保存即可。
            [注:我一般是用exescope編輯的]
             


            附:VC項目文件說明
            .dsp 項目參數配置文件,這個文件太重要,重點保護對象。.
            .dsw 工作區文件,重要性一般,因為它信息不我,容易恢復。
            以下文件在項目中是可丟棄的,有些文件刪除后,VC會自動生成的。
            .clw ClassWizard信息文件,實際上是INI文件的格式,有興趣可以研究一下.有時候ClassWizard出問題,手工修改CLW文件可以解決.如果此文件不存在的話,每次用ClassWizard的時候繪提示你是否重建.
            .ncb 無編譯瀏覽文件(no compile browser)。當自動完成功能出問題時可以刪除此文件。build后會自動生成。
            .opt 工程關于開發環境的參數文件。如工具條位置等信息;(可丟棄)
            .aps (AppStudio File),資源輔助文件,二進制格式,一般不用去管他.
            .plg 是編譯信息文件,編譯時的error和warning信息文件(實際上是一個html文件),一般用處不大.在Tools->Options里面有個選項可以控制這個文件的生成.
            .hpj (Help Project)是生成幫助文件的工程,用microsfot Help Compiler可以處理.
            .mdp (Microsoft DevStudio Project)是舊版本的項目文件,如果要打開此文件的話,會提示你是否轉換成新的DSP格式.
            .bsc 是用于瀏覽項目信息的,如果用Source Brower的話就必須有這個文件.如果不用這個功能的話,可以在Project Options里面去掉Generate Browse Info File,可以加快編譯速度. bitsCN.nET*中國網管博客
            .map 是執行文件的映像信息紀錄文件,除非對系統底層非常熟悉,這個文件一般用不著.
            .pch (Pre-Compiled File)是預編譯文件,可以加快編譯速度,但是文件非常大.
            .pdb (Program Database)記錄了程序有關的一些數據和調試信息,在調試的時候可能有用.
            .exp 只有在編譯DLL的時候才會生成,記錄了DLL文件中的一些信息.一般也沒什么用.

            posted @ 2008-04-13 19:31 wrh 閱讀(237) | 評論 (0)編輯 收藏
            如何干凈的刪除一個類?
            1、先刪除項目中對應的.h.cpp文件,(選中后用Delete鍵刪除)
            2
            、保存后退出項目,到文件夾中刪除實際的.h.cpp文件;
            3
            、刪除.clw文件;
            4
            、重新進入項目,進行全部重建(rebuild all)。

            如何建立一個新類?
                
            插入”(Insert)菜單中選擇新建類”(New Class),在彈出的對話框中選擇基類(Base class),在Name中輸入新類的名字(一般都以C開頭)即可。
            如果想要建立一個沒有基類的自定義類,則在New Class對話框中把Class type設置為generic,再輸入類名即可。

            如何把外來文件添加到項目中?
                
            先把外來文件復制到當前項目的目錄下,從項目”(Project)菜單下選擇添加項目”(Add to Project)下的“Files”菜單項,從彈出的打開文件對話框中把外來文件打開即可。

            如何在一個工作區中打開多個項目?
                
            一般編程者都有這樣的經歷:做了一個項目,由于不滿意,想從頭重做,但又想把舊項目的一些可用內容拷到新項目中來,以免做重復工作,這時就需要在新項目中打開舊項目。
                
            先打開新項目,從項目”(Project)菜單下選擇插入項目到工作區”(Insert Project into Workspace),從彈出的打開文件對話框中打開舊項目的.asp文件即可。
                
            之后,可以利用項目”(Project)菜單下的設置活動項目”(Select Active Project)的選項中切換各打開的項目。
            注意:在一個工作區中打開的各項目不能同名。

            如何把項目中的文件分類存放?
            當我們往項目中添加新類時,它會把源文件放在Source Files下,頭文件放在Header Files下。當項目中文件很多時,管理不便,最好添加新節點,把文件分類放置。
            右擊項目節點樹的根節點,選擇“New Folder...”,在彈出的對話框中填入新節點名,則新節點就建立了,用鼠標節點樹中的文件拖入新節點,就可以把文件分類了。
            以上分類只是在項目的節點樹中分類,它不影響文件在磁盤上的位置,所有.cpp文件和.h文件仍在項目的根目錄下,最好文件本身也能分類存放在不同文件夾中。
            Windows下,用新建文件夾在項目的根目錄下建立子文件夾,如DialogClass,把所有對話框類的.cpp文件和.h文件拖入其中。
            回到VC下,右鍵單擊項目樹中更改了路徑的節點,選擇“Properties”,在彈出的對話框中修改文件路徑,如:把原路徑“.\Dialog1.cpp”改為“.\DialogClass\Dialog1.cpp”
            打開Dialog1.cpp文件,修改它包含的文件路徑。如:
            #include "stdafx.h"
            #include "PluckBox.h"
            #include "Dialog1.h"
            改為:
            #include "stdafx.h"
            #include "..\\PluckBox.h"
            #include "Dialog1.h"
            打開ClassWizard,它會提示你文件不存在,單擊確定后,從對話框中用“Browse...”選擇文件所在路徑,則ClassWizard也可正常使用了。



            編輯
            編輯代碼時,跟隨提示消失了怎么辦?
            單 擊工具”(Tools)菜單中的設置”(Options)菜單項,在彈出的Options對話框中選擇Editor制表頁,把它最下方的四個復選框都 選中(Auto list member、Auto type info、Code comments、Auto parameter info),這樣,當用戶輸入“->”“.”時,會自動顯示跟隨提示,減少了輸入負擔。



            對話框
            如何修改對話框的背景色
            在對話框的OnPaint()函數中加入下面語句:
            CRect rect;
            GetClientRect(&rect); //
            計算對話框的尺寸
            dc.FillSolidRect(&rect,RGB(192,248,202)); //
            繪制對話框背景色

            如何讓彈出式對話框具有統一的背景色
            在應用程序類CxxxAppInitInstance()函數中加入下面的語句:
            SetDialogBkColor( RGB(192,248,202) );
            則所有用戶定義的彈出式對話框都以RGB(192,248,202)為背景色,就不需要逐個進行設置了。


            如何讓打開文件對話框能進行多項選擇
            在定制打開文件對話框時,增加OFN_ALLOWMULTISELECT屬性,就可以使打開文件對話框進行多選了。
            如:
            CFileDialog m_Dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
            | OFN_ALLOWMULTISELECT, NULL, NULL );
            之后,用GetStartPosition()函數獲取選擇的起始文件位置,用GetNextPathName()函數獲取各位置上的文件名。
            如:
            if( m_Dlg.DoModal() == IDOK )
            {
            POSITION pos;
            pos = m_Dlg.GetStartPosition();
            while( pos )
            {
            m_Path = m_Dlg.GetNextPathName(pos);
            …………
            }
            }

            為什么用打開文件對話框選擇多個文件到一定數目時,文件沒有打開?
            CFileDialog
            為文件列表設置有緩沖區,當選擇文件過多時,會造成緩沖區溢出,造成一些文件沒有被打開??梢圆捎米远x大緩沖區代替系統緩沖區的方法解決。
            如:
            CFileDialog m_Dlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
            | OFN_ALLOWMULTISELECT, NULL, NULL );//
            定制打開文件對話框
            char* pBuf = new char[20480]; //
            申請緩沖區
            m_Dlg.m_ofn.nMaxFile = 20480; //
            pBuf代替CFileDialog緩沖區
            m_Dlg.m_ofn.lpstrFile = pBuf;
            m_Dlg.m_ofn.lpstrFile[0] = NULL;
            …………
            delete []pBuf; //
            回收緩沖區

            提示對話框(MessageBox
            在視類和對話框類中可使用MFC函數中用的MessageBox()函數彈出提示對話框。這個函數原型為:
            int MessageBox(LPCTSTR lpszText,LPCTSTR lpsCaption=NULL,UINT nType=MB_OK);
            參數:lpszText 顯示的字符串
            lpsCaption
            對話框的標題
            nType
            風格,可為如下值的組合:
            指定下列標志中的一個來顯示消息框中的按鈕,標志的含義如下。
            MB_ABORTRETRYIGNORE
            :消息框含有三個按鈕:Abort,RetryIgnore。
            MB_OK
            :消息框含有一個按鈕:OK。這是缺省值。
            MB_OKCANCEL
            :消息框含有兩個按鈕:OKCancel。
            MB_RETRYCANCEL
            :消息框含有兩個按鈕:RetryCancel。
            MB_YESNO
            :消息框含有兩個按鈕:YesNo
            MB_YESNOCANCEL
            :消息框含有三個按鈕:Yes,NoCancel。
            指定下列標志中的一個來顯示消息框中的圖標:標志的含義如下。
            MB_ICONEXCLAMATION:
            MB_ICONWARNING
            :一個驚嘆號出現在消息框。
            MB_ICONINFORMATION

            MB_ICONASTERISK
            :一個圓圈中小寫字母i組成的圖標出現在消息框。
            MB_ICONOUESTION:
            一個問題標記圖標出現在消息框。
            MB_ICONSTOP:
            MB_ICONERROR

            MB_ICONHAND
            :一個停止消息圖標出現在消息框。
            指定下列標志中的一個來指定缺省的按鈕:標志的含義如下。
            MB_DEFBUTTON1
            :第一個按鈕為缺省按鈕。如果MB_DEFBUTTON2MB_DEFBUTTON3,MB_DEFBUTTON4沒有被指定,則MB_DEFBUTTON1為缺省值。
            MB_DEFBUTTON2
            ;第二個按鈕為缺省按鈕。
            MB_DEFBUTTON3
            :第三個按鈕為缺省按鈕。
            MB_DEFBUTTON4
            :第四個按鈕為缺省按鈕。
            例:提示文件是否存盤:
            int t;
            t=MessageBox(m_PathName+"
            的文字已經改變,要存盤嗎?",
            "
            警告",MB_YESNOCANCEL | MB_ICONWARNING);
            if(t==0 || t==IDCANCEL)
            return;
            if(t==IDYES)
            OnFileSave();
            在文檔類等其它類中不能使用MFC中的MessageBox()函數,只能使用API函數中的MessageBox()函數:
            int MessageBox(HWND hWnd,LPCTSTR lpszText,LPCTSTR lpCaption,UINT UType);
            hWnd:
            標識將被創建的消息框的擁有窗口。如果此參數為NULL,則消息框沒有擁有窗口。
            后三個參數與視類的MessageBox相同,但沒有缺省值,必須設置。
            例:::MessageBox(NULL,m_PathName+"的文字已經改變,要存盤嗎?",
            "
            警告",MB_YESNOCANCEL | MB_ICONWARNING);



            調試
            error C2146: syntax error : missing ';' before identifier ……
            如果出現這個錯誤且錯誤數目很多,通常并不是缺失了分號引起的,而是忘記了添加某頭文件引起的。
            最常見的是新加入了對話框,然后用它的類定義了一個對象,再編譯出現上面的錯誤。
            解決方法是在引用新類的文件中加入#include "類名.h",再編譯,錯誤消失。

            fatal error C1010: unexpected end of file while looking for precompiled header directive
            在一個項目中,如果用“New”向工程中添加了一個.cpp文件,編譯,出錯。
            解決方法:
                               1)   在新建的.cpp文件的開頭加入#include "stdafx.h"。
                               2)   可以使用右鍵點擊項目工程中的該cpp文件,選擇setting,在c/c++欄,選擇PreCompiled headers,然后設置第一選項,選擇不使用預編譯頭,解決這個問題。發布
            Debug
            模式和Release模式
            早就發現用VC編譯出來的.exe文件比用Turbo C編譯出來的文件大了許多,于是就認為VC編譯時一定加了很多沒用的東西,記得當時還做過把VC自動生成的項目中自認為沒用的函數都刪掉的傻事。后來才從網上的文章中了解到還有編譯模式一說。
            Debug
            模式是用來調試用的,它生成的執行文件中含有大量調試信息,所以很大;
            Release
            模式生成的執行文件消除了這些調試信息,可用來作為成品發布。
            默 認情況下是Debug模式,切換方法是在編譯”(Build)菜單中選設置項目配置”(Set Active Configure)。從彈出的對話框中選擇Win32 Release模式,然后再重新編譯。這時在工作目錄下會多出一個Release目錄,其中的exe文件比Debug目錄下的那個要小得多。

            動態鏈接庫和靜態鏈接庫
            VC 做好了一個程序,拿到別人那里卻不能運行,這也是很多編程者都經歷過的,這樣的軟件只能在安裝有VC的機器上運行,也不應拿出去發布。實際上如果你沒有使 用ActiveX控件和自定義的動態DLL技術,只需把MFC的動態鏈接庫打包到你的程序里就可以了,也就是使用靜態鏈接庫。
            設置方法:從項目”(Project)菜單下選擇設置” (Settings),在彈出的對話框中的General選項卡下,把“User MFC in a Shared DLL”改為“User MFC in a Static Library”,關閉對話框后重新編譯即可。
            在靜態鏈接庫下編譯的文件比動態鏈接庫的要大很多,不過,如果使用Release模式編譯,一般也就幾百K,它就可以在沒有安裝VC的機器上運行了。

            發布VC源代碼時,哪些文件可以刪除?
            AfxGetMainWnd()->SetWindowText("文檔標題"+" - "+"程序標題");

            四、設置默認按鈕:
            在定義控件變量時,ClassWizard在構造函數中會把變量初值設為-1,只需把它改為其它值即可。
            如:
            //{{AFX_DATA_INIT(CWEditView)
            m_Ridio1 = 0; //
            初始時第一個單選按鈕被選中
            m_Ridio4 = 0; //
            初始時第四個單選按鈕被選中
            //}}AFX_DATA_INIT

            旋轉控件(Spin)的使用
            當單擊旋轉控件上的按鈕時,相應的編輯控件值會增大或減小。其設置的一般步驟為:
            一、在對話框中放入一個Spin控件和一個編輯控件作為Spin控件的伙伴窗口
            設置Spin控件屬性:Auto buddy、Set buddy integer、Arrow keys
            設置文本控件屬性:Number
            二、用ClassWizardSpin控件定義變量m_Spin,為編輯控件定義變量m_Edit,定義時注意要把m_Edit設置為int型。
            三、在對話框的OnInitDialog()函數中加入語句:
            BOOL CMyDlg::OnInitDialog()
            {
            CDialog::OnInitDialog();

            m_Spin.SetBuddy( GetDlgItem( IDC_EDIT1 ) ); //
            設置編輯控件為Spin控件的伙伴窗口
            m_Spin.SetRange( 0, 10 ); //
            設置數據范圍為0-10
            return TRUE;
            }
            四、用ClassWizard為編輯控件添加EN_CHANGE消息處理函數,再加入語句:
            void CMyDlg::OnChangeEdit1()
            {
            m_Edit = m_Spin.GetPos(); //
            獲取Spin控件當前值
            }

            UpdateData()
            對于可以接收數據的控件,如編輯控件來說,UpdateData()函數至關重要。當控件內容發生變化時,對應的控件變量的值并沒有跟著變化,同樣,當控件變量值變化時,控件內容也不會跟著變。
            UpdateData()
            函數就是解決這個問題的。
            UpdateData(true);
            把控件內容裝入控件變量
            UpdateData(false);
            用控件變量的值更新控件
            如:有編輯控件IDC_EDIT1,對應的變量為字符串m_Edit1
            1
            、修改變量值并顯示在控件中:
            m_Edit1 = _T("結果為50");
            UpdateData(false);
            2
            、讀取控件的值到變量中:
            ClassWizardIDC_EDIT1添加EN_CHANGE消息處理函數,這個函數在編輯控件內容發生變化時執行。
            void CEditView::OnChangeEdit1()
            {
            UpdateData(true); //
            更新變量值
            }



            其它
            如何獲取程序所在的路徑
            也就是獲取你這個程序本身所在的路徑。
            在應用程序類CxxApp的頭文件中定義一個變量CString m_exePath;用來放置程序的路徑名,在應用程序類CxxAppInitInstance()函數中加入如下語句:
            TCHAR m_Path[MAX_PATH];
            GetModuleFileName( NULL, m_Path, MAX_PATH ); //
            獲取程序路徑(包括程序名)
            int i = 0, j;
            while( m_Path[i]!=0 )
            {
            if( m_Path[i]=='\\' )
            j = i;
            i++;
            }
            m_Path[j+1] = '\0';
            m_exePath.Format( "%s", m_Path ); //
            分離路徑名(去掉程序名)
            這段程序執行后,字符串變量m_exePath中放置的就是程序所在路徑,其中不包括程序名。
            獲取程序的位置有什么用呢?
            1
            、打開與應用程序在一起放置的數據文件:
            如果你運行程序過程中使用過打開文件對話框打開過其它路徑下的文件,這時系統的默認路徑就發生了改變,有可能使你原定的數據文件打不開了,如果采用以下方法就可以沒問題了:
            CFile file;
            file.Open( m_exePath+"
            數據文件名", CFile::modeRead );
            2
            、放置程序運行中的臨時文件:
            同樣,當系統的默認路徑發生改變后,程序中生成的臨時文件就會放得到處都是,成了一個個垃圾文件,采用以下方法可使臨時文件只放在程序所在路徑下:
            CFile file;
            file.Open( m_exePath+"
            臨時文件名", CFile::modeCreate | CFile::modeWrite );
            ……
            程序結束時,用下面的方法刪除臨時文件:
            CFile::Remove( m_exePath+"
            臨時文件名" );

            如何在你的程序中執行其它程序
            在自己的程序中調用其它程序的方法有好幾種,這里我介紹我用過的兩種:
            一、WinExec()函數:
            一般用法:WinExec(m_PathName,SW_SHOWNORMAL);
            m_PathName
            為執行程序的路徑名,必須為可執行文件。
            如:WinExec("C:\\Program Files\\Internet Explorer\\iexplore.exe",SW_SHOWNORMAL);為打開IE瀏覽器

            二、ShellExecute()函數:
            一般用法:ShellExecute(NULL,NULL,m_PathName,NULL,_T("c:\\temp"),SW_SHOWNORMAL);
            m_PathName
            為打開的程序路徑名;
            _T("c:\\temp")
            為工作目錄;
            WinExec()不同的是ShellExecute()函數也可以打開非可執行文件,比如你指定的文件為.txt,結果會打開記事本裝入該文件。我用這種方法調用自己制作的幫助文件(.chm)效果很好。

            如果不使用串行化,如何在程序結束時保存文件?
            在文檔-視圖結構中,用串行化自動保存文件在各種VC書上都有介紹?,F在的問題是我不使用串行化,而是自己動手保存,當點擊窗口的關閉按鈕時,如何提示并保存文檔。
            ClassWizard在文檔類(CxxDoc)中添加函數CanCloseFrame(),再在其中加入保存文件的語句就可以了。
            例:
            //
            退出程序
            BOOL CEditDoc::CanCloseFrame(CFrameWnd* pFrame)
            {
            CFile file;
            if(b_Flag) //b_Flag
            為文檔修改標志,在修改文檔時將其置為True
            {
            int t;
            t=::MessageBox(NULL,"
            文字已經改變,要存盤嗎?","警告",
            MB_YESNOCANCEL | MB_ICONWARNING); //
            彈出提示對話框
            if(t==0 || t==IDCANCEL)
            return false;
            if(t==IDYES)
            {
            CString sFilter="Text File(*.txt)|*.txt||";
            CFileDialog m_Dlg(FALSE,"txt",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,(LPCTSTR)sFilter,NULL); //
            定制文件對話框
            int k=m_Dlg.DoModal(); //
            彈出文件對話框
            if(k==IDCANCEL || k==0)
            return false;
            m_PathName=m_Dlg.GetPathName(); //
            獲取選擇的文件路徑名

            file.Open(m_PathName,CFile::modeCreate | CFile::modeWrite);
            file.Write(m_Text,m_TextLen); //
            數據寫入文件
            file.Close();
            }
            }
            return CDocument::CanCloseFrame(pFrame);
            }
            這樣當你單擊窗口上的關閉按鈕時,如果數據已修改了,就會彈出一個提示保存數據的對話框,提示你保存數據。
            程序中的b_Flag是數據修改標志,應該在修改數據時進行設置,m_Text是準備保存的數據,放在文檔內。

            POSITION
            怎么用?
            POSITION
            類型數據用于表征各種列表中元素的位置,它類似于數組的下標,但又有所不同。主要區別是:
            我們不能訪問POSITION型數據的值,也不能對POSITION數據型數據進行加減、比較等運算。
            POSITION型數據訪問列表時,都是采用迭代法,一般格式為:
            POSITION pos; //
            定義pos型變量
            pos = GetHeadPosition(); //
            獲取列表起始元素位置
            while( pos )
            {
            x = GetNext(pos); //
            獲取pos處的列表值,同時修改pos為下一個元素位置
            }
            GetNext()
            就是一種迭代,其格式為:
            TYPE GetNext(POSITION& rPosition);
            首先,它返回當前pos位置處的元素;再就是把pos值修改為下一個元素位置。這樣循環時,可依次取得列表中各元素的值;當到達列表尾時,posNULL,循環結束。
            所以使用POSITION型數據時,你不要試圖用加減等操作去修改它,只能用GetNext()(向后迭代)或GetPrev()(向前迭代)反復迭代來修改它的值。
            如果你想直接到達指定值,還可以用Find()函數或FindIndex()函數獲得指定值的POSITION值。
            POSITION Find(TYPE Value);
            用于在列表中查找值為Value的元素的POSITION值;
            POSITION FindIndex(int nIndex);
            用于獲取列表中第nIndex個元素的POSITION值,nIndex0開始。
            如:
            pos = FindIndex(5); //
            求列表中第5個元素的位置
            x = GetNext(pos); //
            讀取元素的值
            總之,POSITION類型在多種涉及列表的類中提供,不同的類提供的函數有所不同,但用法都是類似的。

            如何從完整的文件路徑中分離文件名和路徑名?
            從路徑中分離文件名:

            CString GetFileName(CString pathname)
            {
            for( int i=pathname.GetLength()-1; i>=0; i-- )
            {
            if( pathname[i]=='\\' )
            break;
            }
            return pathname.Mid( i+1 );
            }
            從路徑中分離路徑名(去除文件名):

            CString GetPath(CString pathname)
            {
            int i = 0, j;
            while( i<pathname.GetLength() )
            {
            if( pathname[i]=='\\' )
            j = i;
            i++;
            }
            return pathname.Left( j+1 );
            }
             
            posted @ 2008-04-13 11:37 wrh 閱讀(420) | 評論 (0)編輯 收藏
            單選鈕用來表示一系列的互斥選項,這些互斥項常常被分成若干個組,每組僅允許用戶選擇一個選項;復選框與單選按鈕相象,不同之處是復選框代表多重選擇,用戶可以選擇一個或多個選項。

              對話框編輯器中各組控件的對齊

              按下Ctrl鍵并單擊要對齊的各個控件,同時選中。最后選中的控件是對齊的基準,仔細觀察,它周圍的8個小方框是實心的,而其它被選控件周圍的小方框是空心的。

              在Layout菜單中選擇Make Same Size的Both,可以統一控件尺寸,所選控件尺寸與基準控件相同。在Layout菜單中選擇Align的Left,可以使所有被選控件的左邊與基準控件對齊。選擇Layout菜單中Align的Space Evenly的Down,可以使被選控件垂直間距相等。

              單選按鈕和復選框的使用
              為了方便說明,我們假定創建了基于對話框的MFC應用程序,工程名為RadioAndCheckButton。對話框資源加入兩個組框 ,第一個組框‘性別’,內有‘男’,‘女’兩個單選鈕;第二個組框是‘愛好’,內有‘足球’‘排球’‘藍球’三個復選框,如下表:

            控件類型 ID 標題(Caption) 其它屬性
            組框 缺省 性別 缺省
            單選鈕 IDC_SEX1 Group
            單選鈕 IDC_SEX2 缺省
            組框 缺省 愛好 缺省
            復選框 IDC_HOBBY1 足球 缺省
            復選框 IDC_HOBBY2 排球 缺省
            復選框 IDC_HOBBY3 藍球 缺省

              設置控件的Tab Order

              單擊Layout菜單下的Tab Order命令,設置控件的TAB鍵順序(Tab Order),保證單選鈕的Tab Order連續。

              以Tab Order為序,從Group屬性為真的控件開始(包括該控件),到下一個Group屬性為真的控件結束(不包括該控件),所有的這些控件將組成一個組。對于單選鈕,同一組內同時只能有一個處于被選中狀態。對于由資源編輯器生成的單選按鈕控件,在默認情況由Windows自動處理同組控件之間的互斥關系。

              具體使用單選鈕和復選框

              1、調用 CButton的成員函數SetCheck設置單選鈕和復選框的選中狀態。該成員函數帶有一個類型為整形的參數,該參數為0表示清除選中按鈕的選中狀態,參數為1表示設置選中按鈕的選中狀態。參數為2表示把三態復選框設為不確定狀態。

              復選框的Tristate屬性:創建三態復選框。除了處于“選中”和“不選中”狀態外,三態復選框還可以處于變灰狀態。通常,復選框的變灰狀態表示其選中狀態不確定。在很多軟件的安裝程序中,變灰往往表示僅選中該組件的一部分。

              注意,如果我們在程序中調用SetCheck設置同一組中某一單選鈕為選中狀態,并不意味著同時清除同一組中其它單選鈕的選中狀態。否則,將導致同一組中的兩個按鈕同時處于選中狀態。這是應該避免的。因此,如果我們通過代碼改變了單選鈕的選中狀態,一定要記得同時清除同組的其它單選鈕的選中狀態。

              2、調用 CButton的成員函數GetCheck返回單選鈕的選中狀態。該函數的函數原型是

            int GetCheck( ) const;

              返回值可以是0、1、2,分別代表按鈕處于未選中狀態、選中狀態或中間狀態(對三態復選框而言)。

              3、調用類CWnd的成員函數GetCheckedRadioButton返回同一組單選鈕中哪一個被選中。該成員函數原型如下:

            int GetCheckedRadioButton(int nIDFirstButton,int nIDLastButton);

              第一個參數nIDFirstButton是同一組中的第一個單選鈕控件的ID,nIDLastButton是同一組中最后一個單選鈕控件的ID。成員函數GetCheckedRadioButton返回指定組中所選中的單選鈕的ID,如果沒有按扭被選中,則返回0。

              注意,若干個單選鈕是否屬于同一組是以其Tab順序來排定的,而GetCheckedRadioButton函數是以ID順序來檢查按鈕的選定狀態的。因此,如果傳遞給函數GetCheckedRadioButton的第一個參數的值大于第二個參數的值時,其返回值總是為0,而事實上由這兩個參數指定的單選鈕的Tab順序可能恰恰相反。因此,一般情況下我們應該盡量保證同一組單選鈕的資源ID是連續遞增的。通常這些資源ID是在頭文件Resource.h中定義的。如果你同一組的單選鈕不是一次創建的,那么它們的資源ID可能不是連續遞增的,甚至可能是相反的。我們可以手動的修改資源頭文件中的宏定義,以保證GetCheckedRadioButton函數得到正確的結果。

              例:
            UINT nSex=GetCheckedRadioButton(IDC_SEX1,IDC_SEX2); Switch(nSex) { Case IDC_SEX1: ; ……

              4、使用ClassWizard為單選鈕或復選框添加變量,來使用單選鈕或復選框

              一般,一組單選按鈕的第一個屬性選中Group,注意,只有選中Group屬性的單選鈕的ID 才能在ClassWizard中添加變量。

              在對話框類給一組單選鈕加入一個成員變量,單選鈕(組中的第一個按鈕)的數據變量類型是int,0表示選擇了組中的第一個單選鈕,1表示選擇了第二個,-1表示沒有一個被選中。例如:給單選鈕IDC_SEX1添加int型變量m_nSex,并在執行文件中加入如下代碼:

            ……
            UpdateData(TRUE);
            if(m_nSex==0) //選中‘男’
            ;
            else if(m_nSex==1) //選中‘女’
            ;
            else
            ;
            ……

              復選框的數據變量類型是BOOL,TRUE表示選中,FALSE表示未選中。例如:給復選框IDC_HOBBY1添加BOOL型變量m_hobby1,并在執行文件中加入如下代碼:

            ……
            m_hobby1=TRUE;
            UpdateData(FALSE);
            ……

              5、使用消息映射宏ON_CONTROL_RANGE

              單選鈕和復選框都可以響應BN_CLICKED消息,如果一組中有多個單選鈕,分別創建消息處理函數就比較麻煩了,利用MFC的消息映射宏ON_CONTROL_RANGE可以避免這種麻煩,該映射宏把多個ID連續的控件發出的消息映射到同一個處理函數上,這樣,我們只要編寫一個消息處理函數就可以對一組單選鈕的BN_CLICKED消息作出響應,ClassWizard不支持該宏,必須手工創建。

              ON_CONTROL_RANGE消息映射宏的第一個參數是控件消息碼,第二和第三個參數分別指明了一組連續的控件ID中的頭一個和最后一個ID,最后一個參數是消息處理函數名。注意,起始、 終止ID號必須是連續的,如果不能確定該組控件的ID是否是連續,請用View->Resource Symbols…命令檢查控件的ID值,如果發現兩個ID是不連續的,讀者可以改變對ID的定義值使之連續,但要注意改動后的值不要與別的ID值發生沖突。

              在BEGIN_MESSAGE_MAP 和 END_MESSAGE_MAP之間 //}}AFX_MSG_MAP之后加入

            ON_CONTROL_RANGE(BN_CLICKED,IDC_SEX1,IDC_SEX2,OnSexClicked)

              然后在對話框類的頭文件的AFX_MSG 塊中聲明消息處理函數,

            ……
            //{{AFX_MSG(CMyView)
            ……
            //}}AFX_MSG
             afx_msg void OnSexClicked (UINT nCmdID); 
            DECLARE_MESSAGE_MAP()
            ……
              最后,在對話框類所在CPP文件的最后插入消息處理函數,如下所示:
            CRadioAndCheckButtonDialog:: OnSexClicked,
             void CRadioAndCheckButtonDialog:: OnSexClicked (UINT nCmdID)  
             { 
            ……
            switch(nID)
            {
            case IDC_SEX1:
            AfxMessageBox("IDC_SEX1");
            break;
            case IDC_SEX2:
            AfxMessageBox("IDC_SEX2");
            break;
            ……
            }        
              6、使用IsDlgButtonChecked 函數判斷單選鈕或復選框是否被選中

              CWnd::IsDlgButtonChecked函數,用來判斷單選按鈕或檢查框是否被選擇,該函數的聲明為
            UINT IsDlgButtonChecked(int nIDButton) const;

              參數nIDButton為按鈕的ID。若按鈕被選擇,則函數返回1,否則返回0,若按鈕處于不確定狀態,則返回值為2。

            ……
             if(IsDlgButtonChecked(IDC_SEX1)) 
            ……

              以上是使用單選鈕和復選框最常用的幾種方法。

            posted @ 2008-04-12 19:23 wrh 閱讀(635) | 評論 (0)編輯 收藏

            1、改變下拉框大?。合赛c向下的箭頭,就可以調整下拉框大小

            2、如果 ComboBox 的 Sorted 屬性設置為 true,
               則新添加項將按字母順序插入到列表中。
               否則,在列表的結尾處插入項。

            3、要立即響應選擇框的改變(即選擇框一改變選項,就立刻將結果傳遞進去)!
               響應他的哪個消息比較好?

               如果是只能選擇的響應ON_CBN_SELCHANGE
               如果是可以編輯的,那么要立刻響應編輯就是ON_CBN_EDITCHANGE

            4、CBN_SELENDOK是什么作用?
               This notification message is sent when the user clicks a list item,
               or selects an item and then closes the list.
               It indicates the user's selection is to be processed

            5、介紹一下列表框幾種常用的消息映射宏:

               ON_CBN_DBLCLK 鼠標雙擊
               ON_CBN_DROPDOWN 列表框被彈出
               ON_CBN_KILLFOCUS / ON_CBN_SETFOCUS 在輸入框失去/得到輸入焦點時產生
               ON_CBN_SELCHANGE 列表框中選擇的行發生改變
               ON_CBN_EDITUPDATE 輸入框中內容被更新
               使用以上幾種消息映射的方法為定義原型如:afx_msg void memberFxn( );的函數,
               并且定義形式如ON_Notification( id, memberFxn )的消息映射。
               如果在對話框中使用組合框,Class Wizard會自動列出相關的消息,并能自動產生消息映射代碼。

            6、改變ComboBox的下拉列表框寬度
               一般情況下,列表框的寬度和選擇框是一樣寬的,為了讓列表框變的更寬,可以用
               m_Combobox.setdroppedwidth(int width); 來調整 他的寬度

            7、如何使控鍵ComboBox不能輸入只能在下拉菜單中選擇?
               VC6中style屬性設為csDropDownList
               VC2005中Type屬性設為Drop List

            8、設置當前項或得到當前是第幾項
               
               m_ComboBox1.SetCurSel(N);    //SetCurSel函數可改變標簽控件當前選定的項目
                //這個N可以是-1,表示無選擇,0表示第一項,1表示第二項。。
               m_ComboBox1.GetCurSel();     //得到當前是第幾項.0是第一項,1是第二項

            posted @ 2008-04-12 18:53 wrh 閱讀(1477) | 評論 (0)編輯 收藏
            僅列出標題
            共25頁: First 17 18 19 20 21 22 23 24 25 

            導航

            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            統計

            常用鏈接

            留言簿(19)

            隨筆檔案

            文章檔案

            收藏夾

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            伊人久久大香线蕉综合网站| 伊人 久久 精品| 亚洲精品乱码久久久久久蜜桃不卡| 青草影院天堂男人久久| 久久国产精品99精品国产| 亚洲av伊人久久综合密臀性色| 日韩欧美亚洲综合久久影院Ds | 久久久精品视频免费观看| 久久99热精品| 久久99精品久久久久久秒播| 国产精品狼人久久久久影院| 91精品国产91热久久久久福利| 久久精品国产精品国产精品污| 久久精品国产精品亚洲精品| 久久亚洲国产中v天仙www| 国产精品一区二区久久精品| 一级做a爰片久久毛片人呢| 99热成人精品免费久久| 久久久久久久久久免免费精品| 欧美精品丝袜久久久中文字幕| 亚洲天堂久久久| 久久精品国产亚洲AV香蕉| 精品免费tv久久久久久久| 国产日韩欧美久久| 中文字幕亚洲综合久久菠萝蜜| 精品久久久久久无码不卡| 久久婷婷五月综合97色| 国产巨作麻豆欧美亚洲综合久久 | 欧美丰满熟妇BBB久久久| 国产精品久久久久久搜索| 久久影院久久香蕉国产线看观看| 久久国语露脸国产精品电影| 99久久婷婷免费国产综合精品| 久久久91人妻无码精品蜜桃HD| 99久久国产宗和精品1上映| 狠狠色丁香久久婷婷综合五月| 久久www免费人成精品香蕉| 伊人久久精品无码二区麻豆| 日本精品久久久久中文字幕8| 国产精品久久新婚兰兰| 99久久国产免费福利|