ComboBox: How to center text?

Windows specific forum
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

ComboBox: How to center text?

Post by IdeasVacuum »

So I thought it was time to ask another dumb question :shock:

Is it possible to force the item text of a (non editable) ComboBox to be central?
Without requiring 10 kilometers of code or a call-back?

Image
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4659
Joined: Sun Apr 12, 2009 6:27 am

Re: ComboBox: How to center text?

Post by RASHAD »

HI
You can optimize for speed by calculating gadw and width2 after creating the gadget directly(It is needed only once)

Code: Select all

Procedure _AddGadgetItem(gad,Text$)
  gadw = GadgetWidth(gad,#PB_Gadget_ActualSize) - GadgetWidth(gad,#PB_Gadget_RequiredSize)
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    width = TextWidth(Text$)
    width2 = TextWidth(" ")
  StopDrawing()
  trim = (gadw - width)/2/width2
  text$ = Space(trim)+text$
  AddGadgetItem(gad, -1,text$)
EndProcedure

LoadFont(0,"Tahoma",12)

If OpenWindow(0, 0, 0, 400, 400, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ComboBoxGadget(0, 10, 10, 250, 24)  
  SetGadgetFont(0,FontID(0))
  _AddGadgetItem(0,"IdeasVacuum")
  _AddGadgetItem(0,"ComboBox item #!")
  _AddGadgetItem(0,"RASHAD")
 
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
#2 :
Center text Val. & Hal.
You must take care for if the text length exceeds the gadget width

Code: Select all

Procedure _GetGadgetText(gad)
  text$ = LTrim(GetGadgetText(gad)," ")
  Debug text$
EndProcedure

Procedure _AddGadgetItem(gad,Text$)
  gadw = GadgetWidth(gad,#PB_Gadget_ActualSize); - GadgetWidth(gad,#PB_Gadget_RequiredSize)
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    width = TextWidth(Text$)
    width2 = TextWidth(" ")
  StopDrawing()
  trim = (gadw - width)/2/width2
  text$ = Space(trim)+text$
  AddGadgetItem(gad, -1,text$)
EndProcedure

LoadFont(0,"Tahoma",14)

If OpenWindow(0, 0, 0, 400, 400, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ComboBoxGadget(0, 10, 10, 250, 20) 
  SetGadgetFont(0,FontID(0))
  StartDrawing(WindowOutput(0))
    DrawingFont(FontID(0))
    height = TextHeight("Q")+10
  StopDrawing()  
  ResizeGadget(0,#PB_Ignore,#PB_Ignore,#PB_Ignore,height)
  _AddGadgetItem(0,"IdeasVacuum")
  _AddGadgetItem(0,"ComboBox item #!")
  _AddGadgetItem(0,"RASHAD")
  SetGadgetState(0,1)
 ButtonGadget(1,10,370,80,25,"Get Text")
  Repeat
    Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
        Quit = 1
        
      Case #PB_Event_Gadget
        Select EventGadget()
          Case 1
            _GetGadgetText(0)
        EndSelect
    EndSelect
  Until Quit = 1
EndIf
Egypt my love
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: ComboBox: How to center text?

Post by Shardik »

You may also try the following example which uses Windows API functions and is therefore only usable in Windows. Unfortunately it needs a callback! I have tested it successfully in Windows 10 x64 Version 1809 with PB 5.46 x86 and x64 in ASCII and Unicode mode and with PB 5.71 x86.

Code: Select all

EnableExplicit

Procedure WindowCallback(WindowHandle.I, Message.I, WParam.I, LParam.I)
  Protected Brush.I
  Protected DC.I
  Protected *DrawItem.DRAWITEMSTRUCT
  Protected ItemText.S
  Protected Result.I
  Protected Size.SIZE
  Protected x.I

  Result = #PB_ProcessPureBasicEvents

  If Message = #WM_DRAWITEM
    *DrawItem = LParam

    If *DrawItem\CtlType = #ODT_COMBOBOX
      SetBkMode_(*DrawItem\hDC, #TRANSPARENT)

      If *DrawItem\ItemState & #ODS_FOCUS
        Brush = CreateSolidBrush_($FF901E)
        FillRect_(*DrawItem\hDC, *DrawItem\rcItem, Brush)
        DeleteObject_(Brush)
        SetTextColor_(*DrawItem\hDC, $FFFFFF)
      Else
        FillRect_(*DrawItem\hDC, *DrawItem\rcItem,
          GetStockObject_(#WHITE_BRUSH))
      EndIf

      If *DrawItem\itemID <> -1
        ItemText = Space(128)
        SendMessage_(*DrawItem\hwndItem, #CB_GETLBTEXT,
          *DrawItem\itemID, @ItemText)

        DC = GetDC_(WindowHandle)
        SelectObject_(DC, GadgetID(WParam))     
        GetTextExtentPoint32_(DC, @ItemText, Len(ItemText), Size)
        ReleaseDC_(GadgetID(WParam), DC)

        x = *DrawItem\rcItem\left +
          (*DrawItem\rcItem\right - *DrawItem\rcItem\left - Size\cx) / 2
        TextOut_(*DrawItem\hDC, x, *DrawItem\rcItem\top, ItemText,
          Len(ItemText))
      EndIf
    EndIf
  EndIf

  ProcedureReturn Result
EndProcedure

Define i.I

OpenWindow(0, 200, 100, 270, 130, "ComboBoxGadget demo")
SetGadgetFont(#PB_Default, LoadFont(0, "Verdana", 10))
ComboBoxGadget(0, 10, 20, 120, 23)
ComboBoxGadget(1, 140, 20, 120, 23, #CBS_OWNERDRAWFIXED | #CBS_HASSTRINGS)
SetWindowCallback(@WindowCallback())

For i = 1 To 5
  AddGadgetItem(0, -1, "Item " + Str(i))
  AddGadgetItem(1, -1, "Item " + Str(i))
Next

SetGadgetState(0, 0)
SetGadgetState(1, 0)
  
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: ComboBox: How to center text?

Post by IdeasVacuum »

Thanks for your help Shardik, Rashad.

I have used the API method before (blasted call-back :D).

What I have done recently is to use a monoblock font, verified the text length, packed-out with spaces. Vertical center is done by matching the font height to the gadget height. That method mostly works and of course is a lot "lighter" than API.

I have also DIY'd a combo using a Button and a single column ListIcon for the pop-down, centered with a bit of API:

Code: Select all

Procedure JustifyListCol(iListIconID.i, iCol.i, iFlag.i, iColWidth.i)
;#--------------------------------------------------------------------
;Justify ListIcon and Set Column Width
;Column Flag: 1 = Left, 2 = Right, 3 = Center

Protected lvc.LVCOLUMN

          lvc\Mask = #LVCF_FMT

              Select iFlag

                            Case 1: lvc\fmt = #LVCFMT_LEFT
                            Case 2: lvc\fmt = #LVCFMT_RIGHT
                            Case 3: lvc\fmt = #LVCFMT_CENTER
                           Default: lvc\fmt = #LVCFMT_LEFT
              EndSelect

              SetGadgetItemAttribute(iListIconID, 0, #PB_ListIcon_ColumnWidth,  iColWidth, iCol)
                           SendMessage_(GadgetID(iListIconID), #LVM_SETCOLUMN, iCol, @lvc)
EndProcedure
.... now I'm thinking of another DIY approach, Button with a single column HTML table - the beauty of HTML being that it is so easy to center text, and other effects such as selection highlighting etc.

I always have a generous amount of space around combobox and text buttons because other languages like German and Dutch often have longer words for the equivalent English word.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: ComboBox: How to center text?

Post by IdeasVacuum »

Well, experiments complete. For the current project, Rashad's #2 is a clear winner. HTML a close 2nd.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: ComboBox: How to center text?

Post by IdeasVacuum »

Code: Select all

Procedure AddComboItem(iWin.i, iGadget.i, sText.s, iFont.i)
;#---------------------------------------------------------
Protected iGadgetW.i = GadgetWidth(iGadget, #PB_Gadget_ActualSize)
Protected iW1.i, iW2.i, iTrim.i

               StartDrawing(WindowOutput(iWin))

                        DrawingFont(iFont)

                        iW1 = TextWidth(sText)
                        iW2 = TextWidth(" ")

               StopDrawing()

               iTrim = ((iGadgetW - iW1) /2 /iW2)
               sText = Space(iTrim) + sText

               AddGadgetItem(iGadget, -1, sText)
EndProcedure

Procedure.i ComboHeight(iWin.i, iGadget.i, iFont.i)
;#-------------------------------------------------
Protected iComboHgt.i
Protected iVertPadding.i

               StartDrawing(WindowOutput(iWin))

                         DrawingFont(iFont)

                         iVertPadding = TextHeight("Q") / 2
                            iComboHgt = TextHeight("Q") + iVertPadding

               StopDrawing()

               ProcedureReturn(iComboHgt)
EndProcedure
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
Post Reply