MDI - Problem
-
hallo.
ich habe hier ein 'ernsthaftes' problem mit einer MDI-anwendung, in der die childwindows alle glut-fenster sind. soweit ist alles okay. zusätzlich habe ich eine trackball klasse, mit der ich erreichen will, dass sich meine objekte im fenster bewegen lassen. klappt auch gut, wenn ich das erste fenster aufmache. sobald ich aber ein zweites child-fenster aufmache, kann ich nur in diesem fenster das objekt rotieren. das objekt im ersten steht still.
BEGIN_MESSAGE_MAP(COpenGL_MDIApp, CWinApp) ON_COMMAND(ID_APP_ABOUT, &COpenGL_MDIApp::TEST) ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew) //öffnet neues GLUT-fenster ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen) ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup) END_MESSAGE_MAP()int COpenGL_MDIView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (__super::OnCreate(lpCreateStruct) == -1) return -1; if(IniOpenGL(this) == -1) //GLUT-fenster wird initialisiert ... return -1; DrawScene(); // ... und objekt gezeichnet return 0; }void COpenGL_MDIView::OnMouseMove(UINT nFlags, CPoint point) { if ( (nFlags & MK_LBUTTON) == MK_LBUTTON ) { m_lastMouse = m_currMouse; // speichert die mausbewegung ... m_currMouse = point; LookAtScene(); // ... verändert standort ... RenderScene(); // ... und zeichnet das objekt neu } __super::OnMouseMove(nFlags, point); }würde mich freuen, wenn ihr mir weiterhelfen könnt.
DANKE.
STICK.
-
Das hat nichts mit MDI zu tun.
Das Problem ist, dass Windows nur zeichnet wenn auch ein WM_PAINT kommt.
Du zeichnest aber beim Erzeugen und wenn ein Mousemove kommt.
Wie sieht Dein OnDraw aus?Wenn sich etwas ändert soltest Du Invalidate aufrufen was dafür sorgt das ein neuer WM_PAINT versendet wird. Das wiedrum ruft Dein OnDraw auf!
-
hi.
vielen dank für die antwort.
dies ist mein OnDraw:
void COpenGL_MDIView::OnDraw(CDC* /*pDC*/) { COpenGL_MDIDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); RenderScene(); if (!pDoc) return; // TODO: add draw code for native data here }weiter schreibst du:
Wenn sich etwas ändert soltest Du Invalidate aufrufen
wie kann ich dem childwindow begreiflich machen, dass sich was geändert hat?
DANKE.
STICK.
-
Wann sich etwas geändert hat, solltest du selber am besten wissen
Und an der Stelle rufst du dann Invalidate() auf, um Windows darüber zu informieren. (da du RenderScene() ja beim Zeichnen nutzt, könntest du diesen Aufruf in der OnMouseMove() ersetzen durch Invalidate()).
-
Hi CStoll.
danke für den hinweis mit Invalidate, aber leider scheint das nicht zu klappen. mein code sieht wie folgt aus:
void COpenGL_MDI_GUT2View::OnMouseMove(UINT nFlags, CPoint point) { if (GetCapture()) { CSize d = pntLast - point; pntLast = point; if (mode==right) dist *= pow(1.01,d.cy); if (mode==left) { angleY += d.cx; angleX += d.cy; } // Invalidate(); InvalidateRect(NULL, FALSE); } CView::OnMouseMove(nFlags, point); }ich habe beide versionen (Invalidate und InvalidateRect) ausprobiert, aber beide klappen nicht. hinzukommt, dass bei Invalidate der hintergrund anfängt zu flackern, wenn das fenster neu gezeichnet wird. dies ist bei InvalidateRect nicht der fall. liegt das daran, dass ich auf das child-fenster noch ein OpenGL-fenster lege?
wie kann ich nun erreichen, dass ich die objekte in allen child-fenstern bewegen kann?VIELEN DANK!
STICK.
-
1. Das malen des Hintergrundes und das Malen des Fensters selbst sind zwei Operationen.
2. Invalidate verfügt über ein default flag das steuert, ob der Hintergrund gelöscht werden soll (dieses ist standardmäßig auf TRUE), Du hast InvalidateRect verwendet und dort den Schalter auf FALSE gesetzt.
3. Wenn Du immer das ganze Fenster selbst komplett (inkl. Hintergrund) selbst zeichnest solltest Du WM_ERASEBKGND überladen und sofort TRUE returnieren ohne etwas zu machen. Dann hat es ein Ende mit dem Flackern.
4. Schau Dir mal "Doublebuffering" oder Code zu CMemDC an (Siehe Codeproject)
5. Wird denn nun OnPaint angesprungen nach OnMouseMove und neu gezeichnet?
6. Was meinst Du mit Zitat: wie kann ich nun erreichen, dass ich die Objekte in allen child-Fenstern bewegen kann?
Abhängig von was sollen sich diese Objekte wann und wie bewegen?
-
HI MARTIN.
danke für die hilfe. das mit WM_ERASEBKGND war eine gute idee. jetzt flackert auch nichts mehr. aber sobald ich ein zweites OpenGl-Child-Window aufmache, kann ich das objekt im ersten window trotzdem nicht mehr modifizieren.
da ich aber nicht weis, wie ich WM_PAINT in meinen code einbringen muss, möchte ich gerne einen etwas größeren programmauschnitt mitschicken. könnte mir jemand kurz beschreiben, wie der modifiziert werden muss? weil mit der aussage, "da fehlt noch WM_PAINT", kann ich nicht viel anfangen
VIELEN DANK!!
STICK.class COpenGL_MDI_GUT2View : public CView { //... public: HGLRC m_hRC; HDC m_hdc; double angleX,angleY,dist; // Betrachtungswinkel und -entfernung CPoint pntLast, pntCenter; enum mouseMode {left,right,up}; mouseMode mode; //... protected: int IniOpenGL(CView* pView); void DrawScene(void); void Reshape(int cx, int cy); void RenderScene(void); public: afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonUp(UINT nFlags, CPoint point); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg BOOL OnEraseBkgnd(CDC* pDC); };void COpenGL_MDI_GUT2View::OnDraw(CDC* /*pDC*/) { COpenGL_MDI_GUT2Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); RenderScene(); if (!pDoc) return; } int COpenGL_MDI_GUT2View::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; if(IniOpenGL(this) == -1) return -1; DrawScene(); return 0; } int COpenGL_MDI_GUT2View::IniOpenGL(CView* pView) { PIXELFORMATDESCRIPTOR pfd = {//... }; m_hdc = ::GetDC(pView->GetSafeHwnd()); int iD = ChoosePixelFormat(m_hdc, &pfd); SetPixelFormat (m_hdc, iD, &pfd); m_hRC = wglCreateContext (m_hdc); wglMakeCurrent (m_hdc, m_hRC); RenderScene(); return 0; } void COpenGL_MDI_GUT2View::DrawScene(void) { glColor3f(1.0f,0.0f,0.0f); glNewList(1, GL_COMPILE); glutWireTeapot(1.5); glEndList(); } void COpenGL_MDI_GUT2View::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); Reshape(cx,cy); } void COpenGL_MDI_GUT2View::Reshape(int cx, int cy) { if(cy == 0) return; double dAspect = cx<=cy ? double(cy)/cx : double(cx)/cy; glMatrixMode (GL_PROJECTION); glLoadIdentity(); gluPerspective (90,dAspect,0.1,1000.); glViewport(0, 0, cx, cy); } void COpenGL_MDI_GUT2View::RenderScene(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(1.0f, 1.0f, 1.0f, 0.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); ::gluLookAt( 0.0f, 0.0f, dist, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f ); glRotated(angleY, 0.0, 1.0, 0.0); glRotated(angleX, 1.0, 0.0, 0.0); glCallList(1); SwapBuffers(m_hdc); } void COpenGL_MDI_GUT2View::OnLButtonDown(UINT nFlags, CPoint point) { pntLast = point; mode = left; SetCapture(); CView::OnLButtonDown(nFlags, point); } void COpenGL_MDI_GUT2View::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture()) ReleaseCapture(); mode = up; CView::OnLButtonUp(nFlags, point); } void COpenGL_MDI_GUT2View::OnMouseMove(UINT nFlags, CPoint point) { if (GetCapture()) { CSize d = pntLast - point; pntLast = point; if (mode==right) dist *= pow(1.01,d.cy); if (mode==left) { angleY += d.cx; angleX += d.cy; } //WIE KANN ICH HIER ERREICHEN, DASS WM_CREATE ERNEUT AUFGERUFEN WIRD? MIT 'INVALIDATE' SCHEINTS NICHT ZU KLAPPEN :( } CView::OnMouseMove(nFlags, point); }
-
HI.
könnte sich vielleicht doch bitte jemand den zuvor geposteten code anschauen und mir einen hinweis geben, wie ich ihn modifizieren muss, so dass ich unabhängige childwindows bekomme?
ich habe gerade feststellen müssen, dass beim vorhandensein mehrerer childwindows und beim verstellen der größe des zuerst geöffneten fensters, sich die darstellung des zuletzt geöffneten fensters ebenfalls ändert (es erfolgt eine art transformation des objektes in diesem fensters). in dem fenster mit der veränderten größe wird mein objekt total verzerrt oder gar nicht mehr dargestellt, wahrscheinlich weil WM_PAINT für ein neues zeichen des objektes fehlt?
irgendwie muss ich wohl in OnMouseMove die funktion OnCreate aufrufen. ist da INVALIDATE die einzige möglichkeit, denn die scheint nicht zu gehen.
VIELEN DANK für eure HILFE.
STICK.
-
stick_thai schrieb:
aber sobald ich ein zweites OpenGl-Child-Window aufmache, kann ich das objekt im ersten window trotzdem nicht mehr modifizieren.
Was heißt modifizieren für Dich?
stick_thai schrieb:
da ich aber nicht weiß, wie ich WM_PAINT in meinen code einbringen muss, möchte ich gerne einen etwas größeren Programmausschnitt mitschicken. könnte mir jemand kurz beschreiben, wie der modifiziert werden muss? weil mit der aussage, "da fehlt noch WM_PAINT", kann ich nicht viel anfangen

Ich kenne Deine Lib nicht die Du verwendest.
Wenn Reshape alles neu anzeigt, dann muss diese Funktion in Dein OnDraw/OnPaint.Mach Dir bitte klar, dass OnPaint in Deinem Programm die einzige Stelle sein sollte an der Ausgaben auf Dein Fenster gemacht werden sollten.
Wenn Du nicht weißt was Du mit WM_PAINT anfangen sollst, dann musst Du ein Grundlagenbuch lesen um es zu verstehen.Windows ist so konstruiert, dass nicht Du entscheidest wann etwas gemalt wird, sondern Windows invalidiert Deinen Anzeigebereich wenn etwas geschieht was es notwendig macht das neu gezeichnet werden muss. (Oder Invalidate aufgerufen wird).
Dann sendet Windows eine WM_PAINT Nachricht auf die Du hin zeichnen musst. Da Du WM_PAINT gar nicht behandelst (Bzw. OnDraw was die Entsprechung in einem View ist) wundert mich nichts...