Что нового

Как создать combo-список в GUICtrlCreateListView ?

agikon

Знающий
Сообщения
789
Репутация
17
Подскажите пожалуйста как создать вот такую таблицу с выпадающим комбо списком?
image.jpg
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
За основу можно взять пример с редактируемой ячейкой, где при активации правки появляется поле ввода поверх ListView. Только вместо поля ввода использовать выпадающий список.
 
Автор
A

agikon

Знающий
Сообщения
789
Репутация
17
AZJIO
Вот только заменил в 25 строчке инпут на комбо, и вырезал вторую табличку и от что получилось.

Неполадки:
1)по-умолчанию отображаются просто ячейка, а не комбо
2)если сохранил первую ячейку то следующая ячейка затирает предыдущую
3)элемент комбо по высоте больше чем ячейки

Код:
#include <EditConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <GuiListView.au3>

    $LngTitle = 'Double click the'
    $LngCol = 'Col'

	Opt("GUIOnEventMode", 1)
    Global $aElement[2], $hActive, $iInput
    Global $iListView, $hListView, $iExit, $iSaveChange

	$hGUI = GUICreate($LngTitle, 230, 365)
    GUISetOnEvent(-3, '_Exit')

	$iInput = GUICtrlCreateCombo("", 0, 0, 0, 0)
	GUICtrlSetState(-1, $GUI_HIDE)
	GUICtrlSetData(-1, '1|2|3')

	$iListView = GUICtrlCreateListView($LngCol & ' 1|' & $LngCol & ' 2', 7, 5, 220, 330, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_REPORT, $LVS_SHOWSELALWAYS))
    $hListView = GUICtrlGetHandle(-1)

	 _ListView_Random_Fill($iListView)
	_GUICtrlListView_SetExtendedListViewStyle ($hListView, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)

	$iExit = GUICtrlCreateDummy()
    GUICtrlSetOnEvent(-1, "_Exit")

	Global $AccelKeys[2][2] = [["{ESC}", $iExit],["{ENTER}", $iSaveChange]]
    GUISetAccelerators($AccelKeys)
    GUISetState()
    GUIRegisterMsg(0x4E, "_WM_NOTIFY")
    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; для скрытия поля ввода при потере фокуса.


    While 1
            Sleep(100000)
	WEnd


Func _ListView_Random_Fill($iListView)
            Local $item1, $item2
            For $i = 1 To 20
                    $item1 = Random(10, 99, 1)
                    $item2 = ''
                    For $j = 1 To 9
                            $item2 &= Chr(Random(65, 90, 1)) ; 192, 255 - Ru
                    Next
                    GUICtrlCreateListViewItem($item1 & '|' & $item2, $iListView) ; создаём пункты
            Next
EndFunc







    ; Выводит элемент Input на передний план
    Func _GUICtrlListView_EditItem($hWnd, $iIndex, $iSubItem)
            ;funkey 19.02.2010
            If $iIndex < 0 Then Return
            Local $aPos, $aRect, $iSum = 0
            Local $x, $y, $w, $h
            For $i = 0 To $iSubItem - 1
                    $iSum += _GUICtrlListView_GetColumnWidth($hWnd, $i)
            Next
            $aRect = _GUICtrlListView_GetItemRect($hWnd, $iIndex)
            $aPos = ControlGetPos($hGUI, "", $hWnd)
            $x = $iSum + $aPos[0] + $aRect[0]
            $y = $aPos[1] + $aRect[1]
            $w = _GUICtrlListView_GetColumnWidth($hWnd, $iSubItem)
            $h = $aRect[3] - $aRect[1]
            GUICtrlSetPos($iInput, $x - 1, $y + 1, $w + 1, $h + 1)
            GUICtrlSetData($iInput, _GUICtrlListView_GetItemText($hWnd, $iIndex, $iSubItem))
            GUICtrlSetState($iInput, $GUI_SHOW)
            GUICtrlSetState($iInput, $GUI_FOCUS)
            $aElement[0] = $iIndex
            $aElement[1] = $iSubItem
    EndFunc



    ; Сохранить изменения редактирования пункта
    Func _SaveChange()
            Local $sText = GUICtrlRead($iInput)
            If StringInStr($sText, @CR) Or StringInStr($sText, @LF) Then
                    If StringLeft($sText, 1) <> '"' And StringInStr(StringMid($sText, 2, StringLen($sText) - 2), '"') Then $sText = StringReplace($sText, '"', "'")
                    $sText = '"' & StringReplace($sText, '"', '') & '"'
            EndIf
            _GUICtrlListView_BeginUpdate($hActive)
            _GUICtrlListView_SetItemText($hActive, $aElement[0], $sText, $aElement[1])
            GUICtrlSetState($iInput, $GUI_HIDE)
            _GUICtrlListView_SetColumnWidth($hActive, $aElement[1], -2) ;$LVSCW_AUTOSIZE_USEHEADER
            _GUICtrlListView_EndUpdate($hActive)
            Return $sText ; возвращаем текст, если требуется его использовать после применения
    EndFunc



    Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
            Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
            $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
            $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
            $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
            $iCode = DllStructGetData($tNMHDR, "Code")
            Switch $hWndFrom
