платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Сообщение  electrik в Вт Июн 30, 2009 6:22 pm

Win32 API. Урок 19. Tree View Control

В этом туториале мы изучим как использовать контрол tree view. Более того, мы также узнаем как реализовать drag and drop для этого контрола и как использовать image list.

Теория:

Контрол tree view - это особый вид окна, который представляет объекты в иерархическом порядке. В качестве примера может служить левая панель Windows Explorer'а. Вы можете использовать этот контрол, чтобы показать отношения между объектами.

Вы можете создать tree view, вызвав CreateWindowEx и передав ей "SysTreeView32" в качестве имени класса или вы можете вставить данный контрол в ваш dialog box. Не забудте поместить вызов InitCommonControls в ваш код.

Есть несколько стилей присущих только tree view. Вот наиболее часто используемые:

• TVS_HASBUTTONS - отображает кнопки плюс (+) и минус (-) перед родительским пунктом. Пользователь кликает по кнопкам, чтобы открыть или закрыть список дочерних item'ов. Чтобы вставить кнопки с пунктами в корень tree view, также должен быть указан TVS_LINESATROOT.

• TVS_HASLINES - используются линии для показа иерархии пунктов.

• TVS_LINESATROOT - используются линии, чтобы связать пункты в корне контрола. Этот стиль игнорируется, если не указан TVS_HASLINES.

Tree view, как и любой другой common control, взаимодействует с родительским окном с помощью сообщений. Родительское окно может посылать различные сообщения tree view, а тот может посылать "уведомительные" сообщения своему родительскому окну. В этом отношении tree view ничем не отличается от других окон.

Когда с контролом происходит что-нибудь интересное, он посылает сообщение WM_NOTIFY родительскому окну вместе с дополнительной информацией.

• wparam - ID контрола, но то, что оно будет уникальным не гарантируется, поэтому не используйте его. Вместо этого мы будем использовать hwndFrom или IDFrom из структуры NMHDR, на которую указывает lparam.
• lparam - указатель на структуру NMHDR. Некоторые контролы могут передавать указатель на большую структуру, но они должны иметь в качестве первого поля структуру NMHDR. Поэтому вы можете быть уверены, что lparam по крайней мере указывает на NMHDR.

Затем мы проанализируем структуру NMHDR.

type NMHDR
hwndFrom as HWND
idFrom as UINT
code as UINT
end type

hwndFrom - это хэндл окна контрола, который послал это сообщение.

idFrom - это ID этого контрола.

code - это настоящее сообщение, которое контрол хотел послать родительскому окну.

Уведомления от tree view начинаются с префикса TVN_.

Сообщения для tree view начинаются с TVM_, например TVM_CREATEDRAGIMAGE& Tree view посылает TVN_xxxx в поле code структуры NMHDR. родительское окно может посылать TVM_xxxx контролу.

Добавление пунктов в tree view

После того, как вы создадите контрол tree view, вы можете добавить в него пункты. Вы можете сделать это, послав контролу TVM_INSERTITEM.

TVM_INSERTITEM

• wparam = 0;
• lparam = pointer to a TV_INSERTSTRUCT;

Вам следует знать кое-какую терминологию, касающуюся взаимоотношений между item'ами в tree view.

Item может быть родительским, дочерним или тем и другим одновременно. родительский item - это такой item, с которым ассоциированы под-item'ы. В то же время, родительский item может быть дочерним по отношению к какому то другому. Item, у которого нет родителя, называется корнем (root). В tree view может быть много корневых элементов. Теперь мы проанализируем структуру TV_INSERTSTRUCT.

type TV_INSERTSTRUCT
hParent as HTREEITEM
hInsertAfter as HTREEITEM
union
itemex as TVITEMEX
item as TVITEM
end union
end type

hParent - хэндл родительского item'а. Если этот параметр равен TVI_ROOT или NULL, тогда item вставляется в корень tree view.

hInsertAfter - хэндл item'а, после которого будет вставляться новый item, или одно из следующих значений:

 TVI_ROOT - вставка элемента в корень
