![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Есть такой класс:
Код:
TCustomTreeView = class(TTreeView)
private
FCheckBox: Boolean;
FAutoCheck: Boolean;
procedure SetCheckBox(const Value: Boolean);
public
function GetChecked(Node: TTreeNode): Boolean;
procedure SetChecked(Node: TTreeNode; Checked: Boolean);
published
property CheckBox: Boolean read FCheckBox write SetCheckBox default False;
property AutoCheck: Boolean read FAutoCheck write FAutoCheck default False;
end;
Методы:
const
TVIS_CHECKED = $2000;
function TCustomTreeView.GetChecked(Node: TTreeNode): Boolean;
var
Item :TTVItem;
begin
Item.Mask := TVIF_STATE;
Item.hItem := Node.ItemId;
TreeView_GetItem(Node.TreeView.Handle, Item);
Result := (Item.State and TVIS_CHECKED) = TVIS_CHECKED;
end;
procedure TCustomTreeView.SetCheckBox(const Value: Boolean);
var
FStyle: Integer;
begin
FCheckBox := Value;
FStyle := GetWindowLong(Handle, GWL_STYLE);
if FCheckBox then
FStyle := FStyle or TVS_CHECKBOXES
else
if (FStyle and TVS_CHECKBOXES) = TVS_CHECKBOXES then
FStyle := FStyle and not TVS_CHECKBOXES;
SetWindowLong(Handle, GWL_STYLE, FStyle);
Repaint;
end;
procedure TCustomTreeView.SetChecked(Node: TTreeNode; Checked: Boolean);
var
Item :TTVItem;
begin
FillChar(Item, SizeOf(TTVItem), 0);
with Item do
begin
hItem := Node.ItemId;
Mask := TVIF_STATE;
StateMask := TVIS_STATEIMAGEMASK;
if Checked then
Item.State :=TVIS_CHECKED
else
Item.State :=TVIS_CHECKED shr 1;
TreeView_SetItem(Node.TreeView.Handle, Item);
end;
end;Как сделать так, чтобы при AutoCheck=True галочки выставлялись во всех дочерних чекбоксах? Последний раз редактировалось kasimka, 09.04.2014 в 14:55. |
|
#2
|
||||
|
||||
|
Поскольку до чекбокса добраться стандартными средствами не удалось, придётся немного извратиться в рантайме и для начала, при инициализации компонента нужно добавить строчку
Код:
... CustomTreeView.OnMouseDown:= CTVMouseDown; ... Код:
procedure TMainForm.CTVMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
ctv: TCustomTreeView absolute Sender;
Node: TTreeNode;
flg: boolean;
begin
if ctv.AutoCheck then
begin
Node:= ctv.GetNodeAt(X, Y);
if (Node <> nil) and
(Node.Parent = nil) and // Если Parent = nil то это корневой элемент
(ctv.GetHitTestInfoAt(X, Y) = [htOnItem, htOnStateIcon]) then
begin
flg:= ctv.GetChecked(Node);
Node:= Node.getFirstChild;
while Assigned(Node) do
begin
ctv.SetChecked(Node, flg);
Node:= Node.GetNextChild(Node);
end;
end;
end;
end;З.Ы. Достучался всё же до птисы, с помощью GetHitTestInfoAt, теперь точно похоже Вложенность идёт на два уровня, если нужно "глубже" то тогда крутите цикл while ещё дополнительно, или вынесите его в рекурсивную внешнюю функцию Последний раз редактировалось Alegun, 09.04.2014 в 10:02. Причина: дополнение |
| Этот пользователь сказал Спасибо Alegun за это полезное сообщение: | ||
kasimka (09.04.2014)
| ||
|
#3
|
|||
|
|||
|
Спасибо огромное!
Может кому-нибудь пригодиться... Немного переписанное событие OnMouseDown и рекурсивная процедура (позволяет проставить галочки во всех дочерних нодах): Код:
procedure TMainForm.CTVMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
Node: TTreeNode;
begin
if (Sender as TCustomTreeView).AutoCheck=True then
begin
Node:=(Sender as TCustomTreeView).GetNodeAt(X, Y);
if (Node <> nil) and
((Sender as TCustomTreeView).GetHitTestInfoAt(X, Y) = [htOnItem, htOnStateIcon]) then
CheckSubNode(Sender, Node);
end;
end;
procedure TMainForm.CheckSubNode(Sender: TObject; Node: TTreeNode);
var
flag: boolean;
begin
if not Node.HasChildren then Exit;
flag:=(Sender as TCustomTreeView).GetChecked(Node);
Node:=Node.getFirstChild;
while Assigned(Node) do
begin
(Sender as TCustomTreeView).SetChecked(Node, flag);
CheckSubNode(Sender, Node);
Node:=Node.GetNextChild(Node);
end;
end;Еще раз переписанное событие (позволяет снимать родительский чекбокс при снятии последнего дочернего и ставить родительский чекбокс при включении первого дочернего): Код:
procedure TMainForm.CTVMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
NodeParent, Node: TTreeNode;
begin
if (Sender as TCustomTreeView).AutoCheck=True then
begin
Node:=(Sender as TCustomTreeView).GetNodeAt(X, Y);
if (Node <> nil) and
((Sender as TCustomTreeView).GetHitTestInfoAt(X, Y) = [htOnItem, htOnStateIcon]) then
CheckSubNode(Sender, Node);
if Node.Parent<>nil then
begin
NodeParent:=Node.Parent;
Node:=NodeParent.getFirstChild;
while Assigned(Node) do
begin
if (Sender as TCustomTreeView).GetChecked(Node) then
Checked:=True;
Node:=NodeParent.GetNextChild(Node);
end;
if not Checked then
(Sender as TCustomTreeView).SetChecked(NodeParent, false)
else
(Sender as TCustomTreeView).SetChecked(NodeParent, true);
end;
end;
end;Таким образом, имеем полностью рабочее дерево с чекбоксами. Последний раз редактировалось M.A.D.M.A.N., 15.04.2014 в 17:10. |