Aktuelle Ansicht einer SDI Anwendung per Button-Klick ändern, nicht per Menüleiste!



  • Liebe C++ Community, ich bin völlig verzweifelt.
    Ich arbeite nun seit 4 Tagen mit visual Studio (Community) und bin neu in der MFC Materie.
    Mein Hauptproblem ist das Ändern der Ansicht einer SDI Application innerhalb des MainFrames über einen Klick Button.

    Ich würde es gern über die Doc/View Architektur lösen aber das ist mir nicht gelungen. Stattdessen habe ich eine SDI App erstellt (ohne Document/Ansicht Unterstützung) und im Designer 2 neue Views erstellt und ihnen Klassen zugewiesen. Beide Klassen sind von CFormView abgeleitet und der Konstruktor/Destruktor wurde in public geändert.

    Nun habe der CMainFrm.h Pointer auf die View Klassen gegeben:

    CMainView*        m_pMainView;
    CSecondView*      m_pSecondView; 
    

    Und die OnCreate(), OnSetFocus() und OnCmdMsg() Methoden der MainFrm.cpp abgeändert, sodass beim starten der App meine CMainView angezeigt wird, die ich ja im Designer erstellt hab.

    OnCreate():

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    
    	// First, build the view context structure
    	CCreateContext ccx;
    
    	// Designate the class from which to build the view
    	ccx.m_pNewViewClass = RUNTIME_CLASS(CMainView);
    
    	// Using the structure, create a view
    	m_pMainView = DYNAMIC_DOWNCAST(CMainView, this->CreateView(&ccx));
    	
    
    	if (!m_pMainView)
    	{
    		TRACE0("creation of view failed");
    	}
    
    	// Do layout recalc
    	RecalcLayout();
    
    	// Show the view and do an initial update
    
    	m_pMainView->ShowWindow(SW_SHOW);
    	m_pMainView->OnInitialUpdate();
    
    	// Set this view active
    	SetActiveView(m_pMainView);
    
    	// Order it to resize the parent window to fit
    	m_pMainView->ResizeParentToFit(FALSE);
    
    
    	return 0;
    }
    

    OnSetFocus() und OnCmdMsg():

    void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
    {
    	
    	m_pMainView->SetFocus();
    }
    
    BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
    {
    	
    	if (m_pMainView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
    		return TRUE;
    
    	return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
    }
    

    Nun wird mein erster View angezeigt. Ich habe mit dem Designer einen Button zu diesem View hinzugefügt und möchte das, wenn er gedrückt wird, mein 2. View angezeigt wird. Über den Event Handler habe ich folgende Funktion für den Button bekommen:

    void CMainView::OnBnClickedButton1()
    {
    	// What to do here? I want to change the current view to another View by clicking the button
    }
    

    Ich schaffe es nicht, den View über den Button zu ändern der zu CMainView gehört, ich habe es lediglich geschafft ihn über das Menü zu ändern, welches ja zu CMainFrame gehört.
    Über MainFrame habe ich es so gelöst:

    //Activated when Menue Button in Frame is clicked
    void CMainFrame::OnViewNextview()
    {
    	CCreateContext ccx2;
    	ccx2.m_pNewViewClass = RUNTIME_CLASS(CSecondView);
    	m_pSecondView = DYNAMIC_DOWNCAST(CSecondView, this->CreateView(&ccx2));
    
    	RecalcLayout();
    
    	m_pMainView->ShowWindow(SW_SHOW);
    	m_pMainView->OnInitialUpdate();
    
    	SetActiveView(m_pMainView);
    
    	m_pMainView->ResizeParentToFit(FALSE);
    
    }
    

    Das klappt, aber ich möchte es über den Button lösen. Das muss doch irgendwie möglich sein.
    Ich sitze jetzt 3 Tage an dem Problem und komme einfach nicht weiter. Ich bräuchte in CMainView einen Zeiger auf das MainFrame Object um eine Methode aufzurufen die den View erneut wechselt (auf CSecondView) aber das hat zu Fehlermeldungen geführt.

    Vielleicht hat jemand ja eine Idee und kann mir weiterhelfen. Vielen Lieben Dank im vorraus!



  • @xe-li sagte in Aktuelle Ansicht einer SDI Anwendung per Button-Klick ändern, nicht per Menüleiste!:

    Ich bräuchte in CMainView einen Zeiger auf das MainFrame Object um eine Methode aufzurufen die den View erneut wechselt (auf CSecondView) aber das hat zu Fehlermeldungen geführt.

    Was hast Du versucht? Welche Fehlermeldungen?



  • Ich habe in der CMainFrame eine Funktion geschrieben:

    void CMainFrame::changeToScndView()
    {
    	CCreateContext ccx2;
    	ccx2.m_pNewViewClass = RUNTIME_CLASS(CSecondView);
    	m_pSecondView = DYNAMIC_DOWNCAST(CSecondView, this->CreateView(&ccx2));
    }
    

    Dann habe ich versucht einen Pointer auf CMainFrame in die CMainView zu packen:

    #include "CSecondView.h"
    #include "MainFrm.h"
    ...
    public:
    	CMainView();           
    	virtual ~CMainView();
    	CSecondView* m_pSecondView;
    	CMainFrame* m_frame; 
    

    über m_frame würde ich nun gerne die Methode aufrufen um den View zu wechseln:

    void CMainView::OnBnClickedButton1()
    {
    	// What to do here? I want to change the current view to another View by clicking the button
           m_frame->changeToScndView();
    }
    

    Das gibt mir diverse Fehlermeldungen:
    Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand
    Fehler C2238 Unerwartete(s) Token vor ";" Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18
    Fehler C4430 Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt. Test2 C:\Users\xelia\source\repos\Test2\Test2\MainFrm.h 44
    Fehler C4430 Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt. Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18
    Fehler C4430 Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt. Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18
    Fehler C2143 Syntaxfehler: Es fehlt ";" vor "" Test2 C:\Users\xelia\source\repos\Test2\Test2\MainFrm.h 44
    Fehler C2143 Syntaxfehler: Es fehlt ";" vor "
    " Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18
    Fehler C2143 Syntaxfehler: Es fehlt ";" vor "*" Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18
    Fehler C2238 Unerwartete(s) Token vor ";" Test2 C:\Users\xelia\source\repos\Test2\Test2\MainFrm.h 44
    Fehler C2238 Unerwartete(s) Token vor ";" Test2 C:\Users\xelia\source\repos\Test2\Test2\CMainView.h 18



  • Das liest sich als würden da ein paar includes oder zumindest forward-declarations fehlen.



  • Schau dir die Fehlermeldungen im Output Tab an.



  • Ich habe es nun durch eine Antwort von StackOverflow hinbekommen.
    Der Trick liegt in Messages , die von einem Objekt gesendet werden können. Die Lösung war also dem Button zu sagen, dass er eine Message an das Frame Window schickt, welche die Funktion für den ViewChange triggert.

    void CMainView::OnBnClickedButton1()
    {
        //ID_VIEW_NEXTVIEW is the ID of my Mainframe menue Button that works to 
        //change the view
    
        AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_VIEW_NEXTVIEW);     
    }
    

    Man tut also so, als ob der Menü Button ID_VIEW_NEXTVIEW den ich im MainFrame Designer erstellt habe gedrückt wird.
    Dieser Button hat ein Event welches in einer Funktion definiert wurde:

    void CMainFrame::OnViewNextview()
    {
    	CCreateContext ccx2;
    	ccx2.m_pNewViewClass = RUNTIME_CLASS(CSecondView);
    	m_pSecondView = DYNAMIC_DOWNCAST(CSecondView, this->CreateView(&ccx2));
    
    	RecalcLayout();
    
    	m_pMainView->ShowWindow(SW_SHOW);
    	m_pMainView->OnInitialUpdate();
    
    	SetActiveView(m_pMainView);
    
    	m_pMainView->ResizeParentToFit(FALSE);
    
    }
    

    Hier wird der view gewechselt und das klappt wunderbar.



  • Viele Wege ...



  • Was hätte man denn noch machen können?^^



  • Deine ursprüngliche Idee hätte schon auch funktioniert. Messages sind aber auch toll.



  • Jetzt hat sich leider ein neues Problem aufgetan, ich dachte, dass es über die message Methode kein Problem mehr ist, auch von View2 zu View3 zu springen... aber fasch gedacht 😞 ...

    Ich habe im Designer einen Button auf View2 gepackt um zu View3 zu springen und im Event handler eine Methode hinzugefügt:
    CSecondView.h:

    public:
    	afx_msg void OnBnClickedButton2();
    

    CSecondView.cpp:

    void CSecondView::OnBnClickedButton2()
    {
    	AfxGetMainWnd()->PostMessage(WM_COMMAND, ID_VIEW_3);
    }
    

    In MainFrame wird das genauso behandelt wie beim ersten mal (was ja geklappt hat):

    void CMainFrame::OnViewNextview()
    {
    	CCreateContext ccx2;
    	ccx2.m_pNewViewClass = RUNTIME_CLASS(CSecondView);
    	m_pSecondView = DYNAMIC_DOWNCAST(CSecondView, this->CreateView(&ccx2));
    	RecalcLayout();
    	m_pSecondView->ShowWindow(SW_SHOW);
    	//m_pSecondView->OnInitialUpdate();
    	SetActiveView(m_pSecondView);
    	m_pSecondView->SetFocus();
    	//m_pSecondView->ResizeParentToFit(FALSE);
    
    }
    
    
    void CMainFrame::OnView3()
    {
    	CCreateContext ccx3;
    	ccx3.m_pNewViewClass = RUNTIME_CLASS(CThirdView);
    	m_pThirdView = DYNAMIC_DOWNCAST(CThirdView, this->CreateView(&ccx3));
    	RecalcLayout();
    	m_pThirdView->ShowWindow(SW_SHOW);
    	//m_pThirdView->OnInitialUpdate();
    	SetActiveView(m_pThirdView);
    	//m_pThirdView->ResizeParentToFit(FALSE);
    }
    

    Wenn ich im MainFrame Menü den Button klicke klappt es auch wunderbar, aber wenn ich es über die Buttons im View navigiere, gibt es ein problem mit der SetActiveView() Methode von MainFrame wie mir scheint. Die Fenster werden nicht gescheit in den aktiven Fokus gesetzt.

    Wie müsste ich die Methode implementieren??? :

    void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
    {
    	m_pMainView->SetFocus();
    	//m_pSecondView->SetFocus();
    
    }
    
    

    Ich möchte einfach über Buttond von View zu View wechseln können 😞