in the OnExit event of a TEdit I make some validation and set the focus back to the Edit, if the edit doesn't have a valid content. This works fine when I try to switch to an other edit field. When I try to enter a TListView component the OnExit event gets called again after calling SetFocus().
void __fastcall TForm1::Edit1Exit(TObject *Sender)
{
//if entry not valid
dynamic_cast<TEdit*>(Sender)->SetFocus();
}
Has anybody an idea why the event is called twice when a TListView is entered?
Related
I have a ListBox on my form with an OnClick event registered to it. This event works as intended, except for one particular situation:
My form contains a SpinEdit (values 8-12), to let the user adjust the ListBox.Font.Size property (I also adjust the ListBox.ItemHeight property is accordingly). These adjustments are done in the SpinEdits OnExit event and also work as intended.
The problem however occurs when the SpinEdit is selected, the value is changed and then the ListBox is clicked. So what should happen is:
SpinEdit OnExit fired: ListBox.Font.Size adjusted.
ListBox OnClick fired: subsequent actions defined in the OnClick event.
But in reality, only the SpinEdits OnExit is fired and the fontsize is adjusted correctly, but the OnClick event of ListBox does not fire. Not that big a deal in itself, but after that point the entire ListBox has become unresponsive to mouseclicks!
Noteworthy observations:
Switching back and forth to another application/window and back to
my application: responsiveness of the ListBox is regained.
After triggering the problem, interacting with a CheckListBox that is on the same form, followed by clicking on the ListBox fires the ListBox Onclick event.
Triggering the SpinEdits OnExit event with the Enter key introduces no problems.
The form contains a few more SpinEdit objects with OnExit events, that do not change properties of the ListBox. Exiting these SpinEdits by clicking the ListBox works just fine, with the OnClick event executed right after the SpinEdits OnExit event.
When programmatically changing the value of ItemIndex of a TComboBox component in Delphi, one would expect for the corresponding OnChange event to get triggered.
Afterall, the visible value of the ComboBox get's changed as a result. Strangely it does not. Same behavior in Delphi6, Delphi 2010 and Delphi XE7.
Is there any reason behind this behavior or it's just a pending bug?
From documentation:
Occurs when the user changes the text displayed in the edit region.
Write an OnChange event handler to take specific action immediately after the user edits the text in the edit region or selects an item from the list. The Text property gives the new value in the edit region.
Note: OnChange only occurs in response to user actions. Changing the Text property programmatically does not trigger an OnChange event.
Since there is no editing done, this means that programmatically changing the ItemIndex does not trigger the OnChange event.
As others have answered, it is as designed. You can, however, achieve the functionality you are missing by overriding the SetItemIndex() procedure as follows:
type
TComboBox = class(Vcl.StdCtrls.TComboBox)
procedure SetItemIndex(const Value: Integer); override;
end;
TForm3 = class(TForm)
...
implementation
procedure TComboBox.SetItemIndex(const Value: Integer);
begin
inherited;
if Assigned(OnSelect) then
OnSelect(self);
end;
As you see I activate the OnSelect event instead of OnChange, because OnSelect is the one fired when you select an item from the dropdown list. You can, if you like, just as well use the OnChange event instead.
That is designed behavior. OnChange event is triggered only by user actions and not programatically.
OnChange Event
Occurs when the user changes the text displayed in the edit region.
Write an OnChange event handler to take specific action immediately
after the user edits the text in the edit region or selects an item
from the list. The Text property gives the new value in the edit
region.
Note: OnChange only occurs in response to user actions.
Changing the Text property programmatically does not trigger an
OnChange event.
I'm using XE7 and FMX.
My problem is that the OnChange-Event for TListbox works not correctly with multiselect (it does not fire everytime when a change occured).
Steps to reproduce:
Create a FMX-application and add a TListbox to his form.
Add items to this listbox.
Set 'MultiSelectStyle' of Listbox to 'default'.
Handle the OnChangeEvent (set a breakpoint or do something ...).
Now run the project and click on the first Item -> OnChange is executed.
But if first item is clicked again the OnChange will not be executed.
Can tell me somebody how I can fix this, so that everytime when a the selection changes I get a event.
From documentation FMX.ListBox.TCustomListBox.OnChange:
Occurs when the selection in the list box changes.
Write an OnChange event handler to take specific action immediately after a new item or items are selected in the list box.
Use the OnClick or OnItemClick event instead to monitor when the user reselects the same selection. And keep the OnChange handler for all new selections.
I'm having an issue with the combo box. I have an event handler for OnClick which refreshes data based on what item was selected. The problem is when this scenario occurs:
Drop-down the combo box to list the various options
Type on the keyboard to find a matching item
Combo box changes this selection and calls the OnClick event
My screen refreshes due to this selection / event
Click somewhere outside of the combo box to take the focus away from it
Combo box goes back to the previous selection, even though OnClick was already called
Even though Combo box changed back to prior selection, OnClick isn't called again
After this, Combo Box shows different value than what my data actually represents
So when you open a combo box, and type a few letters on the keyboard to find the item in the drop-down list, OnClick is fired which refreshes my screen. But when you click somewhere outside the combo box (thus taking the focus away from it), the combo box changes back to whatever value was previously selected, instead of what I had typed. And at the same time, the OnClick event isn't fired, so the combo box shows the incorrect value compared to what I had loaded on the screen.
How do I make the combo box stay on the selected item in this scenario of typing the item on the keyboard?
In my code, I deal with this using the OnCloseUp event. Well, in fact I'm using a sub-classed combo for my drop-down lists and they override both the Change and CloseUp methods:
procedure TMyDropDownList.Change;
begin
RespondToChange;
inherited;
end;
procedure TMyDropDownList.CloseUp;
begin
RespondToChange;
inherited;
end;
The RespondToChange method reacts to the new ItemIndex value. If it is expensive to react to every single change whilst the combo is dropped down, then you might consider omitting the call to RespondToChange from the Change method.
You could use OnExit to make the entry with the keyboard jive with the Index on the ComboBox; where VarS is assigned OnChange and is the answer you would like to keep:
procedure TForm1.ComboBox1Exit(Sender: TObject);
begin
{ Windows keyboard select bug, force use of selected }
ComboBox1.ItemIndex := ComboBox1.Items.IndexOf(VarS);
end;
I would call this a bug in the ComboBox design.
I have a TComboBox on a form. Its Style property is set to csDropDownList. If I open the dropdown and select an option with my mouse or keyboard and hit ENTER, the dropdown box closes and the ItemIndex property is changed before the KeyPress event handler is fired. If I hit TAB, the dropdown doesn't disappear until after the KeyPress event handler has fired and focus has moved off the control, and the ItemIndex doesn't get updated; it reverts back to whatever had been selected before I opened the list.
If I want TAB to update ItemIndex to whatever's currently selected in the dropdown list, how would I implement it?
Set the Form's KeyPreview property to True.
In the ComboBox OnKeyDown event:
procedure TForm1.ComboBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key = VK_TAB) then
begin
Key := VK_RETURN;
Perform(WM_NEXTDLGCTL,0,0);
end;
end;
This emulates the return key and then moves focus to the next control.
I believe this is the default behavior, and to change it you might need to subclass the control (or even a class helper), intercept the windows message for the keystroke, then if its a tab send a return to the control and handle the tab yourself.
You should try to trap TAB earlier in the KeyUp event or maybe even earlier in the KeyDown.
When you retrieve your index use this instead of the classical ComboBox->ItemIndex
ComboBox->Items->IndexOf(ComboBox->Text)