Link to home
Start Free TrialLog in
Avatar of wqclatre
wqclatre

asked on

TListView and checkboxes

How can I trap when a checkbox get checked and unchecked (an checkbox inside a listview. IE Checkboxses = True on TListView)

How can I set the state to clGreyed on a checkbox inside a TListView
Avatar of Mike Littlewood
Mike Littlewood
Flag of United Kingdom of Great Britain and Northern Ireland image

You can simulate it using the onClick event

procedure TForm1.ListView1Click(Sender: TObject);
var
  ListItem:TListItem;
  CurrPos:TPoint;
begin
  CurrPos:=Mouse.CursorPos;
  CurrPos:=ListView1.ScreenToClient(CurrPos);
  ListItem:=ListView1.GetItemAt(CurrPos.x,CurrPos.y);
  if Assigned(ListItem) then
  begin
    if ListItem.Checked then ShowMessage(ListItem.Caption+' Checked')
    else ShowMessage(ListItem.Caption+' not Checked');
  end;
end;
Just make sure you have rowselect = True
In fact it will work if you dont have rowselect on.
My mistake.
>How can I set the state to clGreyed on a checkbox inside a TListView<

Sorry this part Im not sure if you can.
Avatar of wqclatre
wqclatre

ASKER

Strange. I thought I made a comment here before.

Your "solution" don't solve my problem since I don't know the state before. I can't know if just an item is cliked at or if the chekbox is checked. The strange thing is that VB have an OnItemChecked event. Delphi don't.
Avatar of TheRealLoki
well you can code it manually
here is an example i wrote for you on how to notice the "Checkbox change" if the viewstyle is vsReport

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls;

// some constants for dealing with the checkbox position - only for ViewStyle vsReport atm
const
    lv_distancefromleft = 3;
    lv_distancefromtop = 18;
    lv_checkboxheight = 18;
    lv_checkboxwidth = 15;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Memo1: TMemo;
    procedure ListView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
// ADDED EVENT HERE FOR HANDLING CHECKBOX CHANGE NICELY
    procedure OnListviewItemChecked(Sender: TObject; const Item: TListItem; const NewState: boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
    CurrentlyPressedListViewCheckbox: integer;
begin
    if
      ( X >= lv_distancefromleft) and
      (X < (lv_distancefromleft + lv_checkboxwidth)) and
      (Y >= lv_distancefromtop) and
      (Y < lv_distancefromtop + ( lv_checkboxheight * (Sender as TListView).Items.Count) )
    then
    begin
        CurrentlyPressedListViewCheckbox := Trunc( (Y - lv_distancefromtop) / lv_checkboxheight);
// now call our nice handling routine
        OnListviewItemChecked( Sender, (Sender as TListView).Items[CurrentlyPressedListViewCheckbox],
          (Sender as TListView).Items[CurrentlyPressedListViewCheckbox].Checked);
    end;

end;

// This procedure is just an example f you wanted to have 1 nice routine for handling the "checkbox"
procedure TForm1.OnListviewItemChecked(Sender: TObject; const Item: TListItem; const NewState: boolean);
begin
    if NewState then memo1.lines.add('checked item: ' + inttostr(Item.index))
    else memo1.lines.add('unchecked item: ' + inttostr(Item.index))
// old check state is obviously "not item.checked"
end;

end.
That does the same as what I wrote before

Im not sure why you want to know the state before, it can only be one of two, so if it is checked now, it must have been unchecked.

If you REALLY wanted to hold values for some other reason, maybe store them in an array for checking later

type
  TForm1 = class(TForm)
    ListView1: TListView;
    Memo1: TMemo;
    procedure ListView1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    arrChecked: array of Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm;

implementation

{$R *.dfm}

procedure TForm1.ListView1Click(Sender: TObject);
var
  ListItem:TListItem;
  CurrPos:TPoint;
  i: Integer;
begin
  CurrPos:=Mouse.CursorPos;
  CurrPos:=ListView1.ScreenToClient(CurrPos);
  ListItem:=ListView1.GetItemAt(CurrPos.x,CurrPos.y);
  if Assigned(ListItem) then
  begin
    // this bit is pretty pointless to be honest
    // it can only be one of two states
    i := ListItem.Index;
    if arrChecked[i] then
      Memo1.Lines.Add('Item ' + IntToStr(i) + ' was previously Checked')
    else
      Memo1.Lines.Add('Item ' + IntToStr(i) + ' was previously unchecked');

    if ListItem.Checked then
      Memo1.Lines.Add('Item ' + IntToStr(i) + ' is now Checked')
    else
      Memo1.Lines.Add('Item ' + IntToStr(i) + ' is now unchecked');

    // set the item
    arrChecked[i] := ListItem.Checked;
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  i: Integer;
begin
  // get current states
  SetLength(arrChecked, ListView1.Items.Count);
  for i := 0 to Pred(ListView1.Items.Count) do
    arrChecked[i] := ListView1.Items[i].Checked;
end;
ASKER CERTIFIED SOLUTION
Avatar of Mike Littlewood
Mike Littlewood
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Im presuming that you are populating a lot of data rather than one column, otherwise you could use a CheckListBox which has an OnClickCheck event.