проблема с редактированием в Treeview

  • Автор темы yxoglyxo
  • Дата начала
Y

yxoglyxo

#1
Всем привет!
Имеется TreeView на форме типа:

-RootNodeText

----------Node11Text

---------------Node12Text

------------------Node13Text: 10

-RootNodeText

----------Node21Text

---------------Node22Text

------------------Node23Text: 20

etc


при щелкании мышкой по Node13Text или Node23Text нужно их отредактировать (использую StartLabelEdit). Загвоздка тут вот в чем:
текст должен редактироваться РЯДОМ с текстом Node13Text, т.е. щелкаю мышкой по Node13Text и в режим редактирования переходия не сам
текст Node13Text, а пространство рядом с ним - там где на схеме цифра 10 (или 20), чтобы фактически редактировать цифры рядом с выбранным Node'ом, оставляя название нетронутым... Ух, лучше бы раз показать чем вслепую объяснять.

Зараннее благодарна любым советам и просто мыслям вслух :(
 
T

Tanya

#2
Наверняка, существует несколько возможностей реализации такой задачи. Например:
1) Создать (нарисовать) на форме TextBox. сделать его по умолчани невидимым, затем в нужный момент определить расположение SelectedNode и в нем требуемый текст и не запускать StartEditLabel, а расположить по известным уже координатам TextBox, внести в тего требуемый текст и сделать его видимым. По окончании ввода в SelectedItem записывать фиксированную + введенное значение

Плюс: отдельная обработка числового значения
Минус: а бог его знает, как это делается ))), то есть приблизительно понятно, что от API не уйти, но сложность с определением выделенного Node, а так бы этот вариант был бы лучше следующего )))

2) Запустить StartEditLabel, определить хендл окна редактирования, перехватывать сообщения к этому окну и обрабатывать так как нужно по задаче.
Плюсы: а) не нужно искать SelectedNode
б) лично я знаю как это делается ))))
Минусы: а) API! Замена процедуры окна - вещь деликатная!
б) при обработке сообщение окну редактирования могут быть всякие неточности ... нонет предела совершенству, возможно ты сможешь устранить все эти баги.

Итак, вариант 2! )))
Потребуется: модуль формы и стандартный модуль
В модуле формы Form1:
Код:
Option Explicit

Private Sub Form_Load()
With Me.TreeView1
'Просто заполняем тривью
.Nodes.Add(, , "R1", "RootNodeText").Expanded = True
.Nodes.Add("R1", tvwChild, "R2", "Node11Text").Expanded = True
.Nodes.Add("R2", tvwChild, "R3", "Node12Text").Expanded = True
.Nodes.Add("R2", tvwChild, "R4", "Node13Text: 10").Expanded = True
.Nodes.Add(, , "R5", "RootNodeText").Expanded = True
.Nodes.Add("R5", tvwChild, "R6", "Node21Text").Expanded = True
.Nodes.Add("R6", tvwChild, "R7", "Node22Text").Expanded = True
.Nodes.Add("R6", tvwChild, "R8", "Node23Text: 20").Expanded = True
End With
End Sub

Private Sub TreeView1_AfterLabelEdit(Cancel As Integer, NewString As String)
'на всякий случай после редактирования устанавливаем процедуру обработки по умолчанию
If hProcEditOld<>0 Then
Call SetWindowLong(hEdit, GWL_WNDPROC, hProcEditOld)
hProcEditOld=0
End If

End Sub

Private Sub TreeView1_DblClick()

Dim i As Integer

With Me.TreeView1
If Not .SelectedItem Is Nothing Then

i = InStr(1, .SelectedItem.Text, ": ")

'В примере - признак редактирования Node символы двоеточие+пробел 
If i > 0 Then
iStart = i + 1

.StartLabelEdit

'Определяем хендл окна редактирования
hEdit = SendMessage(.hWnd, &H110F, 0, 0)