• TVI_FIRST - вставка элемента в начало списка.
• TVI_LAST - вставка элемента в конец списка.
• TVI_SORT - вставка элемента в список согласно алфавитному порядку.

union
itemex as TVITEMEX
item as TVITEM
end union

Мы будем использовать только TVITEM.

type TV_ITEM
mask as UINT
hItem as HTREEITEM
state as UINT
stateMask as UINT
pszText as LPSTR
cchTextMax as integer
iImage as integer
iSelectedImage as integer
cChildren as integer
lParam as LPARAM
end type

Эта структура используется для отсылки и получения информации об элементе tree view (в зависимости от сообщений). Например, с помощью TVM_INSERTITEM, она используется для указания атрибутов item'а, который должен быть вставлен в tree view. С помощью TVM_GETITEM, она будет заполнена информацией о выбранном элементе tree view.

imask используется для указания, какой член структуры TV_ITEM верен. Например, если значение в imask равно TVIF_TEXT, оно означает, что только pszText верно. Вы можете комбинировать несколько флагов вместе.

hItem - это хэндл элемента tree view. Каждый item имеет хэндл, как и в случае с окнами. Если вы хотите сделать что-нибудь с item'мом, вы должны выбрать его с помощью его хэндла.

pszText - это указатель на строку, оканчивающуюся NULL'ом, которая является названием элемента tree view.

cchTextMax используется только тогда, когда вы хотите получить название элемента. Windows надо будет знать размер предоставленного вами буфера (pszText), поэтому этот элемент используется именно для этого.

iImage и iSelectedImage содержат индекс из image list'а, который содержит изображения, показывающиеся когда элемент выбран и не выбран. Если вспомните левую панель Windows Explorer'а, то изображения директорий задаются именно этими двумя параметрами.

Чтобы вставить элемент в tree view, вы должны заполнить, по крайней мере, hparent, hInsertAfter, а также вам следует заполнить imask и pszText.

Добавление изображений в tree view

Если вы хотите поместить изображение слева от названия элемента, вам следует создать image list и ассоциировать его с контролом tree view.

function ImageList_Create _
(byval cx as integer, _
byval cy as integer, _
byval flags as UINT, _
byval cInitial as integer, _
byval cGrow as integer) as HIMAGELIST

Если вызов пройдет успешно, функция возвратит хэндл на пустой image list.

cx - ширина любого изображения в этом image list'е в пикселях.

cy - высота любого изображения в этом image list'е в пикселях. Все изображения в image list'е должны быть равны друг другу по размеру. Если вы укажете больший bitmap, Windows разрежет его на несколько кусков согласно значению в cx и cy. Поэтому вам следует тщательно подготовить необходимые изображения.

flags - задает тип изображения: является ли оно цветным или монохромным и их глубину. Проконсультируйтесь с вашим справочником по Win32 API.

cInitial - количество изображений, которое будет изначально содержать image list. Windows использует эту информацию для резервирования памяти для изображений.

cGrow - количество изображений, на которое должен увеличиваться image list, когда системе необходимо изменить размер списка, чтобы выделить место для новых изображений. Этот параметр представляет количество новых изображений, которое может содержать image list, изменивший размер.

Image list - это не окно! Это только хранилище изображений, которые будут использоваться другими окнами.

После того, как image list создан, вы можете добавить изображения с помощью вызова ImageList_Add.

function ImageList_Add _
(byval himl as HIMAGELIST, _
byval hbmImage as HBITMAP, _
byval hbmMask as HBITMAP) as integer

Если во время вызова произойдет какая-либо ошибка, будет возвращен -1.

himl - хэндл image list'а, в который вы хотите добавить изображения. Это значение возвращается ImageList_Create.

hbmImage - хэндл битмапа, который должен быть добавлен в image list. Обычно изображения задаются в ресурсах и вызываются с помощью LoadBitmap.

Заметьте, что вам не надо указывать количество изображений, содержащихся в этом bitmap'е, потому что это вытекает из параметров cx и cy, переданных ImageList_Create.

hbmMask - хэндл битмапа, в котором содержится маска. Если маска в image list'е не используется, этот параметр игнорируется.

