Tabstops
-
Dein Problem ist, dass offensichtlich Deine Unterdialoge Kinder des CTabCtrls sind. Das geht so niht. Dann müsste WS_EX_CONTROLPARENT für das Tab Control gesetzt sein.
Wenn aber auch Dein Tab Control den Focus erhalten soll, beißt sich hier alles in den Schwanz.Schau Dir mal an wie Windows das mit CPropertySheet macht:
http://msdn.microsoft.com/en-us/library/139z22ye(VS.80).aspxWarum baust Du das selber und greifst nicht auf entsprechenden Code zurück:
http://www.codeproject.com/KB/docview/cpropertyview.aspx
-
BTW: Wurde hier
http://groups.google.de/group/microsoft.public.de.vc/browse_frm/thread/7e90a2dee7196cde#
kürzlich auch schon diskutiert!
-
Hi Martin,
vielen Dank für Deine Hilfe!
Ich hab mir gleich einmal die Demos von CodeProject heruntergelanden und angeschaut. Leider ist es da auch so, dass ich mit der Tab-Taste, die Tab-Reiter nicht erreichen kann.
Mir persönlich würde es auch schon reichen wenn ich in meiner aktuellen Anwendung alle Controls auf einem Tab durchlaufen könnte. Hast du evtl. einen Tipp?
Das PropertySheet hab ich aus folgendem Grund nicht eingesetzt.
Ich füge Komponenten dynamisch zu einer Seite hinzu, dann sind diese Komponenten Child einer bestimmten Seite.
Nun ist es möglich, dass ich einige Komponenten nicht mehr benötige und sich dadurch die Anzahl der Seiten reduziert. Benötigte Komponenten befinden sich aber noch auf der Seite die entfernt werden soll.
Ich kann zwar die Komponenten verschieben und das Parent-Fenster aus der Sicht des Controls ändern, aber die zu löschende Seite bekommt davon nichts mit und geht immer noch davon aus, dass die verschobene Komponente ein Child-Objekt wäre, lösche ich diese Seite wird auch die Komponente gelöscht.
Das ist alles nicht so einfach, vorallem wenn man programmieren mit C# gewöhnt ist

