Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
SysTreeView32 show folder contents and QM folder contents
#1
- Could you provide an example of how to display "$windows$" in a Systreeview
- And an example of how to display a QM folder in the Systreeview

Is it possible to collapse everything? And is it possible to enforce one item to be expanded at all times?
(I could not find "TVM_COLLAPSE", only expand.)

This is the first time for me working with Tree items, I looked in the Archive folder and forum.
#2
Function SelectFileDialogWithTreeview
Code:
Copy      Help
;/test SelectFileDialogWithTreeview
;\Dialog_Editor
function! str&sSelectedFile [$initFolder] [hwndOwner]

;Shows a dialog with a treeview control that displays a file folder.
;The user can expand subfolders and select a file or folder.
;On OK stores full path of the selected file or folder in sSelectedFile and returns 1. On Cancel returns 0.
;Similar to OpenSaveDialog.

;EXAMPLE
;str s
;if SelectFileDialogWithTreeview(s "C:")
,;out s


if(empty(initFolder)) initFolder="$documents$"
str _sInitF; _sInitF.expandpath(initFolder); _sInitF.rtrim("\"); initFolder=_sInitF
ARRAY(str) a ;;full paths of all displayed files; treeview lparam is its element index
;__ImageList il=ImageList_Create(16  ;;maybe later

str dd=
;BEGIN DIALOG
;1 "" 0x90C80AC8 0x0 0 0 224 280 "SelectFileDialogWithTreeview"
;3 SysTreeView32 0x54030823 0x0 0 0 224 256 ""
;1 Button 0x54030001 0x4 116 260 48 14 "OK"
;2 Button 0x54030000 0x4 168 260 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040201 "*" "" "" ""

if(!ShowDialog(dd &sub.DlgProc 0 hwndOwner)) ret
ret 1


#sub DlgProc v
function# hDlg message wParam lParam

int i htv htvi
sel message
,case WM_INITDIALOG
,;add initFolder to the treeview and expand; we'll catch TVN_ITEMEXPANDINGW and add children
,htv=id(3 hDlg)
,htvi=sub.TvAdd(htv 0 initFolder -1 1)
,SendMessage htv TVM_EXPAND TVE_EXPAND htvi
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
,case WM_NOTIFY goto messages3
ret
;messages2
sel wParam
,case IDOK
,;sSelectedFile = full path of the selected file
,htv=id(3 hDlg)
,htvi=SendMessage(htv TVM_GETNEXTITEM TVGN_CARET 0)
,i=TvGetParam(htv htvi); if(i<0 or i>=a.len) ret
,sSelectedFile=a[i]
,
,case IDCANCEL
ret 1
;messages3
NMHDR* nh=+lParam
NMTREEVIEWW* nt=+nh
if(nh.idFrom!=3) ret
sel nh.code
,case TVN_ITEMEXPANDINGW
,;enum this folder and add children to the treeview, unless already done for this folder
,if(nt.action&TVE_EXPAND=0) ret
,i=nt.itemNew.lParam; if(i<0 or i>=a.len) ret
,if nt.itemNew.cChildren=1 and !SendMessage(nh.hwndFrom TVM_GETNEXTITEM TVGN_CHILD nt.itemNew.hItem)
,,sub.AddFolderChildren nh.hwndFrom nt.itemNew.hItem a[i]


#sub AddFolderChildren v
function htv htviFolder $folder

;Enumerates direct child files and subfolders of folder, and adds to the treeview.
;We'll add their children later on demand, on TVN_ITEMEXPANDINGW.

;at first add files and folders to separate arrays, because we want to display folders first
ARRAY(str) aFolders aFiles
int lastFolder=TVI_FIRST
Dir d
foreach(d F"{folder}\*" FE_Dir 2|64)
,str path=d.FullPath
,if(d.IsFolder) aFolders[]=path; else aFiles[]=path

int i
for(i 0 aFolders.len) sub.TvAdd(htv htviFolder aFolders[i] -1 1)
for(i 0 aFiles.len) sub.TvAdd(htv htviFolder aFiles[i] -1 0)


#sub TvAdd v
function# htv htviFolder $fullPath iimage cChildren

;Adds treeview item. Also adds fullPath to a.

TVINSERTSTRUCTW in
in.hParent=htviFolder
in.hInsertAfter=TVI_LAST
TVITEMW& r=in.item
r.mask=TVIF_TEXT|TVIF_PARAM
_s.getfilename(fullPath 1); if(!_s.len) _s=fullPath
r.pszText=@_s
if iimage>=0
,r.mask|=TVIF_IMAGE|TVIF_SELECTEDIMAGE
,r.iImage=iimage
,r.iSelectedImage=iimage
if(cChildren) r.cChildren=cChildren; r.mask|=TVIF_CHILDREN
r.lParam=a.len; a[]=fullPath

ret SendMessage(htv TVM_INSERTITEMW 0 &in)
#3
Quote:Is it possible to collapse everything? And is it possible to enforce one item to be expanded at all times?
(I could not find "TVM_COLLAPSE", only expand.)
TVM_EXPAND can collapse, but not all. Need to send TVM_EXPAND for each expanded item (folder).

Quote:And is it possible to enforce one item to be expanded at all times?
under case TVN_ITEMEXPANDINGW:
if(is it my always expanded item) ret DT_Ret(hDlg 1)
#4
Thank you!!! I really appreciate this!!!!!
#5
How could you enumerate a QM folder?
#6
Function SelectQmItemDialogWithTreeview
Code:
Copy      Help
;/test SelectQmItemDialogWithTreeview
;\Dialog_Editor
function! str&sSelectedItem [$initFolder] [hwndOwner]

;Shows a dialog with a treeview control that displays a QM folder.
;The user can expand subfolders and select an item or folder.
;On OK stores full path of the selected QM item or folder in sSelectedItem and returns 1. On Cancel returns 0.

;EXAMPLE
;str s
;if SelectQmItemDialogWithTreeview(s "\System\Functions")
,;out s


ARRAY(str) a ;;full paths of all displayed items; treeview lparam is its element index
;__ImageList il=ImageList_Create(16  ;;maybe later

str dd=
;BEGIN DIALOG
;1 "" 0x90C80AC8 0x0 0 0 224 280 "SelectQmItemDialogWithTreeview"
;3 SysTreeView32 0x54030823 0x0 0 0 224 256 ""
;1 Button 0x54030001 0x4 116 260 48 14 "OK"
;2 Button 0x54030000 0x4 168 260 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040201 "*" "" "" ""

if(!ShowDialog(dd &sub.DlgProc 0 hwndOwner)) ret
ret 1


#sub DlgProc v
function# hDlg message wParam lParam

int i htv htvi
sel message
,case WM_INITDIALOG
,;add initFolder to the treeview and expand; we'll catch TVN_ITEMEXPANDINGW and add children
,htv=id(3 hDlg)
,htvi=sub.TvAdd(htv 0 initFolder -1 1)
,SendMessage htv TVM_EXPAND TVE_EXPAND htvi
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
,case WM_NOTIFY goto messages3
ret
;messages2
sel wParam
,case IDOK
,;sSelectedItem = full path of the selected file
,htv=id(3 hDlg)
,htvi=SendMessage(htv TVM_GETNEXTITEM TVGN_CARET 0)
,i=TvGetParam(htv htvi); if(i<0 or i>=a.len) ret
,sSelectedItem=a[i]
,
,case IDCANCEL
ret 1
;messages3
NMHDR* nh=+lParam
NMTREEVIEWW* nt=+nh
if(nh.idFrom!=3) ret
sel nh.code
,case TVN_ITEMEXPANDINGW
,;enum this folder and add children to the treeview, unless already done for this folder
,if(nt.action&TVE_EXPAND=0) ret
,i=nt.itemNew.lParam; if(i<0 or i>=a.len) ret
,if nt.itemNew.cChildren=1 and !SendMessage(nh.hwndFrom TVM_GETNEXTITEM TVGN_CHILD nt.itemNew.hItem)
,,sub.AddFolderChildren nh.hwndFrom nt.itemNew.hItem a[i]


#sub AddFolderChildren v
function htv htviFolder $folder

;Enumerates direct child items and subfolders of folder, and adds to the treeview.
;We'll add their children later on demand, on TVN_ITEMEXPANDINGW.

if(!folder) folder=""
ARRAY(QMITEMIDLEVEL) af
GetQmItemsInFolder(folder &af 1)

if(!empty(folder) and folder[0]!'\') str _s1; folder=_s1.from("\" folder)
int i
for i 0 af.len
,QMITEM q; qmitem(af[i].id 0 q 1)
,sub.TvAdd(htv htviFolder F"{folder}\{q.name}" -1 q.itype=5)


#sub TvAdd v
function# htv htviFolder $fullPath iimage cChildren

;Adds treeview item. Also adds fullPath to a.

TVINSERTSTRUCTW in
in.hParent=htviFolder
in.hInsertAfter=TVI_LAST
TVITEMW& r=in.item
r.mask=TVIF_TEXT|TVIF_PARAM
_s.getfilename(fullPath 1); if(!_s.len) _s=fullPath
r.pszText=@_s
if iimage>=0
,r.mask|=TVIF_IMAGE|TVIF_SELECTEDIMAGE
,r.iImage=iimage
,r.iSelectedImage=iimage
if(cChildren) r.cChildren=cChildren; r.mask|=TVIF_CHILDREN
r.lParam=a.len; a[]=fullPath

ret SendMessage(htv TVM_INSERTITEMW 0 &in)
#7
Superb! That's exactly what I want. Thanks a lot!
#8
Is it possible that in the TreeView window, when I click on an item, it could do one of 2 things below:
1/ Show me the content of that macro/function.
2/ Or jump to that macro/function name so I could view/edit/run it.
#9
insert this under sel nh.code:
Code:
Copy      Help
,case TVN_SELCHANGEDW
,i=nt.itemNew.lParam; if(i<0 or i>=a.len) ret
,out a[i]
#10
I saw it just show the macro/function name only but not the content of it.
What I see is just like in the example:
If I choose ListDialog and it just shows:
\System\Functions\Dialog\ListDialog
and not the content of ListDialog function.
#11
How can you put the focus on a folder or file?
For example:
c:\Windows\notepad.exe

I think it begins with:
Code:
Copy      Help
SendMessage htv TVM_SELECTITEM ... (?)

TVM_SELECTITEM MSDN: http://msdn.microsoft.com/en-us/library ... 85%29.aspx
TVM_SELECTITEM in other qm forum thread: Drag Drop ListBox..

(and is it also possible to focus on folder?)
#12
,out _s.getmacro(a[i]) ;;see also qmitem, mac+
#13
Quote:I think it begins with:

SendMessage htv TVM_SELECTITEM

Yes. But then need treeview item handle. You can store TV item handles in array a of user-defined type, or in another array. But this code adds TV items only for expanded folders. Enumerating folder+subfolders at startup would be slow.
#14
Macro Macro24
Code:
Copy      Help
,out _s.getmacro(a[i]) ;;see also qmitem, mac+
The above line did show the content.
Thanks Gin!
#15
Problem
I am having problems when using a rich editfield.
If I add a rich editfield in the top tree example from this forum thread (file/folder-example), the tree gets correctly populated.
but, the rich editfield can not display .rtf files correctly, it shows the .rtf markup code in stead of the formatted text.
The richeditfield get's declared like this (in green decleration code): RichEdit20W (should be ...20A)?
If I try to change "RichEdit20W" to "RichEdit20A" it wont commit to that change, it will keep it's "RichEdit20W" name.

NOTE: the very first time when I copy and paste the example code and go to the dialog editor it will place the rich editfield as "rea4".
BUT when I reopen the dialog in the dialogeditor it is renamed "rew4" (and it stays that way).

If I change:

1 "" 0x90C80AC8 0x0 ....

to

0 "" 0x90C80AC8 0x0...

The the tree only shows "C:" at the top but not it's populated content.
The rich editfield gets declared like this: RichEdit20A which is correct. (as far as I know).
When I place a rich editfield it is placed "rea#" and it stays that way. Which is what I want, because I assume .rtf content will be displayed correctly.
BUT as said earlier, in the tree only "C:" shows at the top of the tree and NOT it's contents. This makes it impossible to send selected tree items to the rich editfield.


Question
How can I refresh the tree if I modify a filename that is currently selected/focussed?
Because: I have a button called [RENAME SELECTED] when pressed it shows a simple inputfield where the user can change the filename.
As soon as the user presses 'ok' the focus get's back to the tree, but it errors out.
This is expected because the filename got changed, that's why I need some kind of refresh BEFORE it puts the focus back on the tree.
(If you have a better/elegant/effective solution then it is very welcome).
#16
Quote:the rich editfield can not display .rtf files correctly, it shows the .rtf markup code in stead of the formatted text
I cannot reproduce it. How do you populate the rich edit control? What QM and Windows versions?
The dialog is Unicode, therefore QM uses Unicode version of rich edit control, with W in classname.

tested with
Function Dialog151
Code:
Copy      Help
\Dialog_Editor

str dd=
;BEGIN DIALOG
;1 "" 0x90C80AC8 0x0 0 0 282 168 "Dialog"
;3 RichEdit20W 0x54233044 0x200 0 0 284 110 ""
;1 Button 0x54030001 0x4 116 116 48 14 "OK"
;2 Button 0x54030000 0x4 168 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040201 "*" "" "" ""

str controls = "3"
str re3
re3="&$desktop$\b.rtf"
if(!ShowDialog(dd &sub.DlgProc &controls)) ret


#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
#17
When I use your last example code and add a button "load b.rtf into rich edit" and use that button to load the rtf into the rich edit, it shows RTF markup. I use File >> New >> Dialog >> Smart dialog (use: #sub DlgProc.) and paste the example code over the existing generated code, and then adjust it. The slightly adjusted code is as follows (with load rtf button):

Function re_test
Code:
Copy      Help
\Dialog_Editor

str dd=
;BEGIN DIALOG
;1 "" 0x90C80AC8 0x0 0 0 282 168 "Dialog"
;3 RichEdit20W 0x54233044 0x200 0 0 284 110 ""
;4 Button 0x54032000 0x0 116 135 99 21 "load b.rtf into rich edit"
;1 Button 0x54030001 0x4 116 116 48 14 "OK"
;2 Button 0x54030000 0x4 168 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040105 "*" "" "" ""

str controls = "3"
str rew3
;;rew3="&$desktop$\b.rtf"
if(!ShowDialog(dd &sub.DlgProc &controls)) ret


#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case 4
,,str rtf_path="$desktop$\b.rtf"
,,_s.getfile(rtf_path)
,,_s.setwintext(id(3 hDlg))        
,case IDOK
,case IDCANCEL
ret 1

I have another project that uses listbox to get the textpath and it is a smart dialog, that does not use #sub DlgProc.
It has a similair setup that loads .rtf into the rich edit and it works perfectly.

It is a huge project (at least for me), pasting the whole code would lead to confusion. That's why I pasted parts of it:

Code:
Copy      Help
BEGIN DIALOG
0 "" 0x90CA0AC8 0x0 0 0 834 387 "Snippet Manager" "2 50"
....
4 RichEdit20A 0x54333044 0x200 175 44 656 253 ""
...
END DIALOG
DIALOG EDITOR: "" 0x2040105 "" "0" "" ""

The moment the user focuses on a listbox item that is an .rtf file, it executes this function and it works.

Code:
Copy      Help
/snippetmanager_init
function int'hDlg str&right_pane_content
str- current_selected_item_path
int i j k
str- snippets_root
str- root_limit
str- root_limit_folder

right_pane_content.setwintext(id(4 hDlg))

QM: 2.4.1.5, portable
Windows 7 64bit
#18
I didn't know that rich edit controls can accept RTF through setwintext. The normal way is EM_STREAMIN. QM function RichEditLoad uses it. Another way - EM_SETTEXTEX. Documented in MSDN.

Function Dialog151
Code:
Copy      Help
\Dialog_Editor

str dd=
;BEGIN DIALOG
;1 "" 0x90C80AC8 0x0 0 0 282 168 "Dialog"
;3 RichEdit20W 0x54233044 0x200 0 0 284 110 ""
;1 Button 0x54030001 0x4 116 116 48 14 "OK"
;2 Button 0x54030000 0x4 168 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040201 "*" "" "" ""

str controls = "3"
str re3
;re3="&$desktop$\b.rtf"
if(!ShowDialog(dd &sub.DlgProc &controls)) ret


#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,RichEditLoad id(3 hDlg) "$desktop$\b.rtf"
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1

See also
Convert rtf to plain text
#19
I thought setwintext was the way to load the rtf in rich edit controls.
But this explains it! Thank you!
#20
Sorry another question, in the very first example at the top of this topic I see:

str dd=
;BEGIN DIALOG
=> ;1 "" 0x90C80AC8 0x0 0 0 224 280 "SelectFileDialogWithTreeview"
;3 SysTreeView32 0x54030823 0x0 0 0 224 256 ""
=> ;1 Button 0x54030001 0x4 116 260 48 14 "OK"
;2 Button 0x54030000 0x4 168 260 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040201 "*" "" "" ""

Both the main dialog AND button 'OK' have both same ID: 1 (I have put arrow indicators above)
Is this technically allowed? All the examples work, I just found it strange. I thought all the objects should have their own unique ID.
(The same question goes for the "SelectQmItemDialogWithTreeview" example).
#21
The first line is for dialog. Dialogs usually are not child windows and therefore don't have an id. QM dialog functions use this field for dialog flags. Flag 1 is Unicode, and it can be set in DE Options.
#22
Ok, thank you!!!
#23
Excellent and very useful routine. I wonder whether there exists an extension to output this folder tree in an ascii type .txt file.

I am aware of post

Creating SysTreeView32 dialog
#24
Initially it is not a tree. It is a simple list. When user expands an item, only then grows a simple-list branch, and so on.
If you need to format a files tree to a string or file, then don't need a dialog+control, instead use file functions.
If you need a generic way to get all systreeview32 items and format a string or file, then use messages like TVM_GETNEXTITEM.
Possibly functions for it exist in the forum, I don't remember.
#25
Many thanks for very useful advice. Actually, I found the solution in

Creating SysTreeView32 dialog

for control id(3 hDlg).

Best regards.
#26
One more question :
Is it possible to have all items entirely expanded at once?
Many thanks in advance.
#27
Probably need to send TVM_EXPAND message for all items. Enumerate with TVM_GETNEXTITEM. To make faster, temporarily hide the control.
#28
Dear Gintaras,

It worked perfectly using recursively the following statements :
Function tempf03
Code:
Copy      Help
,,,sub.AddFolderChildren htv htvi a[i]
,,,SendMessage htv TVM_EXPAND TVE_EXPAND htvi
,,,key D           ;; Down
,,,htvi=SendMessage(htv TVM_GETNEXTITEM TVGN_CARET 0)
,,,i=TvGetParam(htv htvi)

I wonder whether there exists any alternative, indeed in what it concerns the
Quote:key D
directive, which I would like to avoid.

Many thanks in advance.
#29
Found this function to collapse all. Similar would be to expand.

Function TreeViewCollapseAll
Code:
Copy      Help
;/
function htv [flags] [hItem] ;;flags: don't collapse first item

hItem=SendMessage(htv TVM_GETNEXTITEM iif(hItem TVGN_CHILD TVGN_ROOT) hItem)
rep
,if(!hItem) break
,if(flags&1) flags~1
,else SendMessage(htv TVM_EXPAND TVE_COLLAPSE hItem)
,TreeViewCollapseAll htv 0 hItem
,hItem=SendMessage(htv TVM_GETNEXTITEM TVGN_NEXT hItem)
#30
Gintaras, Thank you very much! It works perfectly both ways !

Have a nice weekend.


Forum Jump:


Users browsing this thread: 11 Guest(s)