Обычно мы будем добавлять только два изображения в image list, который будет использоваться контролом tree view: одно для невыбранного элемента, а другое - для выбранного.

Когда image list готов, мы ассоциируем его с tree view, посылая тому сообщение TVM_SETIMAGELIST:

• wparam - тип image list'а. Есть две возможности:

• TMSIL_NORMAL - задает обычный image list, который содержит изображения выбранного и невыбранного элементов.
• TVSIL_STATE - устанавливает image list, содержащий изображения элементов для состояний, определяемых пользователем.

• lparam - хэндл image list'а.

Получение информации о элементе tree view

Вы можете получить информацию об элементе tree view, послав ей сообщение TVM_GETITEM:

• wparam = 0
• lparam = pointer to the TV_ITEM structure to be filled with the information

Прежде, чем вы пошлете это сообщение, вы должны заполнить параметр imask флагами, которые укажут, какие из полей TV_ITEM должны быть заполнены Windows.
А самое главное, вы должны заполнить hItem хэндлом элемента, о котором вы хотите получить информацию. И это порождает следующую проблему: где взять этот хэндл? Надо ли вам сохранять все хэндлы tree view?

Ответ достаточно прост: вам не надо этого делать. Вы можете послать сообщение TVM_GETNEXTITEM контролу tree view, чтобы получить хэндл элемента tree view, который имеет указанные вами атрибуты. Например, вы можете получить хэндл первого дочернего элемента, корневого элемента, выбранного элемента и так далее.

TVM_GETNEXTITEM:

• wparam = флаг
• lparam - хэндл на элемент tree view (не всегда необходим)

Значение wparam очень важно, поэтому я привожу ниже все возможные флаги:

• TVGN_CARET - получение хэндла выбранного элемента.
• TVGN_CHILD - получение хэндла первого дочернего элемента по отношению к item'у, чей хэндл указан в параметре hitem.
• TVGN_DROрHILITE - получение хэндла item'а, который является целью операции drag-and-drop.
• TVGN_FIRSTVISIBLE - получение хэндла первого видимого item'а.
• TVGN_NEXT - получение хэндла следующего родственного элемента.
• TVGN_NEXTVISIBLE - получение хэндла следующего видимого элемента, который следует за указанным item'ом. Указанный элемент должен быть видимым. Используйте сообщение TVM_GETITEMRECT, чтобы определить, является ли item видимым.
• TVGN_PARENT - получение хэндла указанного родительского элемента по отношению к указанному.
• TVGN_PREVIOUS - получение хэндла предыдущего родственного элемента.
• TVGN_PREVIOUSVISIBLE - получение хэндла первого видимого элемента, который предшествует указанному item'у, который должен быть видимым. Используйте сообщение TVM_GETITEMRECT, чтобы определить, является ли item видимым.
• TVGN_ROOT - получает хэндл самого первого из корневых элементов tree view.

Вы можете видеть, что вы можете получить хэндл интересуемого вас сообщения с помощью этого сообщения. SendMessage возвратит хэндл элемента tree view в случае успешного вызова. Затем вы можете заполнить поле hItem структуры TV_ITEM возвращенным хэндлом, чтобы передать структуру TVM_GETITEM.

Операции Drag-and-Drop над контролом tree view

Именно из-за этой части я написал этот туториал. Когда я попытался следовать примеру из справочника по Win32 API (win32.hlp от Inprise), я был сильно обескуражен отсутствием жизненно важной информации. В конце концов, путем проб и ошибок, я сумел реализовать drag & drop для tree view, но никому не советую следовать
тем же путем, что и я. Ниже изложены правильные действия.

Когда пользователь пытается перетащить элемент, tree view посылает уведомление TVN_BEGINDRAG родительскому окну. Вы можете использовать эту возможность для создания специального изображения, которое будет представлять элемент, когда его тащат. Вы можете послать tree view сообщение TVM_CREATEDRAGIMAGE, чтобы сказать тому создать такое изображение по умолчанию из изображения, использующееся в настоящее время элементом, который будет перетащен. Tree view создаст image list с одним drag-изображением и возвратит вам. хэндл этого image list'а

