|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
TreeView и CheckBox
Есть такой класс:
Код:
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. |