Wie MFC Control in den Vordergrund bekommen?
-
Ich habe ein OpenGL-Canvas in ein Image-Control. Bloss versteckt sich dieses Control in den Hintergrund, so dass ich es nicht auf ein TabControl schieben kann. Wie bekomme ich dieses Control nach vorne?
-
Referenzen:
CWnd::SetWindowPos(MFC)
-
Ah, das könnte klappen... wenn ich wüsste was vor das "wndTopMost" muss, mal sehen...
-
Nein, klappt nicht. Hier mein Code:
GetDlgItem(IDC_OPENGL)->SetWindowPos(&CWnd::wndTop,0,0,200,200,NULL);
Das TabControl ist immernoch im Vordergrund.
-
Benutz mal statt CWnd::wndTop den zeiger deines tab controls
-
Ne, geht leider immernoch nicht. Egal, ob ich &DynTabCtrl oder &COpenGLCtrl (meine OpenGL-Klasse) benutze, das Image-Control ist immer im Hintergrund. Die einzige Chance, es sichtbar zu machen, ist das TabControl auf Transparent zu setzen, aber dann sehe ich es ja immer, egal welcher Tab aktiviert ist.
Macht es dann Sinn, mit dem Wechsel eines Tabs das OpenGLCtrl immerwieder zu createn und zu destroyen. Kann man so ohne weiteres während der Laufzeit machen, oder darf man das nur beim Start oder beim Beenden einer Applikation? Andererseits würde das mein zweites Problem lösen: Ich brauche 2 OpenGL-Canvas. Statt 2 zu createn könnte ich dann immer eines createn, das andere destroyen usw. Wie gefragt, macht das Sinn?
-
Probier mal so was ähnliches:
http://blogs.msdn.com/oldnewthing/archive/2005/11/21/495246.aspx
-
Das gibt mir die Fehlermeldung
error C2664: 'SetWindowPos' : cannot convert parameter 1 from 'struct HWND__ *' to 'const class CWnd *'
Der "Zeiger_auf_Fensterobjekt" ist doch graphTab->m_iOGL oder? Ich habe folgende Komponenten in dieser Hierarchie:
- der CDialog (Membervariable: m_pMainWnd, Klasse: CMyApp)
- das TabControl (Membervariable: m_gTabCtrl, Klasse: DynTabCtrl)
- Tab Index 2 (Membervariable: graphTab, Klasse: MyDialog2)
- Image-Control (OpenGL Canvas) (Membervariable: m_iOGL, Klasse: MyDialog2)
- OpenGL-Canvas (Membervariable: OpenGLCtrl, Klasse: COpenGLCtrl)Das oben verlinkte Artikel verwirrt mich nun irgendwie total...
-
BOOL CWnd::SetWindowPos ( const CWnd* pWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags );
pWndInsertAfter
Identifies the CWnd object that will precede this CWnd object in the Z-order. This parameter can be a pointer to a CWnd or a Pointer to one of the following values:wndTop Places the window at the top of the Z-order.
wndTopMost Places the window above all nontopmost windows. The window maintains its topmost position even when it is deactivated.
GetDlgItem(IDC_OPENGL)->SetWindowPos(&CWnd::wndTopMost,0,0,200,200,???);
GetDlgItem(IDC_OPENGL)->SetWindowPos(&CWnd::wndTop,0,0,200,200,???);
-
Nein, klappt nicht. Vielleicht liegt hier auch ein Missverständnis vor: Ich meine nicht, dass mein WINDOW im Hintergrund ist, sondern das Image-Control INNERHALB desselben Fensters hinter allen anderen Controls liegt, in meinem Fall verdeckt das TabControl das Image-Control.
-
Doch, das klappt noch, probier mal Folgendes (hier am Beispiel von drei sich überlappenden Buttons IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4 ausprobiert). Wichtig ist das Invalidate(), ansonsten wird nicht neugezeichnet. Vielleicht liegt es einfach nur daran. Du hast zwei getrennte Ebenen, in denen Du mit CWnd::wndTop nach oben rangieren kannst, nämlich die Ebene der "NonTopMost"-Fenster und die Ebene der "TopMost"-Fenster, dürfte in Deinem Fall aber keine Rolle spielen. Ein TopMost-Parent-Fenster hat automatisch alle Child-Fenster auch TopMost. Nur ein NonTopMost-Parent-Fenster kann beide Typen ( TopMost und NonTopMost) von Child-Fenster haben. (siehe Code):
void CTestDlg::OnChangeOrder() { static BYTE zahl = 0; const BYTE ZAHLMAX = 2; for(int i=0; i<=ZAHLMAX; ++i) { GetDlgItem(IDC_BUTTON2 + i)->SetWindowPos(&CWnd::wndNoTopMost,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); } GetDlgItem(IDC_BUTTON2 + zahl)->SetWindowPos(&CWnd::wndTopMost,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); GetDlgItem(IDC_BUTTON2 + zahl)->SetWindowPos(&CWnd::wndTop,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); GetDlgItem(IDC_BUTTON2 + zahl)->Invalidate(); //Wichtig zahl++; if(zahl > ZAHLMAX) zahl = 0; }
sollte auch damit gehen:
void CStaticTextDlg::OnChangeOrder() { static BYTE zahl = 0; const BYTE ZAHLMAX = 2; /* for(int i=0; i<=ZAHLMAX; ++i) { GetDlgItem(IDC_BUTTON2 + i)->SetWindowPos(&CWnd::wndNoTopMost,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); } */ //GetDlgItem(IDC_BUTTON2 + zahl)->SetWindowPos(&CWnd::wndTopMost,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); GetDlgItem(IDC_BUTTON2 + zahl)->SetWindowPos(&CWnd::wndTop,0,0,200,200, SWP_NOMOVE|SWP_NOSIZE ); GetDlgItem(IDC_BUTTON2 + zahl)->Invalidate(); zahl++; if(zahl > ZAHLMAX) zahl = 0; }
Mit den sich überlappenden Buttons (sind ja auch CWnd) klappt es bestens.
-
Danke für die ausführliche Antwort. Ich teste das morgen mal durch, jetzt ist es etwas spät
Falls es nicht klappen sollte: Liegts vielleicht ganz einfach nicht am Image-Control sondern am OpenGL? Immerhin muss ich das Control auf "invisible" setzen, damit man überhaupt das OpenGL-Canvas sehen kann. Vielleicht hat hier OpenGL ein Problem, das sich nicht über "einfache" MFC Funktionen lösen lässt.
Ich teste es morgen aber wie gesagt mal ausführlich durch. Irgendwie MUSS es ja klappen.
-
Ich gebs in diesem Thread vorerst auf... es wird nicht klappen. Wie ich vermutet habe, muss es eine Eigenheit von OpenGL sein. Denn:
Wenn ich ein normales Static-Text zwischen 2 Groupboxes setze ist der Text im Vordergrund, es überdeckt die Groupboxes. Für OpenGL muss ich es aber wieder invisible setzen und es erscheint stattdessen eine grüne Box, die aber wieder HINTER den Groupboxes liegt. Und das alles obwohl ich nichts an der Reihenfolge der Ebenen geändert habe. Ich werde mich also mal in einem OpenGL Forum umsehen. Danke trotzdem für die Hilfe!EDIT: Ich habe mir mal die Create-Routine meiner OpenGL-Klasse näher angesehen. Dort wird ein komplett neues Fenster als Child erzeugt:
void COpenGLCtrl::oglCreate(CRect rect, CWnd *parent) { CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW | CS_OWNDC, NULL, (HBRUSH)GetStockObject(BLACK_BRUSH), NULL); CreateEx(0, className, "OpenGL", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, rect, parent, 0); // Set initial variables' values m_oldWindow = rect; m_originalRect = rect; hWnd = parent; }
Irgendwie dadrin muss ich was ändern, dann klappt es sicher. Bloss was
-
Halli hallo, ich hab mir mal vor einer Weile eine abstrakte Window-Klasse für OGL erstellt vieleicht hilft Dir das ja weiter, ich poste einfach mal die cpp, da steht eigentlich alles drin was wichtig ist. Probleme, das ich erst ein control auf unvisible setzten musste hatte ich damit bis jetzt noch nicht.
// WndGL.cpp: Implementierungsdatei // #include "stdafx.h" #include "WndGL.h" // CWndGL IMPLEMENT_DYNAMIC(CWndGL, CWnd) CWndGL::CWndGL() : m_pRenderThread(NULL) { } CWndGL::~CWndGL() { } BEGIN_MESSAGE_MAP(CWndGL, CWnd) ON_WM_DESTROY() END_MESSAGE_MAP() // CWndGL-Meldungshandler BOOL CWndGL::PreCreateWindow(CREATESTRUCT& cs) { WNDCLASS wc; HINSTANCE hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = AfxWndProc; // WndProc Handles Messages wc.cbClsExtra = 0; // No Extra Window Data wc.cbWndExtra = 0; // No Extra Window Data wc.hInstance = hInstance; // Set The Instance wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer wc.hbrBackground = NULL; // No Background Required For GL wc.lpszMenuName = NULL; // We Don't Want A Menu wc.lpszClassName = m_strClassName; AfxRegisterClass(&wc); // Attempt To Register The Window Class cs.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC |WS_POPUP;//| //WS_OVERLAPPEDWINDOW; // Required Window Style cs.hInstance = hInstance; // Set The Instance cs.hMenu = NULL; // We Don't Want A Menu cs.lpszClass = m_strClassName; // Set The Class Name cs.dwExStyle = WS_EX_APPWINDOW; return CWnd::PreCreateWindow(cs); } UINT CWndGL::ThreadFunc(LPVOID lpv) { CWndGL* pThis = reinterpret_cast<CWndGL*>(lpv); pThis->m_hRC = wglCreateContext( pThis->m_hDC ); wglMakeCurrent(pThis->m_hDC, pThis->m_hRC); MSG msg; pThis->GLInit(); while(true) { PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); // Is There A Message Waiting? if ( msg.message == WM_QUIT ) // Have We Received A Quit Message? { return FALSE; } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } pThis->GLPreRender(); pThis->GLRender(); pThis->GLPostRender(); pThis->GLSwapBuffers(); } return TRUE; } void CWndGL::GLSwapBuffers() { ::SwapBuffers( m_hDC ); } BOOL CWndGL::Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID) { m_strClassName = "OpenGL"; GLuint glPixelFormat; PIXELFORMATDESCRIPTOR PFD = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format 32, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; if ( CWnd::CreateEx(NULL, m_strClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID) ) { m_hDC = GetDC()->m_hDC; // Did We Get A Device Context? glPixelFormat = ChoosePixelFormat( m_hDC, &PFD ); // Did Windows Find A Matching Pixel Format? SetPixelFormat( m_hDC, glPixelFormat, &PFD ); // Are We Able To Set The Pixel Format? m_pRenderThread = AfxBeginThread( CWndGL::ThreadFunc ,this); return TRUE; } return FALSE; } void CWndGL::OnDestroy() { if (m_pRenderThread)m_pRenderThread->PostThreadMessageA( WM_QUIT,0,0); WaitForSingleObject(m_pRenderThread->m_hThread, INFINITE); if (m_hRC) // Do We Have A Rendering Context? { wglMakeCurrent(NULL,NULL); // Are We Able To Release The DC And RC Contexts? wglDeleteContext(m_hRC); // Are We Able To Delete The RC? m_hRC=NULL; // Set RC To NULL } if (m_hDC) { ReleaseDC(CDC::FromHandle(m_hDC)); // Are We Able To Release The DC m_hDC=NULL; // Set DC To NULL } CWnd::OnDestroy(); }
Viel Glück
-
Yiiiiippiiieeee! Na endlich, es klappt! Das Problem war der Aufruf
m_oglWindow.oglCreate(rect, this);
das im OnInitDialog() der Hauptklasse stand und daher die Hauptklasse als Parent (=this) übergeben hat. Ich habe im TabControl aber für jedes Tab eine eigene Child-Klasse mit eigenen Formularen und Controls. Habe also der Child-Klasse ein OnInitDialog() verpasst und alle Init-Aufrufe von OpenGL dareingeschrieben (statt in die Hauptklasse) und siehe da, das OpenGL Canvas ist endlich zu sehen und verschwindet wieder, wenn ich das Tab wechsel
Puh, endlich gehts weiter...
-