После того, как drag-изображение создано, вы указываете его "горячую точку", вызывая ImageList_BeginDrag.

function ImageList_BeginDrag _
(byval himlTrack as HIMAGELIST, _
byval iTrack as integer, _
byval dxHotspot as integer, _
byval dyHotspot as integer) as BOOL

• himlTrack - это хэндл image list'а, который содержит drag-изображение.
• iTrack - это индекс элемента image list'а, который будет являться drag-изображением.
• dxHotspot указывает относительную горизонтальную координату "горячей точки" (которая нам необходима, так как мы будем использовать drag-изображение вместо курсора мыши. У стандартного курсора "горячая точка" находится на кончике стрелки).
• dyHotspot указывает относительную вертикальную координату "горячей точки".
• Как правило, iTrack будет равен 0, если вам нужно сказать tree view, чтобы тот создал для вас drag-изображение. dxHotspot и dyHotspot могут быть равными 0, если вы хотите, чтобы левый верхний угол drag-изображения был "горячей точкой".

Когда drag-изображение готово, мы вызываем ImageList_DragEnter, чтобы отобразить его в окне.

function ImageList_DragEnter _
(byval hwndLock as HWND, _
byval x as integer, _
byval y as integer) as BOOL

hwndLock - это хэндл окна, которому принадлежит drag-изображение. Drag-изображение нельзя будет двигать за пределы этого окна.

x и y - это x- и y-координата места, где drag-изображение должно быть отображено сначала. Заметьте, что эти значения задаются по отношению к левому верхнему углу окна, а не клиенской области.

Теперь, когда drag-изображение отображено в окне, вам следует поддерживать операцию перетаскивания в контроле tree view. Тем не менее, здесь появляется небольшая проблема. Мы должны отслеживать путь перетаскивания с помощью WM_MOUSEMOVE и позицию сброса (drop) с помощью WM_LBUTTONUp. Однако, если drag-изображение находится над каким-нибудь дочерним окном, родительское окно никогда не получит никаких сообщений от мыши. решение состоит в том, чтобы взять контроль над сообщениями от мыши с помощью SetCapture. Эта функция позволяет направить мышиные сообщения напрямую определенному окну, вне зависимости от того, где находится курсор мыши.

Внутри обработчика WM_MOUSEMOVE, вы будете отслеживать drag-путь с помощью вызова ImageList_DragMove. Эта функция передвигает изображение относительно пути переноса. Более того, если вы захотите, вы можете подсвечивать элемент, над которым находится drag-изображение, посылая сообщение TVM_HITTEST, проверяя, находится ли изображение над каким-нибудь элементом. Если это так, вы можете послать TVM_SELECTITEM с флагом TVGN_DROPHILITE, чтобы подсветить элемент.
Заметьте, что прежде, чем послать сообщение TVM_SELECTITEM, вы должны спрятать drag-изображение или оно будет оставлять уродливый след. Это можно сделать, вызвав ImageList_DragShowNolock, а после того, как элемент будет подсвечен, необходимо вызвать ImageList_DragShowNolock, чтобы снова отобразить drag-изображение.

Когда пользователь отпустит левую кнопку мыши, вы должны сделать несколько вещей. Если вы подсветили элемент, вам нужно перевести его в обычное состояние, снова послав TVM_SELECTITEM с флагом TVGN_DROPHILITE, но в этот раз lparam должен быть равен нулю. Затем вы должны вызвать ImageList_DragLeave, за которым должен следовать вызов ImageList_EndDrag. Вы должны освободить мышь с помощью ReleaseCapture. Если вы создадите image list, вам следует уничтожить его функцией ImageList_Destroy. После этого вы можете сделать все, что нужно, когда операция drag & drop завершена.


Последний раз редактировалось: electrik (Вт Май 23, 2017 5:31 pm), всего редактировалось 1 раз(а)

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 37
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Сообщение  electrik в Вт Июн 30, 2009 6:24 pm

Win32 API. Урок 19. Tree View Control - продолжение