;                    Case $hListView, $hListView2
					Case $hListView
                            Switch $iCode
                                    Case $LVN_BEGINSCROLL ; прокрутка ListView
                                            If $hActive Then
                                                    $hActive = 0
                                                    GUICtrlSetState($iInput, $GUI_HIDE)
                                                    GUICtrlSetData($iInput, '') ; Очищаем поле ввода
                                            EndIf
                                    ;#cs
									Case $NM_DBLCLK ; двойной клик - редактируем пункт ListView
                                            Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
                                            $hActive = $hWndFrom
                                            _GUICtrlListView_EditItem($hActive, DllStructGetData($tInfo, "Index"), DllStructGetData($tInfo, "SubItem"))
                                            ; _GUICtrlListView_EnsureVisible($hActive, DllStructGetData($tInfo, "Index"), True)
									;#ce
                            EndSwitch
            EndSwitch
            Return $GUI_RUNDEFMSG
    EndFunc


    Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
            #forceref $hWnd, $iMsg
            Local $iIDFrom, $iCode
            $iIDFrom = BitAND($iwParam, 0xFFFF) ; младшее слово
            $iCode = BitShift($iwParam, 16) ; старшее слово
            Switch $iIDFrom
                    Case $iInput
                            Switch $iCode
                                    Case $EN_KILLFOCUS
                                            GUICtrlSetState($iInput, $GUI_HIDE)
                                            GUICtrlSetData($iInput, '') ; Очищаем поле ввода
                            EndSwitch
            EndSwitch
            Return $GUI_RUNDEFMSG
    EndFunc

    Func _Exit()
            Exit
    EndFunc
 

ivsatel

Продвинутый
Сообщения
319
Репутация
84
agikon

Код:
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

; En
$LngTitle = 'Double click the'
$LngCol = 'Col'

; Ru
; если русская локализация, то русский язык
If @OSLang = 0419 Then
	$LngTitle = 'Двойной клик на элементе'
	$LngCol = 'колонка'
EndIf

Opt("GUIOnEventMode", 1)
Global $aElement[2], $hActive, $iInput
Global $iListView, $hListView, $iExit, $iSaveChange

$hGUI = GUICreate($LngTitle, 230, 365)
GUISetOnEvent(-3, '_Exit')
$iInput = GUICtrlCreateCombo("", 0, 0, 0, 0)
GUICtrlSetOnEvent($iInput, "_SaveChange")
For $i=0 To 50
	GUICtrlSetData($iInput, $i)
