Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2015-01

Filling ListBox without triggering OnSelectionChange

13 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Marc Santhoff

Hi,

it has been a very long time since I've programmed GUIs. I have forgotten how to fill a ListBox without having the event handler OnSelectionChange executed.

I have tried (Un)LockSelectionChange on the list, setting ItemIndex to -1, all in the forms create method. I've tried using add() or assign() on the listbox's Items, nothing helps.

The wiki on TListBox doesn't say anything on this topic, neither does the LCL help document.

How can it be done?

Marc Santhoff

Reply by email

Howard Page-Clark
to Marc Santhoff
Marc Santhoff wrote 6 lines
Hi, it has been a very long time since I've programmed GUIs. I have forgotten how to fill a ListBox without having the event handler OnSelectionChange executed. How can it be done?
ListBox1.Items.Assign(someStringlist);

does not trigger the OnSelectionChange event.

Howard

---
This email has been checked for viruses by Avast antivirus software. http://www.avast.com

Reply by email

A. Fortuny
to Marc Santhoff: it has been a very long time since I've programmed GUIs. I have forgotten how to fill a…

Le 7/01/2015 07:49, Marc Santhoff a ?crit :

Show quoted text 5 lines
Hi, it has been a very long time since I've programmed GUIs. I have forgotten how to fill a ListBox without having the event handler OnSelectionChange executed.

I've had the same problem for years, until I "invented" my method:
- fill in the two events OnEnter and OnExit for the control
- generate the code for the OnSelectionChange event and drop immediately the event in the component explorer
- manually fill in the following code in the three envents:

TMyForm.MyComponentEnter(Sender: TObject);
begin
   MyComponent.OnSelectionChange := MyComponentSelectionChange;
// do the same for all other events you want to drive
end
TMyForm.MyComponentSlectionChange(Sender: TObject; ...);
begin
   // do whatver to do when the event fires
end
TMyForm.MyComponentExit(Sender: TObject);
begin
   MyComponent.OnSelectionChange := nil
end

Of course you can control any firing event using the OnEnter and OnExit events of the control. This allows the program to fire events only when the user enters the control.
I think that GUI's lack a control property wich indicates whether the events should always fire or fire only when the user enters the control.

Antonio.

Show quoted text 10 lines
I have tried (Un)LockSelectionChange on the list, setting ItemIndex to -1, all in the forms create method. I've tried using add() or assign() on the listbox's Items, nothing helps. The wiki on TListBox doesn't say anything on this topic, neither does the LCL help document. How can it be done?

---
L'absence de virus dans ce courrier ?lectronique a ?t? v?rifi?e par le logiciel antivirus Avast. http://www.avast.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20150107/64e3ff87/attachment-0001.html>

Reply by email

Marc Santhoff
to A. Fortuny
A. Fortuny wrote 34 lines
Le 7/01/2015 07:49, Marc Santhoff a ?crit : > Hi, > > it has been a very long time since I've programmed GUIs. I have > forgotten how to fill a ListBox without having the event handler > OnSelectionChange executed. I've had the same problem for years, until I "invented" my method: - fill in the two events OnEnter and OnExit for the control - generate the code for the OnSelectionChange event and drop immediately the event in the component explorer - manually fill in the following code in the three envents: TMyForm.MyComponentEnter(Sender: TObject); begin MyComponent.OnSelectionChange := MyComponentSelectionChange; // do the same for all other events you want to drive end TMyForm.MyComponentSlectionChange(Sender: TObject; ...); begin // do whatver to do when the event fires end TMyForm.MyComponentExit(Sender: TObject); begin MyComponent.OnSelectionChange := nil end Of course you can control any firing event using the OnEnter and OnExit events of the control. This allows the program to fire events only when the user enters the control. I think that GUI's lack a control property wich indicates whether the events should always fire or fire only when the user enters the control.

