Hi
I would like to create a dialog where I can:
- Type text into a field
- As the text is typed, display a list of items that contain the text
- Be able to use the arrow keys and Enter, or mouse-click to select one of the matching items to perform an action.
The QM Editor Find dialog does everything I need, but I cannot find a dialog file for it.
Is there an example of a dialog that has this functionality?
Thanks for your help,
John
Hi Gintaras
I tinkered with your example to display all items when the edit box is empty and to work out which item is clicked.
I would now like get messages when a key is pressed so I can changed the selected item with the up and down arrow keys (without pressing tab first), leaving the typing focus in the edit box (like the Gmail / Compose Mail / To: drop down list that lets you either keep typing or select from the list with the arrow keys).
Thanks for your help,
John
;__OutWinMsg message wParam lParam sel message ,caseWM_DESTROY ,case [WM_KEYDOWN,WM_KEYUP] ,sel wParam ;;virtual key code ,,case [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT] ,,;relay these keys to the listbox and not to the edit box ,,SendMessageid(4GetParent(hWnd)) message wParam lParam ,,ret
int wndproc=GetProp(hWnd "wndproc");if(!wndproc)ret retCallWindowProcW(wndproc hWnd message wParam lParam)
I've made a bit of progress with my selection dialog.
TheVig: the MyEditSubclassProc SubclassWindow function inserts the select listbox line when the insert key is pressed.
Gintaras:
1. When a key I want to use with the listbox is detected in the MyEditSubclassProc function, can I "eat" the key so that the parent "listDialog" function does not receive it?
2. Is there some way to detect the typing cursor position in the edit field?
I would like to be able to use the right-arrow key to insert the currently selected listbox item, but only when the cursor is at the end of the edit field.
;__OutWinMsg message wParam lParam sel message ,caseWM_DESTROY ,case [WM_KEYDOWN] ;; ,WM_KEYUP ,int he=id(3GetParent(hWnd)) ,int hlb=id(4GetParent(hWnd)) ,;out "wParam=%i" wParam ,sel wParam ;;virtual key code ,, ,,case [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT] ,,;relay these keys to the listbox and not to the edit box ,,;out "%s: %i %i %i" fnName wParam=VK_UP LB_SelectedItem(hlb) LB_GetCount(hlb) ,,if wParam =VK_UPandLB_SelectedItem(hlb)=-1 ,,,;If the up arrow is pressed and nothing is highlighted, then highlight the last entry ,,,LB_SelectItem hlb LB_GetCount(hlb)-1 ,,else ,,,SendMessage hlb message wParam lParam ,,ret ,, ,,case [VK_INSERT] ,,; Copy current list value to text entry field ,,str sEdit.getwintext(he) ,,out"right: %s" sEdit ,,str s ,,LB_SelectedItem(hlb s);; Set edit box to selected item text ,,;; Use LB_GetItemText ,,s.setwintext(he) ,,SendMessage he message VK_END lParam ;; Move cursor to end of new entry field ,,ret ,,;case else ,,;SendMessage hlb message wParam lParam ,,;ret ,; Select one of the list items ,if(wParam>='0'&& wParam<='9') ,,int ind=wParam-'0' ,,LB_SelectItem hlb ind
int wndproc=GetProp(hWnd "wndproc");if(!wndproc)ret retCallWindowProcW(wndproc hWnd message wParam lParam)
1. Parent does not receive messages that are received by the subclass function. To prevent default edit control processing of some keys, don't call CallWindowProcW for these keys. The function also relays the message to another control. If not needed, remove SendMessage.
sel message ,caseWM_DESTROY ,case [WM_PAINT,WM_GETTEXTLENGTH,WM_GETTEXT];; These messages happen lots ,caseWM_GETDLGCODE;; Happens twice per letter keypress ,caseWM_SYSKEYDOWN;; Happens repeatedly while Alt key down ,case [WM_KEYUP];ret;; Ignore keyup messages ,case [WM_KEYDOWN] ,int he=id(3GetParent(hWnd)) ,int hlb=id(4GetParent(hWnd)) ,;out "wParam=%i" wParam ,sel wParam ;;virtual key code ,, ,,case [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT] ,,;relay these keys to the listbox and not to the edit box ,,;out "%s: %i %i %i" fnName wParam=VK_UP LB_SelectedItem(hlb) LB_GetCount(hlb) ,,if wParam =VK_UPandLB_SelectedItem(hlb)=-1 ,,,;If the up arrow is pressed and nothing is highlighted, then highlight the last entry ,,,LB_SelectItem hlb LB_GetCount(hlb)-1 ,,else ,,,SendMessage hlb message wParam lParam ,,ret ,, ,,case [VK_INSERT,VK_RIGHT] ,,int cursorPos;SendMessage(he EM_GETSEL0&cursorPos) ,,str sEdit.getwintext(he) ,,if cursorPos <>len(sEdit) ,,,goto passMessageUp ;; Only replace edit text when cursor is at end of edit field ,,if(LB_SelectedItem(hlb)=-1);ret;; Exit if no list item selected ,,; Copy current list value to text entry field ,,str s ,,LB_SelectedItem(hlb s);; Set edit box to selected item text ,,s.setwintext(he) ,,SendMessage he message VK_END lParam ;; Move cursor to end of new entry field ,,ret
,caseWM_CHAR;; Standard letter ,;out "WM_CHAR %i %c" wParam wParam ,;sel wParam ;;virtual key code ,,;case ['a'] ,,;ret ,caseWM_SYSKEYUP;; Fires when Alt-letter keyup (but alt still held down) ,hlb=id(4GetParent(hWnd)) ,; Select one of the list items ,if(wParam>='A'&& wParam<='Z') ,,int ind = wParam -'A' ,,LB_SelectItem hlb ind ,,ret ,caseelse;; for sel message ,int- cxx; cxx+1 ,;out "%s uncaught message %i: x%X(%i) %i %i %i" fnName cxx message message wParam lParam hWnd
;passMessageUp int wndproc=GetProp(hWnd "wndproc");if(!wndproc)ret retCallWindowProcW(wndproc hWnd message wParam lParam)
I tried to add a horizontal scrollbar to ListSelect.qml but can't make it work. I want to be able to add lines in the list that are longer than the dialog window width and scroll horizontally to see the rest of the lines.
I find this thread very useful for what I want to do....
But I have one little problem: I'm using QM 2.2.1.5
LB_Add doesn't exist in this release, so I want ask you for two things:
1st. If I add the file LB_add will just run fine with my old version?
And second, only if the first question was true, can someone send me this function?
str databaseFile="$my qm$\test5725w.db3";;change this int createTableNow=1;;change 1 to 0 if don't want to create table everytime here
Sqlite- db
db.Open(databaseFile 04)
;create an example table and add several items if createTableNow ,str sql= ,;PRAGMA journal_mode=WAL; ,;BEGIN; ,;DROP TABLE IF EXISTS t; ,;CREATE TABLE t(name,tag); ,;INSERT INTO t VALUES ,;('January','month'), ,;('Apple','fruit'), ,;('Banana','fruit'), ,;('April','month'), ,;('Other',''); ,;COMMIT ,db.Exec(sql) ;Edit the above sql string. ;To add/remove/edit items later, you can anywhere use code like this (except the DROP TABLE and CREATE TABLE lines). ;;;Or use a database management program, eg SQLite Expert Personal. ;;;Then set createTableNow=0 or remove the creation code.
Sqlite- db int hlb hcb i str sql sName sTag ARRAY(str) a
sel message ,caseWM_INITDIALOG ,SetPropid(3 hDlg)"wndproc"SubclassWindow(id(3 hDlg)&sub.EditSubclassProc);;optional, just to select listbox items with arrow keys when the control is not focused , ,;populate the Tag combo ,hcb=id(7 hDlg) ,CB_Add(hcb "") ,db.Exec("SELECT DISTINCT tag FROM t" a) ,for(i 0 a.len)CB_Add(hcb a[0 i]) , ,SetTimer hDlg 1100 , ,caseWM_DESTROY ,RemovePropid(3 hDlg)"wndproc" , ,caseWM_COMMANDgoto messages2 , ,caseWM_TIMER ,sel wParam ,,case1KillTimer hDlg wParam;goto gUpdateList ret ;messages2 sel wParam ,case [EN_CHANGE<<16|3,CBN_EDITCHANGE<<16|7] ,SetTimer hDlg 13000 ,case [CBN_SELCHANGE<<16|7,8] ,SetTimer hDlg 1100 , ,caseLBN_DBLCLK<<16|4goto gShowSelected ,case5goto gShowSelected , ,caseIDOK ,caseIDCANCEL ret1
;gUpdateList
hlb=id(4 hDlg) SendMessage hlb LB_RESETCONTENT00
sName.getwintext(id(3 hDlg)); sName.SqlEscape
sTag.getwintext(id(7 hDlg)); sTag.SqlEscape ;get items from database
sql="SELECT name FROM t" if(sName.len) sql+F" WHERE name LIKE '%{sName}%'";if(sTag.len) sql+F" AND tag='{sTag}'" elseif(sTag.len) sql+F" WHERE tag='{sTag}'" if(but(8 hDlg)) sql+" ORDER BY name"
db.Exec(sql a) for i 0 a.len ,LB_Add hlb a[0 i]
ret
;gShowSelected
hlb=id(4 hDlg)
_i=LB_SelectedItem(hlb);if(_i<0)ret LB_GetItemText hlb _i _s mes _s ret
;OutWinMsg message wParam lParam sel message ,caseWM_DESTROY ,case [WM_KEYDOWN,WM_KEYUP] ,sel wParam ;;virtual key code ,,case [VK_DOWN,VK_UP,VK_PRIOR,VK_NEXT] ,,;relay these keys to the listbox and not to the edit box ,,SendMessageid(4GetParent(hWnd)) message wParam lParam ,,ret
int wndproc=GetProp(hWnd "wndproc");if(!wndproc)ret retCallWindowProcW(wndproc hWnd message wParam lParam)
;create an example table and add several items if createTableNow ,str sql= ,;PRAGMA journal_mode=WAL; ,;BEGIN; ,;DROP TABLE IF EXISTS t; ,;CREATE TABLE t(name,tag); ,;INSERT INTO t(name,tag) VALUES('January','month'); ,;INSERT INTO t(name,tag) VALUES('Apple','fruit'); ,;INSERT INTO t(name,tag) VALUES('Banana','fruit'); ,;INSERT INTO t(name,tag) VALUES('April','month'); ,;INSERT INTO t(name,tag) VALUES('Other',''); ,;COMMIT; ,db.Exec(sql)
The code changes when copy/paste to/from forum.
Because when pasting, QM thinks that the commas are escaped tabs, and replaces them to tabs. But must be commas.
Now I changed the code to avoid it.