Next
GUICtrlSetState(-1, $GUI_HIDE)
$iListView = GUICtrlCreateListView($LngCol & ' 1|' & $LngCol & ' 2', 5, 5, 220, 330, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_REPORT, $LVS_SHOWSELALWAYS))
$hListView = GUICtrlGetHandle(-1)
 _GUICtrlListView_SetExtendedListViewStyle ($hListView, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
_ListView_Random_Fill($iListView)

GUICtrlCreateButton('Button', 10, 340, 70, 25)

$iExit = GUICtrlCreateDummy()
GUICtrlSetOnEvent(-1, "_Exit")
$iSaveChange = GUICtrlCreateDummy()
GUICtrlSetOnEvent($iSaveChange, "_SaveChange")
Global $AccelKeys[2][2] = [["{ESC}", $iExit],["{ENTER}", $iSaveChange]]
GUISetAccelerators($AccelKeys)
GUISetState()
GUIRegisterMsg(0x4E, "_WM_NOTIFY")
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; для скрытия поля ввода при потере фокуса.

While 1
	Sleep(100000)
WEnd

Func _ListView_Random_Fill($iListView)
	Local $item1, $item2
	For $i = 1 To 20
		$item1 = Random(10, 99, 1)
		$item2 = ''
		For $j = 1 To 9
			$item2 &= Chr(Random(65, 90, 1)) ; 192, 255 - Ru
		Next
		GUICtrlCreateListViewItem($item1 & '|' & $item2, $iListView) ; создаём пункты
	Next
EndFunc   ;==>_ListView_Random_Fill

; Выводит элемент Input на передний план
Func _GUICtrlListView_EditItem($hWnd, $iIndex, $iSubItem)
	;funkey 19.02.2010
	If $iIndex < 0 Then Return
	Local $aPos, $aRect, $iSum = 0
	Local $x, $y, $w, $h
	For $i = 0 To $iSubItem - 1
		$iSum += _GUICtrlListView_GetColumnWidth($hWnd, $i)
	Next
	$aRect = _GUICtrlListView_GetItemRect($hWnd, $iIndex)
	$aPos = ControlGetPos($hGUI, "", $hWnd)
	$x = $iSum + $aPos[0] + $aRect[0]
	$y = $aPos[1] + $aRect[1]
	$w = _GUICtrlListView_GetColumnWidth($hWnd, $iSubItem)
	$h = $aRect[3] - $aRect[1]
	GUICtrlSetPos($iInput, $x - 1, $y + 1, $w + 1, $h + 1)
	GUICtrlSetData($iInput, _GUICtrlListView_GetItemText($hWnd, $iIndex, $iSubItem))
	GUICtrlSetState($iInput, $GUI_SHOW)
	GUICtrlSetState($iInput, $GUI_FOCUS)
	$aElement[0] = $iIndex
	$aElement[1] = $iSubItem
EndFunc   ;==>_GUICtrlListView_EditItem

; Сохранить изменения редактирования пункта
Func _SaveChange()
	Local $sText = GUICtrlRead($iInput)
	If StringInStr($sText, @CR) Or StringInStr($sText, @LF) Then
		If StringLeft($sText, 1) <> '"' And StringInStr(StringMid($sText, 2, StringLen($sText) - 2), '"') Then $sText = StringReplace($sText, '"', "'")
		$sText = '"' & StringReplace($sText, '"', '') & '"'
	EndIf
	_GUICtrlListView_BeginUpdate($hActive)
	_GUICtrlListView_SetItemText($hActive, $aElement[0], $sText, $aElement[1])
	GUICtrlSetState($iInput, $GUI_HIDE)
	_GUICtrlListView_SetColumnWidth($hActive, $aElement[1], -2) ;$LVSCW_AUTOSIZE_USEHEADER
	_GUICtrlListView_EndUpdate($hActive)
	Return $sText ; возвращаем текст, если требуется его использовать после применения
EndFunc   ;==>_SaveChange

Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")
	Switch $hWndFrom
		Case $hListView
			Switch $iCode
				Case $LVN_BEGINSCROLL ; прокрутка ListView
					If $hActive Then
						$hActive = 0
						GUICtrlSetState($iInput, $GUI_HIDE)
						GUICtrlSetData($iInput, '') ; Очищаем поле ввода
					EndIf
				Case $NM_DBLCLK ; двойной клик - редактируем пункт ListView
					Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
					$hActive = $hWndFrom
					_GUICtrlListView_EditItem($hActive, DllStructGetData($tInfo, "Index"), DllStructGetData($tInfo, "SubItem"))
					; _GUICtrlListView_EnsureVisible($hActive, DllStructGetData($tInfo, "Index"), True)
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg
	Local $iIDFrom, $iCode
	$iIDFrom = BitAND($iwParam, 0xFFFF) ; младшее слово
	$iCode = BitShift($iwParam, 16) ; старшее слово
	Switch $iIDFrom
		Case $iInput
			Switch $iCode
				Case $EN_KILLFOCUS
					GUICtrlSetState($iInput, $GUI_HIDE)
					GUICtrlSetData($iInput, '') ; Очищаем поле ввода
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

Func _Exit()
	Exit
EndFunc   ;==>_Exit
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
agikon [?]
3)элемент комбо по высоте больше чем ячейки
высота зависит от шрифта. Задать его нельзя, а можно только ширину пунктов ListView увеличить до размера Combo. Создаётся Combo скрытый или за гранью GUI, далее запрашиваешь его высоту, далее полученное значение применяешь к высоте пунктов.
ListView не содержит в себе движок Combo, это можно либо сделать костыль, либо перейти на С++ и использовать сторонний движок ListView, там может даже содержаться TreeView в Combo.
 

