Jose,
I assumed adding a groupbox would be the same as adding a button it appears I missed something.
My groupbox background is not the same color as the Window. I noticed in your CSED editor that groupboxes you use do have the same background.
James
#COMPILE EXE
#DIM ALL
%UNICODE = 1
' // Include files for external files
%USEXPBUTTON = 1
#INCLUDE ONCE "CWindow.inc" ' // CWindow class
' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpszCmdLine AS WSTRINGZ PTR, BYVAL nCmdShow AS LONG) AS LONG
' // Create an instance of the class
LOCAL pWindow AS IWindow
pWindow = CLASS "CWindow"
IF ISNOTHING(pWindow) THEN EXIT FUNCTION
' // Create the main window
' // Note: CW_USEDEFAULT is used as the default value When passing 0's as the width and height
pWindow.CreateWindow(%NULL, "CWindow with an XPButton", 0, 0, 500, 350, -1, -1, CODEPTR(WindowProc))
' // Center the window
pWindow.CenterWindow
' // Add a button
pWindow.AddXPButton(pWindow.hwnd, %IDCANCEL, "&Close", 350, 250, 75, 23, -1, -1)
pWindow.AddGroupBox(pWindow.hwnd,-1,"Group #1",16,16,200,100,-1)
' // Default message pump (you can replace it with your own)
pWindow.DoEvents(nCmdShow)
END FUNCTION
' ========================================================================================
' ========================================================================================
' Main callback function.
' ========================================================================================
FUNCTION WindowProc (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
' // Process window mesages
SELECT CASE uMsg
CASE %WM_COMMAND
SELECT CASE LO(WORD, wParam)
CASE %IDCANCEL
' // If the Escape key has been pressed...
IF HI(WORD, wParam) = %BN_CLICKED THEN
' // ... close the application by sending a WM_CLOSE message
SendMessage hwnd, %WM_CLOSE, 0, 0
EXIT FUNCTION
END IF
END SELECT
CASE %WM_DESTROY
' // End the application
PostQuitMessage 0
EXIT FUNCTION
END SELECT
' // Pass unprocessed messages to Windows
FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)
END FUNCTION
' ========================================================================================
The default styles for the main window are %WS_OVERLAPPEDWINDOW OR %WS_CLIPCHILDREN OR %WS_CLIPSIBLINGS. The WS_CLIPCHILDREN style causes a window to exclude the areas occupied by child windows when the window paints its client area. However, a BS_GROUPBOX style window is a static control that never erases its background. Erasing the background removes any controls or buttons that appear within the group box.
Therefore, use %WS_OVERLAPPEDWINDOW OR %WS_CLIPSIBLINGS instead of -1
pWindow.CreateWindow(%NULL, "CWindow with an XPButton", 0, 0, 500, 350, %WS_OVERLAPPEDWINDOW OR %WS_CLIPSIBLINGS, -1, CODEPTR(WindowProc))
or subclass the groupbox and erase its background.
See: http://support.microsoft.com/kb/79982
Sometimes one has to wonder about some of the articles in the Microsoft Knowledge Base.
That article is out of date and uses terms that are misleading.
The groupbox belongs to the "Button" class not the "Static" class.
The solutions to this problem range from fiddling with window styles to rolling your own groupbox.
My favourite solution is number 2. It is simple and handles the WS_CLIPSIBLINGS style(resizeable windows).
Note: the groupbox should be created after the controls it groups when the controls
on the parent have the WS_CLIPSIBLINGS style.
Solution 1 - no WS_CLIPCHILDREN style
This solution creates the parent window without the WS_CLIPCHILDREN style. This works fine on windows
that are not resizeable, but can cause nasty flickering on ones that are resizeable.
Solution 2 - add WS_EX_TRANSPARENT extended style
This solution keeps the WS_CLIPCHILDREN style on the parent window and adds the WS_EX_TRANSPARENT extended
window style to the groupbox. This works well on both nonresizeable and resizeable windows.
Also, flickering is significantly reduced.
Solution 3 - paint background
This solution keeps the WS_CLIPCHILDREN style on the parent window and subclasses the groupbox in order
to paint it background.
This works well on both nonresizeable and resizeable windows. Also, flickering is significantly reduced.
'-------------------------------------------------------------------------------
'
' PROCEDURE: Form1_Group1_SubclassProc
' PURPOSE: Processes messages for the subclassed Button window.
'
'-------------------------------------------------------------------------------
FUNCTION Form1_Group1_SubclassProc _
( _
BYVAL hWnd AS DWORD, _ ' control handle
BYVAL uMsg AS DWORD, _ ' type of message
BYVAL wParam AS DWORD, _ ' first message parameter
BYVAL lParam AS LONG _ ' second message parameter
) EXPORT AS LONG
LOCAL trc AS RECT
LOCAL lpOldWndProc AS DWORD ' address of original window procedure
LOCAL lMsgResult AS LONG ' value returned to message after message is processed
lpOldWndProc = GetProp(hWnd, "OLDWNDPROC")
SELECT CASE uMsg
CASE %WM_DESTROY
' Remove control subclassing
SetWindowLong hWnd, %GWL_WNDPROC, RemoveProp(hWnd, "OLDWNDPROC")
CASE %WM_ERASEBKGND
GetClientRect hWnd, trc
FillRect hDC, trc, GetClassLong(GetParent(hWnd), %GCL_HBRBACKGROUND)
' The message was processed
FUNCTION = %TRUE
EXIT FUNCTION
END SELECT
FUNCTION = CallWindowProc(lpOldWndProc, hWnd, uMsg, wParam, lParam)
END FUNCTION
Solution 4 - roll your own
A groupbox is a very simple control(read easy to write).
This solution will eliminate flicker.
By the way, adding the WS_EX_COMPOSITED style to the parent or to the parent and children significantly reduces flicker or eliminates it.
But this is an extended style that needs to be checked against various controls before adding it willy-nilly.
Thanks very much for your detailed information. Very useful, as always. For a quick fix, I will add the WS_EX_TRANSPARENT style as the default. Later, maybe I will write a custom control. This one looks nice: http://www.codeproject.com/KB/miscctrl/XGroupBox.aspx
I had to write a specific subroutine just to handle that one in WinLIFT, to process correctly the WM_PAINT / WM_PRINTCLIENT messages ::)
CASE %CTRL_GROUPBOX
IF wParam = 0 THEN
CALL BeginPaint(hWnd, ps): hDC = ps.hDC
ELSE
hDC = wParam
END IF
CALL skPaintGroupBox(hWnd, hDC)
IF wParam = 0 THEN CALL EndPaint(hWnd, ps)
FUNCTION skPaintGroupBox(BYVAL hWnd AS LONG, BYVAL hDC AS LONG) AS LONG
LOCAL rc AS RECT
LOCAL LenLabel, x1, y1, x2, y2, stW, stH, gbX, gbY, Xin, Yin, nUseColor, n1, nBorder AS LONG
LOCAL yOffset, ofX, ofY, UseFont, nStrFormat AS LONG
LOCAL sLabel AS STRING
Item& = skChild(hWnd)
IF Item& THEN
IF Child(Item&).CtrlType = %CTRL_GROUPBOX THEN
gbX = 0 ' Child(Item&).rc.nLeft
gbY = 0 ' Child(Item&).rc.nTop
Xin = Child(Item&).rc.nRight
Yin = Child(Item&).rc.nBottom
' 06-22-2003 Fix to handle empty label (George W. Bleck)
sLabel = skGetCTLtext(hWnd)
' // 4.70
UseFont = skFontPlus()
CALL GdipCreateStringFormat(0, 0, nStrFormat)
CALL GdipSetStringFormatTrimming(nStrFormat, %StringTrimmingCharacter)
LenLabel = LEN(sLabel)
IF LenLabel = 0 THEN sLabel = "W"
' // 4.70
CALL skGetPlusTextSize(hDC, sLabel, UseFont, nStrFormat, stW, stH)
IF LenLabel = 0 THEN sLabel = "": stW = 0
' 06-22-2003 End fix
stW = stW + 4: yOffset = stH \ 2
IF LenLabel THEN
'//4.01 modified
n1 = 1: x1 = gbX + 0: y1 = gbY + yOffset: x2 = Xin: y2 = Yin - yOffset
nUseColor = skGetSysColor(%SKCOLOR_3DRIGHTBOTTOM): nBorder = 8
GOSUB PaintGroupLine
'//4.01 modified
n1 = 0: x1 = gbX + 1: y1 = gbY + yOffset + 1: x2 = Xin - 2: y2 = Yin - yOffset - 2
nUseColor = skGetSysColor(%SKCOLOR_3DLEFTTOP): nBorder = 7
GOSUB PaintGroupLine
' 06-22-2003 Fix to handle empty label (George W. Bleck)
CALL skChildoffset(hWnd, ofX, ofY)
ofX = ofX + 8
' Create OFF screen bitmap to avoid flickering AND allow smooth display
' ---------------------------------------------------------------------
hDCTemp& = skOFFscreen(hDC, stW, stH, 1)
hTmpBmp& = CreateCompatibleBitmap(hDCTemp&, stW, stH)
CALL SelectObject(hDCTemp&, hTmpBmp&)
CALL skAlphaBlend(hDCTemp&, 0, 0, Xin, Yin, skGetHdcMemBmp(skPopupOwner(hWnd)), ofX, ofY, Xin, Yin)
CALL DeleteObject(hTmpBmp&)
' End of OFF screen drawing, fast BitBlt to the target display Window
' -------------------------------------------------------------------
CALL skOFFscreen(0, gbX + 8, gbY + 0, 0)
' 06-22-2003 End fix
CALL SetRect(rc, gbX + 10, gbY + 0, gbX + 10 + stW, gbY + 0 + stH)
' // 4.54
IF skGetSystemMetrics(%SK_OUTER_GLOW) THEN
CALL BlurTextPlus(hDC, sLabel, rc, UseFont, nStrFormat)
END IF
' // 4.70
CALL skDrawText(hDC, slabel, rc, UseFont, zColorARGB(255, skGetSysColor(%SKCOLOR_WINDOWTEXT)), nStrFormat)
ELSE
CALL skDrawRect3D(hDC, gbX + 0, gbY + yOffset, Xin, Yin - yOffset, skGetSysColor(%SKCOLOR_3DRIGHTBOTTOM), skGetSysColor(%SKCOLOR_3DRIGHTBOTTOM))
CALL skDrawRect3D(hDC, gbX + 1, gbY + yOffset + 1, Xin - 2, Yin - yOffset - 2, skGetSysColor(%SKCOLOR_3DLEFTTOP), skGetSysColor(%SKCOLOR_3DLEFTTOP))
END IF
CALL GdipDeleteStringFormat(nStrFormat)
ELSE
CALL skDrawChildBorder(hWnd) ' I need this to draw borders with WM_PRINT for dialog and TAB control
END IF
END IF
FUNCTION = %TRUE ' continue enumeration of children...
EXIT FUNCTION
PaintGroupLine:
x2 = x1 + x2 - 1: y2 = y1 + y2 - 1
CALL zDrawLine(hDC, x1, y2, x1, y1, zColorARGB(255, nUseColor), 1, %DashStyleSolid)
CALL zDrawLine(hDC, x1, y1, x1 + nBorder, y1, zColorARGB(255, nUseColor), 1, %DashStyleSolid)
CALL zDrawLine(hDC, x1 + stW + nBorder, y1, x2 + 1, y1, zColorARGB(255, nUseColor), 1, %DashStyleSolid)
CALL zDrawLine(hDC, x2, y1, x2, y2, zColorARGB(255, nUseColor), 1, %DashStyleSolid)
CALL zDrawLine(hDC, x1, y2, x2 + n1, y2, zColorARGB(255, nUseColor), 1, %DashStyleSolid)
RETURN
END FUNCTION
As you can see, something not trivial, especially to let it work in composited mode.
Indeed, you better have to write your own custom control, but then no way for a theme engine to skin it on the fly ;D
...