Пример:

файл tree.bas

Код:

' Tree View
#include "windows.bi"
#include "win/commctrl.bi"
#include "tree.bi"
declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы
dim shared hModule as HINSTANCE ' Хэндл нашей программы
dim shared hwndTreeView as HANDLE ' хэндл контрола tree view
dim shared hParent  as LRESULT ' хэндл корневого элемента
dim shared hImageList as HANDLE ' хэндл image list'а, который будет использоваться Tree View
dim shared hDragImageList as HRESULT ' хэндл image list'а, в котором будет храниться drag-изображение
dim shared DragMode  as bool = FALSE ' флаг, который определяет, находимся ли мы в режиме перетаскивания
dim shared tvinsert as TV_INSERTSTRUCT ' структура TV_INSERTSTRUCT
hModule = GetModuleHandle( NULL) ' Взять хэндл программы
end WinMain( hModule,NULL,GetCommandLine(), SW_SHOWNORMAL ) ' вызвать основную функцию
InitCommonControls() ' инициализируем Common Control'ы
' здесь заканчивается программа

' процедура окна
function  WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный  параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений
function = 0


dim tvhit as TVHITTESTINFO ' структура TVHITTESTINFO
dim hBitmap as HANDLE ' хэндл битмапа

select case uMsg  'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_CREATE ' если сообщение WM_CREATE
hwndTreeView = CreateWindowEx _ ' создадим Tree View
(NULL, _ ' дополнительные стили
TreeViewClass, _ ' класс Tree View
NULL, _ ' название окна
WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT, _ ' стиль окна
0, _ ' x
0, _ ' y
200, _ ' ширина
400, _ ' высота
hWnd, _ ' хэндл родительского окна
NULL, _
hModule, _ ' хэндл программы
NULL) ' указатель на структуру данных
hImageList = ImageList_Create _ ' создадим ассоциированный с Tree Viev, Image list
(16, _ ' ширина изображения в пикселях
16, _ ' высота изображения в пикселях
ILC_COLOR16, _ ' флаги. тип изображения
2, _ ' количество изображений
10) ' количество новых изображений, которое может содержать image list
hBitmap = LoadBitmap _ ' загрузим Bitmap
(hModule, _ ' хэндл программы
cptr(LPCSTR,IDB_TREE)) ' загрузка bitmap'а из ресурса
ImageList_Add _ ' Добавим bitmap в Image List
(hImageList, _ ' хэндл Image List'а
hBitmap, _ ' хэндл Bitmap'a
NULL) ' хэндл битмапа, в котором содержится маска
DeleteObject _ ' всегда удаляйте ненужный bitmap
(hBitmap) ' хэндл Bitmap'а
SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree Viev'а
TVM_SETIMAGELIST, _ ' ассоциируем Image List с tree view
0, _
cptr(LPARAM,hImageList)) ' хэндл Image List'а

 ' для того, чтобы вставить элемент в корень Tree Viev ,
'  запишем в хэндл родительского item'а Null
tvinsert.hparent = NULL
tvinsert.hInsertAfter = TVI_ROOT ' вставить элемент в корень
tvinsert.item.mask = TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE ' эти члены структуры TV_ITEM верны
tvinsert.item.pszText = @parent ' название элемента Tree View
tvinsert.item.iImage = 0 ' индекс изображения невыбранного элемента
tvinsert.item.iSelectedImage = 1 ' индекс изображения выбранного элемента
hParent = SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree Viev'а
TVM_INSERTITEM, _ ' добавить элемент
0, _
cPtr(LPARAM,@tvinsert)) ' указатель на структуру TV_INSERTSTRUCT
tvinsert.hparent = cPtr(HTREEITEM,hParent) ' запишем в хэндл родительского Item'а, хэндл корневого элемента
tvinsert.hInsertAfter = TVI_LAST ' вставить элемент в конец списка
tvinsert.item.pszText = @Child1 ' название дочернего элемента Tree View
SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree Viev
TVM_INSERTITEM, _ ' добавить элемент
0, _
cPtr(LPARAM,@tvinsert)) ' указатель на структуру TV_INSERTSTRUCT
tvinsert.item.pszText = @Child2 ' название дочернего элемента Tree View
SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree Viev
TVM_INSERTITEM, _ ' добавить элемент
0, _
cptr(LPARAM,@tvinsert)) ' указатель на структуру TV_INSERTSTRUCT
case WM_MOUSEMOVE ' если посылается сообщение перемещение мыши
if DragMode = TRUE then ' если перетаскивание (активен drag режим)
tvhit.pt.x = loword(lparam) ' запишем координату x мыши
tvhit.pt.y = hiword(lparam) ' запишем координату y мыши
ImageList_DragMove(loword(lparam),hiword(lparam)) ' обновим позицию drag-изображения
ImageList_DragShowNolock (FALSE) ' спрячем drag-изображение
scope
    dim ht as LRESULT
