TreeView mixed-state check boxes

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

TreeView mixed-state check boxes

Сообщение pronto » 11.01.2011 (Вт) 14:25

Доброго времени суток, форумчане!

Наткнулся на трудность при попытке установить третье состояние check box'ов в дереве.
MSDN учит обращаться с его состояниями, но только двумя...
Как будто проблема простая, но поиски заводят в порочный «вокруг да около»...

Вот, пример того, что хочется получить
Вложения
three-state checkbox.png
Индикатор смешанного выбора
three-state checkbox.png (10.83 Кб) Просмотров: 2322
O, sancta simplicitas!

just_me
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 3
Зарегистрирован: 20.12.2010 (Пн) 0:32

Re: TreeView mixed-state check boxes

Сообщение just_me » 11.01.2011 (Вт) 15:17

Код: Выделить всё
CheckBox1.CheckState = CheckState.Indeterminate

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 11.01.2011 (Вт) 15:26

just_me, молодец!
Для справки. У элемента TreeView из коллекции Common Controls 5.0 вообще нет свойства Checkboxes. И кудыть мне енто присваивать, а?

Add: Ага, и это не под .NET... (Специфика подфорума такая)
O, sancta simplicitas!

Debugger
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1667
Зарегистрирован: 17.06.2006 (Сб) 15:11

Re: TreeView mixed-state check boxes

Сообщение Debugger » 11.01.2011 (Вт) 16:11

5.0

Насколько мне известно, есть ещё одна, Хорошая версия treeview'a.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 11.01.2011 (Вт) 16:38

Для маленькой такой компании — огромный такой секрет. Debugger, если ты про 6.0, то я тоже про неё знаю, а если нет, то...
O, sancta simplicitas!

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: TreeView mixed-state check boxes

Сообщение Antonariy » 12.01.2011 (Ср) 20:44

Он намекает на api-версию. И тут уж либо делать treeview на апи целиком, либо отказаться от mixed-state, потому что нет способа (по крайней мере я не нашел) однозначно сопоставить объект Node и дескриптор hItem, через который можно полностью контролировать ноду. Впрочем, третье состояние нужно в любом случае кодить на апи ручками, потому что Common Controls сами по себе знают лишь о двух:
TVS_CHECKBOXES
Version 4.70. Enables check boxes for items in a tree-view control. A check box is displayed only if an image is associated with the item. When set to this style, the control effectively uses DrawFrameControl to create and set a state image list containing two images. State image 1 is the unchecked box and state image 2 is the checked box. Setting the state image to zero removes the check box altogether. For more information, see Working with state image indexes.
Вдогонку: TVM_SETIMAGELIST+TVSIL_STATE — это чтобы назначить свой imglist с картинками для всех желаемых состояний.
Лучший способ понять что-то самому — объяснить это другому.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 13.01.2011 (Чт) 3:50

потому что нет способа (по крайней мере я не нашел) однозначно сопоставить объект Node и дескриптор hItem, через который можно полностью контролировать ноду

Да, от самой Ноды получить её hItem невозможно, но есть обходной путь
Код: Выделить всё
Public Sub GetNodesHandles(ByVal NodeCount As Long)
   ' получение указаетлей на структуры TVITEMEX
   ' NodeCound - количество веток во всём дереве
   ' gTV_H     = TreeView.hwnd

   ReDim tvwItem_H(NodeCount + 1)
   
   Dim iStack As Long
   
   ' получение указателя hItem для первого элемента в дереве
   i = 1
   tvwItem_H(i) = SendMessage(ByVal gTV_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_ROOT, ByVal 0)
   
   ' указатели первого уровня
   Do
      tvwItem_H(i + 1) = SendMessage(ByVal gTV_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_NEXT, ByVal tvwItem_H(i))
      i = i + 1
   Loop Until tvwItem_H(i) = 0
   
   Do
      iStack = iStack + 1
      tvwItem_H(i) = SendMessage(ByVal gTV_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_CHILD, ByVal tvwItem_H(iStack))
     
      If tvwItem_H(i) <> 0 Then
         ' перебор дочерних ветвей
         Do
            tvwItem_H(i + 1) = SendMessage(ByVal gTV_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_NEXT, ByVal tvwItem_H(i))
            i = i + 1
         Loop Until tvwItem_H(i) = 0
      End If
     
   Loop Until iStack = NodeCount
   
End Sub

Конечно, чтобы индексы в массиве tvwItem_H соответствовали индексам ветвей, нужно соблюдать их порядок добавления в дерево. Сначала добавляются ветви первого уровня. Потом все ветви второго уровня и т.д.

Ну, а состояния, похоже, придётся отрисовывать самому.
O, sancta simplicitas!

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: TreeView mixed-state check boxes

