Richtiges resizen eines Splitters ?!
-
Hi ;),
also ich habe ein SDI mit einigen Splittern folgendermaßen gebaut :
/************************************************************************/ /* Erstellen des Fensters der Anwendung */ /************************************************************************/ BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { // ShowWindow(SW_MAXIMIZE); CRect cr; GetClientRect(&cr); //------- Hauptsplitters erstellen ---------- m_Splitter_Main.CreateStatic(this, 4, 1); //--- Größe der Zeilen des Hauptsplitters setzen --- m_Splitter_Main.SetRowInfo(0, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(1, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(2, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(3, cr.Height()/4, 10); //----------------------------------------------------------------------------------------- // Mit IdFromRowCol() wird angegeben wo im Hauptsplitter der Childsplitter erstellt wird, - // daher darf in diesem Bereich kein CreateView() ausgeführt werden ! - //----------------------------------------------------------------------------------------- // m_Splitter_Main.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); m_Splitter_Main.CreateView(1, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); m_Splitter_Main.CreateView(2, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); // m_Splitter_Main.CreateView(3, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); m_Splitter_Child_1.CreateStatic(&m_Splitter_Main, 1, 3, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(0, 0)); m_Splitter_Child_1.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 2, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_2.CreateStatic(&m_Splitter_Main, 1, 2, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(3, 0)); m_Splitter_Child_2.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/2, 0), pContext); m_Splitter_Child_2.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/2, 0), pContext); return TRUE; } /************************************************************************/ /* Resizen des Splitters */ /************************************************************************/ void CMainFrame::OnSize(UINT nType, int cx, int cy) { CFrameWnd::OnSize(nType, cx, cy); CRect cr; GetClientRect(&cr); if (nType == SIZE_MAXIMIZED) { m_Splitter_Main.SetRowInfo(0, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(1, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(2, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(3, cr.Height()/4, 10); m_Splitter_Child_1.SetColumnInfo(0, cr.Width()/3, 10); m_Splitter_Child_2.SetColumnInfo(0 ,cr.Width()/2, 10); m_Splitter_Main.RecalcLayout(); } //---------------------------------------------------------------------------------------------------------------- // Das OnSize des MainFrames kommt bevor der Splitter vollständig ist. // Der Splitter wird erst bei OnCreateClient() aufgebaut // und ist beim ersten Durchlauf des OnSize vom MainFrame noch nicht fertig. // Deshalb muss mit IsWindowVisible() geprüft werden ob der Splitter schon zu sehen ist ! //---------------------------------------------------------------------------------------------------------------- if (m_Splitter_Main.IsWindowVisible() && nType == SIZE_RESTORED) { m_Splitter_Main.SetRowInfo(0, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(1, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(2, cr.Height()/4, 10); m_Splitter_Main.SetRowInfo(3, cr.Height()/4, 10); m_Splitter_Child_1.SetColumnInfo(0, cr.Width()/3, 10); m_Splitter_Child_2.SetColumnInfo(0 ,cr.Width()/2, 10); m_Splitter_Main.RecalcLayout(); } }1. Frage
Wenn ich die Applikation starte wird der letzte horizontale Splitter nur zu 2/3 angezeigt, ich nehme an es liegt daran dass mir GetClientRect() das ganze
rect meines Clients also ohne Toolbars und soweiter zurückgibt und deshalb die Berechnung der Höhen schief läuft aber wie bekomme ich das fehlende Stück Höhe ?2. Frage
Das Resizen funktioniert wunderbar bis auf die Tatsache dass alle Splitter die ich geändert habe (in der Größe mit der Maus zurecht gezogen mein ich) beim Maximieren wieder zurück auf die Ursprungspositionen hüpfen, alle bis auf die vertikalen Splitter in der 1. Zeile und so sollen sich alle Splitter verhalten, d.h. sie sollen sich zwar resizen lassen aber nicht in die Ursprungspositionen zurück hüpfen.
Warum funktioniert das in der 1. Zeile mit den m_Splitter_Child_1 aber mit den restlichen nicht ?
Danke für eure Mühe und Hilfe schon vorab
best regards
ShadowEater
-
Zu 1. Das ist korrekt. Dein Mainframe Client ist Größer.
Warum fragst Du nicht Dein eingebettetes Splitter Window nach seiner Größe? Nachdem Aufruf von CFrameWnd::OnSize(nType, cx, cy); hat sich das schon brav an die Restgröße angepasst.
zu 2. Verstehe ich nicht.
Wenn Du das Layout in OnSize anpasst, dann wird es sich sowohl beim verkleinern als auch beim Vergrößern anpassen.BTW:
1. Warum hast Du zwimal den selben Codeblock in Deinem OnSize Handler. Es gibt eine || Funktion!
2. m_Splitter_Main.IsWindowVisible ist IMHO nicht der geeignete Ansatz in der Startphase den OnSize zu verhindern. Prüfe einfach ob das Fenster schon erzeugt wurde: !m_Splitter_Main.m_hWnd
-
Hi ;),
Nachdem Aufruf von CFrameWnd::OnSize(nType, cx, cy); hat sich das schon brav an die Restgröße angepasst.
Ja aber da ist es doch schon zu spät ich möchte die korrekte Darstellung doch schon beim Start der App.
Wenn Du das Layout in OnSize anpasst, dann wird es sich sowohl beim verkleinern als auch beim Vergrößern anpassen.Es geht nur darum dass die vorgenommenen Größenänderungen (mit der Maus verzogene Splittergrößen) erhalten bleiben.
Beim vergrößern/verkleinern soll es ins Verhältnis gesetzt werden (das funzt) aber die Größenänderungen werden auch rückgängig gemacht !!!Gruß
ShadowEater
-
Quatsch! In OnSize ist es nicht zu spät. OnSize wird auch beim Start der Applikation aufgerufen, es ist also auch der korrekte Zeitpunkt initial die Einstellungen festzulegen!
Wenn Du Proportional die Einstellungen immer bhalten willst, dann musst Du eben auch immer umrechnen. D.h. Du musst Dir die Verhältnisse zu einem Zeitpunkt x setzen/merken und jedesmal wenn OnSize aufgerufen wird gemäß diesen Verhältnissen dann wieder anpassen.
D.h. für Dich, nach dem Resizen eines Panes musst Du Dir die neuen Verhältnisse merken.
-
Hmmm ok, das versteh ich, cx, xy merken leuchtet ein, wie ist dann die Umrechnungsformel wenn ich die Größe des Splitters proportional anpassen möchte ?
Gruß und vielen Dank
ShadowEater
-
Hi Martin,
**zu 1)
Warum fragst Du nicht Dein eingebettetes Splitter Window nach seiner Größe?
**
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { CRect spRect; //------- Hauptsplitters erstellen ---------- m_Splitter_Main.CreateStatic(this, 4, 1); m_Splitter_Main.GetClientRect(spRect); //--- Größe der Zeilen des Hauptsplitters setzen --- m_Splitter_Main.SetRowInfo(0, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(1, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(2, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(3, spRect.Height()/4, 10); m_Splitter_Main.CreateView(1, 0, RUNTIME_CLASS(CTest_01View), CSize(0, spRect.Height()/4), pContext); m_Splitter_Main.CreateView(2, 0, RUNTIME_CLASS(CTest_01View), CSize(0, spRect.Height()/4), pContext); m_Splitter_Child_1.CreateStatic(&m_Splitter_Main, 1, 3, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(0, 0)); m_Splitter_Child_1.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(spRect.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(spRect.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 2, RUNTIME_CLASS(CTest_01View), CSize(spRect.Width()/3, 0), pContext); m_Splitter_Child_2.CreateStatic(&m_Splitter_Main, 1, 2, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(3, 0)); m_Splitter_Child_2.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(spRect.Width()/2, 0), pContext); m_Splitter_Child_2.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(spRect.Width()/2, 0), pContext); return TRUE; }Hast Du das so gemeint, leider funktioniert Dein Vorschlag nicht !

Gruß
ShadowEater
-
Das kann in OnCreateClient nicht gehen. In diesem Moment hat noch kein Fenster seine Größe!
-
Hi Martin,
ich habs jetzt in OnSize(...) gepackt.
Aus OnCreateClient (...) hab ich auch das Setzen der Größe des Hauprsplitters rausgenommen, da dies ja nun in OnSize(...) stattfindet !So sieht das ganze optisch aus :
http://filehosting.at/images/download.php?file=ff7d17637e6608627d832c8a10783a9f
Der letzte Splitter ist nun etwas höher aber noch nicht genau gleich hoch wie die anderen horiz. Splitter !
Was kann ich denn noch tun ?/************************************************************************/ /* Erstellen des Fensters der Anwendung */ /************************************************************************/ BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { CRect spRect; CRect cr; GetClientRect(&cr); //------- Hauptsplitters erstellen ---------- m_Splitter_Main.CreateStatic(this, 4, 1); m_Splitter_Main.CreateView(1, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); m_Splitter_Main.CreateView(2, 0, RUNTIME_CLASS(CTest_01View), CSize(0, cr.Height()/4), pContext); m_Splitter_Child_1.CreateStatic(&m_Splitter_Main, 1, 3, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(0, 0)); m_Splitter_Child_1.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_1.CreateView(0, 2, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/3, 0), pContext); m_Splitter_Child_2.CreateStatic(&m_Splitter_Main, 1, 2, WS_CHILD | WS_VISIBLE, m_Splitter_Main.IdFromRowCol(3, 0)); m_Splitter_Child_2.CreateView(0, 0, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/2, 0), pContext); m_Splitter_Child_2.CreateView(0, 1, RUNTIME_CLASS(CTest_01View), CSize(cr.Width()/2, 0), pContext); return TRUE; } /************************************************************************/ /* Resizen des Splitters */ /************************************************************************/ void CMainFrame::OnSize(UINT nType, int cx, int cy) { CFrameWnd::OnSize(nType, cx, cy); CRect spRect; m_Splitter_Main.GetClientRect(spRect); if ((nType == SIZE_MAXIMIZED)||(m_Splitter_Main.IsWindowVisible() && nType == SIZE_RESTORED)) { m_Splitter_Main.SetRowInfo(0, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(1, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(2, spRect.Height()/4, 10); m_Splitter_Main.SetRowInfo(3, spRect.Height()/4, 10); m_Splitter_Main.RecalcLayout(); } }Danke für Deine Hilfe
ShadowEater
-
Ist Dir klar, dass Du bei der Berechnung die Breiten der Splitter nicht berücksichtigst? Evtl. kommt daher die Abweichung.
-
Ja,
aber es kommt mir doch nur auf die Höhe an !
Gruß
ShadowEater
-
Dann musst Du eben auch die Höhe der Zwischenräume/Trackbars berücksichtigen! Ist doch klar, sonst beliebt für das letzte Fenster einfach 3 Trackbar breiten zu wenig übrig.
-
Die Sache mit den 3 Trackbars leuchtet ein, aber wohet bekomm ich die Breite, einfach bei nem ScreenShot die Pixel abzählen und hardcoded dazuaddieren, oder
gibt es eine Get...??? - Funktion ?
Gruß
ShadowEater
-
IMHO stehen die Maße nur in internen Variablen,
int m_cxSplitter, m_cySplitter; // size of splitter bar int m_cxBorderShare, m_cyBorderShare; // space on either side of splitter int m_cxSplitterGap, m_cySplitterGap; // amount of space between panes int m_cxBorder, m_cyBorder; // borders in client area
-
Sorry dass ich so spät antworte, aber in den internen Variablen steht nix, bzw. die gibts gar nicht !
Gruß
ShadowEater
-
Diese Variablen sind in der CSpillterWnd Implementierung bei mir vorhanden!