Author Topic: Treeview find by lParam?  (Read 675 times)

2B||!2B

  • Member
  • **
  • Posts: 61
Treeview find by lParam?
« on: June 28, 2019, 04:29:59 PM »
Hi,

Is there any way to find a treeview item (parent) by its lParam? just like Listview.
Or must iterate through all parents to find the item?

jj2007

  • Member
  • *****
  • Posts: 9744
  • Assembler is fun ;-)
    • MasmBasic
Re: Treeview find by lParam?
« Reply #1 on: June 28, 2019, 05:22:33 PM »
Have you tried something like this, in a WM_NOTIFY event?
Code: [Select]
.if NotifyID==MyTree && NotifyCode==TVN_SELCHANGEDW
mov edx, lParam_
mov eax, [edx.NMHDR.hwndFrom]
push eax
mov tvItem.hItem, rv(SendMessageW, eax, TVM_GETNEXTITEM, TVGN_CARET, 0) ; last="handle to an item"
m2m tvItem._mask, TVIF_TEXT or TVIF_HANDLE ; use handle, receive text
lea eax, buffer
mov tvItem.pszText, eax
m2m tvItem.cchTextMax, 100
pop ecx
invoke SendMessage, ecx, TVM_GETITEM, TVGN_CARET, addr tvItem
print tvItem.pszText
; deb 4, "GetItem", eax, $Err$(), $$tvItem.pszText ; MyTree, NotifyCode, NotifyHandle
.endif 

2B||!2B

  • Member
  • **
  • Posts: 61
Re: Treeview find by lParam?
« Reply #2 on: June 28, 2019, 06:10:05 PM »
Hi Jochen,

Thanks for the reply.
But i do not want to look for a selected item. Just a simple find by lParam like Listview. I think it is not possible since there is no TVM_FINDITEM message.

jj2007

  • Member
  • *****
  • Posts: 9744
  • Assembler is fun ;-)
    • MasmBasic
Re: Treeview find by lParam?
« Reply #3 on: June 28, 2019, 07:55:55 PM »
You want to find what, a string? At a certain point, you put text into the treeview, so you have an array of strings, I suppose, that you could search. What exactly is your goal here?

fearless

  • Member
  • ***
  • Posts: 468
    • LetTheLightIn
Re: Treeview find by lParam?
« Reply #4 on: June 28, 2019, 07:58:37 PM »
I created a TreeViewFindItem function to search for text in a treeview, but could be adapted to look for other stuff I guess:
https://github.com/mrfearless/libraries/blob/master/Treeview/Treeview%20x86/TreeViewFindItem.asm

I use that in the cjsontree to search for a treeview item for text that is entered in the find textbox: https://github.com/mrfearless/cjsontree/blob/master/search.asm#L340
fearless

CM690II Case, HX1000 PSU, Asus Z97, Intel i7-4790K, Seidon 120v Cooler, 16GB DDR3, MSI GTX 980TI

My Github  Twitter

2B||!2B

  • Member
  • **
  • Posts: 61
Re: Treeview find by lParam?
« Reply #5 on: June 28, 2019, 08:17:20 PM »
You want to find what, a string? At a certain point, you put text into the treeview, so you have an array of strings, I suppose, that you could search. What exactly is your goal here?

Finding an item by iterating through all treeview items is not ideal. It is slow when dealing with many items. Instead, you use item's lParam to find the index that has that lParam associated with it like LVM_FINDITEM(LVFI_PARAM set on LVFINDINFO structure) on listview.

I created a TreeViewFindItem function to search for text in a treeview, but could be adapted to look for other stuff I guess:
https://github.com/mrfearless/libraries/blob/master/Treeview/Treeview%20x86/TreeViewFindItem.asm

I use that in the cjsontree to search for a treeview item for text that is entered in the find textbox: https://github.com/mrfearless/cjsontree/blob/master/search.asm#L340

Thanks fearless.
Unfortunately, there is no treeview message to find an item by its lParam value.
Will just have to adapt to this fact and use the string compare method.

fearless

  • Member
  • ***
  • Posts: 468
    • LetTheLightIn
Re: Treeview find by lParam?
« Reply #6 on: June 28, 2019, 09:26:07 PM »
I think the only way is to make an array, and every time you insert a treeview item you add to the array and record the lParam in the array along with the hItem. Then for searching, you only need to search the array table comparing the dword for lParam, once found return the hItem of the treeview item.

Im guessing internally the listview does some search through an array rather than iterate every hListitem
Could also expand the array idea to handle different hTreeview, first matching the treeview handle, then searching it's item array:

Code: [Select]
TVFIND STRUCT
  hTreeview DD ?
  dwItemCount DD ?
  lParamArray DD ? ; point to array of TVFITEM's x dwItemCount
TVFIND ENDS

TVFITEM STRUCT
  lParam DD ?
  hItem DD ?
TVFITEM ENDS
fearless

CM690II Case, HX1000 PSU, Asus Z97, Intel i7-4790K, Seidon 120v Cooler, 16GB DDR3, MSI GTX 980TI

My Github  Twitter