Yes, assigning the event handler does work, if it is done in OnActivate. When done in OnCreate of the form there must be some actions afterwards setting the selection, And it is possible to set the ItemIndex to -1 for deselecting the first item having the selection on start. Beautiful.

procedure TForm1.FormCreate(Sender: TObject);
var
  i: longword;
begin
  tasklist := TStringList.create;
  for i:=0 to taskmax do tasklist.add(tasks[i]);
  ListBox1.Items.Assign(tasklist);
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
  ListBox1.ItemIndex := -1;
  ListBox1.OnSelectionChange := @ListBox1SelectionChange;
end;

Thank you!

Marc Santhoff

Reply by email

Marc Santhoff
to Howard Page-Clark: ListBox1.Items.Assign(someStringlist); does not trigger the OnSelectionChange event.…
Howard Page-Clark wrote 11 lines
On 07/01/2015 06:49, Marc Santhoff wrote: > Hi, > > it has been a very long time since I've programmed GUIs. I have > forgotten how to fill a ListBox without having the event handler > OnSelectionChange executed. > How can it be done? ListBox1.Items.Assign(someStringlist); does not trigger the OnSelectionChange event.

Well, for me it does. Using Lazarus 1.2.0 and fpc 2.6.2, that is. Maybe there has been a change in a later version of LCL?

No, from what I've seen right now the form creation sequence does it at a later time.

Thanks for pointing out.

Marc Santhoff

Reply by email

Michael Thompson
to Marc Santhoff: Yes, assigning the event handler does work, if it is done in OnActivate. When done in…
AM Marc Santhoff wrote
Yes, assigning the event handler does work, if it is done in OnActivate.

I'm sure you're aware of this, but just in case: Form.OnActivate should fire each time your user switches between forms in your UI. I usually put similar code inside a boolean flag to ensure the code only runs once at initialisation. Even if it's not immediately required, having it there will help if you later call an open/save dialog or similar from that form...

procedure TForm1.FormActivate(Sender: TObject);
begin
  if not ListBox1Initialised then
  begin
    ListBox1.ItemIndex := -1;
    ListBox1.OnSelectionChange := @ListBox1SelectionChange;
    ListBox1Initialised := True;  // and set this to false in FormCreate
  end;
end;

Mike
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20150108/75aff608/attachment-0001.html>

Reply by email

Bart
to Marc Santhoff: it has been a very long time since I've programmed GUIs. I have forgotten how to fill a…
Marc Santhoff wrote 5 lines
Hi, it has been a very long time since I've programmed GUIs. I have forgotten how to fill a ListBox without having the event handler OnSelectionChange executed.

When I fill a listbox with items, there is no OnSelectionChange 1.3, win32.

Please show us the code you used to fill the listbox. Also please provide Lazars version and widgetset.

Bart

Reply by email

Marc Santhoff
to Bart
Bart wrote 9 lines
On 1/7/15, Marc Santhoff wrote: > Hi, > > it has been a very long time since I've programmed GUIs. I have > forgotten how to fill a ListBox without having the event handler > OnSelectionChange executed. When I fill a listbox with items, there is no OnSelectionChange executed at all. Lazarus 1.3, win32.

Yes, but if it is done in Form.OnCreate is is (here).

Please show us the code you used to fill the listbox. Also please provide Lazars version and widgetset.

Here we go:
fpc 2.6.2
Lazarus 1.2.0, x86_64-gtk2
FreeBSD 9 amd64

I have simply made a new gui project, put some components on the form and assigned the jhandlers by double clicking the object inspectors event field.

Then I wrote this code:

<snip>

const
  taskmax = 2;
  tasks: array [0..taskmax] of string = (
    'Tudies',
    'Tudas',
    'Sonstwas'
    );
implementation
procedure TForm1.FormCreate(Sender: TObject);
var
  i: longword;
begin
  tasklist := TStringList.create;
  for i:=0 to taskmax do tasklist.add(tasks[i]);
  ListBox1.Items.Assign(tasklist);