ht = SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree Viev
TVM_HITTEST, _ ' проверяем ненаходиться ли drag-изображение над каким-нибудь элементом
NULL, _
cptr(LPARAM,@tvhit)) ' координаты проверяемой точки
if ht <> NULL then
    SendMessage _ ' пошлем сообщение
    (hwndTreeView, _ ' хэндл Tree Viev
    TVM_SELECTITEM, _ ' выбрать элемент
  TVGN_DROPHILITE, _ ' подсветить элемент
  cptr(LPARAM,ht))
  end if
  end scope
ImageList_DragShowNolock (TRUE) ' покажем drag-изображение
end if
case WM_LBUTTONUP ' если отпустили левую кнопку мыши
    if DragMode = TRUE then ' если находимся в drag режиме

' выходим из drag режима
ImageList_DragLeave _
(hwndTreeView) ' хэндл Tree View
ImageList_EndDrag()
ImageList_Destroy _
(cPtr(HIMAGELIST,hDragImageList)) ' хэндл image list'а
scope
    dim dd as LRESULT ' хэндл drag-and-drop
dd = SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree View
TVM_GETNEXTITEM, _ ' ' получить хэндл
TVGN_DROPHILITE, _ ' получить хэндл drag-and-drop
0)
SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree View
TVM_SELECTITEM, _ ' выбрать элемент
TVGN_CARET, _
dd) ' хэндл drag-and-drop
SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree View
TVM_SELECTITEM, _ ' выбрать элемент
TVGN_DROPHILITE, _ ' подсветить элемент
0)
ReleaseCapture() ' освободим захват мыши
DragMode = FALSE ' установим флаг drag режима в FALSE
end scope
end if

case WM_NOTIFY ' если сообщение от Common Control'а
scope
    dim tw as NM_TREEVIEW ptr ' указатель на структуру
tw = cPtr(NM_TREEVIEW ptr,lparam)
if tw->hdr.code = TVN_BEGINDRAG then ' если начали перетаскивание
hDragImageList = SendMessage _ ' пошлем сообщение
(hwndTreeView, _ ' хэндл Tree View
TVM_CREATEDRAGIMAGE, _ ' ' создать drag изображение
0, _
cPtr(LPARAM,tw->itemNew.hItem))
ImageList_BeginDrag _ ' установим горячую точку
(cPtr(HIMAGELIST,hDragImageList), _ ' хэндл драг-изображения
0,0,0)
ImageList_DragEnter _ ' перетаскиваем изображение
(hwndTreeView, _ ' хэндл Tree View
tw->ptDrag.x, _
tw->ptDrag.y)
SetCapture(hWnd) ' перехватываем мышь
DragMode = TRUE ' установим флаг Drag режима в TRUE
end if
end scope
end select
function = DefWindowProc(hWnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function


'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _  'указатель на командную строку
byval iCmdShow as integer ) as integer  ' состояние окна при первом появлении

dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG  ' структура сообщений
dim hWnd as HWND ' хэндл окна

 'структура класса окна wc
 ' заполняем структуру wc
wc.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
wc.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
wc.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
wc.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
wc.cbWndExtra = NULL
wc.hInstance = hInst  ' хэндл модуля
wc.hbrBackground = cast(HGDIOBJ, COLOR_ApPWORKSPACE) ' Цвет фона
wc.lpszMenuName = NULL ' Хэндл меню
wc.lpszClassName = @ClassName ' класс окна
wc.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
wc.hIconSm = wc.hIcon 'Хэндл маленькой иконки
wc.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора


' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(WS_EX_CLIENTEDGE, _ ' дополнительные стили
@ClassName, _ ' указатель на строку с именем класса окна
@AppName, _ ' указатель на строку с именем окна
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
200, _ ' ширина окна
400, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

ShowWindow( hwnd,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hwnd) ' обновить клиентскую область

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 37
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Сообщение  electrik в Вт Июн 30, 2009 6:26 pm

Win32 API. Урок 19. Tree View Control - продолжение

Анализ:

Внутри обработчика WM_CREATE вы создаете контрол tree view.

hwndTreeView = CreateWindowEx _
(NULL, _
TreeViewClass, _
NULL, _
WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT, _
0, _
0, _
200, _
400, _
hWnd, _
NULL, _
hModule, _
NULL)

Обратите внимание на стили. TVS_xxxx - это стили, присущие tree view.

hImageList = ImageList_Create _
(16, _
16, _
ILC_COLOR16, _
2, _
10)
hBitmap = LoadBitmap _ ' загрузим Bitmap(hModule, _ ' хэндл программы
cptr(LPCSTR,IDB_TREE))
ImageList_Add _
(hImageList, _
hBitmap, _
NULL)
DeleteObject _
(hBitmap)
SendMessage _
(hwndTreeView, _
TVM_SETIMAGELIST, _
0, _
cptr(LPARAM,hImageList))

Затем вы создаете пустой image list, который будет принимать изображения размером 16x16 пикселей и с глубиной цвета 16 бит. Вначале он будет содержать 2 изображения, но будет расширен до 10, если это потребуется. Далее мы загружаем bitmap из ресурса и добавляем его в только что созданный image list. После этого мы удаляем хэндл битмапа, так как он больше нам не нужен. Как только image list готов, мы ассоциируем его с tree view, посылая ему TVM_SETIMAGELIST.

tvinsert.hparent = NULL
tvinsert.hInsertAfter = TVI_ROOT
tvinsert.item.mask = TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
tvinsert.item.pszText = @parent
tvinsert.item.iImage = 0
tvinsert.item.iSelectedImage = 1
hParent = SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cPtr(LPARAM,@tvinsert))

Мы вставляем элементы в контрол tree view, начиная с корневого элемента. Так как это будет корневой item, параметр hparent равен NULL, а hInsertAfter - TVI_ROOT. mask указывает, что pszText, iImage и iSelectedImage структуры TV_ITEM верны. Мы заполняем эти три параметра соответствующими значениями. pszText содержит название корневого элемента, iImage - это индекс изображения в image list'е, который будет отображаться слева от невыбранного элемента, а iSelectedImage - индекс изображения выбранного элемента. Когда все требуемые параметры заполнены, мы посылаем сообщение TVM_INSERTITEM контролу tree view, чтобы добавить в него корневой элемент.

tvinsert.hparent = cPtr(HTREEITEM,hParent)
tvinsert.hInsertAfter = TVI_LAST
tvinsert.item.pszText = @Child1
SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cPtr(LPARAM,@tvinsert))
tvinsert.item.pszText = @Child2
SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cptr(LPARAM,@tvinsert))

После этого мы добавляем дочерние элементы. hparent теперь заполнен хэндлом родительского элемента. Мы будем использовать те же изображения, поэтому не меняем iImage и iSelectedImage.

case WM_NOTIFY
scope
dim tw as NM_TREEVIEW ptr
tw = cPtr(NM_TREEVIEW ptr,lparam)
if tw->hdr.code = TVN_BEGINDRAG then
hDragImageList = SendMessage _
(hwndTreeView, _ ' хэндл Tree View
TVM_CREATEDRAGIMAGE, _ '
0, _
cPtr(LPARAM,tw->itemNew.hItem))
ImageList_BeginDrag _
(cPtr(HIMAGELIST,hDragImageList), _
0,0,0)
ImageList_DragEnter _
(hwndTreeView, _
tw->ptDrag.x, _
tw->ptDrag.y)
SetCapture(hWnd)
DragMode = TRUE
end if
end scope

