Page 1 of 1

Disabled item in combobox???

Posted: Thu Sep 10, 2009 3:29 pm
by Tomi
Disabled item in combobox???

A disabled item is nonSelectable and colored by GrayColor
is there a sample for this request?

Re: Disabled item in combobox???

Posted: Fri Sep 11, 2009 5:44 am
by Tomi
if not possible for combobox, maybe be for ListViewGadget???
if it possible for ListViewGadget, it will be great and i can use ListViewGadget Instead combobox
however for my purpose , combobox is better than other gadget

Re: Disabled item in combobox???

Posted: Fri Sep 11, 2009 10:21 am
by klaver
As far as I know it's not possible with native PB commands. That makes us focus on the API. But we need to know the OS.

If it's Windows you should take a look on subclassing and ownerdrawing.

Re: Disabled item in combobox???

Posted: Fri Sep 11, 2009 10:29 am
by Tomi
need for Win xp and next OS only.
have you a keyword or more help, please?

Re: Disabled item in combobox???

Posted: Fri Sep 11, 2009 12:25 pm
by klaver
I've used CallWindowProc_(CBCB, ...) because it's faster than SendMessage_(). It skips all subclassing.

Not sure if the keyboard support (arrow keys) is flawless. It still needs some testing.

Code: Select all

wc.WNDCLASSEX\cbSize = SizeOf(WNDCLASSEX)
GetClassInfoEx_(GetModuleHandle_(0), @"ComboBox", @wc)
Global PrevItm.i, LastKey.i, *Text=AllocateMemory(128), CBCB = wc\lpfnWndProc

Procedure ComboProc(hWnd, uMsg, wParam, lParam)
  OldProc = GetProp_(hWnd, "MyCB")
  Select uMsg
    Case #WM_KEYDOWN
      LastKey = wParam
    Case #WM_NCDESTROY
      RemoveProp_(hWnd, "MyCB")
  EndSelect
  ProcedureReturn CallWindowProc_(OldProc, hWnd, uMsg, wParam, lParam)
EndProcedure

