Posts: 763
Threads: 261
Joined: Jul 2012
- 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.
Posts: 12,078
Threads: 141
Joined: Dec 2002
Function SelectFileDialogWithTreeview
;/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)
Posts: 12,078
Threads: 141
Joined: Dec 2002
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)
Posts: 763
Threads: 261
Joined: Jul 2012
Thank you!!! I really appreciate this!!!!!
Posts: 133
Threads: 15
Joined: Jun 2014
How could you enumerate a QM folder?
Posts: 12,078
Threads: 141
Joined: Dec 2002
Function SelectQmItemDialogWithTreeview
;/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)
Posts: 133
Threads: 15
Joined: Jun 2014
Superb! That's exactly what I want. Thanks a lot!
Posts: 133
Threads: 15
Joined: Jun 2014
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.
Posts: 12,078
Threads: 141
Joined: Dec 2002
insert this under sel nh.code:
,case TVN_SELCHANGEDW
,i=nt.itemNew.lParam; if(i<0 or i>=a.len) ret
,out a[i]
Posts: 133
Threads: 15
Joined: Jun 2014
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.
Posts: 763
Threads: 261
Joined: Jul 2012
How can you put the focus on a folder or file?
For example:
c:\Windows\notepad.exe
I think it begins with:
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?)
Posts: 12,078
Threads: 141
Joined: Dec 2002
,out _s.getmacro(a[i]) ;;see also qmitem, mac+
Posts: 12,078
Threads: 141
Joined: Dec 2002
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.
Posts: 133
Threads: 15
Joined: Jun 2014
Macro Macro24
,out _s.getmacro(a[i]) ;;see also qmitem, mac+
The above line did show the content.
Thanks Gin!
Posts: 763
Threads: 261
Joined: Jul 2012
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).
Posts: 12,078
Threads: 141
Joined: Dec 2002
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
\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
Posts: 763
Threads: 261
Joined: Jul 2012
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
\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:
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.
/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
Posts: 12,078
Threads: 141
Joined: Dec 2002
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
\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
Posts: 763
Threads: 261
Joined: Jul 2012
I thought setwintext was the way to load the rtf in rich edit controls.
But this explains it! Thank you!
Posts: 763
Threads: 261
Joined: Jul 2012
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).
Posts: 12,078
Threads: 141
Joined: Dec 2002
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.
Posts: 763
Threads: 261
Joined: Jul 2012
Posts: 1,058
Threads: 367
Joined: Oct 2007
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
Posts: 12,078
Threads: 141
Joined: Dec 2002
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.
Posts: 1,058
Threads: 367
Joined: Oct 2007
Many thanks for very useful advice. Actually, I found the solution in
Creating SysTreeView32 dialog
for control id(3 hDlg).
Best regards.
Posts: 1,058
Threads: 367
Joined: Oct 2007
One more question :
Is it possible to have all items entirely expanded at once?
Many thanks in advance.
Posts: 12,078
Threads: 141
Joined: Dec 2002
Probably need to send TVM_EXPAND message for all items. Enumerate with TVM_GETNEXTITEM. To make faster, temporarily hide the control.
Posts: 1,058
Threads: 367
Joined: Oct 2007
Dear Gintaras,
It worked perfectly using recursively the following statements :
Function tempf03
,,,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.
Posts: 12,078
Threads: 141
Joined: Dec 2002
Found this function to collapse all. Similar would be to expand.
Function TreeViewCollapseAll
;/
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)
Posts: 1,058
Threads: 367
Joined: Oct 2007
Gintaras, Thank you very much! It works perfectly both ways !
Have a nice weekend.
|