Теперь, когда юзер попытается перетащить item, tree view пошлет сообщение WM_NOTIFY с кодом TVN_BEGINDRAG. lparam - это указатель на структуру NM_TREEVIEW, которая содержит некоторую информацию, которая необходима нам, поэтому мы помещаем значение lparam в tw и используем tw как указатель на структуру NM_TREEVIEW.
Затем мы создаем drag-изображение, посылая TVM_CREATEDRAGIMAGE tree view. Сообщение возвращает хэндл на созданный image list, внутри которого содержится drag-изображение. Мы вызываем ImageList_BeginDrag, чтобы установить его "горячую точку". После этого начинаем операцию переноса с помощью ImageList_DragEnter. Эта функция отображает drag-изображение в указанном месте заданного окна.

Мы используем структуру ptDrag, которая является членом структуры NM_TREEVIEW в качестве точки, в которой должно быть показано drag-изображение. Затем перехватываем мышь и устанавливаем флаг, который показывает, что мы находимся в drag-режиме.

case WM_MOUSEMOVE
if DragMode = TRUE then
tvhit.pt.x = loword(lparam)
tvhit.pt.y = hiword(lparam)
ImageList_DragMove(loword(lparam),hiword(lparam))
ImageList_DragShowNolock (FALSE)
scope
dim ht as LRESULT
ht = SendMessage _
(hwndTreeView, _
TVM_HITTEST, _
NULL, _
cptr(LPARAM,@tvhit))
if ht <> NULL then
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_DROPHILITE, _
cptr(LPARAM,ht))
end if
end scope
ImageList_DragShowNolock (TRUE)
end if

Теперь мы концентрируемся на WM_MOUSEMOVE. Когда пользователь перетаскивает drag-изображение, наше родительское окно получает сообщения WM_MOUSEMOVE. В ответ на них мы обновляем позицию drag-изображения функцией ImageList_DragMove, после чего проверяем, не находится ли оно над каким-нибудь элементом с помощью сообщения TVM_HITTEST с указанием координаты проверяемой точки. Если drag-изображение находится над каким-либо элементом, тот подсвечивается сообщением TVM_SELECTITEM с флагом TVGN_DROPHILITE. Во время операции подсветки мы прячем drag-изображение, чтобы не было лишних глюков.

case WM_LBUTTONUP
if DragMode = TRUE then
ImageList_DragLeave _
(hwndTreeView)
ImageList_EndDrag()
ImageList_Destroy _
(cPtr(HIMAGELIST,hDragImageList))
scope
dim dd as LRESULT
dd = SendMessage _
(hwndTreeView, _
TVM_GETNEXTITEM, _ '
TVGN_DROPHILITE, _
0)
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_CARET, _
dd)
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_DROPHILITE, _
0)
ReleaseCapture()
DragMode = FALSE
end scope
end if

Когда пользователь отпускает левую кнопку мыши, операция переноса закончена. Мы выходим из drag-режима, последовательно вызывая функции ImageList_DragLeave, ImageList_EndDrag и ImageList_Destroy. Также мы проверяем последний подсвеченный элемент и выбираем его. Мы также должны убрать его подсветку, иначе другие элементы не будут подсвечиваться, когда их будут выбирать. И наконец, мы убираем перехват сообщений от мыши.

[C] Iczelion, пер. Aquila.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 37
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Сообщение  electrik в Вт Июн 30, 2009 6:35 pm

Win32 API. Урок 19. Tree View Control - дополнения

вы можете скачать примеры к 23 урокам
http://www.filehoster.ru/files/da3601
как будет все доделано до конца, выложим уже не на файловый обменник, а на сайт к eric'у.
в этом уроке в ресурсах присудствует иконка, вот она там лежит.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 37
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 19 - Tree View Control

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу

- Похожие темы

 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения