grosse Verständinsprobleme bei SDI



  • Hallo

    Ich bin’s mal wieder. Ich habe bisher immer nur Dialogfeldbasierte Anwendungen programmiert. Eigentlich war ich der Meinung die Basics verstanden zu haben, aber da habe ich mich wohl getäuscht. Aber ich will nicht verzagen, sondern fragen:

    Ich wollte ein Programm schreiben, in dem der Benutzer zwischen verschiedenen Seiten navigieren kann. Also dachte ich mir, dass ich dazu eine Klasse schreiben könnte, von der die einzelnen Bildschirme abgeleitet werden:

    // CScreen document
    
    class CScreen : public CDocument
    {
    	DECLARE_DYNCREATE(CScreen)
    
    public:
    	CScreen();
    	virtual ~CScreen();
    	virtual void Serialize(CArchive& ar);   // overridden for document i/o
    #ifdef _DEBUG
    	virtual void AssertValid() const;
    	virtual void Dump(CDumpContext& dc) const;
    #endif
    
    protected:
    	virtual BOOL OnNewDocument();
    
    	DECLARE_MESSAGE_MAP()
    public:
    	HWND m_hWnd;
    	CDC* m_pDC;
    
    };
    

    Nun wollte ich mit dem Startbildschirm beginnen und habe deshalb folgende Klasse geschrieben:

    #include "screen.h"
    
    class CStartScreen :
    	public CScreen
    {
    public:
    	CStartScreen(void);
    	CStartScreen(CDC* p_pDC, HWND p_hWnd);
    	~CStartScreen(void);
    	void ClearScreen(void);
    	void ChangeBkColor(COLORREF p_clrBkColor);
    
    	CStartScreen& operator = (const CStartScreen& v)	{m_pDC = v.m_pDC; m_hWnd = v.m_hWnd; return *this;}
    
    };
    

    In dieser Klasse gibt es nun eine Memberfunktionen um die Hintergrundfarbe zu ändern:

    void CStartScreen::ChangeBkColor(COLORREF p_clrBkColor)
    {
    	CRect r;
    	GetClientRect(m_hWnd,&r);
    	CBrush brush(p_clrBkColor);
    	m_pDC->FillRect(&r,&brush); 
    }
    

    In die Ondraw-Funktion aus der View-Datei habe ich folgendes geschrieben:

    void CFussballmanagerView::OnDraw(CDC* pDC)
    {
    	CFussballmanagerDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CStartScreen StartScreen(pDC, this->m_hWnd);
    	m_classStartScreen = StartScreen;
    	m_classStartScreen.ChangeBkColor(RGB(0,0,255));
    };
    

    Das klappt auch gut, aber ich habe das Problem, dass wenn ich in einer anderen Funktion das hier schreibe nicht passiert:

    void CFussballmanagerView::OnLButtonDown(UINT nFlags, CPoint point)
    {
    	// TODO: Add your message handler code here and/or call default
    
    	m_classStartScreen.ChangeBkColor(RGB(0,255,0));
    	CView::OnLButtonDown(nFlags, point);
    }
    

    Die Hintergrundfarbe müsste sich doch ändern, sobald ich auf die linke Maustaste drücke. Warum ist das denn nicht so? Ich würde gerne außerdem auf folgende Zeilen verzichten:

    CStartScreen StartScreen(pDC, this->m_hWnd);
    m_classStartScreen = StartScreen;
    

    und gleich

    CStartScreen m_StartScreen(pDC, this->m_hWnd)
    

    Schreiben, aber pDC kann ich nur in der OnDraw übergeben, weil ich nicht weiß, wo ich pDC sonst „hernehmen“ soll.

    Ich wollte auch noch fragen, wie ich Buttons benutzen kann.

    Ich hoffe, dass euch mein Problem klar geworden ist. Vielleicht habe ich mich ja verrannt, aber ich weiß nicht mehr, wie ich hier weiter kommen soll.

    Danke
    chrische



  • Hallo

    Habe ich meine Frage falsch gestellt, oder weiß keiner Rat?`

    chrische



  • chrische5 schrieb:

    Habe ich meine Frage falsch gestellt, oder weiß keiner Rat?`

    Dein "Ansatz" ist so wirr, dass allen die Spucke wegbleibt 😉

    Im Ernst, es bringt nichts, sich den Zeiger auf den Gerätekontext zu merken. Der ist bei jedem Aufruf von OnDraw ein anderer, und es würde mich wundern, wenn man ihn außerhalb von OnDraw benutzen könnte.



  • Hallo

    Erstmal danke für deine Antwort. Wie gesagt, es ist das erste Mal, dass ich mich mit SDI beschäftige. Ich dachte schon, dass sich der Zeiger ändert. Was allerdings komisch ist, ist dass wenn ich OnDraw mehrfach aufrufe es immer wieder klappt:

    void CFussballmanagerView::OnDraw(CDC* pDC)
    {
    	CFussballmanagerDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CStartScreen StartScreen(pDC, this->m_hWnd);
    	m_classStartScreen = StartScreen;
    	if(m_iCount==0)
    		m_classStartScreen.ChangeBkColor(RGB(0,0,255));
    	if(m_iCount==1)
    		m_classStartScreen.ChangeBkColor(RGB(255,0,0));
    	if(m_iCount==2)
    		m_classStartScreen.ChangeBkColor(RGB(0,255,0));
    
    	m_iCount++;	
    
    	// TODO: Code zum Zeichnen der systemeigenen Daten hinzufügen
    }
    

    Hat jemand vielleicht eine Idee, wei man das realisieren kann.

    chrische



  • Hallo

    chrische5 schrieb:

    Was allerdings komisch ist, ist dass wenn ich OnDraw mehrfach aufrufe es immer wieder klappt:

    void CFussballmanagerView::OnDraw(CDC* pDC)
    {
    	CFussballmanagerDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	if (!pDoc)
    		return;
    
    	CStartScreen StartScreen(pDC, this->m_hWnd);
    	m_classStartScreen = StartScreen;
    	if(m_iCount==0)
    		m_classStartScreen.ChangeBkColor(RGB(0,0,255));
    	if(m_iCount==1)
    		m_classStartScreen.ChangeBkColor(RGB(255,0,0));
    	if(m_iCount==2)
    		m_classStartScreen.ChangeBkColor(RGB(0,255,0));
    
    	m_iCount++;	
    
    	// TODO: Code zum Zeichnen der systemeigenen Daten hinzufügen
    }
    

    chrische

    das war wohl, wie mein ganzer Ansatz wirklich ein riesen Denkfehler. Ich wollte bloss noch einmal die Frage weiderholen, wie man Buttons und andere Steuerelemente bei SDI benutzen kann.

    Danke
    chrische



  • chrische5 schrieb:

    das war wohl, wie mein ganzer Ansatz wirklich ein riesen Denkfehler. Ich wollte bloss noch einmal die Frage weiderholen, wie man Buttons und andere Steuerelemente bei SDI benutzen kann.

    Danke
    chrische

    Mit CFormView als Basisklasse für den View. 🙂



  • Hallo

    Gibt es keine Möglichkeit auf einem "normalen" View Steuerelemente anzuzeigen und zu benutzen?

    chrische



  • Tja, vielleicht dynamisch erzeugt mir Create - aber das habe ich noch nicht ausprobiert.
    Was hast du gegen CFormView? 😕



  • Hallo

    Ich glaube, dass ich das Prinzip von SDI noch nicht verstanden habe. Wenn ich mit CView arbeite habe ich die Möglichkeit mittels TextOut Texte an vorgeschrieben Stellen zu schreiben. Ich kann das ganze Dokument löschen, um es mit neuen Tabellen usw. zu füllen. Bei CFormView muss ich doch für jede Textausgabe ein Textfeld erstellen und kann auch nicht den ganzen Bildschirm löschen und an anderen Stellen neuen Text ausgeben, oder? Vielleicht muss man dann mit hunderten von Steuerelementen arbeiten, aber wo bleibt denn da Übersichtlichkeit. Habe ich die Möglichkeit mehrere Dialoge zu benutzen und den Bildschirm immer wieder mit diesen zu füllen?

    Vielleicht stehe ich heute wirklich auf den Schlauch, aber ich habe das Gefühl von Brettern vor dem Kopf.

    chrische



  • Irgendwie bist du etwas wirr. 😃

    Also, ein Formview ist sowas wie ein Dialog - nur eben im SDI/MDI.
    Du kannst auch hin und her schalten zwischen "normalem" View und Formview. (Siehe FAQ)

    Beides geht sicherlich auch irgendwie - aber das wird dann was für Fortgeschrittene. 😉

    Klar kannst du zusätzlich zu einer SDI noch Dialoge aufrufen - wieso denn nicht? 😕



  • chrische5 schrieb:

    ...habe ich die Möglichkeit mittels TextOut Texte an vorgeschrieben Stellen zu schreiben...Vielleicht muss man dann mit hunderten von Steuerelementen arbeiten...

    Benutzt man TextOut wirklich? Also ich hab noch nie in ner SDI mit TextOut gearbeitet (bin ich jetzt Außenseiter?)
    Und wieso 100te Steuerelemente? Du kannst Buttons Edits und so weiter doch wie auf nem Dialog auch in ner CFormview platzieren. 😕
    Tut mir leid aber ich glaub ich versteh dein Prob nicht so ganz!



  • Hallo

    Ich glaube, dass ich gestern etwas verwirrt war 😃 Ich werde mal probieren mit meheren Views zu arbeiten, wie estartu_de es in der FAQ erklärt hat. Falls es dazu fragen gibt (und das wird sicher der Fall sein), melde ich mich einfach noch einmal.

    chrische



  • Manchmal hilft drüber schlafen... 😃
    Klar kannste dich wieder melden. 🙂



  • DANKE!! 🙂 👍



  • Hallo

    Ich habe jetzt mal die Geschichte mit den mehreren Views probiert. Ich habe es, wenn ich ehrlich nur abgeschrieben und nicht richtig verstanden und deswegen habe ich noch ein par Fragen:

    1. Wie man einen neuen Dialog erstellt weiß ich und habe ich auch gemacht. Diesem habe ich eine Klasse zugeordnet (abgeleitet von VFormview). Dann habe ich noch einen Klasse von CDocument abgeleitet. Müssen die beiden Klassen irgendwie miteinander verbunden werden, damit einmal als View und einmal als Doc angesehen werden. Wenn ich in CDiaolg2View GetDocument aufrufe, woher weiß er dann, dass ich CDialog2Doc meine? Wie gesagt: Ich bin etwas wirr, was diese View/Doc- Architektur angeht.
    2. Ich bekomme immer folgende Fehlermeldung:

    error C2039: 'CreateWnd' : is not a member of 'CSDITestView'

    gehört hierzu:

    template<class View, class Doc> View* create_view(CWnd* f_pParent)
    {
    		View* view = new View();
    		Doc* doc   = new Doc();
    		CCreateContext createContext;
    		createContext.m_pNewViewClass = 0;
    		createContext.m_pNewDocTemplate = 0;
    		createContext.m_pLastView = 0;
    		createContext.m_pCurrentFrame = 0;
    		createContext.m_pCurrentDoc = doc;
    		view->CreateWnd(f_pParent, createContext);
    		return view;
    }
    

    3. Wie kann ich dann eigentlich die Funktion SwitchView aufrufen? Ich dachte mir, dass ich einen View habe, auf dem es ein Button gibt; und wenn dieser gedrückt wird, ruft er den zweiten View auf. Keine Ahnung wie das gehen soll.

    Danke für eure Geduld

    chrische



  • Zeig mal die Zeile zu der Fehlermeldung.

    Du kannst das SwitchView auch von einem Konpf aus aufrufen - das ist aber etwas schwieriger als vom Menü aus. (Beides zusammen geht wieder rel. einfach.)

    Das mit dem GetDocument funktioniert, nur ein Cast fehlt...

    CMyDoc* pDoc = dynamic_cast<CMyDoc*>(GetDocument());
    	ASSERT(pDoc);
    


  • Hallo!

    Hier die Zeile der Fehlermeldung:

    view->CreateWnd(f_pParent, createContext);
    

    estartu_de schrieb:

    Du kannst das SwitchView auch von einem Konpf aus aufrufen - das ist aber etwas schwieriger als vom Menü aus. (Beides zusammen geht wieder rel. einfach.)

    Wie könnte man das denn lösen?

    estartu_de schrieb:

    Das mit dem GetDocument funktioniert, nur ein Cast fehlt...

    CMyDoc* pDoc = dynamic_cast<CMyDoc*>(GetDocument());
    	ASSERT(pDoc);
    

    Verstehe ich dich richtig: Man muss View und Doc nicht noch einmal speziell einader zuordnen?

    Danke

    chrische



  • chrische5 schrieb:

    Hier die Zeile der Fehlermeldung:

    view->CreateWnd(f_pParent, createContext);
    

    Hast du diese Funktion im View?

    void CSDITestView::CreateWnd(CWnd* f_pParent, CCreateContext& f_rCreateContext) 
    {
        VERIFY(Create(0, 0, WS_CHILD | WS_BORDER, CRect(0, 0, 0, 0), f_pParent, AFX_IDW_PANE_FIRST, &f_rCreateContext));
    	SendMessage(WM_INITIALUPDATE, 0, 0);
    }
    

    chrische5 schrieb:

    Verstehe ich dich richtig: Man muss View und Doc nicht noch einmal speziell einader zuordnen?

    Doch, muss man - aber das machst du ja auch. Mit

    pNextView = create_view<CSDITestView, CSDITestDoc>(this);
    

    Der CreateContext macht das dann.

    Hast du eigentlich schon mal eigene Nachrichten erstellt und behandelt?
    Denn damit kannst du das Umschalten auch von einem Button aus machen.
    Einfach in der Handlerfunktion die Nachricht losschicken:

    AfxGetMainWnd()->SendMessage(WM_SCHALTE_UM_AUF_VIEW, IDD_SDITEST_VIEW2);
    

    Oder so ähnlich. Weiß du, wie ich meine oder soll ich erklären? 🙂



  • Hallo

    Wie immer: Dankeschön schon vorher.

    estartu_de schrieb:

    chrische5 schrieb:

    Hier die Zeile der Fehlermeldung:

    view->CreateWnd(f_pParent, createContext);
    

    Hast du diese Funktion im View?
    [cpp]

    Ich hatte sie nicht drin und habe dies jetzt nachgeholt und ich bekomme leider neue Fehlermeldung:

    error C2065: 'WM_INITIALUPDATE' : undeclared identifier

    Hast du eigentlich schon mal eigene Nachrichten erstellt und behandelt?
    Denn damit kannst du das Umschalten auch von einem Button aus machen.
    Einfach in der Handlerfunktion die Nachricht losschicken:
    [cpp]
    AfxGetMainWnd()->SendMessage(WM_SCHALTE_UM_AUF_VIEW, IDD_SDITEST_VIEW2);[/cpp]
    Oder so ähnlich. Weiß du, wie ich meine oder soll ich erklären? 🙂

    Ich habe noch nie eigenen Nachrichten erstellt und würde mich sehr über eine Erklärung von dir freuen. Ich würde dich aber bitten kleinschrittig vorzugehen, weil das absolutes Neuland für mich ist.

    chrische



  • Hallo!

    chrische5 schrieb:

    error C2065: 'WM_INITIALUPDATE' : undeclared identifier

    Das ist rel. einfach: Du hast ein include vergessen.

    #include "afxpriv.h"
    

    Die Nachrichten mache ich nachher in Ruhe. 🙂



  • Hallo

    Du hattest natürlich Recht. Ich habe deine Anweisung befolgt und es lässt sich erstmal ohne Problem compilieren. Ich wollte nur mal schreiben, dass ich es hingekriegt habe, über das Menü die Views zu wechseln. Wirklich echt super. Dazu hätte ich aber wie immer noch eine Frage: Wie kann ich es einrichten, dass er alle View maximiert anzeigt?

    chrische


Anmelden zum Antworten