Procedure WinCallback(hWnd, uMsg, wParam, lParam)
  Select uMsg
    Case #WM_DRAWITEM
      *lpdis.DRAWITEMSTRUCT = lParam : SetBkMode_(*lpdis\hDC, #TRANSPARENT)
      If *lpdis\CtlType = #ODT_COMBOBOX
        If *lpdis\itemState & #ODS_SELECTED
          If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0);SendMessage_()
            *lpdis\CtlType = GetSysColorBrush_(#COLOR_BTNFACE)
          Else
            *lpdis\CtlType = GetSysColorBrush_(#COLOR_HIGHLIGHT)
          EndIf
        Else
          *lpdis\CtlType = GetSysColorBrush_(#COLOR_WINDOW)
        EndIf
        FillRect_(*lpdis\hDC, *lpdis\rcItem, *lpdis\CtlType) : *lpdis\rcItem\left+4
        
        CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETLBTEXT, *lpdis\itemID, *Text);SendMessage_()
        
        If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0);SendMessage_()
          SetTextColor_(*lpdis\hDC, #Gray);GetSysColor_(#COLOR_GRAYTEXT)
        EndIf
        DrawText_(*lpdis\hDC, *Text, -1, *lpdis\rcItem, #DT_NOCLIP|#DT_VCENTER|#DT_SINGLELINE)
        SetTextColor_(*lpdis\hDC, GetSysColor_(#COLOR_WINDOWTEXT))
      EndIf
    Case #WM_COMMAND
      Select (wParam>>16) & $FFFF;HIWORD
        Case #CBN_SELCHANGE
          Var = CallWindowProc_(CBCB, lParam, #CB_GETCURSEL, 0, 0);SendMessage_()
          If Var <> PrevItm
            If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, Var, 0);SendMessage_()
              If LastKey = 38 Or LastKey = 37
                For i=Var-1 To 0 Step -1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    PrevItm = i : Break
                  EndIf
                Next
              ElseIf LastKey = 40 Or LastKey = 39
                For i=Var+1 To CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    PrevItm = i : Break
                  EndIf
                Next
              EndIf
              CallWindowProc_(CBCB, lParam, #CB_SETCURSEL, PrevItm, 0);SendMessage_()
            Else
              PrevItm = Var
            EndIf
          EndIf
        Case #CBN_DROPDOWN
          LastKey = 0
      EndSelect
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(1, 10, 40, 250, 21, #CBS_OWNERDRAWFIXED)
For n = 1 To 10
  AddGadgetItem(1, -1, "ComboBox Item " + Str(n))
Next
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 3, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 4, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 9, #True);DISABLE ITEM
SetProp_(GadgetID(1), "MyCB", SetWindowLong_(GadgetID(1), #GWL_WNDPROC, @ComboProc()))

SetWindowCallback(@WinCallback(), 0)
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver

Re: Disabled item in combobox???

Posted: Fri Sep 11, 2009 1:01 pm
by Tomi
wow :shock:
very well thanks klaver, that's great :D

Re: Disabled item in combobox???

Posted: Sat Oct 02, 2010 3:50 pm
by Alireza
Hello
i need this sweet code, but sorry it's don't work in Win 7 64bit
can you update it for new Os's ?

i need work in xp and 7 together ...
Image

Re: Disabled item in combobox???

Posted: Sat Oct 02, 2010 4:32 pm
by hallodri

Code: Select all

[...]
ComboBoxGadget(1, 10, 40, 250, 21, #CBS_OWNERDRAWFIXED|#CBS_HASSTRINGS)
[...]

Re: Disabled item in combobox???

Posted: Sun Oct 03, 2010 12:22 pm
by Alireza
:D
Thanks man

Re: Disabled item in combobox???

Posted: Fri May 06, 2011 4:14 pm
by klaver
Updated version with few bugs fixed (drawing, PgUp/PgDn, multiple CB support).

Code: Select all

Structure MyCB
  oldProc.i
  prevItm.i
  lastKey.i
EndStructure
wc.WNDCLASSEX\cbSize = SizeOf(WNDCLASSEX)
GetClassInfoEx_(GetModuleHandle_(0), @"ComboBox", @wc)
Global *TmpCB.MyCB, *Text=AllocateMemory(128), CBCB = wc\lpfnWndProc

Procedure ComboProc(hWnd, uMsg, wParam, lParam)
  *TmpCB = GetProp_(hWnd, "MyCB")
  If *TmpCB
    oldProc = *TmpCB\oldProc
  Else
    oldProc = CBCB;#WM_DELETEITEM
  EndIf
  
  Select uMsg
    Case #WM_KEYDOWN
      *TmpCB\lastKey = wParam
    Case #WM_NCDESTROY
      RemoveProp_(hWnd, "MyCB")
      FreeMemory(*TmpCB)
  EndSelect
  ProcedureReturn CallWindowProc_(oldProc, hWnd, uMsg, wParam, lParam)
EndProcedure

Procedure WinCallback(hWnd, uMsg, wParam, lParam)
  Select uMsg
    Case #WM_DRAWITEM
      *lpdis.DRAWITEMSTRUCT = lParam
      SetBkMode_(*lpdis\hDC, #TRANSPARENT)
      If *lpdis\CtlType = #ODT_COMBOBOX
        If *lpdis\itemState & #ODS_SELECTED
          If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0) And *lpdis\itemID > -1
            *lpdis\CtlType = GetSysColorBrush_(#COLOR_BTNFACE)
          Else
            *lpdis\CtlType = GetSysColorBrush_(#COLOR_HIGHLIGHT)
          EndIf
        Else
          *lpdis\CtlType = GetSysColorBrush_(#COLOR_WINDOW)
        EndIf
        FillRect_(*lpdis\hDC, *lpdis\rcItem, *lpdis\CtlType)
        *lpdis\rcItem\left+4
        
        If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETLBTEXT, *lpdis\itemID, *Text) > -1
          If CallWindowProc_(CBCB, *lpdis\hwndItem, #CB_GETITEMDATA, *lpdis\itemID, 0);SendMessage_()
            SetTextColor_(*lpdis\hDC, #Gray);GetSysColor_(#COLOR_GRAYTEXT)
          EndIf
          DrawText_(*lpdis\hDC, *Text, -1, *lpdis\rcItem, #DT_NOCLIP|#DT_VCENTER|#DT_SINGLELINE)
          SetTextColor_(*lpdis\hDC, GetSysColor_(#COLOR_WINDOWTEXT))
        EndIf
      EndIf
    Case #WM_COMMAND
      *TmpCB = GetProp_(lParam, "MyCB"); it should be checked if pointer isn't NULL (too lazy for that)
      
      Select (wParam>>16) & $FFFF;HIWORD
        Case #CBN_SELCHANGE
          Var = CallWindowProc_(CBCB, lParam, #CB_GETCURSEL, 0, 0);SendMessage_()
          If Var <> *TmpCB\prevItm
            If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, Var, 0);SendMessage_()
              If *TmpCB\lastKey = 38 Or *TmpCB\lastKey = 37;Up
                For i=Var-1 To 0 Step -1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    *TmpCB\prevItm = i : Break
                  EndIf
                Next
              ElseIf *TmpCB\lastKey = 40 Or *TmpCB\lastKey = 39;Down
                For i=Var+1 To CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    *TmpCB\prevItm = i : Break
                  EndIf
                Next
              ElseIf *TmpCB\lastKey = 33;PgUp
                For i=0 To CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    *TmpCB\prevItm = i : Break
                  EndIf
                Next
              ElseIf *TmpCB\lastKey = 34;PgDn
                For i=CallWindowProc_(CBCB, lParam, #CB_GETCOUNT, 0, 0)-1 To 0 Step -1
                  If CallWindowProc_(CBCB, lParam, #CB_GETITEMDATA, i, 0) = #False
                    *TmpCB\prevItm = i : Break
                  EndIf
                Next
              EndIf
              CallWindowProc_(CBCB, lParam, #CB_SETCURSEL, *TmpCB\prevItm, 0);SendMessage_()
            Else
              *TmpCB\prevItm = Var
            EndIf
          EndIf
        Case #CBN_DROPDOWN
          *TmpCB\lastKey = 0
      EndSelect
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

Procedure MakeMyCB(ID)
  *TmpCB = AllocateMemory(SizeOf(MyCB))
  *TmpCB\prevItm = SendMessage_(GadgetID(ID), #CB_GETCURSEL, 0, 0)
  *TmpCB\oldProc = SetWindowLongPtr_(GadgetID(ID), #GWL_WNDPROC, @ComboProc())
  SetProp_(GadgetID(ID), "MyCB", *TmpCB)
EndProcedure

OpenWindow(0, 0, 0, 270, 140, "ComboBoxGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ComboBoxGadget(1, 10, 40, 250, 21, #CBS_OWNERDRAWFIXED|#CBS_HASSTRINGS)
ComboBoxGadget(2, 10, 70, 250, 21, #CBS_OWNERDRAWFIXED|#CBS_HASSTRINGS)
For i = 1 To 10
  AddGadgetItem(1, -1, "ComboBox A Item " + Str(i))
  AddGadgetItem(2, -1, "ComboBox B Item " + Str(i))
Next

MakeMyCB(1)
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 3, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 4, #True);DISABLE ITEM
SendMessage_(GadgetID(1), #CB_SETITEMDATA, 9, #True);DISABLE ITEM

MakeMyCB(2)
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 2, #True);DISABLE ITEM
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 6, #True);DISABLE ITEM
SendMessage_(GadgetID(2), #CB_SETITEMDATA, 7, #True);DISABLE ITEM

SetWindowCallback(@WinCallback(), 0)
Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
  EndSelect
ForEver

Re: Disabled item in combobox???

Posted: Mon May 09, 2011 6:19 pm
by Tomi
nice code really ,many thanks dear klaver :D

Re: Disabled item in combobox???

Posted: Sun Jul 30, 2023 6:52 am
by Olli
Hello,

is there also any updates for Win 10/11 ?

Re: Disabled item in combobox???

Posted: Sun Jul 30, 2023 6:56 am
by BarryG
The last code above by klaver works on Win 10 for me.

Re: Disabled item in combobox???

Posted: Sun Jul 30, 2023 12:34 pm
by Olli
Thank you BarryG, it stays now a successful test on Window 11...

Re: Disabled item in combobox???

Posted: Mon Jul 31, 2023 5:06 pm
by Axolotl
also works under win 11.
Minimal restriction: you see the disabled item for a short time in the edit field, but it disappears again immediately.