CScrollView in Popup-Window
-
Hallo,
ich habe eine SDI-Anwendung am laufen. Ich brauche zur Darstellung von Punkten, genauer gesagt Testpunkte auf Platinen, 4 Ansichten. Die Hauptansicht des Frame-Windows ist mit einem CSplitterWnd in 2 Panes aufgeteilt. Im 1. Pane befindet sich eine Baumansicht, im 2. Pane die Gesamtansicht der Testpunkte, die von CView abgeleitet ist. Jetzt kommt schon mein Problem. Ich will jetzt 2 unabhängige Fenster, eben sogenannte Popup-Windows, die man auf dem gesamten Desktop plazieren kann, nicht nur im Clientbereich des Parent-Frames, für die Darstellung einer Zoomansicht und einer weitern Ansicht mit Testpunkten haben. Beide sollen von CScrollView abgeleitet sein. Aber diese CScrollView-Klasse macht mich fertig.
In den Clientbereich eingebettete Fenster nenne ich jetzt mal Child-Windows und solche, die man auf dem Desktop beliebig plazieren kann, wie oben schon angesprochen, nenne ich Popup-Windows.
Ich habe ein komplett neues Projekt zum Test gestartet (SDI ohne Doc/View). In diesem Projekt habe ich zum Test ein Ansichtsfenster von generic CWnd- und eins von CScrollView abgeleitet um einen Vergleich zu haben plaziert.
Ich bin auf folgende Erkenntnis gestoßen:
1. Das CSrollView-Fenster fängt zu spinnen an, wenn man ihm eine Titelleiste beim Aufruf von Create(...) verpassen will. Das gilt für den Fall als Popup-Window und Child-Window. Egal, ob mit WS_CAPTION oder mit WS_OVERLAPPEDWINDOW. Man muß es ihm schon mindestens 2 mal sagen, indem man unmittelbar nach create(...) nochModifyStyle(GetSyle(),WS_OVERLAPPEDWINDOW)aufruft. Selbst dann ist die Titelleiste nur durch Zufall sichtbar und das Fenster nur durch Zufall verschiebbar. Das generic CWnd funktioniert einwandfrei.
2. Im fall Popup-Window kommt noch ein für mich größeres Phänomen hinzu. Für das Popup-Ansichtsfenster wird die OnInitialUpdate(...)-Memberfunktion nicht mehr aufgerufen. Dadurch kommt es in OnPrepareDC(...) zu einer Assertion, da die ScrollSizes standardmäßig nicht initialisiert sind, was normalerweise in dieser Funktion geschieht. Das kann ich überhaupt nicht verstehen.
Hier die Codes für meinen Versuch:
//Aufruf von OnInitialUpdate in der konkreten Klasse CScrollWnd //Scrollview als Child-Fenster BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) { ... cs.style |= WS_CLIPSIBLINGS; //hinufügen, damit sich die Clientbereiche brüderlich vertragen ... return TRUE; } BOOL CScrollWnd::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen m_nID = (int)cs.hMenu; cs.style |= WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS; cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_UPARROW), HBRUSH(::GetStockObject(LTGRAY_BRUSH)),NULL); return CScrollView::PreCreateWindow(cs); } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... m_pScrollWnd = (CScrollWnd*)RUNTIME_CLASS (CScrollWnd)->CreateObject(); m_pScrollWnd->Create(NULL,"Scroll",WS_VISIBLE|WS_CHILD, CRect(10,10,300,200),this,1,NULL); m_pScrollWnd->SetWindowPos(&wndTop,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); m_pScrollWnd->ModifyStyle(GetStyle(), WS_OVERLAPPEDWINDOW); return 0; } //Kein Aufruf von OnInitialUpdate in der konkreten Klasse CScrollWnd //ScrollView als Popup-Fenster BOOL CScrollWnd::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen m_nID = (int)cs.hMenu; cs.style |= WS_OVERLAPPEDWINDOW|WS_POPUP; cs.hMenu = 0; cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_UPARROW), HBRUSH(::GetStockObject(LTGRAY_BRUSH)),NULL); return CScrollView::PreCreateWindow(cs); } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... m_pScrollWnd = (CScrollWnd*)RUNTIME_CLASS (CScrollWnd)->CreateObject(); m_pScrollWnd->Create(NULL,"Scroll",WS_VISIBLE, CRect(10,10,300,200),this,1,NULL); //m_pScrollWnd->SetWindowPos(&wndTop,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); //für Popup nicht nötig m_pScrollWnd->ModifyStyle(GetStyle(), WS_OVERLAPPEDWINDOW); return 0; }Vielleicht mache ich auch etwas gänzlich falsch. Wenn es eine Möglichkeit gibt, die Popup-Fenster zu umgehen, wäre mir das nur recht. Ich habe schon an modeless Dialoge gedacht. Da wüsste ich aber nicht, wie ich da eine CScrollView hinein bringen soll, wenn man nicht von CDialog und CScrollView (mehrfach) ableiten darf.
Meine konkrete Klasse, die von CScrollview abgeleitet ist, kann ich nur mitm_pScrollWnd = (CScrollWnd*)RUNTIME_CLASS (CScrollWnd)->CreateObjecterzeugen, oder? Der Konstruktor ist protected.
In der MSDN steht, daß man für Popup-Windows die Funktion CreateEx(...) verwenden solle. Ich verwende hier eine Sonderform, indem ich das WS_POPUP-Flag in PreCreateWindow des CScrollWnd-Objekts verlagere (habe ich zufällig entdeckt). Für das generic CWnd funktioniert das einwandfrei, nicht aber bei CScrollView. Auch mit CreateEx(...) habe ich bisher keinen Erfolg erzielen können.
Danke für jeden Tip
WOODZ
-
Hallo,
woodz schrieb:
Ich habe schon an modeless Dialoge gedacht. Da wüsste ich aber nicht, wie ich da eine CScrollView hinein bringen soll, wenn man nicht von CDialog und CScrollView (mehrfach) ableiten darf.
das würde ich mit (nicht-modalen) Dialogen versuchen, die ja geeignete Popups sein können, deine andere Variante erscheint mir viel zu komplex. Wie man Views in Dialoge einbettet, habe ich hier beantwortet:
http://www.c-plusplus.net/forum/viewtopic.php?t=78787
ob es mit einer von CScrollView abgeleiteten Klasse auch klappt, kann ich, da noch nicht probiert, nicht sagen, aber es scheint mir der Ansatz zu sein, der mehr verspricht.
MfG
-
Der Link hat mir schonmal sehr viel geholfen. Vielen Dank!
Ich habe jetzt 2 unabhängige Frame-Windows (von CFrameWnd) in denen je eine Ansicht (jewils abgeleitet von CView) eingebettet ist. Es funktioniert alles wirklich wunderbar, bis auf zwei Phänomene, hinter die ich ums Verrecken nicht komme.1. Ist eines der Frame-Windows sichtbar (eingeblendet), wird beim Beenden der Anwendung nicht mehr gefragt, ob die Datei gespeichert werden soll. Das übernimmt meines Wissens die Funktion CDocument::SaveModified(), die bei Beendigung der Anwendung vom Frame-Work aufgerufen werden sollte. Ist keines der Frame-Windows eingeblendet, wird auch schön brav gefragt. Was ist da los?
2. Die schlimmere Sache ist, daß es beim Speichern eines Dokuments (Aufruf aller entsprechenden Serialize()-Funktionen, begonnen bei der von CDocument, initiiert vom Frame-Work) davon abhängt, ob gerade ein Frame-Window eingeblendet ist oder nicht. Wenn ich nach dem Speichern des Dokuments versuche, die Datei wieder zu öffnen (ebanfalls Aufruf aller Serialize-Funktionen) klappt das nur, wenn die Frame-Windows genauso eingeblendet sind, wie sie es beim Speichern waren. Wenn also beim Speichern kein Frame-Window eingelblentet war, darf das beim anschließenden Öffnen auch nicht der Fall sein. Die Anwendung reagiert sonst mit der Fehlermeldung "Unerwartets Dateiformat".
Ich weiß nicht wie das geregelt bekomme. Hat einer vielleicht mal ähnliche Erfahrungen gemacht?
Noch ein paar Worte zur Erstellung der Frame-Windows. In der Rahmenklasse CMainFrame erzeuge ich die beiden Frame-Windows (bei mir jeweils von der Klasse CExtFrame, abgeleitet von CFrameWnd). Die Erzeugung geschieht auf je einen Menübefehl, wenn die eingebettete Ansicht also eingeblendet werden soll. Während des Erzeugens des Frames, wird auch die Ansicht (bei mir CZoomView bzw. CInterfaceView jeweils abgeleitet von CScrollView) mit einer Entsprechenden Funktion erzeugt.
Anschließend wird jede Ansicht mit CDocument::AddView(...) in die Liste der Ansichten des Dokuments aufgenommen. Wird das Frame-Window geschlossen, wird die Ansicht aus dem Dokument mit CDocument::RemoveView(...) wieder entfernt und das Frame-Window zerstört.
Und hier könnte das Problem liegen. CDocument speichert möglicherweise implizit irgendwelche Informationen über seine aktuell in der Ansichtsliste geführten Ansichten bei Aufruf von CDocument::Serialize() durch das Frame-Work. Ich hab nur leider überhaupt keine Ahnung, wie man da eingreifen kann, falls denn das überhaupt das Problem ist.Danke für jeden Tip.
WOODZ