ivsatel

Продвинутый
Сообщения
319
Репутация
84
AZJIO [?]
высота зависит от шрифта. Задать его нельзя, а можно только ширину пунктов ListView увеличить до размера Combo

Не очень красиво получается, но получается:

Код:
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <GuiComboBox.au3>

; En
$LngTitle = 'Double click the'
$LngCol = 'Col'

; Ru
; если русская локализация, то русский язык
If @OSLang = 0419 Then
	$LngTitle = 'Двойной клик на элементе'
	$LngCol = 'колонка'
EndIf

Opt("GUIOnEventMode", 1)
Global $aElement[2], $hActive, $iInput
Global $iListView, $hListView, $iExit, $iSaveChange

$hGUI = GUICreate($LngTitle, 230, 365)
GUISetOnEvent(-3, '_Exit')
$iInput = GUICtrlCreateCombo("", -1, -1, -1, 5)
GUICtrlSetOnEvent($iInput, "_SaveChange")
For $i=0 To 50
	GUICtrlSetData($iInput, $i)
Next
GUICtrlSetState(-1, $GUI_HIDE)
$iListView = GUICtrlCreateListView($LngCol & ' 1|' & $LngCol & ' 2', 40, 5, 152, 330, $LVS_SINGLESEL)
$hListView = GUICtrlGetHandle(-1)
 _GUICtrlListView_SetExtendedListViewStyle ($hListView, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)
_ListView_Random_Fill($iListView)

GUICtrlCreateButton('Button', 10, 340, 70, 25)

$iExit = GUICtrlCreateDummy()
GUICtrlSetOnEvent(-1, "_Exit")
$iSaveChange = GUICtrlCreateDummy()
GUICtrlSetOnEvent($iSaveChange, "_SaveChange")
Global $AccelKeys[2][2] = [["{ESC}", $iExit],["{ENTER}", $iSaveChange]]
GUISetAccelerators($AccelKeys)
GUISetState()
GUIRegisterMsg(0x4E, "_WM_NOTIFY")
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") ; для скрытия поля ввода при потере фокуса.

While 1
	Sleep(100000)
WEnd

Func _ListView_Random_Fill($iListView)
	Local $item1, $item2
	For $i = 1 To 20
		$item1 = Random(10, 99, 1)
		$item2 = ''
		For $j = 1 To 9
			$item2 &= Chr(Random(65, 90, 1)) ; 192, 255 - Ru
		Next
		GUICtrlCreateListViewItem($item1 & '|' & $item2, $iListView) ; создаём пункты
	Next
EndFunc   ;==>_ListView_Random_Fill