jj2007

  • Member
  • *****
  • Posts: 9744
  • Assembler is fun ;-)
    • MasmBasic
Re: Treeview find by lParam?
« Reply #7 on: June 28, 2019, 10:57:35 PM »
Finding an item by iterating through all treeview items is not ideal. It is slow when dealing with many items.

Sure, it's slow:

include \masm32\MasmBasic\MasmBasic.inc         ; download
include ArrayFind.inc   ; see attachment
  Init
  PrintCpu 0
  Recall "Bible.txt", bible$()
  NanoTimer()
  Print Str$("The string is at index %i", ArrayFind(bible$(id), "He which testifieth these things saith"))      ; one of the last lines in Bible.txt
  PrintLine CrLf$, NanoTimer$(), " for finding the string"
EndOfCode


Code: [Select]
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz
The string is at index 33975
6536 µs for finding the string

Six milliseconds for a 4 MB text file (or 1.5 ms with the FAST version of Instr_()).

Do what fearless wrote, and what I tried to convey further up: Grab the index while you are adding text to your treeview.

2B||!2B

  • Member
  • **
  • Posts: 61
Re: Treeview find by lParam?
« Reply #8 on: June 29, 2019, 02:07:26 PM »
Nice example there Jochen. It is very fast method.

Edit: Thanks guys i have it working now.

Jochen.
Does your Masmbasic have a function similar to wInStr(unicode) but from right to left instead of left to right?
I couldn't find it in Masmbasic reference.
Or maybe is it wRinstr?

jj2007

  • Member
  • *****
  • Posts: 9744
  • Assembler is fun ;-)
    • MasmBasic
Re: Treeview find by lParam?
« Reply #9 on: June 29, 2019, 07:08:44 PM »
wRinstr is available but only as wRinstr(src, pattern) with a one-byte pattern (e.g. "\")

Yes indeed. No idea why I never implemented that properly, probably because I never needed it :badgrin:

There is a workaround:

include \masm32\MasmBasic\MasmBasic.inc
  Init
  wLet esi=wRec$("This is a Unicode string: текст текст текст текст etc etc")
  Print Str$("The first occurrence of текст is at position %i\n", Instr_(Utf8$(esi), "текст"))
  Inkey Str$("The last occurrence of текст is at position  %i", Rinstr(Utf8$(esi), "текст"))
EndOfCode


Code: [Select]
The first occurrence of текст is at position 27
The last occurrence of текст is at position  60

It works, somehow, but the position of текст returned is in bytes, not Utf8 chars. No problem if you just want to extract a part of the string, though. What do you need it for?

TimoVJL

  • Member
  • ***
  • Posts: 475
Re: Treeview find by lParam?
« Reply #10 on: June 29, 2019, 07:14:57 PM »
Maybe making a hash value from string to lParam while inserting to tree is a good idea ?
Reading LPARAM is only about 2 times faster ?
« Last Edit: June 29, 2019, 09:16:37 PM by TimoVJL »
May the source be with you

2B||!2B

  • Member
  • **
  • Posts: 61
Re: Treeview find by lParam?
« Reply #11 on: July 01, 2019, 06:06:18 AM »
Thanks Jochen.
I was needing it to get file extension but i later used a windows API PathFindExtensionW.
It's always difficult for me to get the function i need from Masmbasic due to the poor documentation  :sad:
« Last Edit: July 01, 2019, 11:59:26 AM by 2B||!2B »

jj2007

  • Member
  • *****
  • Posts: 9744
  • Assembler is fun ;-)
    • MasmBasic
Re: Treeview find by lParam?
« Reply #12 on: July 01, 2019, 10:56:57 AM »
Since thousands of coders stumble over this problem sooner or later, you have a chance to google the solution if a Windows API exists. But MasmBasic does have a solution, too:

include \masm32\MasmBasic\MasmBasic.inc
  Init

  ; version A, Unicode as Utf-8 strings:
  Let esi="Имя файла Доброе утро.текст"
  Let edi=Mid$(esi, Rinstr(esi, ".")+1)         ; the +1 is not possible with wRinstr()
  PrintLine "The extension is [", edi, "]  excluding the dot"

  ; version B, Unicode as wide strings:
  wLet esi=wRec$("Имя файла Доброе утро.текст")
  wLet edi=wMid$(esi, wRinstr(esi, "."))
  wPrintLine "The extension is [", edi, "] including the dot"

  ; version C, Unicode as wide strings:
  wLet esi=wRec$("Имя файла Доброе утро.текст")
  mov ecx, wLen(esi)
  .Repeat
        dec ecx
  .Until word ptr [esi+2*ecx]=="."
  lea ecx, [2*ecx+esi+2]
  wInkey "The extension is [", ecx, "]  excluding the dot"

EndOfCode


Code: [Select]
The extension is [текст]  excluding the dot
The extension is [.текст] including the dot
The extension is [текст]  excluding the dot

wRinstr is available but only as wRinstr(src, pattern) with a one-byte pattern (e.g. "\")

And the dot is a one-byte pattern, too :thumbsup: