I want to make a component based on TListBox.
When the Items.Count changes, I want to update the Caption of a TLabel:
Label1.Caption := IntToStr(ListBox1.Items.Count);
I made the component below, but it does not work:
unit UChangeListBox;
interface
uses
Classes, StdCtrls, Messages;
type
TChListBox = class(StdCtrls.TListBox)
private
FItemIndex: Integer;
FOnChange: TNotifyEvent;
procedure CNCommand(var AMessage: TWMCommand); message CN_COMMAND;
protected
procedure DoChange; virtual;
procedure SetItemIndex(const Value: Integer); override;
published
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
procedure Register;
implementation
procedure TChListBox.DoChange;
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TChListBox.CNCommand(var AMessage: TWMCommand);
begin
inherited;
if (AMessage.NotifyCode = LBN_SELCHANGE) and (FItemIndex <> ItemIndex) then
begin
FItemIndex := ItemIndex;
DoChange;
end;
end;
procedure TChListBox.SetItemIndex(const Value: Integer);
begin
inherited;
if FItemIndex <> ItemIndex then
begin
FItemIndex := Value;
DoChange;
end;
end;
procedure Register;
begin
RegisterComponents('MyComponents',[TChListBox]);
end;
end.
TListBoxinherits a protectedChanged()method fromTControl, which sends aCM_CHANGEDmessage to derived classes.TListBoxcallsChanged()in reply toLBN_SELCHANGE. You don't need to define your ownChange()method, just handleCM_CHANGEDinstead.TListBox.SetItemIndex()sends aLB_SETCURSELmessage to the ListBoxHWND. That message does not triggerLBN_SELCHANGE, so you would have to detect theItemIndexchange yourself. Which you attempted to do.However, these issues only apply to selection changes, not to
Item.Countchanges. Changing theItemIndexdoes not change theItems.Count. If your goal is simply to display a newItems.Countwhenever an item is added or removed from the ListBox, you need to handle theLB_ADDSTRING,LB_INSERTSTRING,LB_DELETESTRINGandLB_RESETCONTENTmessages instead.Try something more like this: