• <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++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              7 Posts :: 0 Stories :: 13 Comments :: 0 Trackbacks

            2008年12月17日 #

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

            第三步:在類頭文件的AFX_MSG塊中說明消息處理函數(shù):
            class CMainFrame:public CMDIFrameWnd
            {
                ...
                // 一般消息映射函數(shù)
                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宏指令將消息映射到消息處理函數(shù)中。
            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()

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

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


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

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

            第一步:在VC++中新建工程Message,所有ClassWizard步驟選項均為缺省,完成。
            第二步:在主菜單中添加測試菜單為調(diào)出對話框,在框架類中建立相應(yīng)函數(shù)OnTest().
            第三步:在資源中建立對話框,通過ClassWizard添加新類TestDialog,添加測試按鈕, 在對話框類中建立相應(yīng)函數(shù)OnDialogTest()
            //通過對話框按鈕發(fā)送消息的函數(shù)
            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);//發(fā)送消息
            }
              在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()
            添加相應(yīng)的0消息處理函數(shù)
            LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
            {
                CRect rect;
                GetClientRect(&rect);
                InvalidateRect(&rect);
                test=!test;
                return 0;
            }
            在MessageView.h中添加布爾變量 public:BOOL test;
            在視類構(gòu)造函數(shù)中初始化 test變量:test=FALSE;
            修改CMessageView::OnDraw()函數(shù)
            void CMessageView::OnDraw(CDC* pDC)
            {
                CMessageDoc* pDoc = GetDocument();
                ASSERT_VALID(pDoc);
                // 以下程序顯示消息響應(yīng)效果
                if(test)
                pDC->TextOut(0,0,"消息響應(yīng)!");
            }
            第五步:顯示測試對話框
            在MainFrame類中包含對話框頭文件:
            #include "TestDialog.h";
            OnTest()函數(shù)中添加代碼
            void CMainFrame::OnTest()
            {
                TestDialog dialog;
                dialog.DoModal();
            }
            運(yùn)行程序,在測試菜單打開對話框,點(diǎn)擊測試按鈕即可看到結(jié)果
            posted @ 2008-12-17 13:18 讓心飛翔 閱讀(1576) | 評論 (0)編輯 收藏

            2006年6月23日 #

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

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

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

            HBRUSH CDialogColor::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
            {
            HBRUSH hbr = CDialog::OnCtlColor(pDC,pWnd, nCtlColor);
            // TODO: Change any attributes of theDC here
            //設(shè)置顯示字體
            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: //對所有靜態(tài)文本控件的設(shè)置
            {
            pDC->SetBkMode(TRANSPARENT);
            //設(shè)置背景為透明
            pDC->SetTextColor(RGB(255,255,0)); //設(shè)置字體顏色
            pWnd->SetFont(cFont); //設(shè)置字體
            HBRUSH B = CreateSolidBrush(RGB(125,125,255));
            //創(chuàng)建畫刷
            return (HBRUSH) B; //返回畫刷句柄
            }
            case CTLCOLOR_EDIT: //對所有編輯框的設(shè)置
            {
            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 靜態(tài)文本

            2.你可能覺得對所有的控件使用統(tǒng)一的界面設(shè)置覺得不自由,其實(shí)VC同樣可以對特定的ID的控件進(jìn)行設(shè)置,方法如下:


            switch (pWnd->GetDlgCtrlID())
            {
            //針對ID為IDC_CTL1、IDC_CTL2和IDC_CTL3的控件進(jìn)行同樣的設(shè)置
            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 讓心飛翔 閱讀(6967) | 評論 (1)編輯 收藏

            ??? 在對話框程序的打印功能中,如果使用針式打印機(jī),那么你可能希望連續(xù)打印的多個表中不換頁。我們知道,在使用打印功能的時候,每當(dāng) dc.startpage()就會開始一頁的打印,而dc.endpage()就會結(jié)束一頁的打印,那么如何能使多個dc.startpage()與 dc.endpage()不換頁而實(shí)現(xiàn)連續(xù)打印呢,方法如下: 假設(shè)我們要打印m_nTotalNum個表,每個表有m行,那么要實(shí)現(xiàn)m_nTotalNum個表連續(xù)打印不換頁可以如下實(shí)現(xiàn):(由于打印機(jī)制問題,在打滿一張后是必須要換頁的,我們的做法是在換頁的地方讓給它留出一定的空白,不太影響表的連續(xù)性)
            /////////////主函數(shù)
            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; //當(dāng)前表數(shù)為1,這個用來控制打印的表數(shù)
            int nPageTotalScale=0; //初始化從0開始
            Info.m_nCurPage=1; //從第一頁開始
            dc.StartPage(); //開始打印頁
            for(;;)
            {
            //打印完需要的表數(shù)m_nTotalNum則退出循環(huán)
            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); //結(jié)束一頁
            m_nCurrentNum_WhenPrint =0;
            if(bPrintingOk)
            dc.EndDoc();
            else
            dc.AbortDoc();
            }
            else
            {
            MessageBox("請檢查打印機(jī)是否連接完好?","我的程 序",MB_ICONEXCLAMATION);
            }
            dc.Detach();
            }

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

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

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

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

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

            步驟二 構(gòu)造與析構(gòu)

            構(gòu)造函數(shù)中:
            ???m_pGridCtrl = NULL;
            析構(gòu)函數(shù)中:
            ???if(m_pGridCtrl)
            ???????delete m_pGridCtrl;


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

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

            其它兩個打印函數(shù)也一樣的做法.

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

               //創(chuàng)建非模式對話框
            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); //設(shè)置行數(shù)為k行
            m_pGridCtrl->SetColumnCount(4); //k列
            m_pGridCtrl->SetFixedRowCount(1); //標(biāo)題行為一行
            m_pGridCtrl->SetFixedColumnCount(1); //同上
            }
            catch (CMemoryException* e)
            {
            e->ReportError();
            e->Delete();
            return 0;
            }
            //填充列標(biāo)題
            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) { //行標(biāo)題頭
            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();

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


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

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



            ?在對話框中的使用方法

            步驟一 創(chuàng)建數(shù)據(jù)顯示表格對話框

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

            在CDlgTestReportBox類的頭文件中:

            #include "GridCtrl.h"

            再定義成員變量:

            CGridCtrl* m_pGrid;

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

            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); //得到顯示區(qū)域
            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++)
            {
            //設(shè)置表格顯示屬性
            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) //設(shè)置0行表頭顯示
            {
            Item.nFormat = DT_CENTER|DT_WORDBREAK;
            Item.szText.Format(_T(" 項目%d"),col);
            }
            else if (col < 1) //設(shè)置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();
            }
            //--------------設(shè)置行列距------------------
            for(int a=0;aGetRowCount();a++)
            m_pGrid->SetRowHeight(a,16); //設(shè)置各行高
            m_pGrid->SetColumnWidth(0,58); //設(shè)置0列寬
            for(int b=1;bGetColumnCount();b++)
            m_pGrid->SetColumnWidth(b,59); //設(shè)置各列寬
            }

            ?

            步驟二 嵌入上面的對話框 顯示數(shù)據(jù)

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

            #include "GridCtrl.h"

            CDlgTestReportBox* m_pTestReportBox;

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

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

            m_pTestReportBox->Create(IDD_DlgTestReportBox,this);

            //定義區(qū)域變量
            CRect rectDraw;
            GetDlgItem(IDC_AeraReport)->GetWindowRect(rectDraw);
            ScreenToClient(&rectDraw); //動態(tài)測試數(shù)據(jù)顯示區(qū)域rectDraw

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

            自定義填充數(shù)據(jù)的函數(shù):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); //提交數(shù)據(jù)
            if(row==0||col==0)
            {
            COLORREF clr = RGB(0, 0, 0);
            pGrid->SetItemBkColour(row, col, clr);
            pGrid->SetItemFgColour(row, col, RGB(255,0,0));
            }
            }//循環(huán)結(jié)束
            pGrid->Invalidate();
            }
            好累啊,忙了一天時間終于寫完了!


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

            一、ADO概述
            ADO是Microsoft為最新和最強(qiáng)大的數(shù)據(jù)訪問范例 OLE DB 而設(shè)計的,是一個便于使用的應(yīng)用程序?qū)咏涌凇DO 使您能夠編寫應(yīng)用程序以通過 OLE. DB 提供者訪問和操作數(shù)據(jù)庫服務(wù)器中的數(shù)據(jù)。ADO 最主要的優(yōu)點(diǎn)是易于使用、速度快、內(nèi)存支出少和磁盤遺跡小。ADO 在關(guān)鍵的應(yīng)用方案中使用最少的網(wǎng)絡(luò)流量,并且在前端和數(shù)據(jù)源之間使用最少的層數(shù),所有這些都是為了提供輕量、高性能的接口。之所以稱為 ADO,是用了一個比較熟悉的暗喻,OLE 自動化接口。
            OLE DB是一組”組件對象模型”(COM) 接口,是新的數(shù)據(jù)庫低層接口,它封裝了ODBC的功能,并以統(tǒng)一的方式訪問存儲在不同信息源中的數(shù)據(jù)。OLE DB是Microsoft UDA(Universal Data Access)策略的技術(shù)基礎(chǔ)。OLE DB 為任何數(shù)據(jù)源提供了高性能的訪問,這些數(shù)據(jù)源包括關(guān)系和非關(guān)系數(shù)據(jù)庫、電子郵件和文件系統(tǒng)、文本和圖形、自定義業(yè)務(wù)對象等等。也就是說,OLE DB 并不局限于 ISAM、Jet 甚至關(guān)系數(shù)據(jù)源,它能夠處理任何類型的數(shù)據(jù),而不考慮它們的格式和存儲方法。在實(shí)際應(yīng)用中,這種多樣性意味著可以訪問駐留在 Excel 電子數(shù)據(jù)表、文本文件、電子郵件/目錄服務(wù)甚至郵件服務(wù)器,諸如 Microsoft Exchange 中的數(shù)據(jù)。但是,OLE DB 應(yīng)用程序編程接口的目的是為各種應(yīng)用程序提供最佳的功能,它并不符合簡單化的要求。您需要的API 應(yīng)該是一座連接應(yīng)用程序和OLE DB 的橋梁,這就是 ActiveX Data Objects (ADO)。
            二、在VC中使用ADO(開發(fā)步驟好下:)
            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的名字空間,并且為了避免常數(shù)沖突,將常數(shù)EOF改名為adoEOF。現(xiàn)在不需添加另外的頭文件,就可以使用ADO接口了。
            2、初始化OLE/COM庫環(huán)境
            必須注意的是,ADO庫是一組COM動態(tài)庫,這意味應(yīng)用程序在調(diào)用ADO前,必須初始化OLE/COM庫環(huán)境。在MFC應(yīng)用程序里,一個比較好的方法是在應(yīng)用程序主類的InitInstance成員函數(shù)里初始化OLE/COM庫環(huán)境。
            ?
            BOOL CMyAdoTestApp::InitInstance()
            {
            if(!AfxOleInit())//這就是初始化COM庫
            {
            AfxMessageBox(“OLE初始化出錯!”);
            return FALSE;
            }
            ……
            }
            ?
            3、ADO接口簡介
            ADO庫包含三個基本接口:_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。
            _ConnectionPtr 接口返回一個記錄集或一個空指針。通常使用它來創(chuàng)建一個數(shù)據(jù)連接或執(zhí)行一條不返回任何結(jié)果的SQL語句,如一個存儲過程。使用 _ConnectionPtr接口返回一個記錄集不是一個好的使用方法。對于要返回記錄的操作通常用_RecordserPtr來實(shí)現(xiàn)。而用 _ConnectionPtr操作時要想得到記錄條數(shù)得遍歷所有記錄,而用_RecordserPtr時不需要。
            _CommandPtr 接口返回一個記錄集。它提供了一種簡單的方法來執(zhí)行返回記錄集的存儲過程和SQL語句。在使用_CommandPtr接口時,你可以利用全局 _ConnectionPtr接口,也可以在_CommandPtr接口里直接使用連接串。如果你只執(zhí)行一次或幾次數(shù)據(jù)訪問操作,后者是比較好的選擇。但 如果你要頻繁訪問數(shù)據(jù)庫,并要返回很多記錄集,那么,你應(yīng)該使用全局_ConnectionPtr接口創(chuàng)建一個數(shù)據(jù)連接,然后使用_CommandPtr 接口執(zhí)行存儲過程和SQL語句。
            _RecordsetPtr是一個記錄集對象。與以上兩種對象相比,它對記錄集提供了更多的控制功能,如記錄鎖定,游標(biāo)控制等。同 _CommandPtr接口一樣,它不一定要使用一個已經(jīng)創(chuàng)建的數(shù)據(jù)連接,可以用一個連接串代替連接指針賦給 _RecordsetPtr的connection成員變量,讓它自己創(chuàng)建數(shù)據(jù)連接。如果你要使用多個記錄集,最好的方法是同Command對象一樣使用 已經(jīng)創(chuàng)建了數(shù)據(jù)連接的全局_ConnectionPtr接口
            ,然后使用_RecordsetPtr執(zhí)行存儲過程和SQL語句。 
            4、使用_ConnectionPtr接口
            _ConnectionPtr主要是一個連接接口,取得與數(shù)據(jù)庫的連接。它的連接字符串可以是自己直接寫,也可以指向一個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接口獲取數(shù)據(jù)
            ?
            _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、關(guān)于數(shù)據(jù)類型轉(zhuǎn)換由于COM對象是跨平臺的,它使用了一種通用的方法來處理各種類型的數(shù)據(jù),
            因此Cstring 類和COM對象是不兼容的,我們需要一組API來轉(zhuǎn)換COM對象和C++類型的數(shù)據(jù)。_vatiant_t和_bstr_t就是這樣兩種對象。它們提供了通用的方法轉(zhuǎn)換COM對象和C++類型的數(shù)據(jù)。
            posted @ 2006-06-23 23:14 讓心飛翔 閱讀(1976) | 評論 (0)編輯 收藏

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

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

            你必須在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;} //拷貝構(gòu)造函數(shù)
            ????? ? virtual ~CBank();
            private:
            ?????? CString? m_bankname;
            public:
            ??? virtual void Serialize(CArchive& ar);
            };

            typedef CTypedPtrMap<CMapStringToOb,

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

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

            它的實(shí)現(xiàn)文件.cpp如下:

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

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

            /*----------------------------------------------------
            從文件中讀取參數(shù):
            注意: 其中的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)?? //如果文件為空則不進(jìn)行讀取操作
            ???? ????? {
            ?????????? }
            ?????????? else
            ?????????? {
            ??????????????? CArchive ar(&file, CArchive::load);
            ??????????????? m_map.Serialize(ar);?? //讀取文件
            ?????????????? //根據(jù)文件內(nèi)容填充列表框
            ???? ?????????? 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();
            }

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

            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)? //如果文件為空則不進(jìn)行序列化操作
            ???? ??????????? {

            ???????????????? }
            ???????????????? else
            ???????????????? {
            ????????????????? CArchive ar(&file, CArchive::load);
            ????????????????? m_map.Serialize(ar);
            ???????????????? }
            ?????????????? //分析文件并給文件添加編輯框的內(nèi)容
            ???? ?????????? if(!m_map.Lookup(strKey,(CBank*)pB))? //當(dāng)不存在時才需要添加
            ????? ??????????? {
            ????????????????????? if (CB_ERR != m_ListBox.AddString(strKey))
            ????????????????????? {
            ???????????????????????? m_map.SetAt(strKey, new CBank(strKey));? //給關(guān)鍵字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);?? //序列化存儲
            ???? }
            ??? }
            }

            /*-------------------------------------------------
            功能: 先打開文件,然后查找文件中的關(guān)鍵字,
            ????找到后則刪除此關(guān)鍵字, 但是注意關(guān)鍵字對應(yīng)的內(nèi)容仍然沒有刪除,這點(diǎn)期待改進(jìn).
            -------------------------------------------------*/

            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);
            ????????????? //分析文件并給文件添加編輯框的內(nèi)容
            ???? ????????? CBank? *pB=NULL;
            ????????????? if(m_map.Lookup(strKey,(CBank*)pB))
            ????????????? {
            ????????????????? m_map.RemoveKey(strKey);?? //刪除關(guān)鍵字,但沒有刪除關(guān)鍵字對應(yīng)的內(nèi)容
            ???? ????????? }
            ??????????? }
            ??????????? 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 讓心飛翔 閱讀(1936) | 評論 (0)編輯 收藏

            僅列出標(biāo)題  
            亚洲va国产va天堂va久久| 青青草原综合久久大伊人导航| 久久影视综合亚洲| 国内精品久久国产| 亚洲国产美女精品久久久久∴ | 久久精品国产亚洲AV无码麻豆| 一本色道久久HEZYO无码| 精品久久一区二区三区| 国产伊人久久| 色综合久久久久综合体桃花网| 999久久久免费精品国产| 性做久久久久久久久| 久久久久久午夜成人影院| 精品国产热久久久福利| 亚洲精品乱码久久久久久久久久久久 | 亚洲欧美日韩精品久久亚洲区 | 久久这里都是精品| 欧美777精品久久久久网| 伊人久久大香线蕉av不变影院| 国产精品热久久毛片| 亚洲国产精品无码久久| 色婷婷噜噜久久国产精品12p| 国产精品无码久久综合| 伊人色综合久久天天网| 国产成人精品久久| 久久久久久狠狠丁香| 久久久久亚洲AV无码永不| 久久精品国产亚洲αv忘忧草| 久久久久国产精品三级网| 国产成人精品久久亚洲| 久久这里只精品国产99热| 国内精品久久久久久99蜜桃| 中文字幕热久久久久久久| 欧美亚洲国产精品久久高清| 日韩久久无码免费毛片软件 | 婷婷综合久久狠狠色99h| 久久精品www人人爽人人| 久久久久久国产精品免费无码 | 色成年激情久久综合| 一本大道加勒比久久综合| 国内精品久久久久久中文字幕|