Сообщение Antonariy » 13.01.2011 (Чт) 10:00

обходной путь
Сомневаюсь, что эта процедура работает адекватно. Чтобы было наверняка, нужно сабклассингом отслеживать добавление нод, записывать новый hItem в глобальную переменную, а после выхода из Nodes.Add проверять, что записалось.

нужно соблюдать их порядок добавления в дерево
Если правильно обходить дерево, это условие соблюдать необязательно. Позже напишу как.
Лучший способ понять что-то самому — объяснить это другому.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 13.01.2011 (Чт) 14:43

Сомневаюсь, что эта процедура работает адекватно.

Для готового дерева, которое не предполагает изменяться (а большего и не надо) — самое то. Проверял на нескольких вариантах заполнения дерева.
Меня сейчас больше интересует не добавление нод, а отлавливание события щелчка по Check'у... Пока не знаю с какой стороны подходить.
O, sancta simplicitas!

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: TreeView mixed-state check boxes

Сообщение Antonariy » 13.01.2011 (Чт) 14:50

Итак, правильный обход:
Код: Выделить всё
Redim ObjNodes(Tree.Nodes.Count)
Redim ApiNodes(Tree.Nodes.Count)

Dim i as Long

Sub EnumTree(Node as Node)
    If Node is nothing then exit sub
    i = i + 1
    Set ObjNodes(i) = Node
    EnumTree Node.Child
    EnumTree Node.Next
End Sub
Аналогично нужно делать обход через апи.
Лучший способ понять что-то самому — объяснить это другому.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 13.01.2011 (Чт) 17:16

Как-то так?
Код: Выделить всё
Public Sub GetNodesHandles(ByVal nhItem As Long)
'   ' получение указаетлей на структуры TVITEMEX
   If nhItem Then
      i = i + 1
      tvwItem_H(i) = nhItem
      Debug.Print i, nhItem
     
      GetNodesHandles ByVal SendMessage(ByVal gOperaList_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_CHILD, ByVal tvwItem_H(i))
      GetNodesHandles ByVal SendMessage(ByVal gOperaList_H, ByVal TVM_GETNEXTITEM, ByVal TVGN_NEXT, ByVal tvwItem_H(i))
   Else
      Exit Sub
   End If
End Sub
O, sancta simplicitas!

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: TreeView mixed-state check boxes

Сообщение Antonariy » 13.01.2011 (Чт) 17:33

Ага. Только Else Exit Sub занимает место не неся пользы :)
Меня сейчас больше интересует не добавление нод, а отлавливание события щелчка по Check'у...
Тебе нужно отловить простой клик, его координаты, и с помощью HitTest выяснить, куда именно было кликнуто. Это делается с помощью TVM_HITTEST + TVHITTESTINFO. Если в структуре TVHITTESTINFO поле flags имеет значение TVHT_ONITEMBUTTON, значит кликнули по чекбоксу. В нее же возвращается дескриптор ноды, находящейся по указанным координатам.
Лучший способ понять что-то самому — объяснить это другому.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Re: TreeView mixed-state check boxes

Сообщение Antonariy » 13.01.2011 (Чт) 17:44

Кстати запись If nhItem Then — дурная привычка. Если число одно, то ничего страшного не произойдет, а если If long1 and long2, то в переменных могут оказаться такие ненулевые значения, что операция and вернет 0. Я с этим столкнулся при работе с апишным тулбаром на такой строчке:
Код: Выделить всё
If m_hToolbar And m_hImageList Then
Это проверка на то, что тулбар и имаджлист созданы, после которой в имаджлист добавляется картинка. Но иногда при старте программы я наблюдал кнопки без картинок, и месяца, не побоюсь этого слова, три, ломал голову о причинах. Чисто на волне интуиции сделал явную проверку на 0 и глюк исчез.
Лучший способ понять что-то самому — объяснить это другому.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 13.01.2011 (Чт) 17:50

Присутствие Else Exit Sub не так страшно, как затыкание перебора на пятом индексе. Это получается первый потомок первой ветки.
А про подсказку спасибо! Тока ковыряться с этим буду уже завтра.
O, sancta simplicitas!

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: TreeView mixed-state check boxes

Сообщение pronto » 15.01.2011 (Сб) 7:35

Если функцию HitTest вызывать из события TreeView_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single), то координаты нужно делить на Screen.TwipsPerPixelX и Screen.TwipsPerPixelY, соответственно. Клик по чекбоксу устанавливает флаг TVHT_ONITEMSTATEICON, а не TVHT_ONITEMBUTTON, который устанавливается по клику на «плюс/минус».
O, sancta simplicitas!


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot и гости: 89

    TopList