Transparente GroupBox



  • Hallo zusammen,

    habe eine Frage bezgl. transparenter Groupboxen. Da diese Buttons sind, lässt sich der Hintergrund nicht einfach mit WM_CTLCOLOR ändern. Deshalb habe ich das folgende Klasse CTGroupBox runtergeladen:
    http://www.codeguru.com/cpp/controls/controls/groupbox/article.php/c2273

    So die GroupBox zu erstellen auch die Radiobuttons zu positionieren ist kein Problem. Jedoch kann ich nicht mehr die Radiobuttons anklicken.

    Hier einige wichtige Funktionen aus der Klasse CTGroupBox:

    void CTGroupBox::PreSubclassWindow() 
    {
    	ModifyStyle(0, BS_OWNERDRAW|BS_GROUPBOX);
    
    	CButton::PreSubclassWindow();
    }
    
    // Since groupboxes never get WM_DRAWITEM even if they are BS_OWNERDRAW,
    // we must handle our painting in OnPaint.
    // Fortunately they have no such things like focus rects or "pressed" states.
    void CTGroupBox::OnPaint() 
    {
    	CRect rc;
    	CPoint ptStart, ptEnd;
    	CSize seText;
    	CString sText, sTemp;
    	CPen pnFrmDark, pnFrmLight, *ppnOldPen;
    	int iUpDist, nSavedDC;
    	DWORD dwStyle, dwExStyle;
    
    	CPaintDC dc(this); // device context for painting
    
    	// save dc state
    	nSavedDC = dc.SaveDC();
    
    	// window rect
    	GetWindowRect(&rc);
    	ScreenToClient(&rc);
    
    	// determine text length
    	GetWindowText(sTemp);
    	sText.Format(_T(" %s "), sTemp); // looks better with a blank on each side	
    	seText = dc.GetTextExtent(sText);
    
    	// distance from window top to group rect
    	iUpDist = (seText.cy / 2);
    
    	// calc rect and start/end points
    	dwStyle = GetStyle();
    	dwExStyle = GetExStyle();
    
    	// handle the extended windows styles
    	if (dwExStyle & WS_EX_DLGMODALFRAME)
    	{
    		rc.DeflateRect(2*GetSystemMetrics(SM_CXEDGE), 2*GetSystemMetrics(SM_CYEDGE));
    		rc.left--;
    	}
    	if (dwExStyle & WS_EX_CLIENTEDGE)
    	{
    		rc.DeflateRect(GetSystemMetrics(SM_CXEDGE)+1, GetSystemMetrics(SM_CYEDGE)+1);
    		rc.left--;
    		if (dwExStyle & WS_EX_DLGMODALFRAME)
    		{
    			rc.right++;
    		}
    	}	
    	if(dwExStyle & WS_EX_STATICEDGE)
    	{
    		rc.DeflateRect(2*GetSystemMetrics(SM_CXBORDER), 2*GetSystemMetrics(SM_CYBORDER));
    		rc.left--;
    	}
    
    	// handle text alignment (Caution: BS_CENTER == BS_LEFT|BS_RIGHT!!!)
    	ptStart.y = ptEnd.y = rc.top + iUpDist;
    	if ((dwStyle & BS_CENTER) == BS_RIGHT) // right aligned
    	{
    		ptEnd.x = rc.right - OFS_X;
    		ptStart.x = ptEnd.x - seText.cx;
    	}
    	else if ((!(dwStyle & BS_CENTER)) || ((dwStyle & BS_CENTER) == BS_LEFT))// left aligned	/ default
    	{
    		ptStart.x = rc.left + OFS_X;
    		ptEnd.x = ptStart.x + seText.cx;
    	}
    	else if ((dwStyle & BS_CENTER) == BS_CENTER) // text centered
    	{
    		ptStart.x = (rc.Width() - seText.cx) / 2;
    		ptEnd.x = ptStart.x + seText.cx;
    	}	
    
    	if (dwStyle & BS_FLAT) // "flat" frame
    	{
    		VERIFY(pnFrmDark.CreatePen(PS_SOLID, 1, RGB(0, 0, 0)));
    		VERIFY(pnFrmLight.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHILIGHT)));
    
    		ppnOldPen = dc.SelectObject(&pnFrmDark);
    
    		dc.MoveTo(ptStart);
    		dc.LineTo(rc.left, ptStart.y);
    		dc.LineTo(rc.left, rc.bottom);
    		dc.LineTo(rc.right, rc.bottom);
    		dc.LineTo(rc.right, ptEnd.y);
    		dc.LineTo(ptEnd);
    
    		dc.SelectObject(&pnFrmLight);
    
    		dc.MoveTo(ptStart.x, ptStart.y+1);
    		dc.LineTo(rc.left+1, ptStart.y+1);
    		dc.LineTo(rc.left+1, rc.bottom-1);
    		dc.LineTo(rc.right-1, rc.bottom-1);
    		dc.LineTo(rc.right-1, ptEnd.y+1);
    		dc.LineTo(ptEnd.x, ptEnd.y+1);
    
    	}
    	else // 3D frame
    	{
    		VERIFY(pnFrmDark.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW)));
    		VERIFY(pnFrmLight.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHILIGHT)));
    
    		ppnOldPen = dc.SelectObject(&pnFrmDark);
    
    		dc.MoveTo(ptStart);
    		dc.LineTo(rc.left, ptStart.y);
    		dc.LineTo(rc.left, rc.bottom-1);
    		dc.LineTo(rc.right-1, rc.bottom-1);
    		dc.LineTo(rc.right-1, ptEnd.y);
    		dc.LineTo(ptEnd);
    
    		dc.SelectObject(&pnFrmLight);
    
    		dc.MoveTo(ptStart.x, ptStart.y+1);
    		dc.LineTo(rc.left+1, ptStart.y+1);
    		dc.LineTo(rc.left+1, rc.bottom-1);
    		dc.MoveTo(rc.left, rc.bottom);
    		dc.LineTo(rc.right, rc.bottom);
    		dc.LineTo(rc.right, ptEnd.y-1);
    		dc.MoveTo(rc.right-2, ptEnd.y+1);
    		dc.LineTo(ptEnd.x, ptEnd.y+1);	
    	}
    
    	// draw text (if any)
    	if (!sText.IsEmpty() && !(dwExStyle & (BS_ICON|BS_BITMAP)))
    	{
    		if (!IsWindowEnabled())
    		{
    			ptStart.y -= iUpDist;
    			dc.DrawState(ptStart, seText, sText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
    		}
    		else
    		{
    			dc.SetBkMode(TRANSPARENT);
    			dc.DrawText(sText, CRect(ptStart, ptEnd), DT_VCENTER|DT_LEFT|DT_SINGLELINE|DT_NOCLIP);
    		}
    	}
    
    	// cleanup
    	dc.SelectObject(ppnOldPen);
    	dc.RestoreDC(nSavedDC);
    }
    

    Ich erzeuge die Gruppenbox auf dem Hauptfenster. Dazu habe ich in der Headerdatei einen Member angelegt und im Kosntruktor Speicher belegt:

    CTGroupBox *btnMat;
    ...
    btnMat = new CTGroupBox;
    

    So jetzt kommt der Unterschied zu dem auf Codeguru angegebenem Beispiel. Dort wird in der OnInitDialog folgender Quellcode gefunden, den ich nicht nachvollziehen kann:

    m_TGrpBox1.SubclassDlgItem(IDC_GRPBOX1, this);
    

    Ich erzeuge meine GroupBox aber mit Create:

    btnMat->Create(_T("Test Group Box"),WS_VISIBLE|BS_GROUPBOX ,
               CRect(xpos,ypos,xpos+xlength,ypos+3* ylength),this,IDC_BTN_MAT);
    

    Die GroupBox wird richtig erzeugt aber wie gesagt auf die Radiobuttons kann ich nicht zugreifen. Kann mir bitte jemand weiterhelfen? Komme einfach nicht weiter..



  • das liegt an der z-Order deiner Gruppbox welche vor deinem radiobuttons liegt. Aber um die z-order nicht durcheinander zu bringen, erzeungst du mit dem resourceneditor in dialog deine Groupbox und subclasst die groupbox auf deine klasse.

    m_TGrpBox1.SubclassDlgItem(IDC_GRPBOX1, this);
    

    m_TGrpBox1 ist der deine CTGroupBox welche du im header mit

    CTGroupBox m_TGrpBox1;
    

    erstellt. IDC_GRPBOX1 ist die ID deine Groupbox im Dialog und this ist der this-zeiger deines dialoges, damit die nachrichten auch zugeordnet werden können.
    Das wars.

    weiteres unter
    http://msdn.microsoft.com/en-us/library/0wx11zk9(VS.80).aspx

    und auf ähnlichen seiten, ich hoffe das hilt weiter


  • Mod

    Die Z-Order darf bei Groupboxen nichts ausmachen, denn diese sollten auf einen WM_NCHITTEST brav HTTRANSPARENT zurückgeben.
    Evtl. wurde hier was falsch überschrieben. Dito sollten Sie in der Tab-Order vor den Radios liegen um die Accelerator Steuerung nicht durcheinander zu bringen 😉



  • Hallo zusammen,

    also die Radiobuttons erzeuge ich nach der GroupBox. Jedoch ist die übergeordnete Klasse vom Typ CWnd. Und für die gibt es keine OnInitDialog.

    Deshalb führe ich den Befehl
    btnMat->SubclassDlgItem(IDC_BTN_MAT, this);
    vor der Erzeugung der GroupBox mit Create durch.

    Das mit der z-Order habe ich mir auch schon überlegt. Falls ich nämlich die GroupBox als CButton erzeuge, so kann ich auf die Radiobuttons zugreifen. Ich will jedoch den Hintergrund transparent haben und auch die Captions verändern. Dies geht ja für Buttons nur über eigene Klassen.

    Damit bin ich aber leider noch keinen Schritt weitergekommen 😕



  • So Problem gelöst:

    Zuerst GroupBox erstellen, dann die Radiobuttons. Anschliessend die Radiobuttons mit BringWindowToTop() "nach vorne " bringen und schon kann man die Radiobuttons auswählen.


Anmelden zum Antworten