• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

CWindow GroupBox

Started by James C. Fuller, May 29, 2011, 04:20:26 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

James C. Fuller

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
' ========================================================================================




José Roca

 
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

Dominic Mitchell

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.
Dominic Mitchell
Phoenix Visual Designer
http://www.phnxthunder.com

Dominic Mitchell

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.
Dominic Mitchell
Phoenix Visual Designer
http://www.phnxthunder.com

José Roca

 
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

Patrice Terrier

#5
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

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com