Что нового

[Элементы GUI] ListBox с иконками... Можно?

sss

Продвинутый
Сообщения
332
Репутация
96
Доброго времени суток всем! Можно ли добавить к пунктам ListBox'a иконки? Каждой строке свой? И если можно то как? Рыл мануал по UDF - GuiCtrlListBox - ничего нет...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Вот пример:

Код:
#include <Constants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <GUIListBox.au3>
#include <GUIImageList.au3>

; Example by rasim
; modified by [email protected] / MsCreatoR (Index storing issue, UDF merge, and tidy source :) )

Global Const $ODT_LISTBOX = 2
Global Const $ODA_DRAWENTIRE = 0x1
Global Const $ODA_SELECT = 0x2
Global Const $ODS_SELECTED = 0x1

$hGUI = GUICreate("ListBox with images - Demo!", 300, 200)

$hListBoxIMGList = _GUIImageList_Create(16, 16, 5, 1, 4, 90)
_GUIImageList_SetBkColor($hListBoxIMGList, $CLR_NONE)

GUIRegisterMsg($WM_MEASUREITEM, "WM_MEASUREITEM")

$ListBox = GUICtrlCreateList("", 10, 10, 280, 180, BitOR($LBS_HASSTRINGS, $LBS_OWNERDRAWFIXED, $WS_VSCROLL))
$hListBox = GUICtrlGetHandle($ListBox)

For $i = 1 To 10
	_GUICtrlListBox_AddStringEx($ListBox, "String " & $i, $hListBoxIMGList, @SystemDir & "\shell32.dll", $i)
Next

GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

GUISetState()

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func _GUICtrlListBox_AddStringEx($hWnd, $sText, $hImageList = 0, $sIconFile = "", $iIndex = 0)
	If $hImageList = 0 Then
		Return _GUICtrlListBox_AddString($hWnd, $sText)
	Else
		Local $iIconIDX = _GUIImageList_AddIcon($hImageList, $sIconFile, $iIndex, 0)
		Local $iStrIndex = _GUICtrlListBox_AddString($hWnd, $sText)
		_GUICtrlListBox_SetItemData($hWnd, $iStrIndex, $iIconIDX)
		
		Return $iStrIndex
	EndIf
EndFunc

Func WM_MEASUREITEM($hWnd, $Msg, $wParam, $lParam)
	Local $CtlType, $tagMEASUREITEMSTRUCT = "UINT CtlType;UINT CtlID;UINT itemID;UINT itemWidth;UINT itemHeight;ULONG_PTR itemData;"
	Local $MEASUREITEMSTRUCT = DllStructCreate($tagMEASUREITEMSTRUCT, $lParam)
	
	$CtlType = DllStructGetData($MEASUREITEMSTRUCT, "CtlType")
	If $CtlType <> $ODT_LISTBOX Then Return $GUI_RUNDEFMSG
	
	DllStructSetData($MEASUREITEMSTRUCT, 5, 18)
	DllStructSetData($MEASUREITEMSTRUCT, 4, DllStructGetData($MEASUREITEMSTRUCT, 4) + 18)
	
	Return