; Выводит элемент Input на передний план
Func _GUICtrlListView_EditItem($hWnd, $iIndex, $iSubItem)
	;funkey 19.02.2010
	If $iIndex < 0 Then Return
	Local $aPos=0, $aRect=0, $iSum = 0
	Local $x=0, $y=0, $w=0, $h=0
	For $i = 0 To $iSubItem - 1
		$iSum += _GUICtrlListView_GetColumnWidth($hWnd, $i)
	Next
	$aRect = _GUICtrlListView_GetItemRect($hWnd, $iIndex)
	$aPos = ControlGetPos($hGUI, "", $hWnd)
	$x = $iSum + $aPos[0] + $aRect[0]
	$y = $aPos[1] + $aRect[1]
	$w = _GUICtrlListView_GetColumnWidth($hWnd, $iSubItem)
	$h = $aRect[3] - $aRect[1]
	ConsoleWrite($aRect[3]&@LF&$aRect[1]&@LF)
	GUICtrlSetPos($iInput, $x - 1, $y + 1, $w + 1)
	 _GUICtrlComboBox_SetItemHeight($iInput, 10)
	GUICtrlSetData($iInput, _GUICtrlListView_GetItemText($hWnd, $iIndex, $iSubItem))
	GUICtrlSetState($iInput, $GUI_SHOW)
	GUICtrlSetState($iInput, $GUI_FOCUS)
	$aElement[0] = $iIndex
	$aElement[1] = $iSubItem
EndFunc   ;==>_GUICtrlListView_EditItem

; Сохранить изменения редактирования пункта
Func _SaveChange()
	Local $sText = GUICtrlRead($iInput)
	If StringInStr($sText, @CR) Or StringInStr($sText, @LF) Then
		If StringLeft($sText, 1) <> '"' And StringInStr(StringMid($sText, 2, StringLen($sText) - 2), '"') Then $sText = StringReplace($sText, '"', "'")
		$sText = '"' & StringReplace($sText, '"', '') & '"'
	EndIf
	_GUICtrlListView_BeginUpdate($hActive)
	_GUICtrlListView_SetItemText($hActive, $aElement[0], $sText, $aElement[1])
	GUICtrlSetState($iInput, $GUI_HIDE)
	_GUICtrlListView_SetColumnWidth($hActive, $aElement[1], -2) ;$LVSCW_AUTOSIZE_USEHEADER
	_GUICtrlListView_EndUpdate($hActive)
	Return $sText ; возвращаем текст, если требуется его использовать после применения
EndFunc   ;==>_SaveChange

Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR
	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")
	Switch $hWndFrom
		Case $hListView
			Switch $iCode
				Case $LVN_BEGINSCROLL ; прокрутка ListView
					If $hActive Then
						$hActive = 0
						GUICtrlSetState($iInput, $GUI_HIDE)
						GUICtrlSetData($iInput, '') ; Очищаем поле ввода
					EndIf
				Case $NM_DBLCLK ; двойной клик - редактируем пункт ListView
					Local $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
					$hActive = $hWndFrom
					_GUICtrlListView_EditItem($hActive, DllStructGetData($tInfo, "Index"), DllStructGetData($tInfo, "SubItem"))
					; _GUICtrlListView_EnsureVisible($hActive, DllStructGetData($tInfo, "Index"), True)
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY

Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg
	Local $iIDFrom, $iCode
	$iIDFrom = BitAND($iwParam, 0xFFFF) ; младшее слово
	$iCode = BitShift($iwParam, 16) ; старшее слово
	Switch $iIDFrom
		Case $iInput
			Switch $iCode
				Case $EN_KILLFOCUS
					GUICtrlSetState($iInput, $GUI_HIDE)
					GUICtrlSetData($iInput, '') ; Очищаем поле ввода
			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

Func _Exit()
	Exit
EndFunc   ;==>_Exit
 
Автор
A

agikon

Знающий
Сообщения
789
Репутация
17
AZJIO
Ясно, та и то что есть нормально пройдёт.

ivsatel
Спасибо за корректировку, мне так кажется что очень красиво даже получилось.
 

AZJIO

Меценат
Меценат
Сообщения
2,879
Репутация
1,194
ivsatel
Ну тогда размеры точнее подогнать чтобы вписывался до краёв.

1. Ещё сделать проверку, чтобы пункт не был частично видим. Получить координаты прямоугольника пункта и проверить что он в пределах клиентской области.
2. Можно провоцировать открытие по одиночному клику, а обновлять данные если был сделан выбор. Первый клик показывает Combo, второй раскрывает его (со стилем не редактируемого). Или двойной клик показывает Combo и сразу раскрывает его (_GUICtrlComboBox_ShowDropDown). А то вязкий интерфейс сейчас.
 
Верх