Menü wechseln



  • Soda, hab das ganze jetzt mal umgesetzt allerdings funktioniert das noch nicht so, wie ich will.

    Zuerst mal im detail, wie ich das ganze implementiert habe:

    Meinem App die Membervariable

    CMultiDocTemplate* m_pDocTemplate;
    

    hinzugefügt.

    InitInstance der App abgeändert (m_pDocTemplate statt neuem CMultiDocTemplate-Pointer):

    m_pDocTemplate = new CMultiDocTemplate(IDR_xxxTYPE,
    		RUNTIME_CLASS(xxxDoc),
    		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    		RUNTIME_CLASS(xxxView));
    	if (!m_pDocTemplate)
    		return FALSE;
    	AddDocTemplate(m_pDocTemplate);
    

    MainFrame (OnNewFile):

    CMenu menu;
    	HMENU hMenu = theApp.AppGetLangMenu(IDR_xxxTYPE);
    	if (hMenu == NULL)
    		return;
    
    	menu.Attach(hMenu);
    
    	CxxxDoc *pDoc = new CxxxDoc();
    	CFrameWnd *frameWnd = theApp.m_pDocTemplate->CreateNewFrame(pDoc, NULL);
    	frameWnd->InitialUpdateFrame(pDoc, TRUE);
    
    	CWnd::SetMenu(NULL);
    	CWnd::SetMenu(&menu);
    
    	//delete pDoc;
    

    Ist doch richtig, dass ich hier nicht CDocument, sondern CxxxDoc verwende (CDocument ist nur eine abstrakte Klasse und kann nicht instanziert werden!)?

    Wenn ich pDoc lösche schlägt ein Assert fehl, sobald die View das Dokument mittels GetDocument holen möchte...

    View (OnNewFile):

    CMenu menu;
    	HMENU hMenu = theApp.AppGetLangMenu(IDR_xxxTYPE);
    	if (hMenu == NULL)
    		return;
    
    	menu.Attach(hMenu);
    
    	CxxxDoc *pDoc = GetDocument();
    	CFrameWnd *frameWnd = theApp.m_pDocTemplate->CreateNewFrame(pDoc, NULL);
    	frameWnd->InitialUpdateFrame(pDoc, TRUE);
    
    	CWnd::SetMenu(NULL);
    	CWnd::SetMenu(&menu);
    
    	delete pDoc;
    

    Eigentlich keine große Änderung bezüglich des oben vorgeschlagenen Codes vorgenommen (außer wieder CxxxDoc statt CDocument).

    Nun meine Probleme:

    - Wenn ich ein neues Dokument öffne wird kein neuer Standard-Name mehr vergeben (xxx1.xx). Menüleiste sah zuvor nach öffnen einer neuen Dokuments immer folgendermaßen aus: xxx - [xxx1.xxx]
    - Die neue View bekommt keinen eigenen Verkleinern-, Vergrößern- & Schließen-Button mehr (So sollte es aussehen, So sieht es aus).

    Weiters muss ich das ganze ja dann noch so erweitern, dass das Menü nicht nur beim öffnen eines neuen sondern auch beim öffnen eines bereits bestehenden Dokuments geladen wird (was aber hoffentlich kein allzu großes Problem darstellen sollte).

    Hoffentlich kann mir nun auch noch wer weiterhelfen!

    danke, mfg

    ps.: Die xxx stehen für den Namen des Programms!



  • @LowFly und alle anderen!

    Keiner mehr eine Ahnung?

    Sorry fürs pushen, will nicht, dass der Thread vergessen wird, wenn ich mir doch sicher bin, dass es hier wen gibt, der mir weiterhelfen kann!

    danke, mfg



  • jo sorry hab dich tutal vergessen 😉 wollt eigendlich antworten aber der thread ist nach unten durchgerutscht.

    warum nimmst du nicht

    CDocument *pDoc = new CDocument();
    

    sondern

    CxxxDoc *pDoc = new CxxxDoc();
    

    da motzt bei mir der compiler

    Compiler schrieb:

    Kein Zugriff auf protected Element, dessen Deklaration in der Klasse "C...Doc" erfolgte

    das funst nur wenn ich die deklaration public mach und die is ja nicht umsonst protected.
    CDocument funst bei mir an dieser stelle ohne probleme auch das delete pDoc;

    ja und wie gesagt du bist jetzt dafür verantwortlich was bei der erstellung des Documentes passiert somit must du ihm auch einen Namen gebene wenn du es willst.
    ich ahb da grad mal ein wenig rumgespielt wie unten folgt geb ich den documenten so wieder einen titel jedoch ist GetTypeInfoCount nicht das richtige da 2 documente der gleichen art immer noch 0 documente sind war ein versuch ich habs jetzt mal dringelassen damit i in format einen wert hat.

    int i = pDoc->GetTypeInfoCount();
    
    CString sText,sWindowText;
    GetWindowText(sWindowText);
    
    sText.Format("%s EditView%i",sWindowText,i);
    SetWindowText(sText);
    sText.Format("EditView%i",i);
    pDoc->SetTitle(sText);
    

    was das mit dem systembutten verkleinern vergrößern usw.. auf sich hat kann ich jetzt nur raten aber hast du zufällig die PreCreateWindow function bzw die CREATESTRUCT des Fensters geändert oder ist diese in deiner classe forhanden, nur so verschwinden die nämlich.

    NEW EDIT;
    was mir da grad noch so eingefallen ist, für die fenstertitel erstellung wäre eigendlich der richtige platz in dem CDocument::NewDocument da ja die MainFrame immer den Documententitel annimmt. 😉



  • LowFly schrieb:

    jo sorry hab dich tutal vergessen 😉 wollt eigendlich antworten aber der thread ist nach unten durchgerutscht.

    Na dann is ja gut, dass ich den Thread gepusht habe 😉

    LowFly schrieb:

    warum nimmst du nicht

    CDocument *pDoc = new CDocument();
    

    sondern

    CxxxDoc *pDoc = new CxxxDoc();
    

    da motzt bei mir der compiler

    Compiler schrieb:

    Kein Zugriff auf protected Element, dessen Deklaration in der Klasse "C...Doc" erfolgte

    das funst nur wenn ich die deklaration public mach und die is ja nicht umsonst protected.
    CDocument funst bei mir an dieser stelle ohne probleme auch das delete pDoc;

    Wie oben bereits geschrieben kann ich CDocument nicht instanzieren, weil es eine abstrakte Klasse ist (genaue Compiler-Meldung: "error C2259: 'CDocument' : cannot instantiate abstract class").
    Dazu hab ich natürlich die deklaration von CxxxDoc public gemacht (schon klar, dass das nicht sein soll, aber nachdem es anders nicht funzt...).

    Die Sache mit dem Namen sollte kein allzu großes Problem sein. Durchlaufe einfach alle offenen Dokumente und werd so schon herausfinden, welche fortlaufende Zahl die nächste ist 😉

    LowFly schrieb:

    was das mit dem systembutten verkleinern vergrößern usw.. auf sich hat kann ich jetzt nur raten aber hast du zufällig die PreCreateWindow function bzw die CREATESTRUCT des Fensters geändert oder ist diese in deiner classe forhanden, nur so verschwinden die nämlich.

    Die PreCreateWindow ist in folgenden Klassen vorhanden: CMainFrame, CxxxView & CChildFrm.
    Geändert wurde sie nur in der CxxxView, wobei diese im Original lediglich eine Anweisung ausführt:

    return CView::PreCreateWindow(cs);
    

    Bei mir wurde nur das CView auf CScrollView geändert:

    return CScrollView::PreCreateWindow(cs);
    

    Kann das hierfür der Grund sein?
    Auch die CREATESTRUCT wird sonst eigentlich nirgends verwendet oder verändert (wird eben nur in den PreCreateWindow-Funktionen als Parameter übergeben aber nicht angerührt)...

    mfg



  • hmm geh ich richtig in der annahme das du vc8 bzw 2005 version hast?
    dann versuch mal eine neue Documentenclasse zu erstellen diese von CDocument abzuleiten so hat es zumindest linus gemacht der hatte das gleiche problem mit der abstracten klasse.

    das mit systembutten verkleinern vergrößern usw.. denke ich kommt daher das
    die CScrollView::PreCreateWindow(cs) evtl nicht den Flag für Systemenu hat.
    evtl könntest du auch mal versuchen bevor du die CREATESTRUCT an CScrollView::PreCreateWindow(cs) sie von dem actuellen fenster zu holen. wenn das ncit hilft halt den flag setzen.



  • LowFly schrieb:

    hmm geh ich richtig in der annahme das du vc8 bzw 2005 version hast?
    dann versuch mal eine neue Documentenclasse zu erstellen diese von CDocument abzuleiten so hat es zumindest linus gemacht der hatte das gleiche problem mit der abstracten klasse.

    Jep, du gehst richtig in der Annahme. VS 2005

    LowFly schrieb:

    evtl könntest du auch mal versuchen bevor du die CREATESTRUCT an CScrollView::PreCreateWindow(cs) sie von dem actuellen fenster zu holen. wenn das ncit hilft halt den flag setzen.

    Wie kann ich die vom aktuellen Fenster holen? Das Flag weiß ich zwar gerade auch nicht, aber das lässt sich ja in der MSDN finden 😉

    Hab gerade keine Zeit das ganze auszuprobieren, werde es aber später mal versuchen!

    danke, mfg



  • ja muste auch erst nachkucken in der MSDN
    an den style kommst du evtl mit .

    DWORD dwStyle = (DWORD)GetWindowLong(m_hWnd, GWL_STYLE);
    dwStyle  &= ~WS_MAXIMIZEBOX;//Deaktiviert die Maximieren button
    dwStyle  &= ~WS_MINIMIZEBOX;//Deaktiviert die Minimieren button
    cs.style = dwStyle;
    CScrollView::PreCreateWindow(cs);
    

    bzw könntest du ihn auch direct von der Function holen

    BOOL C...::PreCreateWindow(CREATESTRUCT& cs)
    {
    	cs.style |= WS_SYSMENU;//Systemenu hinzufügen
    	cs.style &= ~WS_MAXIMIZEBOX;//Deaktiviert die Maximieren button
    	cs.style &= ~WS_MINIMIZEBOX;//Deaktiviert die Minimieren button
    	return CScrollView::PreCreateWindow(cs);
    }
    

    und die styles findest du unter WS_ 😉



  • Soda mir reichts jetzt!

    Irgendwie funktioniert hier überhaupt nichts mehr...

    Gibt es nicht irgend einen einfacheren Weg das ganze zu lösen?

    Dabei könnte ich mir vorstellen einfach auf die 2 unterschiedlichen Menüs zu verzichten und immer das selbe zu zeigen (also das gleiche Menü beim start des Programms, bzw. wenn kein Dokument mehr geöffnet ist und wenn Dokument(e) geöffnet sind).
    Dabei sollten halt lediglich jene Funktionen, die ohne geöffnetes Dokument keinen Sinn machen deaktiviert sein (ist ja denke ich Standardmäßig so, wenn keine View geöffnet ist, welche die Messages empfängt).

    Dann müsste ich ja lediglich beim ändern der Sprache das Menü austauschen und fertig??? Was müsste ich im Programm jetzt umstellen, damit nur noch 1 Menü verwendet wird (Stichwort CMultiDocTemplate im App)?

    Danke für die große Ausdauer mit mir. Hoffentlich könnt ihr mir auch weiterhin helfen!

    mfg



  • Was müsste ich im Programm jetzt umstellen, damit nur noch 1 Menü verwendet wird (Stichwort CMultiDocTemplate im App)?

    hmm 😕 versteh nicht ganz was du meinst

    m_pDocTemplate = new CMultiDocTemplate(
            [b]IDR_MENUDASGELADENWIRD[/b],//<----das ist das Menu was immer geladen wird
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    


  • Ohne das jetzt ausprobiert zu haben steh ich dann aber wieder vor dem Problem, dass bei jedem öffnen eines neuen Dokuments wieder das Standard-Menü (also in dem Fall Englisch) geladen wird und nicht jenes, dass aktuelle eingestellt ist (also zB. Deutsch).

    Naja, werd mal wieder ein wenig herumspielen und trotzdem nicht weiterkommen 😢 (sorry, aber schön langsam nervt mich das ganze einfach)

    mfg



  • also was mir da noch einfallen würde bzw. schon länger ist,
    erstell dir doch in der App einfach ein zweites MultiDocTemplate

    m_pDocTempEng = new CMultiDocTemplate(
            IDR_MENU_ENGLISH,
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    
    m_pDocTempGer = new CMultiDocTemplate(
            IDR_MENU_GERMAN,
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    

    je nachdem welche sprache eingestellt wurde übergibst du zu Beginn an

    AddDocTemplate(....);
    

    das jeweilige MultiDoc für die Sprache des Menus.

    und evtl würde es gehn das du wärend der laufzeit mit

    ((CChangeViewsApp*)AfxGetApp())->AddDocTemplate(NULL);
    ((CChangeViewsApp*)AfxGetApp())->AddDocTemplate(m_pDocTemp...);
    

    das MultiDoc änderst aber das hab ich jetzt nicht probiert wäre nur sone idee
    😉



  • LowFly schrieb:

    m_pDocTemplate = new CMultiDocTemplate(
            [b]IDR_MENUDASGELADENWIRD[/b],//<----das ist das Menu was immer geladen wird
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    

    Hab das jetzt mal versucht, aber irgendwie ändert das nichts:

    Der Aufruf sieht jetzt folgendermaßen aus:

    m_pDocTemplate = new CMultiDocTemplate(IDR_xxxTYPE,
    		RUNTIME_CLASS(CxxxDoc),
    		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    		RUNTIME_CLASS(CxxxView));
    
    	if (!m_pDocTemplate)
    		return FALSE;
    
    	AddDocTemplate(m_pDocTemplate);
    

    Angezeigt wird beim Programmstart trotzdem nicht das Menü IDR_xxxType, sonder IDR_MAINFRAME, also wird das Menü wohl wo anders geladen. Die Frage ist nur, wo? (Das Problem hab ich jetzt umgangen, indem ich in der InitInstance ganz am Schluss einfach mein AppChangeLanguage aufrufe, welches unter anderem auch die unten geschilderte Methode SetMenu vom MeinFrame ausführt. So wird anhand eines Registry-Eintrages zumindest beim Start das zuvor verwendete Sprach-Menü angezeigt ;))

    LowFly schrieb:

    also was mir da noch einfallen würde bzw. schon länger ist,
    erstell dir doch in der App einfach ein zweites MultiDocTemplate

    m_pDocTempEng = new CMultiDocTemplate(
            IDR_MENU_ENGLISH,
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    
    m_pDocTempGer = new CMultiDocTemplate(
            IDR_MENU_GERMAN,
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    

    Das kann ich nicht machen, da die Sprach-Ressourcen nicht fix im Programm eingebetet sind, sondern als Sprach-Dll's zur Verfügung stehen, welche dynamisch geladen werden, dh. das Programm weiß im Prinzip gar nicht, welche Sprachen vorhanden sind (das ganze soll einfach und vor allem unbegrenzt erweiterbar sein).

    Die Umschaltung der Sprache erfolgt über folgende Methode, die im FrmMain definiert ist:

    void CMainFrame::SetMenu()
    	{
    	CMenu menu;
    	HMENU hMenu;
    
    	hMenu = theApp.AppGetLangMenu(IDR_xxxTYPE);
    	if (hMenu == NULL)
    		return;
    
    	menu.Attach(hMenu);
    
    	CWnd::SetMenu(NULL);
    	CWnd::SetMenu(&menu);
    	::DrawMenuBar(m_hWnd);
    	}
    

    Beim starten des Programms wird über eben diesen Befehl das Menü der zuletzt verwendeten Sprache geladen. Nun stehe ich wieder vor dem Problem, dass beim öffnen eines neuen Dokuments wieder das Standard-Menü und nicht das Sprach-Spezifische geladen wird.

    Und noch ein (bereits bekanntes) Problem: Wenn ein Dokument geöffnet wurde und ich dann erst die Sprache umschalte (mit oben geposteter Methode) verschwinden die System-Button (maximieren, minimieren, schließen) des Dokuments...

    Ich weiß, dass sich das alles schon ziemlich im Kreis dreht und das bestimmt für euch/dich schon ziemlich nervig und anstrengend sein muss, aber ich hoffe trotzdem, dass ich gemeinsam mit euch eine Lösung finden kann!

    danke, mfg



  • hmm also als allerletzte möglichkeit würde mir jetzt noch einfallen menupunkte gezielt zu zerstöhren & wieder neu zu beschriften. kuck dir mal die klasse CMenu genauer an. du kannst jeden einzelnen menupunkt in einem bereits bestehenden Menu zerstöhren und an seiner stellen einen anderen Menupunkt einfügen.

    nur ist halt ne crasse arbeit das zu bewerkstelligen.



  • Die Möglichkeit ist mir auch schon in den Sinn gekommen, allerdings hab ich sie gleich wieder verworfen (wegen dem doch relativ großen Aufwand). Vor allem ist das Programm noch nicht ganz fertig, dass heißt bei jeder Änderung des Menüs entsteht hier wieder ein "unnötig" großer Aufwand...

    Naja, sollte ich anders wirklich nicht weiterkommen wird es wohl keine andere Möglichkeit als diese geben.

    danke, mfg



  • Muss mich hier wieder melden (war ja auch nicht anders zu erwarten ;))

    Hab zwar die Sprachumschaltung mal hinten angestellt aber bin gerade wieder auf ein Problem gekommen, welches ich dann doch relativ schnell lösen sollte:

    Ich hab mich ja jetzt dazu entschieden immer das selbe Menü anzuzeigen (also kein abgespecktes Menü, wenn kein Dokument geöffnet ist).

    Das Problem dabei hab ich ja vorher schon beschrieben und ich es umgangen habe:

    suamikim schrieb:

    LowFly schrieb:

    m_pDocTemplate = new CMultiDocTemplate(
            [b]IDR_MENUDASGELADENWIRD[/b],//<----das ist das Menu was immer geladen wird
            RUNTIME_CLASS(xxxDoc),
            RUNTIME_CLASS(CChildFrame), 
            RUNTIME_CLASS(xxxView));
    

    Hab das jetzt mal versucht, aber irgendwie ändert das nichts:

    Der Aufruf sieht jetzt folgendermaßen aus:

    m_pDocTemplate = new CMultiDocTemplate(IDR_xxxTYPE,
    		RUNTIME_CLASS(CxxxDoc),
    		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
    		RUNTIME_CLASS(CxxxView));
    
    	if (!m_pDocTemplate)
    		return FALSE;
    
    	AddDocTemplate(m_pDocTemplate);
    

    Angezeigt wird beim Programmstart trotzdem nicht das Menü IDR_xxxType, sonder IDR_MAINFRAME, also wird das Menü wohl wo anders geladen. Die Frage ist nur, wo? (Das Problem hab ich jetzt umgangen, indem ich in der InitInstance ganz am Schluss einfach mein AppChangeLanguage aufrufe, welches unter anderem auch die unten geschilderte Methode SetMenu vom MeinFrame ausführt. So wird anhand eines Registry-Eintrages zumindest beim Start das zuvor verwendete Sprach-Menü angezeigt ;))

    Jetzt bin ich aber gerade auf folgendes Problem dabei gestoßen:

    Programm starten -> IDR_xxxType-Menü wird angezeigt (kein Dokument offen, also sind alle irrelevanten Einträge deaktiviert) -> Dokument öffnen -> IDR_xxxType-Menü wird angezeigt (Einträge aktiviert) -> Dokument schließen -> IDR_MAINFRAME-Menü wird angezeigt (wobei hier wieder das IDR_xxxType-Menü angezeigt werden sollte.

    Hoffe ihr könnt mir folgen und versteht mein Problem.

    Jetzt komme ich eigentlich wieder zu meiner Ausgangsfrage dieses Threads:

    Wo genau findet der Wechsel zwischen den unterschiedlichen Menüs (IDR_xxxType (Dokument(e) geöffnet) / IDR_MAINFRAME (kein Dokument geöffnet)) im Programm statt? Kann beim besten Willen keine Stelle im Code finden, die das erledigt...

    Sorry, aber irgendwie fehlt mir zeitweise einfach noch der nötige Durchblick in c++ & mfc (hatte bisher Hauptsächlich mit C# und ein wenig Java zu tun).

    danke, mfg


Anmelden zum Antworten