EndFunc

Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
	Local $tagDRAWITEMSTRUCT, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $iBrushColor, $hBrush, $hBrushOld
	
	$tagDRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _
			"hwnd hItm;hwnd hDC;int itmRect[4];dword itmData", $lParam)
	If DllStructGetData($tagDRAWITEMSTRUCT, "cType") <> $ODT_LISTBOX Then Return $GUI_RUNDEFMSG
	
	$cID = DllStructGetData($tagDRAWITEMSTRUCT, "cID")
	$itmID = DllStructGetData($tagDRAWITEMSTRUCT, "itmID")
	$itmAction = DllStructGetData($tagDRAWITEMSTRUCT, "itmAction")
	$itmState = DllStructGetData($tagDRAWITEMSTRUCT, "itmState")
	$hItm = DllStructGetData($tagDRAWITEMSTRUCT, "hItm")
	$hDC = DllStructGetData($tagDRAWITEMSTRUCT, "hDC")
	
	Switch $itmAction
		Case $ODA_DRAWENTIRE, $ODA_SELECT
			If $itmState = $ODS_SELECTED Then
				$iBrushColor = 0x6495ED
			Else
				$iBrushColor = 0x66CDAA
			EndIf
			
			$hBrush = _WinAPI_CreateSolidBrush($iBrushColor)
			$hBrushOld = _WinAPI_SelectObject($hDC, $hBrush)

			DllCall("user32.dll", "int", "FillRect", _
					"hwnd", $hDC, _
					"ptr", DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), _
					"hwnd", $hBrush)
			
			_WinAPI_SelectObject($hDC, $hBrushOld)
			_WinAPI_DeleteObject($hBrush)
			
			DllCall("gdi32.dll", "int", "SetBkMode", "hwnd", $hDC, "int", 1)
			
			Local $tBuffer = DllStructCreate("char[256]")
			DllCall("user32.dll", "int", "SendMessage", _
					"hwnd", $hItm, _
					"int", $LB_GETTEXT, _
					"int", $itmID, _
					"ptr", DllStructGetPtr($tBuffer))
			
			Local $itmText = DllStructGetData($tBuffer, 1)
			Local $itmTextIMG = _GUICtrlListBox_GetItemData($hListBox, $itmID)
			
			Local $tRECT = DllStructCreate("int Left;int Top;int Right;int Bottom")
			DllStructSetData($tRECT, "Left", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1) + 18)
			DllStructSetData($tRECT, "Top", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 2))
			DllStructSetData($tRECT, "Right", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 3))
			DllStructSetData($tRECT, "Bottom", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 4))
			
			DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $itmText, "int", StringLen($itmText), _
					"ptr", DllStructGetPtr($tRECT), "int", $DT_LEFT)
			
			Local $iX = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1) + 1
			Local $iY = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 2) + 1
			Local $fIsSelected = ($itmState = $ODS_SELECTED) * 2
			
			If $itmTextIMG >= 0 Then _GUIImageList_Draw($hListBoxIMGList, $itmTextIMG, $hDC, $iX, $iY, BitOR(1, $fIsSelected))
	EndSwitch
	
	Return $GUI_RUNDEFMSG
EndFunc
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Не мучайтесь, используйте ListView.
 
Автор
sss

sss

Продвинутый
Сообщения
332
Репутация
96
Yashied
Спасибо за совет, но с ListView вообще не сталкивался. Обязательно посмотрю, изучу, но все-таки есть интерес именно к ListBox, изучил чуть больше половины UDF да и к тому же к условиям он больше подходит. Да и вообще - легкие пути - неинтересные :smile:
CreatoR
А можно поподробнее про функции WM_DRAWITEM и WM_MEASUREITEM? Честно говоря, ничего не понял кроме того где пути к иконкам создавать... А как настроить задний фон? А цвет выделения? Очень заинтересовало... Если Вы добавить к Вашему примеру комментарии, я буду очень рад!
UPD: нашел методом тыка где цвет, классно, настроил под себя, все работает... Но про функции так и не понял...
_GuiCtrlListBox_AddStringEx - спасибо, супер! Намного проще.
 
Автор
sss

sss

Продвинутый
Сообщения
332
Репутация
96
Какая-то странная ошибка - попытался засунуть код из примера в свою программу. Ошибка №1 - цвет выделения - прозрачный, хотя он не такой. С фоном проблем нет. ошибка №2 - последняя строка (наполнение происходит функцией) сначала получает неправильную иконку, но когда на нее встаешь, иконка меняется на нормальную. Как это можно побороть? Код - FTP Client, хочу чтобы там красиво отображались папки и файлы. Исходник прилагаю.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Sky-WaLkeR [?]
можно поподробнее про функции WM_DRAWITEM и WM_MEASUREITEM
Первая это сообщение отрисовки пунктов в ListBox, вторая это измерение пунктов.

[?]
Какая-то странная ошибка
Не нужно выделять всё красным, оно и без этого видно.
У меня прикреплённый файл выдаёт ошибку «can't open include file <myFTPEx.au3>».
 
Автор
sss

sss

Продвинутый
Сообщения
332
Репутация
96
Сотри my из инклюды, я там просто русский язык сделал...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Sky-WaLkeR
Добавь в константы:
Код:
Global Const $ODS_NOACCEL = 0x100
Global Const $ODS_NOFOCUSRECT = 0x200


А в WM_DRAWITEM замени:
Код:
If $itmState = $ODS_SELECTED Then

на:
Код:
If $itmState = $ODS_SELECTED Or $itmState = BitOR($ODS_SELECTED, $ODS_NOACCEL, $ODS_NOFOCUSRECT) Then
 
Автор
sss

sss

Продвинутый
Сообщения
332
Репутация
96
CreatoR
Спасибо большое! Выделение появилось. Но иногда бывают ошибки с иконками - на файл ставится иконка папки. Когда выделение на ней, все прорисовывается правильно. Как это исправить?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Sky-WaLkeR [?]
иногда бывают ошибки с иконками
Я бы на твоём месте не мучался и послушал совета Yashied, ListView тут намного удобнее в использований.
 
Верх