Delayed Close Programmatically Dropped TComboBox (If Mouse NOT Over Combo and Combo’s List) Using Multi Threading
Žarko Gajić
The Combo Box Windows control (aka TComboBox in Delphi) is one of the most frequently used user interface elements along with buttons and edits in Windows applications. TComboBox control represents an edit box with a scrollable drop-down list attached to it. Users can select an item from the list or type directly into the edit box. When the Style property is set to csDropDownList the combo allows to display a list of predefined items a user can select from the combo’s drop down list.
I’ve had a request from a user of my application: can the selection list be dropped down and then closed if no selection has been made in some period of time? Well, the user is asking. So, certainly it can!
The task to drop combo’s list is super easy: just set DroppedDown property to true (this sends CB_SHOWDROPDOWN to the combo). Then wait – but do not block the main thread !! – so some multithreading needed. Ok, use Для просмотра ссылки Войдиили Зарегистрируйся. Finally, once the wait period is over, close the combo’s list – but, let’s say, only if the user is not hovering the mouse over combo’s items!
Looks pretty straightforward.
The only part to figure out is how to know if the mouse is over the list. Luckily, there’s a super handy Windows API call: GetComboBoxInfo. This function fills in the tagCOMBOBOXINFO structure (TComboBoxInfo record in Delphi’s implementation) with handles to the combo’s list box, edit box and the combo box itself. Therefore: get the mouse coordinates, and if over combo’s list (or combo itself) – simply leave it open.
And how to use (example):
That’s it. Nice and quick and neat …
Žarko Gajić
The Combo Box Windows control (aka TComboBox in Delphi) is one of the most frequently used user interface elements along with buttons and edits in Windows applications. TComboBox control represents an edit box with a scrollable drop-down list attached to it. Users can select an item from the list or type directly into the edit box. When the Style property is set to csDropDownList the combo allows to display a list of predefined items a user can select from the combo’s drop down list.
I’ve had a request from a user of my application: can the selection list be dropped down and then closed if no selection has been made in some period of time? Well, the user is asking. So, certainly it can!
The task to drop combo’s list is super easy: just set DroppedDown property to true (this sends CB_SHOWDROPDOWN to the combo). Then wait – but do not block the main thread !! – so some multithreading needed. Ok, use Для просмотра ссылки Войди
Looks pretty straightforward.
The only part to figure out is how to know if the mouse is over the list. Luckily, there’s a super handy Windows API call: GetComboBoxInfo. This function fills in the tagCOMBOBOXINFO structure (TComboBoxInfo record in Delphi’s implementation) with handles to the combo’s list box, edit box and the combo box itself. Therefore: get the mouse coordinates, and if over combo’s list (or combo itself) – simply leave it open.
Threaded Approach to Dropping Down and Closing Combo’s List
And here’s the resulting procedure: ComboDropAndCloseDelayed. Feed it with a TComboBox instance and set the needed delay time. Combo’s list will show, time will pass, and if the user is not over the combo’s list with the mouse (so still deciding of the selection) – close the list.
Код:
procedure ComboDropAndCloseDelayed(const theCombo : TComboBox; const closeDelayMS : Cardinal = 2500);
begin
TTask.Run(
procedure
var
cbi : TComboBoxInfo;
begin
cbi.cbSize := SizeOf(TComboBoxInfo);
if NOT GetComboBoxInfo(theCombo.Handle, cbi) then Exit;
TThread.Queue(nil,
procedure
begin
theCombo.DroppedDown := true;
end);
Sleep(closeDelayMS);
TThread.Queue(nil,
procedure
var
undrop : boolean;
hw : THandle;
begin
undrop := true;
if theCombo.HandleAllocated AND theCombo.DroppedDown then
begin
hw := WindowFromPoint(Mouse.CursorPos);
undrop := (hw <> 0) AND (hw <> cbi.hwndCombo) AND (hw <> cbi.hwndList) AND (hw <> cbi.hwndItem);
if undrop then
theCombo.DroppedDown := false;
end;
end);
end);
end;
Код:
procedure TMainForm.Button1Click(Sender: TObject);
begin
//if no selection already: drop the list
if ComboBox1.ItemIndex = -1 then
ComboDropAndCloseDelayed(ComboBox1);
end;