end;
procedure TForm1.ListBox1SelectionChange(Sender: TObject; User:
boolean);
begin
  if (Sender  NIL) then begin
    InvokeAction(tasks[(Sender as TListBox).ItemIndex]);
  end;
end;

</snip>

InvokeAction() is a method of the same form and does get triggered when I start the program, having the form in question as its main form. The first Item in the list is selected.

Marc Santhoff

Reply by email

Bart
to Marc Santhoff
Marc Santhoff wrote
Yes, but if it is done in Form.OnCreate is is (here).

No, it does not (with fpc 2.6.4/win32)

Here we go: fpc 2.6.2 Lazarus 1.2.0, x86_64-gtk2 FreeBSD 9 amd64

So, might be WS related.

Show quoted text 17 lines
tasks: array [0..taskmax] of string = ( 'Tudies', 'Tudas', 'Sonstwas' ); implementation procedure TForm1.FormCreate(Sender: TObject); var i: longword; begin tasklist := TStringList.create; for i:=0 to taskmax do tasklist.add(tasks[i]); ListBox1.Items.Assign(tasklist); end;

Tried that, no OnSelectionChange.

Workaround would be like:

procedure TForm1.FormCreate(Sender: TObject);
var
  i: longword;
begin
  tasklist := TStringList.create;
  for i:=0 to taskmax do tasklist.add(tasks[i]);
  ListBox1.OnSelectionChange := nil;
  ListBox1.Items.Assign(tasklist);
  ListBox1.OnSelectionChange := @ListBox1SelectionChange;
end;

If the InvokeAction only is supposed to be as a respons to the user clicking, you could also check the User parameter.

Bart

Reply by email

Marc Santhoff
to Bart
Bart wrote 5 lines
On 1/9/15, Marc Santhoff wrote: > Yes, but if it is done in Form.OnCreate is is (here). No, it does not (with fpc 2.6.4/win32)

I'll see next time my Lazarus is updated. If the current version works with fpc 2.6.2 that could happen immeadiately.

Show quoted text 12 lines
Workaround would be like: procedure TForm1.FormCreate(Sender: TObject); var i: longword; begin tasklist := TStringList.create; for i:=0 to taskmax do tasklist.add(tasks[i]); ListBox1.OnSelectionChange := nil; ListBox1.Items.Assign(tasklist); ListBox1.OnSelectionChange := @ListBox1SelectionChange; end;

Tried that solution already, but it does not help. There must be something special later in the form creation chain, that forces selection on the listbox and in turn trigger SelectionChange.

If the assignment of OnSelectionChange hanlder is done a bit later, in FormShow that is, it works as expected.

Maybe something else regarding the creation of forms has changed inside LCL between Lazarus 1.2 and 1.3.

If the InvokeAction only is supposed to be as a respons to the user clicking, you could also check the User parameter.

Will do.

Marc Santhoff

Reply by email

Bart
to Marc Santhoff
Marc Santhoff wrote
Tried that solution already, but it does not help. There must be something special later in the form creation chain, that forces selection on the listbox and in turn trigger SelectionChange.

Filling at designtime and setting ItemIndex to -1 also shows this behaviour:
- Itemindex will be 0 at program start
- OnSelectionChange is fired (with User = True).

Only happens on GTK2
QT behaves as expected.

Filed a bugreport about it: http://bugs.freepascal.org/view.php?id=27276

Bart

Reply by email

Marc Santhoff
to Bart
Bart wrote 12 lines
On 1/9/15, Marc Santhoff wrote: > Tried that solution already, but it does not help. There must be > something special later in the form creation chain, that forces > selection on the listbox and in turn trigger SelectionChange. Filling at designtime and setting ItemIndex to -1 also shows this behaviour: - Itemindex will be 0 at program start - OnSelectionChange is fired (with User = True). Only happens on GTK2 QT behaves as expected.

I see.

Thank you!

Marc Santhoff

Reply by email