'Заменяем стандартную процедуру обработки, на свою
hProcEditOld = SetWindowLong(hEdit, GWL_WNDPROC, AddressOf [b]SubWndProcEdit[/b])

'Выделяем в поле весь текст после двоеточие + пробел
SendMessage hEdit, EM_SETSEL, iStart, Len(.SelectedItem.Text)

End If
End If
End With
В стандартном модуле Module1
Код:
Option Explicit

Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, _
ByVal hWnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long

Public Const GWL_WNDPROC = (-4)

Public Const WM_CHAR = &H102
Public Const WM_KEYUP = &H101
Public Const WM_KEYDOWN = &H100
Public Const WM_LBUTTONUP = &H202


Public Const EM_SETSEL = &HB1
Public Const EM_GETSEL = &HB0

Public Const VK_END = &H23
Public Const VK_BACK = &H8
Public Const VK_DELETE = &H2E
Public Const VK_ESCAPE = &H1B
Public Const VK_HOME = &H24
Public Const VK_RETURN = &HD
Public Const VK_RIGHT = &H27
Public Const VK_LEFT = &H25
Public Const VK_UP = &H26
Public Const VK_DOWN = &H28

Public hProcEditOld As Long
Public hEdit As Long
Public iStart As Long
'

'своя процедура обработки сообщение окну редактирования
Public Function SubWndProcEdit(ByVal hWnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long

On Error Resume Next

Dim bln As Boolean 'флаг, который если Истина, показывает, что нужно запускать обработку сообщения стандартной процедурой
Dim i1 As Long, i2 As Long

bln = False

Select Case uMsg
Case WM_CHAR 'был введен символ, мы допускаем ввод только цифр
If wParam < &H30 Or wParam > &H39 Then
bln = False
Else
bln = True 'вот они цифры! )))
End If

Case WM_KEYDOWN, WM_KEYUP
Select Case wParam
Case VK_HOME
'не позволим перемещаться за пределы редактируемого текста
bln = False
'Тут тоже не совсем верно работает, выделяется весь редактируемый текст, вместо простого перемещения курсора
SendMessage hEdit, EM_SETSEL, iStart, iStart
SubWndProcEdit = True

Case VK_LEFT, VK_BACK, VK_UP
'строго говоря BackSpace не работает, это относится к минусам )))
'проверяем текущее положение курсора
i1 = SendMessage(hEdit, EM_GETSEL, 0, i2) Mod (2 ^ 8)

'здесь попытка предотвратить перемещения курсора в нередактируемый текст
If i1 = iStart And i1 = i2 Then
bln = False

ElseIf (i1 <= iStart And i1 <> i2) Then
bln = False

Else
bln = True
End If

Case VK_END, VK_RIGHT, VK_DOWN, VK_DELETE, VK_ESCAPE, VK_RETURN
bln = True' эти клавиши обрабатываются как обычно

Case Else

'мы допускаем ввод только цифр
If wParam < &H30 Or wParam > &H39 Then
bln = False
Else
bln = True
End If

End Select

Case WM_LBUTTONUP
'здесь мы не знаем, где кликнули, вернее знаем, но не заморачиваемся: позволяем выполниться процедуре по умолчанию
SubWndProcEdit = CallWindowProc(hProcEditOld, hEdit, uMsg, wParam, lParam)

'и затем проверяем новое положение курсора, если в нередактируемом тексте - возврат к редактируемому 
i1 = SendMessage(hEdit, EM_GETSEL, 0, i2) Mod (2 ^ 8)

If i1 <= iStart Then
bln = False

SendMessage hEdit, EM_SETSEL, iStart, iStart
End If

bln = False
Case Else
bln = True
'все остальные сообщения обрабатываются стандартно 

End Select

'обязательно нужно вернуть значение
If bln Then
SubWndProcEdit = CallWindowProc(hProcEditOld, hEdit, uMsg, wParam, lParam)
Else
SubWndProcEdit = True
End If

End Function