Событие списка обмена, компонент

Я хочу сделать компонент на основе TListBox,

Когда Items.Count изменения, я хочу обновить Caption из TLabel:

Label1.Caption := IntToStr(ListBox1.Items.Count);

Я сделал компонент ниже, но он не работает:

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.

1 ответ

Решение

TListBox наследует защищенный Changed() метод из TControl, который отправляет CM_CHANGED сообщение для производных классов. TListBox звонки Changed() в ответ на LBN_SELCHANGE, Вам не нужно определять свой собственный Change() метод, просто справиться CM_CHANGED вместо.

TListBox.SetItemIndex() отправляет LB_SETCURSEL сообщение в ListBox HWND, Это сообщение не срабатывает LBN_SELCHANGEтак что вам придется обнаружить ItemIndex изменить себя. Что вы пытались сделать.

Однако эти проблемы относятся только к изменениям выбора, а не к Item.Countизменения. Изменение ItemIndex не меняет Items.Count, Если ваша цель просто показать новый Items.Count всякий раз, когда элемент добавляется или удаляется из ListBox, вам нужно обрабатывать LB_ADDSTRING, LB_INSERTSTRING, LB_DELETESTRING а также LB_RESETCONTENT сообщения вместо.

Попробуйте что-то вроде этого:

type
  TChListBox = class(TListBox)
  private
    FOnItemCountChange: TNotifyEvent;
  protected
    procedure WndProc(var Message: TMessage); override;
  published
    property OnItemCountChange: TNotifyEvent read FOnItemCountChange write FOnItemCountChange;
  end;

procedure TChListBox.WndProc(var Message: TMessage);
var
  OldCount: Integer;
begin
  case Message.Msg of
    LB_ADDSTRING, LB_INSERTSTRING, LB_DELETESTRING:
    begin
      // for LB_(ADD|INSERT)STRING, Message.Result is the 0-based
      // index of the added string, or a LB_ERR... error code.
      //
      // for LB_DELETESTRING, Message.Result is the number of items
      // remaining in the list, or a LB_ERR... error code.
      //
      inherited;
      if (Message.Result >= 0) and Assigned(FOnItemCountChange) then
        FOnItemCountChange(Self);
    end;
    LB_RESETCONTENT:
    begin
      // the Message.Result is not used in this message.
      //
      OldCount := Items.Count;
      inherited;
      if (OldCount <> Items.Count) and Assigned(FOnItemCountChange) then
        FOnItemCountChange(Self);
    end;
  else
    inherited;
  end;
end;
Другие вопросы по тегам