An Issue with Combobox Focus...
-
- Posts: 355
- Joined: May 29, 2015 20:37
An Issue with Combobox Focus...
Hi all.
I've run into a little problem in one of my programs.
In my window, I have a combobox and a button. The combobox has several items, and the program selects an item for you at the very beginning of the program. I, the user, select the edit control within the combobox to select all the text.
When the button is clicked, I would like the selected text within the combobox to be copied.
Trouble is, once the user has clicked off of the combobox and clicked the button, the edit control loses focus and therefore no text is copied as no text is selected because of this.
Do any of you guys know how to keep combobox/edit focus in this case?
I was reading this blog, and even though the blogger said he would post the answer to a very similar problem, he hadn't: at least not for the next several blogs in the linked series. It helped part of the way, but not all the way, if you see what I mean.
Thanks for your time.
I've run into a little problem in one of my programs.
In my window, I have a combobox and a button. The combobox has several items, and the program selects an item for you at the very beginning of the program. I, the user, select the edit control within the combobox to select all the text.
When the button is clicked, I would like the selected text within the combobox to be copied.
Trouble is, once the user has clicked off of the combobox and clicked the button, the edit control loses focus and therefore no text is copied as no text is selected because of this.
Do any of you guys know how to keep combobox/edit focus in this case?
I was reading this blog, and even though the blogger said he would post the answer to a very similar problem, he hadn't: at least not for the next several blogs in the linked series. It helped part of the way, but not all the way, if you see what I mean.
Thanks for your time.
-
- Posts: 8586
- Joined: May 28, 2005 3:28
- Contact:
Re: An Issue with Combobox Focus...
pseudo code:
Code: Select all
var last_item = -1
if combo_clicked then last_item = combo_with_focus_get_active_item
if copy_button_clicked and (last_item <> -1) then copy(combo_get_item(last_item))
-
- Posts: 355
- Joined: May 29, 2015 20:37
Re: An Issue with Combobox Focus...
Thanks!D.J.Peters wrote:pseudo code:Code: Select all
var last_item = -1 if combo_clicked then last_item = combo_with_focus_get_active_item if copy_button_clicked and (last_item <> -1) then copy(combo_get_item(last_item))
-
- Posts: 56
- Joined: Dec 11, 2016 17:22
Re: An Issue with Combobox Focus...
Hey,
For the fun of it, one may also subclass the edit part of the combobox to get access to usefull messages.
Pierre
For the fun of it, one may also subclass the edit part of the combobox to get access to usefull messages.
Pierre
Code: Select all
#Include Once "windows.bi"
#Include Once "win/commctrl.bi"
#Include Once "win/shellapi.bi"
Dim Shared pComboboxEdit As WndProc
Dim Shared hStatic As HWnd
Dim Shared SelStart As wParam
Dim Shared SelEnd As lParam
Dim Shared hInstance As HINSTANCE : hInstance = GetModuleHandle(NULL)
Function GetEditSelText(ByVal hWnd As HWND) As String
'Get the selected text of the edit part of the combobox control
Dim TextLen As Long
Dim sBuffer As String
SendMessage(hWnd, EM_GETSEL, Cast(wParam, @SelStart), Cast(lParam, @SelEnd)) 'Get selection
TextLen = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1
sBuffer = String(TextLen, 0)
SendMessage(hWnd, WM_GETTEXT, TextLen, Cast(lParam, StrPtr(sBuffer)))
Function = Mid(sBuffer, SelStart + 1, SelEnd - SelStart)
End Function
Function ComboboxEditProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer
'Subclassed edit part of the combobox control
Select Case uMsg
Case WM_SETFOCUS
SetWindowText(hStatic, "SetFocus: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """")
Case WM_KILLFOCUS
SetWindowText(hStatic, "KillFocus: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """")
Case EM_SETSEL
wParam = SelStart 'Memorise SelStart
lParam = SelEnd 'Memorise SelEnd
Case WM_KEYUP, WM_LBUTTONUP
SetWindowText(hStatic, "KeyUp/LButtonUp: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """")
End Select
Function = CallWindowProc(pComboboxEdit, hWnd, uMsg, wParam, lParam)
End Function
Function WndProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer
Static ComboInfo As COMBOBOXINFO
Static hCombo As HWND
Static hButton As HWND
Dim sEdit As String
Dim EditLen As DWORD
Static StaticId As Word = 101
Static ComboBoxId As Word = 201
Static ButtonId As Word = 301
Function = 0
Select Case (uMsg)
Case WM_CREATE
Dim As HFONT hFont = GetStockObject(DEFAULT_GUI_FONT) 'Get a default font handle for the following controls
hStatic = CreateWindowEx(WS_EX_STATICEDGE, WC_STATIC, "", _'Create a static label to show info
WS_CHILD Or WS_VISIBLE Or SS_CENTER Or _
SS_CENTERIMAGE Or SS_NOTIFY,_
50, 15, 260, 20,_
hWnd, Cast(HMENU, Cast(LONG_PTR, StaticId)), hInstance, 0)
SendMessage(hStatic, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set static label font
hCombo = CreateWindowEx(WS_EX_CLIENTEDGE, WC_COMBOBOX, "", _'Create a combobox
WS_CHILD Or WS_VISIBLE Or WS_BORDER Or WS_TABSTOP Or _
CBS_DROPDOWN Or CBS_NOINTEGRALHEIGHT Or CBS_SORT,_
100, 60, 160, 140,_
hWnd, Cast(HMENU, Cast(LONG_PTR, ComboBoxId)), hInstance, 0)
SendMessage(hCombo, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set ComboBox font
Dim As ZString * 64 szItem
SendMessage(hCombo, WM_SETREDRAW, FALSE, 0) 'Stop redraw to save time
szItem = "Grenada" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
szItem = "Trinidad" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
szItem = "St. Vincent" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
szItem = "St. Lucia" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
szItem = "Antigua" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
szItem = "Dominica" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item
SendMessage(hCombo, CB_SETCURSEL, 2, 0) 'Choose third item
SendMessage(hCombo, WM_SETREDRAW, TRUE, 0) 'Permit to redraw
ComboInfo.cbSize = SizeOf(COMBOBOXINFO) 'Preset ComboInfo version
SendMessage(hCombo, CB_GETCOMBOBOXINFO, 0, Cast(lParam, VarPtr(ComboInfo))) 'Get ComboBox info to have the edit handle
'Subclass the edit part of the ComboBox
pComboboxEdit = Cast(WndProc, SetWindowLongPtr(ComboInfo.hwndItem, GWLP_WNDPROC, Cast(LONG_PTR, ProcPtr(ComboboxEditProc))))
hButton = CreateWindowEx(NULL, "Button", "OK", _ 'Create a button
WS_CHILD Or WS_VISIBLE Or WS_TABSTOP Or _
BS_PUSHBUTTON Or BS_CENTER Or BS_VCENTER, _
140, 110, 80, 25, _
hWnd, Cast(HMENU, Cast(LONG_PTR, ButtonId)), hInstance, 0)
SendMessage(hButton, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set Button font
SelStart = 2 'Preset a selection
SelEnd = 5 'Preset a selection
SendMessage(hCombo, CB_SETEDITSEL, 0, MAKELONG(SelStart, SelEnd)) 'Select a portion of the combobox's edit part
SetFocus(hCombo)
Case WM_COMMAND
Dim Code As Word = HiWord(wParam) 'Notification code
Select Case LoWord(wParam) 'Control id
Case ComboBoxId 'The comboBox
Select Case Code
Case CBN_SETFOCUS
Case CBN_KILLFOCUS
Case CBN_CLOSEUP
Case CBN_EDITUPDATE
Case CBN_EDITCHANGE
Case CBN_DROPDOWN
Case CBN_SELCHANGE
Case CBN_SELENDOK
SelStart = 0 'Select from the start
SelEnd = -1 'Select to the end
PostMessage(hWnd, WM_APP, CBN_SELENDOK, 0) 'PostMessage to let ComboBox complete its stuff
End Select
Case ButtonId 'The buttom
If Code = BN_CLICKED Or Code = 1 Then
'Do nothing
End If
End Select
Case WM_APP 'Custom message
SetWindowText(hStatic, "WM_APP: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(ComboInfo.hwndItem) & """")
Case WM_KEYDOWN
If(LoByte(wParam) = 27) Then 'Escape key
PostMessage(hWnd, WM_CLOSE, 0, 0)
End If
Case WM_DESTROY
'UnSubclass the edit part of the ComboBox
If pComboboxEdit Then SetWindowLongPtr(ComboInfo.hwndItem, GWLP_WndProc, Cast(LONG_PTR, pComboboxEdit))
PostQuitMessage(0) 'Die gracefully
Exit Function
End Select
Function = DefWindowProc(hWnd, uMsg, wParam, lParam)
End Function
Dim wMsg As MSG
Dim wcls As WNDCLASS
Dim WindowSize As SIZEL
Dim hWnd As HWND
Dim hIcon As HICON
hIcon = ExtractIcon(GetModuleHandle(""), "Shell32.dll", 112)
WindowSize.cx = 360
WindowSize.cy = 195
Dim appName As String => "ComboBoxEditSel"
wcls.style = CS_HREDRAW Or CS_VREDRAW
wcls.lpfnWndProc = @WndProc
wcls.cbClsExtra = 0
wcls.cbWndExtra = 0
wcls.hInstance = hInstance
wcls.hIcon = hIcon
wcls.hCursor = LoadCursor(NULL, IDC_ARROW)
wcls.hbrBackground = Cast(HGDIOBJ, COLOR_BTNFACE + 1)
wcls.lpszMenuName = NULL
wcls.lpszClassName = StrPtr(appName)
If RegisterClass(@wcls) Then 'RegisterClass success
hWnd = CreateWindowEx(WS_EX_WINDOWEDGE, AppName, AppName, _
WS_OVERLAPPED Or WS_BORDER Or WS_DLGFRAME Or WS_CAPTION Or _
WS_SYSMENU Or WS_MINIMIZEBOX Or WS_CLIPSIBLINGS Or WS_VISIBLE, _
(GetSystemMetrics(SM_CXSCREEN) - WindowSize.cx) / 2, _
(GetSystemMetrics(SM_CYSCREEN) - WindowSize.cy) / 2, _
WindowSize.cx, WindowSize.cy, _
NULL, NULL, hInstance, NULL)
'Build a messages pump
Do Until(GetMessage(@wMsg, NULL, 0, 0) = FALSE)
If IsDialogMessage(hWnd, @wMsg ) = 0 Then
TranslateMessage(@wMsg)
DispatchMessage(@wMsg)
End If
Loop
End If
DestroyIcon(hIcon) 'Clean up
End
Last edited by Pierre Bellisle on Jan 15, 2017 19:03, edited 1 time in total.
-
- Posts: 564
- Joined: Sep 27, 2016 18:20
- Location: Valencia, Spain
Re: An Issue with Combobox Focus...
Hi Pierre,
To make it to work in both 32 and 64 bit, change GWL_WndProc to GWLP_WndProc in this line:
BTW to cast the control id, instead of the define you can also use:
Keep your nice examples coming.
To make it to work in both 32 and 64 bit, change GWL_WndProc to GWLP_WndProc in this line:
Code: Select all
If pComboboxEdit Then SetWindowLongPtr(ComboInfo.hwndItem, GWL_WndProc, Cast(LONG_PTR, pComboboxEdit))
Code: Select all
Cast(HMENU, cast(LONG_PTR, ComboBoxId))
-
- Posts: 355
- Joined: May 29, 2015 20:37
Re: An Issue with Combobox Focus...
Thanks also for your time and the great example!Pierre Bellisle wrote:Hey,
For the fun of it, one may also subclass the edit part of the combobox to get access to usefull messages.
Pierre
Code: Select all
#Include Once "windows.bi" #Include Once "win/commctrl.bi" #Include Once "win/shellapi.bi" Dim Shared pComboboxEdit As WndProc Dim Shared hStatic As HWnd Dim Shared SelStart As wParam Dim Shared SelEnd As lParam Dim Shared hInstance As HINSTANCE : hInstance = GetModuleHandle(NULL) 'Used To Cast a Word control id in a 32 Or 64 Bit variable #Define MakeUInteger(HighWord, LowWord) CUInt(LowWord Shl 16 Or HighWord) Function GetEditSelText(ByVal hWnd As HWND) As String 'Get the selected text of the edit part of the combobox control Dim TextLen As Long Dim sBuffer As String SendMessage(hWnd, EM_GETSEL, Cast(wParam, @SelStart), Cast(lParam, @SelEnd)) 'Get selection TextLen = SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0) + 1 sBuffer = String(TextLen, 0) SendMessage(hWnd, WM_GETTEXT, TextLen, Cast(lParam, StrPtr(sBuffer))) Function = Mid(sBuffer, SelStart + 1, SelEnd - SelStart) End Function Function ComboboxEditProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer 'Subclassed edit part of the combobox control Select Case uMsg Case WM_SETFOCUS SetWindowText(hStatic, "SetFocus: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """") Case WM_KILLFOCUS SetWindowText(hStatic, "KillFocus: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """") Case EM_SETSEL wParam = SelStart 'Memorise SelStart lParam = SelEnd 'Memorise SelEnd Case WM_KEYUP, WM_LBUTTONUP SetWindowText(hStatic, "KeyUp/LButtonUp: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(hWnd) & """") End Select Function = CallWindowProc(pComboboxEdit, hWnd, uMsg, wParam, lParam) End Function Function WndProc(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM) As Integer Static ComboInfo As COMBOBOXINFO Static hCombo As HWND Static hButton As HWND Dim sEdit As String Dim EditLen As DWORD Static StaticId As Word = 101 Static ComboBoxId As Word = 201 Static ButtonId As Word = 301 Function = 0 Select Case (uMsg) Case WM_CREATE Dim As HFONT hFont = GetStockObject(DEFAULT_GUI_FONT) 'Get a default font handle for the following controls hStatic = CreateWindowEx(WS_EX_STATICEDGE, WC_STATIC, "", _'Create a static label to show info WS_CHILD Or WS_VISIBLE Or SS_CENTER Or _ SS_CENTERIMAGE Or SS_NOTIFY,_ 50, 15, 260, 20,_ hWnd, Cast(HMENU, MakeUInteger(StaticId, 0)), hInstance, 0) SendMessage(hStatic, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set static label font hCombo = CreateWindowEx(WS_EX_CLIENTEDGE, WC_COMBOBOX, "", _'Create a combobox WS_CHILD Or WS_VISIBLE Or WS_BORDER Or WS_TABSTOP Or _ CBS_DROPDOWN Or CBS_NOINTEGRALHEIGHT Or CBS_SORT,_ 100, 60, 160, 140,_ hWnd, Cast(HMENU, MakeUInteger(ComboBoxId, 0)), hInstance, 0) SendMessage(hCombo, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set ComboBox font Dim As ZString * 64 szItem SendMessage(hCombo, WM_SETREDRAW, FALSE, 0) 'Stop redraw to save time szItem = "Grenada" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item szItem = "Trinidad" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item szItem = "St. Vincent" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item szItem = "St. Lucia" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item szItem = "Antigua" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item szItem = "Dominica" : SendMessage(hCombo, CB_ADDSTRING, 0, Cast(lParam, VarPtr(szItem))) 'Add combobox item SendMessage(hCombo, CB_SETCURSEL, 2, 0) 'Choose third item SendMessage(hCombo, WM_SETREDRAW, TRUE, 0) 'Permit to redraw ComboInfo.cbSize = SizeOf(COMBOBOXINFO) 'Preset ComboInfo version SendMessage(hCombo, CB_GETCOMBOBOXINFO, 0, Cast(lParam, VarPtr(ComboInfo))) 'Get ComboBox info to have the edit handle 'Subclass the edit part of the ComboBox pComboboxEdit = Cast(WndProc, SetWindowLongPtr(ComboInfo.hwndItem, GWLP_WNDPROC, Cast(LONG_PTR, ProcPtr(ComboboxEditProc)))) hButton = CreateWindowEx(NULL, "Button", "OK", _ 'Create a button WS_CHILD Or WS_VISIBLE Or WS_TABSTOP Or _ BS_PUSHBUTTON Or BS_CENTER Or BS_VCENTER, _ 140, 110, 80, 25, _ hWnd, Cast(HMENU, MakeUInteger(ButtonId, 0)), hInstance, 0) SendMessage(hButton, WM_SETFONT, Cast(wParam, hFont), TRUE) 'Set Button font SelStart = 2 'Preset a selection SelEnd = 5 'Preset a selection SendMessage(hCombo, CB_SETEDITSEL, 0, MAKELONG(SelStart, SelEnd)) 'Select a portion of the combobox's edit part SetFocus(hCombo) Case WM_COMMAND Dim Code As Word = HiWord(wParam) 'Notification code Select Case LoWord(wParam) 'Control id Case ComboBoxId 'The comboBox Select Case Code Case CBN_SETFOCUS Case CBN_KILLFOCUS Case CBN_CLOSEUP Case CBN_EDITUPDATE Case CBN_EDITCHANGE Case CBN_DROPDOWN Case CBN_SELCHANGE Case CBN_SELENDOK SelStart = 0 'Select from the start SelEnd = -1 'Select to the end PostMessage(hWnd, WM_APP, CBN_SELENDOK, 0) 'PostMessage to let ComboBox complete its stuff End Select Case ButtonId 'The buttom If Code = BN_CLICKED Or Code = 1 Then 'Do nothing End If End Select Case WM_APP 'Custom message SetWindowText(hStatic, "WM_APP: Selection is " & SelStart & " to " & SelEnd & " """ & GetEditSelText(ComboInfo.hwndItem) & """") Case WM_KEYDOWN If(LoByte(wParam) = 27) Then 'Escape key PostMessage(hWnd, WM_CLOSE, 0, 0) End If Case WM_DESTROY 'UnSubclass the edit part of the ComboBox If pComboboxEdit Then SetWindowLongPtr(ComboInfo.hwndItem, GWL_WndProc, Cast(LONG_PTR, pComboboxEdit)) PostQuitMessage(0) 'Die gracefully Exit Function End Select Function = DefWindowProc(hWnd, uMsg, wParam, lParam) End Function Dim wMsg As MSG Dim wcls As WNDCLASS Dim WindowSize As SIZEL Dim hWnd As HWND Dim hIcon As HICON hIcon = ExtractIcon(GetModuleHandle(""), "Shell32.dll", 112) WindowSize.cx = 360 WindowSize.cy = 195 Dim appName As String => "ComboBoxEditSel" wcls.style = CS_HREDRAW Or CS_VREDRAW wcls.lpfnWndProc = @WndProc wcls.cbClsExtra = 0 wcls.cbWndExtra = 0 wcls.hInstance = hInstance wcls.hIcon = hIcon wcls.hCursor = LoadCursor(NULL, IDC_ARROW) wcls.hbrBackground = Cast(HGDIOBJ, COLOR_BTNFACE + 1) wcls.lpszMenuName = NULL wcls.lpszClassName = StrPtr(appName) If RegisterClass(@wcls) Then 'RegisterClass success hWnd = CreateWindowEx(WS_EX_WINDOWEDGE, AppName, AppName, _ WS_OVERLAPPED Or WS_BORDER Or WS_DLGFRAME Or WS_CAPTION Or _ WS_SYSMENU Or WS_MINIMIZEBOX Or WS_CLIPSIBLINGS Or WS_VISIBLE, _ (GetSystemMetrics(SM_CXSCREEN) - WindowSize.cx) / 2, _ (GetSystemMetrics(SM_CYSCREEN) - WindowSize.cy) / 2, _ WindowSize.cx, WindowSize.cy, _ NULL, NULL, hInstance, NULL) 'Build a messages pump Do Until(GetMessage(@wMsg, NULL, 0, 0) = FALSE) If IsDialogMessage(hWnd, @wMsg ) = 0 Then TranslateMessage(@wMsg) DispatchMessage(@wMsg) End If Loop End If DestroyIcon(hIcon) 'Clean up End
-
- Posts: 56
- Joined: Dec 11, 2016 17:22
Re: An Issue with Combobox Focus...
Hi datwil310,
It was a pleasure, have a great day. :-)
It was a pleasure, have a great day. :-)
-
- Posts: 56
- Joined: Dec 11, 2016 17:22
Re: An Issue with Combobox Focus...
Hey Josep,
Always good to ear from you,
Yes, you are right, GWLP_WndProc should have been used.
And Cast(HMENU, Cast(LONG_PTR, SomeWordContolId)) is a cleaner approach.
I did update the code above.
Thank. :-)
Always good to ear from you,
Yes, you are right, GWLP_WndProc should have been used.
And Cast(HMENU, Cast(LONG_PTR, SomeWordContolId)) is a cleaner approach.
I did update the code above.
Thank. :-)