• <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>

            xbgs

            C++博客 首頁 新隨筆 聯系 聚合 管理
              7 Posts :: 0 Stories :: 13 Comments :: 0 Trackbacks

            2008年12月17日 #

                消息映射、循環機制是Windows程序運行的基本方式。VC++ MFC 中有許多現成的消息句柄,可當我們需要完成其它的任務,需要自定義消息,就遇到了一些困難。
                在MFC ClassWizard中不允許添加用戶自定義消息,所以我們必須在程序中添加相應代碼,以便可以象處理其它消息一樣處理自定義消息。通常的做法是采取以下步驟:
            第一步:定義消息。
             推薦用戶自定義消息至少是WM_USER+100,因為很多新控件也要使用WM_USER消息。
            #define WM_MY_MESSAGE (WM_USER+100) 
            第二步:實現消息處理函數。
            該函數使用WPRAM和LPARAM參數并返回LPESULT。
            LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
            {
                // TODO: 處理用戶自定義消息
                ...
                return 0;

            第三步:在類頭文件的AFX_MSG塊中說明消息處理函數:
            class CMainFrame:public CMDIFrameWnd
            {
                ...
                // 一般消息映射函數
                protected:
                // {{AFX_MSG(CMainFrame)
                afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
                afx_msg void OnTimer(UINT nIDEvent);
                afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
                //}}AFX_MSG
                DECLARE_MESSAGE_MAP()
            }
            第四步:在用戶類的消息塊中,使用ON_MESSAGE宏指令將消息映射到消息處理函數中。
            BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
            //{{AFX_MSG_MAP(CMainFrame)
                ON_WM_CREATE()
                ON_WM_TIMER()
                ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
            //}}AFX_MSG_MAP
            END_MESSAGE_MAP()

             
              如果用戶需要一個定義整個系統唯一的消息,可以調用SDK函數RegisterWindowMessage定義消息:
            static UINT WM_MY_MESSAGE=RegisterWindowMessage("User");

              并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步驟同上。
              當需要使用自定義消息時,可以在相應類中的函數中調用函數PostMessage或SendMessage發送消息PoseMessage(WM_MY_MESSAGE,O,O);
            如果向其他進程發送消息可通過如下方法發送消息:
            DWORD result;
            SendMessageTimeout(wnd->m_hWnd, // 目標窗口
                               WM_MY_MESSAGE, // 消息
                               0, // WPARAM
                               0, // LPARAM
                               SMTO_ABORTIFHUNG |
                               SMTO_NORMAL,
                               TIMEOUT_INTERVAL,
                               &result);
            以避免其它進程如果被阻塞而造成系統死等狀態。
                可是如果需要向其它類 (如主框架、子窗口、視類、對話框、狀態條、工具條或其他控件等 發送消息時上述方法顯得無能為力,而在編程過程中往往需要獲取其它類中的某個識別信號 框架給我們造成了種種限制,但是可以通過獲取某個類的指針而向這個類發送消息, 而自定義消息的各種動作則在這個類中定義,這樣就可以自由自在的向其它類發送消息了。 


              下面舉的例子敘述了向視類和框架類發送消息的方法:
            ★在主框架類中向視類發送消息:
            1.視類中定義消息:
            ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //定義消息映射

            2.視類定義消息處理函數:
            LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
            {
                // TODO: 處理用戶自定義消息
                ...
                return 0;
            }
            3.發送消息的測試函數
            void CMainFrame::OnTest()
            {
                CView * active = GetActiveView();//獲取當前視類指針
                if(active != NULL)
                active->PostMessage(WM_MY_MESSAGE,0,0);
            }
            ★在其它類中向視類發送消息:
            //發送消息的測試函數
            void CMyDialog::OnTest()
            {
                CMDIFrameWnd *pFrame;
                CMDIChildWnd *pChild;
                CView *pView;
                //獲取主窗口指針
                pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
                // 獲取子窗口指針
                pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
                //獲取視類指針
                pView = pChild->GetActiveView();
                if(pView != NULL)
                pView->PostMessage(WM_MY_MESSAGE,0,0);//發送消息
            }
            其余步驟同上。
            ★在視類中向主框架發送消息:
            首先在主框架中定義相關的消息,方法同上,然后在發送消息的函數中添加代碼如下
            //發送消息的測試函數
            void CMessageView::OnTest()
            {
                CFrameWnd * active = GetActiveFrame();//獲取當前主窗口框架指針
                if(active != this)
                active->PostMessage(WM_MY_MESSAGE,0,0);
                return 0;
            }
              在其它類中向不同的類發送消息可依次方法類推,這樣我們的程序就可以的不受限制向其它類和進程發送消息,而避免了種種意想不到的風險。
             
            【實例】:
              下面一個例子程序為多文檔程序里在一對話框中向視類發送消息,詳述了發送自定義消息的具體過程。
              實現步驟:

            第一步:在VC++中新建工程Message,所有ClassWizard步驟選項均為缺省,完成。
            第二步:在主菜單中添加測試菜單為調出對話框,在框架類中建立相應函數OnTest().
            第三步:在資源中建立對話框,通過ClassWizard添加新類TestDialog,添加測試按鈕, 在對話框類中建立相應函數OnDialogTest()
            //通過對話框按鈕發送消息的函數
            void TestDialog::OnDialogTest()
            {
                CMDIFrameWnd *pFrame;
                CMDIChildWnd *pChild;
                CView *pView;
                //獲取主窗口指針
                pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;
                // 獲取子窗口指針
                pChild = (CMDIChildWnd *) pFrame->GetActiveFrame();
                //獲取視類指針
                pView = pChild->GetActiveView();
                if(pView != NULL)
                pView ->PostMessage(WM_MY_MESSAGE,0,0);//發送消息
            }
              在Message.h頭文件中添加如下語句:
            static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
            第四步:在視類中添加自定義消息:
            在頭文件MessageView.h中添加消息映射
            protected:
            //{{AFX_MSG(CMessageView)
            //}}AFX_MSG
            afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //此行為添加代碼
            DECLARE_MESSAGE_MAP()
            在視類文件MessageView.cpp中的消息映射中添加自定義消息映射
            BEGIN_MESSAGE_MAP(CMessageView, CView)
            //{{AFX_MSG_MAP(CMessageView)
            //}}AFX_MSG_MAP
            // Standard printing commands
            ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //此行添加代碼定義唯一消息
            END_MESSAGE_MAP()
            添加相應的0消息處理函數
            LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
            {
                CRect rect;
                GetClientRect(&rect);
                InvalidateRect(&rect);
                test=!test;
                return 0;
            }
            在MessageView.h中添加布爾變量 public:BOOL test;
            在視類構造函數中初始化 test變量:test=FALSE;
            修改CMessageView::OnDraw()函數
            void CMessageView::OnDraw(CDC* pDC)
            {
                CMessageDoc* pDoc = GetDocument();
                ASSERT_VALID(pDoc);
                // 以下程序顯示消息響應效果
                if(test)
                pDC->TextOut(0,0,"消息響應!");
            }
            第五步:顯示測試對話框
            在MainFrame類中包含對話框頭文件:
            #include "TestDialog.h";
            OnTest()函數中添加代碼
            void CMainFrame::OnTest()
            {
                TestDialog dialog;
                dialog.DoModal();
            }
            運行程序,在測試菜單打開對話框,點擊測試按鈕即可看到結果
            posted @ 2008-12-17 13:18 讓心飛翔 閱讀(1571) | 評論 (0)編輯 收藏

            2006年6月23日 #

            很多人都覺得自己的程序的界面不那么美觀,往往VC默認產生的對話框比較單調,因此很多人往往找到很多其它的控件對對話框進行美化修飾,例如給靜態控件設置字體,設置背景顏色等等, 其實這些完全可以由VC自己的WM_CTLCOLOR消息來完成!

            WM_CTLCOLOR消息用來完成對EDIT、STATIC、BUTTON等控件設置背景和字體顏色,其用法如下:

            1.首先在自己需要設置界面的對話框上點擊右鍵-->建立類向導-->加入WM_CTLCOLOR消息-->自動生成OnCtlColor()函數,此函數可以對本對話框的控件的界面外觀做修飾,用法如下:
            將類向導產生的函數做如下修改:

            HBRUSH CDialogColor::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
            {
            HBRUSH hbr = CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
            // TODO: Change any attributes of theDC here
            //設置顯示字體
            CFont * cFont=new CFont;
            cFont->CreateFont(16,0,0,0,FW_SEMIBOLD,FALSE,FALSE,0,
            ANSI_CHARSET,OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
            DEFAULT_PITCH&FF_SWISS,"Arial");
            //對特定的控件做修改
            switch()
            {
            case CTLCOLOR_STATIC: //對所有靜態文本控件的設置
            {
            pDC->SetBkMode(TRANSPARENT);
            //設置背景為透明
            pDC->SetTextColor(RGB(255,255,0)); //設置字體顏色
            pWnd->SetFont(cFont); //設置字體
            HBRUSH B = CreateSolidBrush(RGB(125,125,255));
            //創建畫刷
            return (HBRUSH) B; //返回畫刷句柄
            }
            case CTLCOLOR_EDIT: //對所有編輯框的設置
            {
            pDC->SetBkMode(TRANSPARENT);
            pDC->SetTextColor(RGB(255,255,0));
            pWnd->SetFont(cFont);
            HBRUSH B = CreateSolidBrush(RGB(125,125,255));
            return (HBRUSH) B;
            }
            default:
            return CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
            }
            }

            注:case的類別有以下幾種:
            CTLCOLOR_BTN 按鈕控件
            CTLCOLOR_DLG 對話框
            CTLCOLOR_EDIT 編輯框
            CTLCOLOR_LISTBOX 列表框
            CTLCOLOR_MSGBOX 消息框
            CTLCOLOR_SCROLLBAR 滾動條
            CTLCOLOR_STATIC 靜態文本

            2.你可能覺得對所有的控件使用統一的界面設置覺得不自由,其實VC同樣可以對特定的ID的控件進行設置,方法如下:


            switch (pWnd->GetDlgCtrlID())
            {
            //針對ID為IDC_CTL1、IDC_CTL2和IDC_CTL3的控件進行同樣的設置
            case IDC_CTL1:
            case IDC_CTL2:
            case IDC_CTL3:
            {
            pDC->SetBkMode(TRANSPARENT);
            pDC->SetTextColor(RGB(255,255, 0));
            pWnd->SetFont(cFont);
            HBRUSH B = CreateSolidBrush(RGB(125,125,255));
            return (HBRUSH) B;
            }
            default:
            return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
            }
            posted @ 2006-06-23 23:21 讓心飛翔 閱讀(6955) | 評論 (1)編輯 收藏

            ??? 在對話框程序的打印功能中,如果使用針式打印機,那么你可能希望連續打印的多個表中不換頁。我們知道,在使用打印功能的時候,每當 dc.startpage()就會開始一頁的打印,而dc.endpage()就會結束一頁的打印,那么如何能使多個dc.startpage()與 dc.endpage()不換頁而實現連續打印呢,方法如下: 假設我們要打印m_nTotalNum個表,每個表有m行,那么要實現m_nTotalNum個表連續打印不換頁可以如下實現:(由于打印機制問題,在打滿一張后是必須要換頁的,我們的做法是在換頁的地方讓給它留出一定的空白,不太影響表的連續性)
            /////////////主函數
            void CDlgTest::PrintOneNum() 
            {
            CDC dc;
            CPrintDialog printDlg(FALSE);
            CPrintInfo Info;
            printDlg.GetDefaults();
            dc.Attach(printDlg.GetPrinterDC());
            dc.m_bPrinting=TRUE;
            CString strTitle;
            strTitle.LoadString(AFX_IDS_APP_TITLE);
            DOCINFO di;
            ::ZeroMemory(&di,sizeof(DOCINFO));
            di.cbSize=sizeof(DOCINFO);
            di.lpszDocName=strTitle;
            if(dc.m_hDC)
            {
            BOOL bPrintingOk=dc.StartDoc(&di);
            CPrintInfo Info;
            m_nCurrentNum_WhenPrint=1; //當前表數為1,這個用來控制打印的表數
            int nPageTotalScale=0; //初始化從0開始
            Info.m_nCurPage=1; //從第一頁開始
            dc.StartPage(); //開始打印頁
            for(;;)
            {
            //打印完需要的表數m_nTotalNum則退出循環
            if(m_nCurrentNum_WhenPrint >m_nTotalNum) break;
            else //打印一張表
            {
            nPageTotalScale=OnPrintReport (&dc,&Info,nPageTotalScale, m_nCurrentNum_WhenPrint);
            m_nCurrentNum_WhenPrint ++;
            nPageTotalScale+=30; //打印下一張表的行距從+30開始
            }
            }
            bPrintingOk=(dc.EndPage()>0); //結束一頁
            m_nCurrentNum_WhenPrint =0;
            if(bPrintingOk)
            dc.EndDoc();
            else
            dc.AbortDoc();
            }
            else
            {
            MessageBox("請檢查打印機是否連接完好?","我的程 序",MB_ICONEXCLAMATION);
            }
            dc.Detach();
            }

            /////////////打印函數
            int CdlgTest::OnPrintReport(CDC *pDC, CPrintInfo *pInfo, 
            int nXBasePointWhenPrint, int m_nCurrentNum_WhenPrint)
            {
            int nXCurrentPoint=nXBasePointWhenPrint; //進行行控制的變量
            //--------換頁---------
            if(nXCurrentPoint+210> 2000) //210為將要占用的長度
            {
            pDC->EndPage();
            pDC->StartPage();
            nXCurrentPoint=0;
            pInfo->m_nCurPage++;
            }
            nXCurrentPoint+=210;
            pDC->TextOut(0,nXCurrentPoint,"我的報表內容,從0-210的表長度 ");
            //每當打印的輸出要換行的時候就要判斷if(nXCurrentPoint+將要使用的高度> 2000)2000為規定的一張紙的高度。 如果大于紙張高度就要換頁。這樣就保證打印內容連續。
            return nXCurrentPoint; //最后返回打印完當前表時當前的頁面高度,
            以便下一張表接著這個高度打印

            }
            posted @ 2006-06-23 23:18 讓心飛翔 閱讀(974) | 評論 (0)編輯 收藏

            ?在單文檔中的使用方法
            步驟一 初始化

            在CView類的.h頭文件中包含文件:
            ??? #include "Gridctrl.h"

            并且手寫加入如下的成員函數:
            ????CGridCtrl * m_pGridCtrl;

            步驟二 構造與析構

            構造函數中:
            ???m_pGridCtrl = NULL;
            析構函數中:
            ???if(m_pGridCtrl)
            ???????delete m_pGridCtrl;


            步驟三 如果需要打印功能的話添加同名打印函數代碼

            在CView類的OnBeginPrinting()函數中添加如下代碼:
            if(m_pGridCtrl)
            ????m_pGridCtrl->OnBeginPrinting(pDC,pInfo);
            //簡單吧,這就是類的好處

            其它兩個打印函數也一樣的做法.

            步驟四 在OnInitaUpdate()函數中或者你自己添加的要顯示Grid的消息函數中如下初始化:

               //創建非模式對話框
            CDlg *dlg;
            dlg=new CDlg();
            dlg->Create(IDD_Dlg,this);

            //初始化GridCtrl控件
            if(m_pGridCtrl!=NULL)
            {
            delete m_pGridCtrl;
            m_pGridCtrl=NULL;
            }
            if (m_pGridCtrl == NULL)
            {
            // Create the Gridctrl object
            m_pGridCtrl = new CGridCtrl;
            if (!m_pGridCtrl) return 0;
            // Create the Gridctrl window
            CRect rect;
            GetClientRect(rect);
            m_pGridCtrl->Create(rect, this, 100);
            // fill it up with stuff
            m_pGridCtrl->SetEditable(false);
            m_pGridCtrl->SetTextBkColor(RGB(0xFF, 0xFF, 0xE0)); //黃色背景
            m_pGridCtrl->EnableDragAndDrop(false);
            try {
            m_pGridCtrl->SetRowCount(k); //設置行數為k行
            m_pGridCtrl->SetColumnCount(4); //k列
            m_pGridCtrl->SetFixedRowCount(1); //標題行為一行
            m_pGridCtrl->SetFixedColumnCount(1); //同上
            }
            catch (CMemoryException* e)
            {
            e->ReportError();
            e->Delete();
            return 0;
            }
            //填充列標題
            int row=0;
            for(int col=0;col<4;col++)
            {
            GV_ITEM Item;
            Item.mask = GVIF_TEXT|GVIF_FORMAT;
            Item.row = row;
            Item.col = col;
            if(col==0){
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.strText.Format(_T("【類別】"),col);
            }
            else if(col==1){
            Item.nFormat = DT_LEFT|DT_WORDBREAK;
            Item.strText.Format(_T("第一列"),col);
            }
            else if(col==2){
            Item.nFormat = DT_LEFT|DT_WORDBREAK;
            Item.strText.Format(_T("第二列"),col);
            }
            m_pGridCtrl->SetItem(&Item);
            }
            // fill rows/cols with text
            for (row = 1; row < k; row++)
            for (col = 0; col < h; col++)
            {
            GV_ITEM Item;
            Item.mask = GVIF_TEXT|GVIF_FORMAT;
            Item.row = row;
            Item.col = col;
            if (col < 1) { //行標題頭
            Item.nFormat = DT_CENTER|DT_VCENTER
            |DT_SINGLELINE|DT_END_ELLIPSIS
            |DT_NOPREFIX;
            Item.strText.Format(_T("%d"),row);
            }
            else if(col==1){ //第一列的值
            Item.nFormat = DT_CENTER|DT_VCENTER
            |DT_SINGLELINE|DT_END_ELLIPSIS
            |DT_NOPREFIX;
            str="aa";
            Item.strText.Format(_T("%s"),str);
            }else if(col==2){ //第二列第值
            Item.nFormat = DT_CENTER|DT_VCENTER
            |DT_SINGLELINE|DT_END_ELLIPSIS
            |DT_NOPREFIX;
            CString str;
            str="bb";
            Item.strText.Format(_T("%s"),str);
            }
            m_pGridCtrl->SetItem(&Item);
            }
            m_pGridCtrl->AutoSize();

            //--------------設置行列距------------------
            for(int a=1;a<m;a++)
            m_pGridCtrl->SetRowHeight(a,21); //設置各行高
            m_pGridCtrl->SetRowHeight(0,24); //設置0行高
            m_pGridCtrl->SetColumnWidth(1,110); //設置2列寬
            m_pGridCtrl->SetColumnWidth(2,160); //設置3列寬
            m_pGridCtrl->SetColumnWidth(3,100); //設置4列寬
            }
            上例取自實際工程,稍有修改!
            部分注釋:
            void SetVirtualMode(TRUE) //設為虛模式
            BOOL SetRowCount(int nRows) //設置總的行數。
            BOOL SetFixedRowCount(int nFixedRows = 1)//設置固定的行數據
            BOOL SetColumnCount(int nCols) //設置列數
            BOOL SetFixedColumnCount(int nFixedCols = 1)//設置固定的列數


            步驟五: 添加WM_SIZE消息,調整控件的界面占屏幕大小

            ??if(m_pGridCtrl->GetSafeHWnd())
            ???{
            ??????CRect rect;
            ?????GetClientRect(rect);
            ?????m_pGridCtrl->MoveWindow(rect);
            ???}



            ?在對話框中的使用方法

            步驟一 創建數據顯示表格對話框

            在資源管理器中新創建一個對話框,假設為CDlgTestReportBox。 從工具箱中加入Custom Control,就是人頭像的那個,將其區域拉伸至要顯示數據表格的大小,充滿整個對話框。

            在CDlgTestReportBox類的頭文件中:

            #include "GridCtrl.h"

            再定義成員變量:

            CGridCtrl* m_pGrid;

            添加OnShowWindow()消息處理函數如下:

            void CDlgTestReportBox::OnShowWindow(BOOL bShow, UINT nStatus) 
            {
            CDialog::OnShowWindow(bShow, nStatus);
            // TODO: Add your message handler code here
            if(m_pGrid!=NULL)
            {
            delete m_pGrid;
            m_pGrid=NULL;
            }
            if(m_pGrid==NULL)
            {
            m_pGrid=new CGridCtrl;
            CRect rect;
            GetDlgItem(IDC_ReportAera)->GetWindowRect(rect); //得到顯示區域
            ScreenToClient(&rect);
            m_pGrid->Create(rect,this,100);
            m_pGrid->SetEditable(false);
            m_pGrid->SetTextBkColor(RGB(0xFF, 0xFF, 0xE0)); //黃色背景
            try
            {
            m_pGrid->SetRowCount(10); //初始為10行
            m_pGrid->SetColumnCount(11); //初始化為11列
            m_pGrid->SetFixedRowCount(1); //表頭為一行
            m_pGrid->SetFixedColumnCount(1); //表頭為一列
            }
            catch (CMemoryException* e)
            {
            e->ReportError();
            e->Delete();
            // return FALSE;
            }
            for (int row = 0; row < m_pGrid->GetRowCount(); row++)
            for (int col = 0; col < m_pGrid->GetColumnCount(); col++)
            {
            //設置表格顯示屬性
            GV_ITEM Item;
            Item.mask = GVIF_TEXT|GVIF_FORMAT;
            Item.row = row;
            Item.col = col;
            if(row==0&&col==0) //第(0,0)格
            {
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.szText.Format(_T("報表顯示"),col);
            }
            else if (row < 1) //設置0行表頭顯示
            {
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.szText.Format(_T(" 項目%d"),col);
            }
            else if (col < 1) //設置0列表頭顯示
            {
            if(row< m_pGrid->GetRowCount()-4)
            {
            Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
            Item.szText.Format(_T("第%d次"),row);
            }
            }
            else
            {
            Item.nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
            Item.szText.Format(_T(""),2);
            }
            m_pGrid->SetItem(&Item);
            }
            m_pGrid->Invalidate();
            }
            //--------------設置行列距------------------
            for(int a=0;aGetRowCount();a++)
            m_pGrid->SetRowHeight(a,16); //設置各行高
            m_pGrid->SetColumnWidth(0,58); //設置0列寬
            for(int b=1;bGetColumnCount();b++)
            m_pGrid->SetColumnWidth(b,59); //設置各列寬
            }

            ?

            步驟二 嵌入上面的對話框 顯示數據

            在你需要顯示數據的對話框上的頭文件中,假設為CDlgTest,加入

            #include "GridCtrl.h"

            CDlgTestReportBox* m_pTestReportBox;

            將數據顯示對話框放入你的對話框相應位置上,在CDlgTest::OnInitDialog() 中:

            if(!m_pTestReportBox)
            {
            ?????m_pTestReportBox=new CDlgTestReportBox(this);
            }

            m_pTestReportBox->Create(IDD_DlgTestReportBox,this);

            //定義區域變量
            CRect rectDraw;
            GetDlgItem(IDC_AeraReport)->GetWindowRect(rectDraw);
            ScreenToClient(&rectDraw); //動態測試數據顯示區域rectDraw

            //將對應的對話框放到指定區域
            m_pTestReportBox->MoveWindow(rectDraw);
            m_pTestReportBox->ShowWindow(SW_SHOW);

            自定義填充數據的函數:CDlgTest::FillGrid() 如下:

            CGridCtrl* pGrid=m_pTestReportBox->m_pGrid;
            for (int row = pGrid->GetRowCount()-1; row >= pGrid->GetRowCount()-3; row--)
            {
            for (int col = 1; col <= pGrid->GetColumnCount(); col++)
            {
            GV_ITEM Item;
            Item.mask = GVIF_TEXT|GVIF_FORMAT;
            Item.row = row;
            Item.col = col;
            if(row==pGrid->GetRowCount()-3&&col>0) //平均值
            {
            if(col==10){
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.szText.Format(_T(" %6.2f "),avjch);
            }
            else{
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.szText.Format(_T(" %6.2f "),av[col-1]);
            }
            }
            pGrid->SetItem(&Item); //提交數據
            if(row==0||col==0)
            {
            COLORREF clr = RGB(0, 0, 0);
            pGrid->SetItemBkColour(row, col, clr);
            pGrid->SetItemFgColour(row, col, RGB(255,0,0));
            }
            }//循環結束
            pGrid->Invalidate();
            }
            好累啊,忙了一天時間終于寫完了!


            posted @ 2006-06-23 23:16 讓心飛翔 閱讀(10138) | 評論 (12)編輯 收藏

            一、ADO概述
            ADO是Microsoft為最新和最強大的數據訪問范例 OLE DB 而設計的,是一個便于使用的應用程序層接口。ADO 使您能夠編寫應用程序以通過 OLE. DB 提供者訪問和操作數據庫服務器中的數據。ADO 最主要的優點是易于使用、速度快、內存支出少和磁盤遺跡小。ADO 在關鍵的應用方案中使用最少的網絡流量,并且在前端和數據源之間使用最少的層數,所有這些都是為了提供輕量、高性能的接口。之所以稱為 ADO,是用了一個比較熟悉的暗喻,OLE 自動化接口。
            OLE DB是一組”組件對象模型”(COM) 接口,是新的數據庫低層接口,它封裝了ODBC的功能,并以統一的方式訪問存儲在不同信息源中的數據。OLE DB是Microsoft UDA(Universal Data Access)策略的技術基礎。OLE DB 為任何數據源提供了高性能的訪問,這些數據源包括關系和非關系數據庫、電子郵件和文件系統、文本和圖形、自定義業務對象等等。也就是說,OLE DB 并不局限于 ISAM、Jet 甚至關系數據源,它能夠處理任何類型的數據,而不考慮它們的格式和存儲方法。在實際應用中,這種多樣性意味著可以訪問駐留在 Excel 電子數據表、文本文件、電子郵件/目錄服務甚至郵件服務器,諸如 Microsoft Exchange 中的數據。但是,OLE DB 應用程序編程接口的目的是為各種應用程序提供最佳的功能,它并不符合簡單化的要求。您需要的API 應該是一座連接應用程序和OLE DB 的橋梁,這就是 ActiveX Data Objects (ADO)。
            二、在VC中使用ADO(開發步驟好下:)
            1、引入ADO庫文件
            使用ADO前必須在工程的stdafx.h頭文件里用直接引入符號#import引入ADO庫文件,以使編譯器能正確編譯。代碼如下所示:
            用#import引入ADO庫文件
            ?
            #import "c:\program files\common files\system\ado\msado15.dll"no_namespaces rename("EOF" adoEOF")
            ?
            這行語句聲明在工程中使用ADO,但不使用ADO的名字空間,并且為了避免常數沖突,將常數EOF改名為adoEOF。現在不需添加另外的頭文件,就可以使用ADO接口了。
            2、初始化OLE/COM庫環境
            必須注意的是,ADO庫是一組COM動態庫,這意味應用程序在調用ADO前,必須初始化OLE/COM庫環境。在MFC應用程序里,一個比較好的方法是在應用程序主類的InitInstance成員函數里初始化OLE/COM庫環境。
            ?
            BOOL CMyAdoTestApp::InitInstance()
            {
            if(!AfxOleInit())//這就是初始化COM庫
            {
            AfxMessageBox(“OLE初始化出錯!”);
            return FALSE;
            }
            ……
            }
            ?
            3、ADO接口簡介
            ADO庫包含三個基本接口:_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。
            _ConnectionPtr 接口返回一個記錄集或一個空指針。通常使用它來創建一個數據連接或執行一條不返回任何結果的SQL語句,如一個存儲過程。使用 _ConnectionPtr接口返回一個記錄集不是一個好的使用方法。對于要返回記錄的操作通常用_RecordserPtr來實現。而用 _ConnectionPtr操作時要想得到記錄條數得遍歷所有記錄,而用_RecordserPtr時不需要。
            _CommandPtr 接口返回一個記錄集。它提供了一種簡單的方法來執行返回記錄集的存儲過程和SQL語句。在使用_CommandPtr接口時,你可以利用全局 _ConnectionPtr接口,也可以在_CommandPtr接口里直接使用連接串。如果你只執行一次或幾次數據訪問操作,后者是比較好的選擇。但 如果你要頻繁訪問數據庫,并要返回很多記錄集,那么,你應該使用全局_ConnectionPtr接口創建一個數據連接,然后使用_CommandPtr 接口執行存儲過程和SQL語句。
            _RecordsetPtr是一個記錄集對象。與以上兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定,游標控制等。同 _CommandPtr接口一樣,它不一定要使用一個已經創建的數據連接,可以用一個連接串代替連接指針賦給 _RecordsetPtr的connection成員變量,讓它自己創建數據連接。如果你要使用多個記錄集,最好的方法是同Command對象一樣使用 已經創建了數據連接的全局_ConnectionPtr接口
            ,然后使用_RecordsetPtr執行存儲過程和SQL語句。 
            4、使用_ConnectionPtr接口
            _ConnectionPtr主要是一個連接接口,取得與數據庫的連接。它的連接字符串可以是自己直接寫,也可以指向一個ODBC DSN。
            ?
            _ConnectionPtr pConn;
            if (FAILED(pConn.CreateInstance("ADODB.Connection")))
            {
            AfxMessageBox("Create Instance failed!");
            return;
            }

            CString strSRC;
            strSRC="Driver=SQL Server;Server=";
            strSRC+="suppersoft";
            strSRC+=";Database=";
            strSRC+="mydb";
            strSRC+=";UID=SA;PWD=";
            CString strSQL = "Insert into student(no,name,sex,address) values(3,'aaa','male','beijing')";
            _variant_t varSRC(strSRC);
            _variant_t varSQL(strSQL);
            _bstr_t bstrSRC(strSRC);
            if (FAILED(pConn->Open(bstrSRC,"","",-1)))
            {
            AfxMessageBox("Can not open Database!");
            pConn.Release();
            return;
            }
            COleVariant vtOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
            pConn->Execute(_bstr_t(strSQL),&vtOptional,-1);
            pConn.Release();
            AfxMessageBox("ok!");
            ?
            5、使用_RecordsetPtr接口(以連接SQL Server為例)

            _RecordsetPtr pPtr;
            if (FAILED(pPtr.CreateInstance("ADODB.Recordset")))
            {
            AfxMessageBox("Create Instance failed!");
            return FALSE;
            }
            CString strSRC;
            strSRC="Driver=SQL Server;Server=";
            strSRC+="210.46.141.145";
            strSRC+=";Database=";
            strSRC+="mydb";
            strSRC+=";UID=sa;PWD=";
            strSRC+="sa";
            CString strSQL = "select id,name,gender,address from personal";
            _variant_t varSRC(strSRC);
            _variant_t varSQL(strSQL);
            if(FAILED(pPtr->Open(varSQL,varSRC,adOpenStatic,adLockOptimistic,adCmdText)))
            {
            AfxMessageBox("Open table failed!");
            pPtr.Release();
            return FALSE;
            }
            while(!pPtr->GetadoEOF())
            {
            _variant_t varNo;
            _variant_t varName;
            _variant_t varSex;
            _variant_t varAddress;
            varNo = pPtr->GetCollect ("id");
            varName = pPtr->GetCollect ("name");
            varSex = pPtr->GetCollect ("gender");
            varAddress = pPtr->GetCollect ("address");
            CString strNo =(char *)_bstr_t(varNo);
            CString strName =(char *)_bstr_t(varName);
            CString strSex =(char *)_bstr_t(varSex);
            CString strAddress =(char *)_bstr_t(varAddress);
            strNo.TrimRight();
            strName.TrimRight();
            strSex.TrimRight();
            strAddress.TrimRight();
            int nCount = m_list.GetItemCount();
            int nItem = m_list.InsertItem (nCount,_T(""));
            m_list.SetItemText (nItem,0,strNo);
            m_list.SetItemText (nItem,1,strName);
            m_list.SetItemText (nItem,2,strSex);
            m_list.SetItemText (nItem,3,strAddress);
            pPtr->MoveNext();
            }
            pPtr->Close();
            pPtr.Release();
            ?
            6、使用_CommandPtr接口
            _CommandPtr接口返回一個Recordset對象,并且提供了更多的記錄集控制功能,以下代碼示例了使用_CommandPtr接口的方法:
            代碼11:使用_CommandPtr接口獲取數據
            ?
            _CommandPtr pCommand;
            _RecordsetPtr pRs;
            pCommand.CreateInstance(__uuidof(Command));
            pCommand->ActiveConnection=pConn;
            pCommand->CommandText="select * from student";
            pCommand->CommandType=adCmdText;
            pCommand->Parameters->Refresh();
            pRs=pCommand->Execute(NULL,NULL,adCmdUnknown);
            _variant_t varValue = pRs->GetCollect("name");
            Cstring strValue=(char*)_bstr_t(varValue);
            ?
            7、關于數據類型轉換由于COM對象是跨平臺的,它使用了一種通用的方法來處理各種類型的數據,
            因此Cstring 類和COM對象是不兼容的,我們需要一組API來轉換COM對象和C++類型的數據。_vatiant_t和_bstr_t就是這樣兩種對象。它們提供了通用的方法轉換COM對象和C++類型的數據。
            posted @ 2006-06-23 23:14 讓心飛翔 閱讀(1970) | 評論 (0)編輯 收藏

            ??? Forms2.0系列的控件,如: Microsoft forms 2.0 labelMicrosoft forms 2.0 commandbutton等,其依賴的動態鏈接庫為Fm20.dlls。在使用過程中我發現,如果在發布軟件的時候,用戶的客戶機上沒有安裝word的話,程序就不能運行(雖然程序運行了,但是看不到界面出現)。 后來在網上搜索了很多資料,終于找到了問題的關鍵,在微軟網站上找到關于這個問題的解釋為: Fm20.dlls 不是可以重分配的,你必須安裝一個象OFFICE97那樣的系統在你的目標客戶機上作為你軟件分發的一部分。 如果不安裝Microsoft Office 97那樣的系統的話,即使你使用regsvr32注冊都沒有作用(我翻譯的,有點不通順哦^_^)。
            ??? 最終的解決辦法就是,做為Microsoft Office 97的替代,你可以免費下載和安裝Microsoft ActiveX Control Pad. 安裝完畢,客戶機上就可以無需安裝office而使用你的程序了。[需要的請留下email,我會發給你的]
            posted @ 2006-06-23 23:11 讓心飛翔 閱讀(1288) | 評論 (0)編輯 收藏

            下面是我在編程中運用CTypedPtrMap指針模板類的方法,其存儲結構占用物理空間小,比單純的用數組結構存儲的文件將小很多,所以是一種非常推薦的存儲及讀取文件的方法。

            你必須在stdafx.h文件中 包含? #include <afxtempl.h>??? // MFC templates
            在頭文件中包含? #include <io.h>

            其中 CBank.h文件如下:

            class CBank : public CObject? 
            {
            DECLARE_SERIAL(CBank)?? //聲明序列化存儲
            public:
            ??? ?? CBank();
            ?????? CBank(CString str){ m_bankname = str; }
            ?????? CBank(const CBank &b){ m_bankname= b.m_bankname;} //拷貝構造函數
            ????? ? virtual ~CBank();
            private:
            ?????? CString? m_bankname;
            public:
            ??? virtual void Serialize(CArchive& ar);
            };

            typedef CTypedPtrMap<CMapStringToOb,

            ???????????????????? CString,

            ???????????????????? CBank*>CBanktmp;? //這個才是我們根據此類生成的類型

            它的實現文件.cpp如下:

            IMPLEMENT_SERIAL(CBank, CObject, 1)?? //實現序列化存儲
            CBank::CBank()
            {
            ? ? m_bankname="";
            }
            CBank::~CBank()
            {

            }
            void CBank::Serialize(CArchive& ar)
            {
            ??? if (ar.IsLoading())
            ??? {
            ??????? ar >> m_bankname;
            ??? }
            ??? else
            ??? {
            ??????? ar << m_bankname;
            ??? }
            }

            /*----------------------------------------------------
            從文件中讀取參數:
            注意: 其中的m_map是這樣定義的:CBanktmp? m_map;
            -------------------------------------------------*/

            void CDlgBankIn::LoadBankName()
            {
            ?????? UINT? nFlags = CFile::typeBinary |CFile::modeReadWrite;
            ?????? if(_access(_T("BankName.dat"),0))
            ?????? {
            ????????????? nFlags |= CFile::modeCreate;
            ?????? }
            ?????? CFile file;
            ?????? CFileException fe;
            ?????? if (file.Open(_T("BankName.dat"),nFlags, &fe))
            ?????? {
            ?????????? if(file.GetLength()==0)?? //如果文件為空則不進行讀取操作
            ???? ????? {
            ?????????? }
            ?????????? else
            ?????????? {
            ??????????????? CArchive ar(&file, CArchive::load);
            ??????????????? m_map.Serialize(ar);?? //讀取文件
            ?????????????? //根據文件內容填充列表框
            ???? ?????????? POSITION?? pos;
            ??????????????? CString??? strKey;
            ??????????????? CBank?? *pB=NULL;
            ??????????????? for( pos = m_map.GetStartPosition(); pos != NULL; )
            ??????????????? {
            ??????????????????? m_map.GetNextAssoc(pos,strKey,(CBank*)pB);
            ??????????????????? m_CmbBank.AddString(strKey);
            ??????????????? }
            ??????????????? delete? pB;
            ????????????? }
            ?????? }
            ?????? file.Close();
            }

            /*-------------------------------------------------
            功能: 先打開文件,然后查找文件中是否有與編輯框關鍵字相同的內容,
            ??? ?? 如果有相同內容則不添加,如果沒有相同內容則寫文件.
            ------------------------------------- ------------*/

            void CDlgBankList::OnBtnAdd() 
            {
            ?????? // TODO: Add your control notification handler code here
            ?????? CString? strKey;
            ?????? GetDlgItemText(IDC_EDITBank,strKey);
            ?????? if (0 != strKey.GetLength())
            ?????? {
            ????????? CBank? *pB;
            ????????? //打開文件
            ????? ?? UINT? nFlags = CFile::typeBinary |CFile::modeRead;
            ????????? CFile file;
            ????????? CFileException fe;
            ????????? if (file.Open(_T("BankName.dat"),nFlags, &fe))
            ????????? {
            ???????????????? if(file.GetLength()==0)? //如果文件為空則不進行序列化操作
            ???? ??????????? {

            ???????????????? }
            ???????????????? else
            ???????????????? {
            ????????????????? CArchive ar(&file, CArchive::load);
            ????????????????? m_map.Serialize(ar);
            ???????????????? }
            ?????????????? //分析文件并給文件添加編輯框的內容
            ???? ?????????? if(!m_map.Lookup(strKey,(CBank*)pB))? //當不存在時才需要添加
            ????? ??????????? {
            ????????????????????? if (CB_ERR != m_ListBox.AddString(strKey))
            ????????????????????? {
            ???????????????????????? m_map.SetAt(strKey, new CBank(strKey));? //給關鍵字strKey賦值
            ???? ???????????????? }
            ???????????????? }
            ????????? }
            ?????? file.Close();

            ?????? //存儲文件
            ???? nFlags = CFile::typeBinary |CFile::modeWrite;
            ?????? if (file.Open(_T("BankName.dat"),nFlags, &fe))
            ?????? {
            ??????????? CArchive ar(&file, CArchive::store);
            ??????????? m_map.Serialize(ar);?? //序列化存儲
            ???? }
            ??? }
            }

            /*-------------------------------------------------
            功能: 先打開文件,然后查找文件中的關鍵字,
            ????找到后則刪除此關鍵字, 但是注意關鍵字對應的內容仍然沒有刪除,這點期待改進.
            -------------------------------------------------*/

            void CDlgBankList::OnBtnDel() 
            {
            ?????? // TODO: Add your control notification handler code here
            ?????? int iIndex;??????
            ?????? CString? strKey;
            ?????? if(LB_ERR!=m_ListBox.GetCurSel())
            ?????? {
            ??????? //打開文件
            ?????& nbsp;???? UINT? nFlags = CFile::typeBinary |CFile::modeRead;
            ?????????? CFile file;
            ?????????? CFileException fe;
            ?????????? if (file.Open(_T("BankName.dat"),nFlags, &fe))
            ?????????? {
            ????????????? CArchive ar(&file, CArchive::load);
            ????????????? m_map.Serialize(ar);?
            ????????????? iIndex=m_ListBox.GetCurSel();
            ????????????? m_ListBox.GetText(iIndex,strKey);
            ????????????? m_ListBox.DeleteString(iIndex);
            ????????????? //分析文件并給文件添加編輯框的內容
            ???? ????????? CBank? *pB=NULL;
            ????????????? if(m_map.Lookup(strKey,(CBank*)pB))
            ????????????? {
            ????????????????? m_map.RemoveKey(strKey);?? //刪除關鍵字,但沒有刪除關鍵字對應的內容
            ???? ????????? }
            ??????????? }
            ??????????? file.Close();
            ??????????? //存儲文件
            ????? ???? nFlags = CFile::typeBinary |CFile::modeWrite;
            ?????????? if (file.Open(_T("BankName.dat"),nFlags, &fe))
            ?????????? {
            ??????????????? CArchive ar(&file, CArchive::store);
            ??????????????? m_map.Serialize(ar);?? //序列化存儲
            ????? ???? }
            ?????? }
            }

            posted @ 2006-06-23 23:07 讓心飛翔 閱讀(1929) | 評論 (0)編輯 收藏

            僅列出標題  
            久久精品国产亚洲av影院| 久久久久人妻一区精品| 亚洲欧美成人综合久久久| 亚洲午夜久久久影院| 久久精品无码午夜福利理论片| 久久精品免费观看| 青青热久久国产久精品| 伊人久久大香线蕉av一区| 国产成人精品久久免费动漫| 国产精品美女久久久久av爽| 亚洲AV无码久久精品色欲| 青青草原1769久久免费播放| 亚洲精品午夜国产va久久| 伊人久久无码中文字幕| 久久99免费视频| 久久久久久久久久久久久久| 91久久精品无码一区二区毛片| 久久青青草视频| 精品久久综合1区2区3区激情| 久久综合狠狠色综合伊人| 伊人久久大香线蕉成人| 9191精品国产免费久久| 国产精品9999久久久久| 国产精品久久网| 久久精品国产久精国产果冻传媒| 精品无码久久久久久久动漫| 久久超乳爆乳中文字幕| 人妻无码久久一区二区三区免费| 亚洲人成无码久久电影网站| 国产精品久久久久乳精品爆| 91久久香蕉国产熟女线看| 久久午夜无码鲁丝片| 久久久久久久精品成人热色戒| 久久久精品波多野结衣| 久久久精品视频免费观看| 99久久夜色精品国产网站| 久久国产精品99精品国产987| 久久久久久国产精品无码超碰 | 精品久久久久久无码专区| 久久精品国产清自在天天线| 2019久久久高清456|