单击CheckListBox项目以切换该项目的检查状态

问题描述:

我试图切换TCheckListBox项目状态,因此如果选中它,则取消选中它,反之亦然。这通常只在您点击物理盒本身时才会切换,但我希望它在用户单击项目行上的任意位置时切换。单击CheckListBox项目以切换该项目的检查状态

下面的代码可以工作,但是现在可以防止物品在物理框中单击时可以切换(例如,如果当前未选中,那么它们会在框中单击,并保持未选中状态)。

是否有可能在代码中同时存在两种行为或错误?

procedure TMainFrm.CheckListBoxModulesMouseDown(Sender: TObject; 
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
var 
    APoint: TPoint; 
    Index: integer; 
begin 
    if (Button = mbLeft) then 
    begin 
    APoint.X := X; 
    APoint.Y := Y; 
    Index := CheckListBoxModules.ItemAtPos(APoint, True); 

    if(Index > -1) then 
    begin 
     CheckListBoxModules.Checked[Index] := not CheckListBoxModules.Checked[Index]; 
    end;  
    end;  
end; 
+1

类似于'如果y> 16然后开始...结束' – bummi 2014-09-19 22:41:08

+0

嗯我想这是有效的。 X确实。 – ikathegreat 2014-09-19 22:52:27

你的问题是,在你切换状态后,盒子本身会在检查命中后再次切换它。

一个解决办法是取消这个内置的检查行为:

procedure TMainFrm.CheckListBoxModulesClickCheck(Sender: TObject); 
begin 
    CheckListBoxModules.Checked[CheckListBoxModules.ItemIndex] := 
     not CheckListBoxModules.Checked[CheckListBoxModules.ItemIndex]; 
end; 


这工作,因为当您通过代码更改检查状态OnClickCheck不被解雇。只有在复选框中鼠标点击导致的状态变化才会颠倒过来。


更好的解决方案是当点击复选框时不切换状态。如果您决定实施此解决方案,请参阅TCheckListBox.GetCheckSize中的代码,了解VCL如何确定复选框大小以及TCheckListBox.MouseDown确定位置的方式。

这是一种点击测试帮助点的情况。如果用户点击复选框,则不要手动切换检查状态。您可以使用类似TCheckListBox内部使用的逻辑来确定用户是否在复选框上单击。如果鼠标位于复选框上,让TCheckListBox处理点击。否则,请手动切换。例如:

type 
    TCheckListBoxAccess = class(TCheckListBox) 
    end; 

procedure TMainFrm.CheckListBoxModulesMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    Index: Integer; 

    procedure DoToggle; 
    var 
    State: TCheckBoxState; 
    begin 
    if (Index >= 0) and (Index < CheckListBoxModules.Items.Count) and CheckListBoxModules.ItemEnabled[Index] then 
    begin 
     State := CheckListBoxModules.State[Index]; 
     case State of 
     cbUnchecked: 
      if CheckListBoxModules.AllowGrayed then State := cbGrayed else State := cbChecked; 
     cbChecked: State := cbUnchecked; 
     cbGrayed: State := cbChecked; 
     end; 
     CheckListBoxModules.State[Index] := State; 
     TCheckListBoxAccess(CheckListBoxModules).ClickCheck; 
    end; 
    end; 

begin 
    if Button = mbLeft then 
    begin 
    Index := CheckListBoxModules.ItemAtPos(Point(X,Y),True); 
    if (Index <> -1) and CheckListBoxModules.ItemEnabled[Index] then 
     if not TCheckListBoxAccess(CheckListBoxModules).UseRightToLeftAlignment then 
     begin 
     if X - CheckListBoxModules.ItemRect(Index).Left >= TCheckListBoxAccess(CheckListBoxModules).GetCheckWidth then 
      DoToggle; 
     end 
     else 
     begin 
     Dec(X, CheckListBoxModules.ItemRect(Index).Right - TCheckListBoxAccess(CheckListBoxModules).GetCheckWidth); 
     if (X <= 0) or (X >= TCheckListBoxAccess(CheckListBoxModules).GetCheckWidth) then 
      DoToggle; 
     end; 
    end; 
end; 

我已经给Sertac的答案添加了一些代码,以检查按下的女巫键,以便我们也可以使用键盘上下移动。

procedre TfrmRelBalanceteGerencial.cklGrupoContasClick(Sender: TObject); 
begin 
inherited; 
    if HiWord(GetKeyState(VK_UP)) <> 0 or HiWord(GetKeyState(VK_DOWN)) then 
    begin 
    // do nothing 
    end 
    else 
    begin 
    cklGrupoContas.Checked[cklGrupoContas.ItemIndex] := not cklGrupoContas.Checked[cklGrupoContas.ItemIndex]; 
    end; 
end;