-
kerberos schrieb:
Ich hab mir gleich einmal die Demos von CodeProject heruntergelanden und angeschaut. Leider ist es da auch so, dass ich mit der Tab-Taste, die Tab-Reiter nicht erreichen kann.
Mir persönlich würde es auch schon reichen wenn ich in meiner aktuellen Anwendung alle Controls auf einem Tab durchlaufen könnte. Hast du evtl. einen Tipp?
Das ist der Nromalfall, wenn ein CDialog bzw. CFormView verwendet wird.
Da muss man nichts machen! Dann wäre der CodeProject Code doch Deine Lösung!
Das PropertySheet hab ich aus folgendem Grund nicht eingesetzt.
Ich füge Komponenten dynamisch zu einer Seite hinzu, dann sind diese Komponenten Child einer bestimmten Seite.Nun ist es möglich, dass ich einige Komponenten nicht mehr benötige und sich dadurch die Anzahl der Seiten reduziert. Benötigte Komponenten befinden sich aber noch auf der Seite die entfernt werden soll.
Und wo ist das Problem?
Ich kann zwar die Komponenten verschieben und das Parent-Fenster aus der Sicht des Controls ändern, aber die zu löschende Seite bekommt davon nichts mit und geht immer noch davon aus, dass die verschobene Komponente ein Child-Objekt wäre, lösche ich diese Seite wird auch die Komponente gelöscht.
Verstehe ich nicht. Wnen man eine Seite löscht, dann löscht man diese und. Dann ist diese und alle Subfenster weg.
Ebenso kann man neue hinzufügen. Ich verstehe aktuell gar nichts von Deinem Design.Schau Dir bittemal die grundsätzliche Diskussion an, die ich Dir gepostet habe. Vielleiucht verstehst Du dann die Grundprinzipien, wie IsDialogMessage WS_EX_CONTROLPARENT funktioniert.
Wichtig ist auch, dass IsDialogMessage nicht von dem entsprechenden Child Dialog ausgeführt wird, sondern von dem außeren View, wenn WM_EX_CONTROLPARENT im Spiel ist.
-
Hi,
also mir ist heute Nachmittag eine "leichtere" Lösung eingefallen. Ich poste mal meinen Lösungsvorschlag für alle die ein ähnliches Problem haben (chriss_2oo4).
Ich packe einfach alle GUI-Element inkl. dem CTabCtrl als Geschwister auf der CFormView. Verwalten kann ich das ganze ja immer noch über eine eigene Klasse.
Funktioniert tadellos.
Lg Kerberos
-
Exakt. So macht es auch CPropertySheet!
So habe ich es auch in dem Thread
http://groups.google.de/group/microsoft.public.de.vc/browse_frm/thread/7e90a2dee7196cde#
angeraten.
-
Hi,
nochmals Danke, Maritn!
ein Problem gelöst, schon kommt das nächste Problem :).
Jetzt funktioniert das Durchlaufen der Controls mit der Tab-Taste zwar einwandfrei, nur wird nicht automatisch weitergescrollt wenn ein Control außerhalb des sichtbaren Bereichs liegt.
Soetwas wie ein Flag AutoScroll habe ich nicht gefunden, gibt es wahrscheinlich auch nicht, oder?Nun ist die Frage, wie kann ich das implementieren?
Meine einzige Lösung, die mir einfällt ist:
in der OnCommand die Nachricht von jedem Control abfangen und Prüfen ob ein Control den Fokus bekommen hat.
Ist dies der Fall, muss man die Koordinaten des controls verwenden um die Scroll-Position anzupassen.Ich finde diese Methode etwas umständlich, desshalb frag ich nochmal nach, vllt. gibt es ja schon was fertiges in den MFC, oder einen wesentlich besseren Lösungsweg?
Lg Kerberos
-
Nein! So wie Du das beschriebst ist es einekorrekte Lösung.
Ich verwende oft eine Helper Klasse, die einen Subclass macht und auf WM_SETFOCUS lauert.Aber es geht auch mit einem Timer. Alle 1/20 Sekunde schaut man nach wer den Focus hat. Ist das Control das den Focus hat außerhalb des sichtbaren Scrollbereiches, dann rollt man es in den sichtbaren Bereich...
-
Hi,
hat vllt. jemand einen Beispiel-Code? Ich bekomm das einfach nicht hin. Ich kann ja mal meine bisherigen Überlegungen posten:
pWnd = GetDlgItem(iId); pWnd -> GetWindowRect(rcComponent); //Es muss nach links gescrollt werden if(rcComponent.left < rcParent.left + GetScrollPos(SB_HORZ)) { int iOffset = rcComponent.left - rcParent.left; ScrollWindow(SB_HORZ, iOffset); } //Es muss nach rechts gescrollt werden else if(rcComponent.right > rcParent.right + GetScrollPos(SB_HORZ)) { int iOffset = rcComponent.right - rcParent.right; ScrollWindow(SB_HORZ, iOffset); }rcParent ist das CRect der CFormView und rcComponent ist das CRect der aktuellen Componente (z. B. Button).
Danke und Lg
Kerberos
-
Du hast doch en CScrollView! Dann nutze das doch.
ScrollWindow ist IMHO der falsche Ansatz. Zur Not (wenn kein CScrollView im Spiel ist) sende einen WM_xSCROLL/thumb Nachricht an Dich selbst und behandle das dort.Rollen musst da jetzt auch schon können. Es macht doch keinen Sinn, den Rollmechanismus überall in Deiner Klasse zu streuen.
Bei einem Scrollview ist das ganz einfach:
// pView ist ein CScrollView // Diese Werte Brauchen wir CRect rcControl, rcParent; // Erstmal das Client pView->GetClientRect(&rcParent); // Fenster Koordinaten bzgl. des Parents Wnd()->GetWindowRect(&rcControl); pView->ScreenToClient(&rcControl); // Aktuelle Position bestimmen CPoint ptScrollPosition= pView->GetScrollPosition(); // Verticales rollen? CPoint ptNewScrollPosition = ptScrollPosition; // Eine Unit Platz lasen CSize sOffset = CSize(irgendwasx,irgendwasy); // Vertikales rollen if (rcControl.left < rcParent.left) // Verschieben nach links (Distanz ist Negativ) ptNewScrollPosition.x += rcControl.left-rcParent.left-sOffset.cx; else if (rcControl.right > rcParent.right) // Verschieben nach rechts (Distanz ist positv) ptNewScrollPosition.x += rcControl.right-rcParent.right+sOffset.cx; // Horizontales rollen if (rcControl.top < rcParent.top) // Verschieben nach oben (Distanz ist Negativ) ptNewScrollPosition.y += rcControl.top-rcParent.top-sOffset.cy; else if (rcControl.bottom > rcParent.bottom) // Verschieben nach unten (Distanz ist positv) ptNewScrollPosition.y += rcControl.bottom-rcParent.bottom+sOffset.cy; /* Nun bliebt die Frage ob durch diesen Scroll Vorgang etwa * die linke obere Ecke aus dem Fenster gerät */ rcControl.OffsetRect(ptScrollPosition-ptNewScrollPosition); if (rcControl.left<0) ptNewScrollPosition.x += rcControl.left; if (rcControl.top<0) ptNewScrollPosition.y += rcControl.top; // Scroll nur wenn notwendig if (ptScrollPosition!=ptNewScrollPosition) pView->ScrollToPosition(ptNewScrollPosition);
-
Hi Martin,
vieeelen Daaaank, da wäre ich wohl noch zwei Tage dran gesessen...
Wie ich mir dachte, ein Problem gelöst schon taucht das nächste auf
Meine Anwendung springt nur in die OnCommand wenn ich durch das Drücken der Tab-Taste auf eine Combo-Box komme, erreiche ich einen Button, komme ich erst garnicht in die OnCommand. Muss ich jetzt wieder irgendwelche "Spezialänderungen" an meiner Anwendung vornehmen oder muss ich das Ganze in einen Timer verlagern, sobald ich Buttons einsetze?
-
Buttons haben keine Benachrichtigung für Focus bekommen/verlieren.
Also Subclass Hook setzen und WM_SETFOCUS abfangen oder Timer nutzen. (Sagte ich das nicht schon...)
-
fehlpost
-
Hi,
Ich hab den Thread gestartet, und mich auch inzwischen angemeldet. Ich hab das Ganze jetzt versucht zu implementieren, aber bin auf ein Problem gestoßen
In einer Klasse die von CFormView abgeleitet ist gibt es die Methode ScrollToPosition(...) und die funktioniert auch ganz prima, aber in meiner Klasse, die von CDialog abgeleitet ist gibt es das leider nicht.
Da gibt es nur folgende zwei Methoden
SetScrollPos(...);
ScrollWindow(...);Ich hab OnHScroll(...) überschrieben und ich komm mit dem Zusammenspiel beider Methoden (SetScrollPos / ScrollWindow) und (OnHScroll / Timer) nicht klar.
void CExpertModeDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int iDelta; switch (nSBCode) { case SB_LINERIGHT: if (m_iHScrollPos >= m_iHScrollWidth) { return; } iDelta = 5; break; case SB_LINELEFT: if (m_iHScrollPos <= 0) { return; } iDelta = -5; break; case SB_PAGERIGHT: if (m_iHScrollPos >= m_iHScrollWidth) { return; } iDelta = 5; break; case SB_THUMBTRACK: case SB_THUMBPOSITION: iDelta = (int)nPos - m_iHScrollPos; break; case SB_PAGELEFT: if (m_iHScrollPos <= 0) { return; } iDelta = -5; break; default: return; } m_iHScrollPos += iDelta; SetScrollPos(SB_HORZ, m_iHScrollPos); ScrollWindow(-iDelta, 0); CDialog::OnHScroll(nSBCode, nPos, pScrollBar); }m_iHScrollPos ist die aktuelle Position des "Scrollers"
m_iHScrollWidth ergibt sich aus der Breite des anzuzeigenden Bereichs (tatsächliche Breite) minus der aktuellen Breite des Fensters.
Ich bin jetzt einfach wie folgt im Timer vorgegangen, aber dann wird immer mein ganzes Fenster verschoben und ich kann nicht zurückscrollen.
Implementierung im Timer
CWnd* pWnd = GetFocus(); CRect rcControl, rcParent; int iDelta = 0; GetClientRect(&rcParent); pWnd -> GetWindowRect(rcControl); ScreenToClient(&rcControl); // Aktuelle Position bestimmen CPoint ptScrollPosition = GetScrollPos(SB_HORZ); CPoint ptNewScrollPosition = ptScrollPosition; // Eine Unit Platz lasen CSize sOffset = CSize(20,20); if (rcControl.left < rcParent.left) { iDelta = rcControl.left - rcParent.left - sOffset.cx; ptNewScrollPosition.x += iDelta; } else if (rcControl.right > rcParent.right) { iDelta = rcControl.right - rcParent.right + sOffset.cx; ptNewScrollPosition.x += iDelta; } rcControl.OffsetRect(ptScrollPosition-ptNewScrollPosition); if (rcControl.left < 0) { ptNewScrollPosition.x += rcControl.left; } if (rcControl.top < 0) { ptNewScrollPosition.y += rcControl.top; } if (ptScrollPosition!=ptNewScrollPosition) { m_iHScrollPos += iDelta; SetScrollPos(SB_HORZ, m_iHScrollPos); ScrollWindow(-iDelta, ptNewScrollPosition.y); }Grüße
Chris
-
Und warum benutzt Du einen Dialog?
Stilistisch halte ich von rollbaren Dialogen gar nichts. Nimm ein CPropetySheet mit mehreren Seiten um die Dialoge vernünftig aufzuteilen.Ansonsten:
http://www.codeproject.com/KB/dialog/scrolling_support.aspx
-
Hi Martin,
ich habe ein kleines Problem mit deinem Code, den du für mich gepostet hast.
Zunächst habe ich den Code so abgeändert, dass überprüft wird ob sich der Focus geändert hat, da ich
den Code in einem Timer implementiert habe. Sonst würde die Bedienung mit der Maus nicht funktionieren.m_LastControl = m_CurControl; m_CurControl = GetFocus(); if(m_CurControl != m_LastControl) { CRect rcControl, rcParent; GetClientRect(&rcParent); m_CurControl->GetWindowRect(rcControl); ScreenToClient(&rcControl); CPoint ptScrollPosition = GetScrollPosition(); CPoint ptNewScrollPosition = ptScrollPosition; CSize sOffset = CSize(20,20); if (rcControl.left < rcParent.left) { ptNewScrollPosition.x += rcControl.left-rcParent.left - sOffset.cx; } else if (rcControl.right > rcParent.right) { ptNewScrollPosition.x += rcControl.right-rcParent.right + sOffset.cx; } if (rcControl.top < rcParent.top) { ptNewScrollPosition.y += rcControl.top-rcParent.top + sOffset.cy; } else if (rcControl.bottom > rcParent.bottom) { ptNewScrollPosition.y += rcControl.bottom-rcParent.bottom + sOffset.cy; } rcControl.OffsetRect(ptScrollPosition-ptNewScrollPosition); if (rcControl.left < 0) { ptNewScrollPosition.x += rcControl.left; } if (rcControl.top < 0) { ptNewScrollPosition.y += rcControl.top; } if (ptScrollPosition!=ptNewScrollPosition) { ScrollToPosition(ptNewScrollPosition); } }Nun zum Problem, die Bedienung mit der Tastatur funktioniert einwandfrei, nur bei der Bedienung mit der Maus gibt gibt es Probleme.
Wie bereits erwähnt habe ich dynamische Controls, das letze Control ist ein Button.
Durch das Klicken auf den Buttton wird ein Dialog geöffnet. Dieser Dialog ist breiter, als die Standrdgröße des Hauptfensters, wenn es minimiert ist.Öffnet sich der Dialog, dann verschiebt sich der Fensterinhalt meines Hauptfensters nach links.
Beim Start der Anwendung hat das TabControl den Focus und genau um die Größe dieses Reiters wird der Inhalt nach links geschoben, auch wenn ich den Focus mit der Tab-Taste auf ein anderes Control setze (z. B. den Button auf den ich klicke.Und was noch seltsamer ist, ist dass sich der Inhalt des Hauptfensters noch mehr nach links verschiebt, wenn ich mit der Tab-Taste durch die
Controls des Dialogs navigiere. Ich habe auch keine Scrollbar in meinem Dialog, wie CChris das hat.Danke und Lg
Kerberos
-
Hi,
weiß wirklich keiner wie ich den Fehler beheben kann? Ich will ja nicht aufdränglich sein, aber ich komm an dieser stelle einfach nicht weiter... ist wahrscheinlich nur 'ne Kleinigkeit. Durch Debuggen komm ich auch nicht weiter und ich weiß auch nicht wonach ich mit google oder hier im Forum suchen soll.
Danke und Lg
Kerberos
-
Du solltest das Rollen natürlich nur dann machen, wenn das Fenster, dass den Focus hat auch zu Deinem Dialog gehört oder. Was macht es bitte für einen Sinn, ein beliebiges Control, dass den Focus hat zur Basis Deiner Berechnung zu nutzen.
Zudem kann m_CurControl NULL werden! Und ich sehe nicht, dass Du Dir m_CurControl auch wirklich merkst!Also:
if (m_CurControl!=NULL && IsChild(m_curControl) && m_CurControl!=m_LastControl) {
-
--
-
Kerberos CChris 
Wer nun?