我用mfc做的一个sdi程序,想实现的功能是把视图分为2部分,左边是一排按钮。点击其中一个右边出现相应的页面。
现在我已经用CSPlietWnd分割视图成功了。添加了一个class CLeftView : public CFormView。代码如下:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext)
{
    CRect rect;    
    GetClientRect(rect); 
    if (!m_wndSplitter.CreateStatic(this,1,2))
return FALSE; 
    if (!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CLeftView),CSize(rect.Width()/4,100),pContext)) 
return FALSE; 
    if (!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CMy8View),CSize(100,100),pContext))     
return FALSE; 
    return TRUE; }
class CMy8View : public CFormView从向导里直接生成的视图类。
我询问过应该怎么做,大家说是查一个SwitchViewInSplitter 函数。我已经查到了,这个函数的功能应该是切换视图吧。但是我不知道该怎么使用它,是放到CMainFrame里吗?而且我左边有4个按钮,是不是得定义4个视图类啊,上面的代码也需要改动一下呢?请大家指教,谢谢

解决方案 »

  1.   


    //网上摘抄的一段代码,可以参考一下
    void SwitchViewInSplitter( CSplitterWnd * pSplitter, int row, int col, CRuntimeClass * pViewClass )
    {
        ///////////////////////////////////////////////////////////   
        //   Replace   the   current   view   in   the   splitter   pSplitter   
        //   at   pane   (row,   col)   by   a   new   view   of   class   pViewClass   
        ASSERT_VALID( pSplitter );
        ASSERT( pViewClass != NULL );    ASSERT( pViewClass->IsDerivedFrom( RUNTIME_CLASS( CView ) ) );    //   1   -   Find   the   view   to   be   replaced   
        CWnd *pPaneWnd = pSplitter->GetPane( row, col );
        if( !pPaneWnd->IsKindOf( RUNTIME_CLASS( CView ) ) )   
        {   
            TRACE2( "Unable   to   switch:   pane   (%d,%d)   is   not   a   view\n", row, col );
            return;
        }       CView*   pCurrentView   =   static_cast<CView*>( pPaneWnd );
        ASSERT_VALID(   pCurrentView   );
        ASSERT_KINDOF(   CView,   pCurrentView   );    if(   pCurrentView->IsKindOf(   pViewClass   )   )   
        {   
            //   No   need   to   switch   for   same   view   class   
            return;
        }       //   2   -   Store   current   view   position   and   activation   state   
        CRect   rcView;
        pCurrentView->GetWindowRect(   &rcView   );    CView*   pActiveView   =   pSplitter->GetParentFrame()->GetActiveView();
        BOOL   bSaveActive   =   (   pActiveView   ==   NULL   )    ||   (   pActiveView   ==   pCurrentView   );    //   3   -   Find   the   associated   document   
        CDocument*   pDoc   =   pCurrentView->GetDocument();
        ASSERT_VALID(   pDoc   );    //   4   -   Make   sure   the   document   won't   self-destruct   
        //   when   current   view   is   destroyed   
        BOOL   bSaveAutoDelete   =   pDoc->m_bAutoDelete;
        pDoc->m_bAutoDelete   =   FALSE;    //   5   -   Destroy   the   current   view   
        pCurrentView->DestroyWindow();    //   6   -   Restore   document   to   initial   state   
        pDoc->m_bAutoDelete   =   bSaveAutoDelete;    //   7   -   Initialize   creation   context   used   by   CreateView()   
        CCreateContext   context;
        context.m_pNewDocTemplate   =   NULL;
        context.m_pLastView   =   NULL;
        context.m_pCurrentFrame   =   NULL;    context.m_pNewViewClass   =   pViewClass;
        context.m_pCurrentDoc   =   pDoc;    //   8   -   Create   the   new   view   
        pSplitter->CreateView( row,   col,   pViewClass,   
        rcView.Size(),   &context   );    CView*   pNewView   =   static_cast<CView*>(   pSplitter->GetPane(   row,   col   )   );
        ASSERT_VALID(   pNewView   );
        ASSERT_KINDOF(   CView,   pNewView   );    //   9   -   Position   the   new   view   like   the   old   one   and
        //   activate   it   if   needed
        pSplitter->ScreenToClient(   &rcView   );
        pNewView->MoveWindow(   &rcView,   TRUE   );
        if(   bSaveActive   )
        {
            pSplitter->GetParentFrame()->SetActiveView(   pNewView   );
        }    //   10   -   Send   WM_INITIALUPDATE   to   the   view   
        pNewView->GetParentFrame()->InitialUpdateFrame(   pDoc,   TRUE   );
    }
      

  2.   

    可以放在mainframe里
    当然得4个视图类,视图相同的话就没有必要切换了。
      

  3.   

    我现在已经创建了4个视图类, 全都继承自CFormView。并且每一个类都关连了一个Dialog资源。把SwitchViewInSplitter函数也添加到了mainframe里。
    接着该怎么办呢?我想是不是为左边的一排按钮中每一个按钮都增添一个点击事件啊。在点击事件函数中使用这个SwitchViewInSplitter函数呢?
    不过我不太明白这个函数应该怎么用,请大家指教
      

  4.   

    使用很简单吧,就像这样SwitchViewInSplitter( &m_wndSplitter_v, 0, 1, RUNTIME_CLASS( CMyRightView1 ) );
    红色字体是被切换的类名。
      

  5.   

    我在CLeftView中添加了一个按钮事件,并把代码添加到函数里:
    void CLeftView::OnXl() 
    {
    SwitchViewInSplitter( &m_wndSplitter_v, 0, 1, RUNTIME_CLASS( CPage2  ) ); 
    }
    可是编译有错误;
    error C2065: 'SwitchViewInSplitter' : undeclared identifier
    F:\8\LeftView.cpp(68) : error C2065: 'm_wndSplitter_v' : undeclared identifier
    我把SwitchViewInSplitter'定义到CMainFrame里。在CLeftView的.cpp的文件里也加上了#include "MainFrm.h"了啊。为什么还会说'SwitchViewInSplitter' : undeclared identifier???
      

  6.   

    'm_wndSplitter_v' 是我的程序里的,你要改常规做法,leftview发消息给frame,frame去切换子view。
      

  7.   

    1.'m_wndSplitter_v' 是什么?SwitchViewInSplitter函数定义中是CSplitterWnd *pSplitter,是不是为CSplitterWnd 的继承类定义一个成员变量啊,还是直接定义CSplitterWnd *pSplitter在mainframe里呢?
    2.常规做法,leftview发消息给frame,frame去切换子view。
    你的意思是不是并不在按钮事件中调用SwitchViewInSplitter函数。而只是在这个按钮事件里发一个消息给frame,让frame去处理切换子view。
      

  8.   


    //我觉得你的按钮函数还是放在Mainfrm中比较好。
    void CMainfrm::OnXl() 

    SwitchViewInSplitter( &m_wndSplitter, 0, 1, RUNTIME_CLASS( CMy8View) ); 

    //我想知道你CPage2是不是一个视图类呢?还是CMy8View里面的一个Tab控件。
    //你可以把几个Cpage做成基于CFormView的基类,然后在使用上面的函数切换就可以了。
    //如果你是CTabCtrl,就不需要要用切换视图来达到你需要的效果,直接切换就可以了。
    m_wndSplitter
      

  9.   

    CPage2是一个视图类,是继承CFormView的基类。
    m_wndSplitter是怎么定义的啊?
      

  10.   

    void CMainfrm::OnXl()
    是怎么做到的呢?一般直接就到Cleftview类里了啊,这个按钮是放在Cleftview视图类的啊
      

  11.   


    BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) 

        CRect rect;    
        GetClientRect(rect); 
        if (!m_wndSplitter.CreateStatic(this,1,2)) 
        //
    //就是你在MainFrm.h里面定义的啊
    }
      

  12.   

    看看www.vckbase.com下有很多例子。
      

  13.   


    //在你这个按钮上面点击右键,然后选择添加添加事件处理程序,在弹出对话框中选择类列表为CMainFrm就可 以了,(2003)如果你是VC6,点击右键以后选择class Wizard,在弹出对话框中的类名种选择CMainframe,选择BN_CLICKED然后点Edit Code就可以了。
      

  14.   


    //不知上面的方法是否可行,你可以这样实现
    //按钮函数还是在Cleftview中。
    void CLeftView::OnXl() 

    CMainFrame *pMainFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
    pMainFrame->SwitchView(1); 

    //在你CMainFrame中定义一个函数:
    //mainfrm.h
    void SwitchToView(int view);
    //mainfrm.cpp
    void CMainFrame::SwitchToView(int view)
    {
    switch(view) 

    case 1: // CPage1 

                     SwitchViewInSplitter(&m_wndSplitter,0,1, RUNTIME_CLASS( CPage1) ); 
                     break;
                    }
            case 2://CPage2
                   {
                    SwitchViewInSplitter(&m_wndSplitter,0,1, RUNTIME_CLASS( CPage2) ); 
                    break;
                    }  
           //.......
    //基本上这样就可以咯。
      

  15.   

    GetPane函数吧,具体忘了,很容易就得到一个view的指针。
      

  16.   

    Cpage1 *p1 =(cpage1)pmainframe->m_wndspitter.getpane(0,1);
    这样可以得到视图的指针,然后就可以通信了。
      

  17.   

    我在第2个视图里的某个函数里加了这句代码:(在视图2里获得视图1的指针)
    CMainFrame* pmainframe=(CMainFrame*)this->GetParent(); 
    Cpage1 *p1 =(cpage1)pmainframe->m_wndspitter.GetPane(0,1);
    编译错误如下:
    error C2440: 'type cast' : cannot convert from 'class CWnd *' to 'class Cpage1'
            No constructor could take the source type, or constructor overload resolution was ambiguous
    为什么呢,哪里有错了。
      

  18.   

    Cpage1 *p1 =(cpage1 *)pmainframe->m_wndspitter.GetPane(0,1); 多注意点。
      

  19.   

    感谢,我获得了该视图的指针了,可是我的主要目的是获得这个视图中某个函数里获得的值.我就加了这句
    p1->OnBrowse();//
    可我发现这个函数是一个afx_msg void OnBrowse();
    编译就有问题了 error C2248: 'OnBrowse' : cannot access protected member declared in class 'CMy8View'
    这该怎么办?
    这个函数代码:
    void CMy8View::OnBrowse() 
    {
    CFileDialog fileDlg(TRUE);
    if(IDOK == fileDlg.DoModal())
    {
    GetDlgItem(IDSRCDIR)->SetWindowText(fileDlg.GetPathName());
    }
    CString dstSrc;
    dstSrc = fileDlg.GetPathName();
    }
    我就想获得这个值dstSrc
      

  20.   

    我改了,public:
    //{{AFX_MSG(CMyView)
    afx_msg void OnBrowse();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    编译后有2错误了:
    Page2.obj : error LNK2001: unresolved external symbol "public: void __thiscall CMyView::OnBrowse(void)" (?OnBrowse@CMyView@@QAEXXZ)
    Debug/8.exe : fatal error LNK1120: 1 unresolved externals
    Error executing link.exe.
      

  21.   

    clean一下,rebuild试试。把你相关部分的代码贴一下。
      

  22.   

    class CMyView : public CFormView
    {...
    public:
    //{{AFX_MSG(CMy8View)
    afx_msg void OnBrowse();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };
    void CMyView::OnBrowse() 
    {
    CFileDialog fileDlg(TRUE);
    if(IDOK == fileDlg.DoModal())
    {
    GetDlgItem(IDSRCDIR)->SetWindowText(fileDlg.GetPathName());
    }
    CString dstSrc;
    dstSrc = fileDlg.GetPathName();
    }
    class CPage2 : public CFormView
    {
    protected:
    CPage2();           // protected constructor used by dynamic creation
    DECLARE_DYNCREATE(CPage2)// Form Data
    public:
    //{{AFX_DATA(CPage2)
    enum { IDD = IDD_FORM3 };
    CWebBrowser2 m_htmlShow;
    //}}AFX_DATA// Attributes
    public:// Operations
    public:
    BOOL PreTranslateMessage(MSG *pMsg);
    CString ResourceToURL(LPCTSTR lpszURL);
    void OnInitialUpdate();// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CPage2)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL// Implementation
    protected:
    virtual ~CPage2();
    #ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
    #endif // Generated message map functions
    //{{AFX_MSG(CPage2)
    afx_msg void OnTj();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };
    void CPage2::OnTj() 
    {
    CMainFrame* pmainframe=(CMainFrame*)this->GetParent(); 
        
           CMyView *p1 =(CMyView *)pmainframe->m_wndSplitter.GetPane(0,1); 
           p1->OnBrowse();// 
    }
      

  23.   

    class CMyView : public CFormView 是通过向导生成的,其他视图都是后来添加的