evilone
evilone

Reputation: 22750

Checkboxes are not scrolling in TListView component

I've created ListView and added checkboxes to check each row if needed. All was fine until there was a lot of items in the listview so that it needed scolling. I checked on line and then I saw that checkboxes are not scrolling with other content if I scroll the scrollbar.

My code:

unit ShareCommissionDialog;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, sButton, ComCtrls, sListView, sCheckBox, DataManager;

type
  TdlgShareCommission = class(TForm)
    lvEmployees: TsListView;
    btnCancel: TsButton;
    btnDone: TsButton;
    procedure FormCreate(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnDoneClick(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);

  private
    manager: TDataManager;
    ListViewCheckBoxList: TList;
    employeeIDs: TStringList;

    procedure ListViewCheckBoxCreate(List: TsListView; employeeID: string; R: TRect);
    procedure ListViewCheckBoxClick(Sender: TObject);
    procedure ListViewCheckBoxSelected(item: Integer; List: TsListView);
    procedure ListViewCheckBoxUnselected(item: Integer; List: TsListView);

    procedure PopulateEmployees;
    procedure ShowSelectedEmployees;
    procedure MarkRows;

  public
    property DataManager: TDataManager read manager write manager;
    property CommissionReceivers: TStringList read employeeIDs write employeeIDs;

  end;

var
  dlgShareCommission: TdlgShareCommission;

implementation

{$R *.dfm}

procedure TdlgShareCommission.btnCancelClick(Sender: TObject);
begin
  employeeIDs := employeeIDs;
end;

procedure TdlgShareCommission.btnDoneClick(Sender: TObject);
var
  i, j: Integer;

begin
  employeeIDs := TStringList.Create;

  for i := 0 to ListViewCheckBoxList.Count - 1 do
  begin
    if TsCheckBox(ListViewCheckBoxList[i]).Checked then
    begin
      for j := 0 to manager.Data.Employees.Count - 1 do
      begin
        if TsCheckBox(ListViewCheckBoxList[i]).Tag = StrToInt(manager.Data.Employees[j].ID) then
        begin
          employeeIDs.Add(manager.Data.Employees[j].ID);
          Break;
        end;
      end;
    end;
  end;
end;

procedure TdlgShareCommission.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  manager.GetEmployees(manager.Data.SelectedPOS.ID);
end;

procedure TdlgShareCommission.FormCreate(Sender: TObject);
begin
  ListViewCheckBoxList := TList.Create;
end;

procedure TdlgShareCommission.ListViewCheckBoxCreate(List: TsListView; employeeID: string; R: TRect);
function NewViewCheckBox: TsCheckBox;
  begin
    Result := TsCheckBox.Create(Self);
    Result.Tag := StrToInt(employeeID);
    Result.Parent := List;
    Result.BoundsRect := R;
    Result.Checked := False;

    Result.OnClick := ListViewCheckBoxClick;
  end;
begin
  ListViewCheckBoxList.Add(NewViewCheckBox);
end;

procedure TdlgShareCommission.FormShow(Sender: TObject);
begin
  if employeeIDs <> nil then
  begin
    PopulateEmployees;
    ShowSelectedEmployees;
    MarkRows;
  end
  else
  begin
    PopulateEmployees;
    MarkRows;
  end;

  //PopulateEmployees;
  //MarkRows;
end;

procedure TdlgShareCommission.ListViewCheckBoxClick(Sender: TObject);
var
  i: Integer;

begin
  for i := 0 to ListViewCheckBoxList.Count - 1 do
  begin
    if (i+1) <= (ListViewCheckBoxList.Count - 1) then
      if not TsCheckBox(ListViewCheckBoxList[i+1]).Enabled then
      begin
        TsCheckBox(ListViewCheckBoxList[i+1]).Checked := TsCheckBox(ListViewCheckBoxList[i]).Checked;
      end;
  end;

  MarkRows;
end;

procedure TdlgShareCommission.MarkRows;
var
  j: Integer;

begin
  for j := 0 to lvEmployees.Items.Count - 1 do
  begin
    if not TsCheckBox(ListViewCheckBoxList[j]).Checked then
    begin
      ListViewCheckBoxSelected(j, lvEmployees);
    end
    else
    begin
      ListViewCheckBoxUnselected(j, lvEmployees);
    end;
  end;
end;

procedure TdlgShareCommission.ListViewCheckBoxSelected(item: Integer; List: TsListView);
begin
  with List do
  begin
    Items[item].Selected := False;
  end;
end;

procedure TdlgShareCommission.ListViewCheckBoxUnselected(item: Integer; List: TsListView);
begin
  with List do
  begin
    Items[item].Selected := False;
  end;
end;

procedure TdlgShareCommission.PopulateEmployees;
var
  i: Integer;
  R: TRect;
  employeeRow: TListItem;

begin
  with lvEmployees do
  try
    Items.BeginUpdate;
    Items.Clear;

    manager.GetEmployees(manager.Data.SelectedPOS.ID);

    for i := 0 to manager.Data.Employees.Count - 1 do
    begin
      employeeRow := Items.Add;

      R := Items[i].DisplayRect(drBounds);
      R.Left := 5;
      R.Top := R.Top + 1;
      ListViewCheckBoxCreate(lvEmployees, manager.Data.Employees[i].ID, R);
      Items[i].Data := TsCheckBox(ListViewCheckBoxList[i]);

      employeeRow.SubItems.Add(manager.Data.Employees[i].FirstName + ' ' + manager.Data.Employees[i].LastName);
    end;
  finally
    lvEmployees.Items.EndUpdate;
  end;
end;

procedure TdlgShareCommission.ShowSelectedEmployees;
var
  i, j: Integer;

begin
  for j := 0 to lvEmployees.Items.Count - 1 do
  begin
    for i := 0 to employeeIDs.Count - 1 do
    begin
      if TsCheckBox(ListViewCheckBoxList[j]).Tag = StrToInt(employeeIDs[i]) then
      begin
        TsCheckBox(ListViewCheckBoxList[j]).Checked := True;
      end;
    end;
  end;
end;
end.

What I need to add to code that checkboxes also will scroll with other content?

Upvotes: 3

Views: 826

Answers (1)

Johan
Johan

Reputation: 76753

The standard ListView has a property called checkboxes that can be set to true.
If you use that then you don't have to mess with making your own checkboxes.
I've never had any problems with checkboxes not showing properly in this control.

This property works best in ViewStyle:= vsList or ViewStyle:= vsReport

Alternatively if you want checkboxes on some items but not on others then make a picture of a checkbox (1 unchecked, 1 checked) and add both of them to an ImageList.
If an item needs a checkbox, set its ImageIndex property to that of the unchecked item. If it needs to be checked, set its ImageIndex property to the checked Image.
This works in ViewStyle:= vsReport and ViewStyle:= vsList.

You are using a custom ListView (TsListView) control, try using a standard ListView instead and see if the strange behaviour shows up.

Upvotes: 6

Related Questions