Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
MultiLine ListBox
#1
Hi Gintaras,
Is there any way any of these could be adapted to QM dialog listboxes?
http://www.codeguru.com/cpp/controls/con....php/c2291
http://www.codeproject.com/KB/combobox/listboxxp.aspx

I have seen some others but they use .NET which I think you said doesn't work in QM:
http://www.codeproject.com/KB/combobox/n...isbox.aspx

Thanks!!!
Stuart
ps. perhaps this is something QM can already do and I am just not aware yet Big Grin
Stuart
#2
Function dlg_listbox_multiline
Code:
Copy      Help
\Dialog_Editor
function# hDlg message wParam lParam
if(hDlg) goto messages

str controls = "3 4"
str lb3 cb4
;note: don't use dialog variable to add ownerdraw listbox/combobox items.

if(!ShowDialog("dlg_listbox_multiline" &dlg_listbox_multiline &controls)) ret

;note: in dialog editor, select the listbox control and add styles LBS_OWNERDRAWVARIABLE and LBS_HASSTRINGS. Similar with combobox.

;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "Dialog"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;3 ListBox 0x54230161 0x200 0 0 108 114 ""
;4 ComboBox 0x54230262 0x0 118 0 102 215 ""
;END DIALOG
;DIALOG EDITOR: "" 0x2030300 "" "" ""

ret
;messages

;call this function before sel message
if(DT_LbCbOwnerDraw(hDlg message wParam lParam 0 3)) ret 1

sel message
,case WM_INITDIALOG
,;optionally set font
,__Font-- t_f.Create("Comic Sans MS" 10 2)
,t_f.SetDialogFont(hDlg "3 4")
,
,;add items. Or can add/remove later. To remove all, send message LB_RESETCONTENT or CB_RESETCONTENT.
,ARRAY(str) a.create(3)
,a[0]="normal"
,a[1]="line[]line[]line"
,a[2]="wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap"
,int i h
,h=id(3 hDlg)
,for(i 0 a.len) LB_Add h a[i]
,h=id(4 hDlg)
,for(i 0 a.len) CB_Add h a[i]
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1

Function DT_LbCbOwnerDraw
Code:
Copy      Help
;/dlg_listbox_multiline
function! hDlg message wParam lParam [ctlId] [flags] ;;flags: 1 wrap lines, 2 draw separators

;Draws items in owner-draw listbox or combobox control.
;Items can have multiple lines.
;Call this function from a dialog function, like in dlg_listbox_multiline.
;Returns 1 if draws, 0 if not.

;hDlg message wParam lParam - hDlg message wParam lParam.
;ctrlId - control id. If 0, draws all owner-draw listbox and combobox controls.


sel(message) case [WM_MEASUREITEM,WM_DRAWITEM] case else ret

int ct cid msg1 msg2

sel message
,case WM_MEASUREITEM
,MEASUREITEMSTRUCT& mi=+lParam
,ct=mi.CtlType
,cid=mi.CtlID
,
,case WM_DRAWITEM
,DRAWITEMSTRUCT& di=+lParam
,ct=di.CtlType
,cid=di.CtlID

if(ctlId and cid!ctlId) ret
sel ct
,case ODT_LISTBOX msg1=LB_GETTEXT; msg2=LB_GETTEXTLEN
,case ODT_COMBOBOX msg1=CB_GETLBTEXT; msg2=CB_GETLBTEXTLEN
,case else ret

int hwnd i hdc fl
RECT rt
hwnd=id(cid hDlg)

sel message
,case WM_MEASUREITEM
,i=mi.itemID
,hdc=GetDC(hwnd)
,RECT rc; GetClientRect hwnd &rc; rt.right=rc.right
,fl=DT_CALCRECT
,
,case WM_DRAWITEM
,i=di.itemID
,if(i<0) ret
,hdc=di.hDC
,rt=di.rcItem
,
,int colBk colTxt
,if(di.itemState&ODS_SELECTED) colBk=COLOR_HIGHLIGHT; colTxt=COLOR_HIGHLIGHTTEXT
,else colBk=COLOR_WINDOW; colTxt=COLOR_WINDOWTEXT
,FillRect hdc &rt GetSysColorBrush(colBk)
,SetBkMode hdc TRANSPARENT
,SetTextColor hdc GetSysColor(colTxt)

int tl=SendMessageW(hwnd msg2 i 0)
if tl>0
,BSTR s.alloc(tl)
,tl=SendMessageW(hwnd msg1 i s.pstr)
,if tl>0
,,if(flags&1) fl|DT_WORDBREAK
,,int oldfont=SelectObject(hdc SendMessageW(hwnd WM_GETFONT 0 0))
,,DrawTextW(hdc s tl &rt fl|DT_EXPANDTABS|DT_NOPREFIX)
,,SelectObject hdc oldfont

sel message
,case WM_MEASUREITEM
,ReleaseDC hwnd hdc
,mi.itemHeight=rt.bottom
,
,case WM_DRAWITEM
,if(di.itemState&ODS_FOCUS) DrawFocusRect hdc &rt
,else if flags&2
,,int pen=CreatePen(PS_SOLID 1 0xc0c0c0)
,,int oldpen=SelectObject(hdc pen)
,,MoveToEx hdc 0 rt.bottom-1 0; LineTo hdc rt.right rt.bottom-1
,,DeleteObject SelectObject(hdc oldpen)

ret DT_Ret(hDlg 1)
#3
Hi Gintaras, this is really fantastic, especially the ability to wrap - I can't believe this works perfectly with the Splitters!!!
Anyway, it seems to prevent CB_ItemColor from adding any colors to the new listbox. Is this an easy fix?
Thanks!!!
Stuart
#4
CB_ItemColor cannot be used together.

This version can draw items with colors.
Also shows how to repaint correctly when listbox size changes, for example when using splitters.


Attached Files
.qml   Owner-draw listbox, combobox.qml (Size: 6.67 KB / Downloads: 485)
#5
Hi Gintaras,
Thanks so much for this update. I am trouble getting it to work from outside the dialog...i.e. separate functions that fill the LB at various times. I think it has to do with passing
Quote:message wParam lParam
i've tried to pass this on as well but not successfully.
Any advice?
Thanks,
Stuart
#6
From other threads? Can use LB_RESETCONTENT and LB_Add from other thread. May need to use lock. More difficult would be with colors, because need to recreate the arrays.

Macro Macro1548
Code:
Copy      Help
ARRAY(str) a.create(3)
a[0]="wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap"
a[1]="normal"
a[2]="line[]line[]line"
int i h hDlg=win("Dialog" "#32770")
h=id(3 hDlg)
lock lb_multiline
SendMessage h LB_RESETCONTENT 0 0
for(i 0 a.len) LB_Add h a[i]
lock- lb_multiline
#7
The solution to my problem was creating global arrays (
Code:
Copy      Help
ARRAY(str)+
instead of thread arrays
Code:
Copy      Help
ARRAY(str)--
I can't believe how well it works...thanks so much!!!
Stuart
#8
Maybe better would be, instead of arrays, to use tags?

LB_Add h "<colors 0xff 0xccffcc>Text"
#9
I managed to color items with which begin with a square bracket: "["
But is it also possible to style it differently regarding it's font size and style (bold)?
In other words, items that begin with a square bracket also get styled: bold.

I assume the function must have an array added like "t_act" but called "t_style" or something like that?
But it would also mean you have to modifying the function "DT_LbCbOwnerDraw" would take to much time.

Function lb_color
Code:
Copy      Help
\Dialog_Editor

str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 224 136 "Dialog"
;3 ListBox 0x54230161 0x200 31 14 112 73 ""
;1 Button 0x54030001 0x4 116 116 48 14 "OK"
;2 Button 0x54030000 0x4 168 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040301 "*" "" "" ""

str controls = "3"
str lb3

if(!ShowDialog(dd &sub.DlgProc &controls)) ret

#sub DlgProc
function# hDlg message wParam lParam

ARRAY(int)-- t_act t_acb
if(DT_LbCbOwnerDraw(hDlg message wParam lParam 0 1 t_act t_acb 0xffff 0x1)) ret 1
sel message
,case WM_INITDIALOG
,,int- dark_orange=ColorFromRGB(180 90 10)
,,int- dark_grey=ColorFromRGB(95 95 95)
,,int- black=ColorFromRGB(0 0 0)
,,int- green=ColorFromRGB(0 153 0)
,,int- red=ColorFromRGB(255 0 0)
,
,,;; DECLARE LISTBOX
,,int lb=id(3 hDlg)
,
,,;; SET FONT
,,__Font-- t_f.Create("Courier" 10 0)
,,t_f.SetDialogFont(hDlg "3")

,,;; ITEMS THAT WILL POPULATE LISTBOX
,,str lb_text="[ test 1 ][][ test 2 ][]test 3[]test 4"
,,
,,;; SET THE COLOR STYLE FOR THE DESIRED ITEMS
,,;; JUST SET IT'S CORRESPONDING 't_act[]' TO THE DESIRED COLOR
,,foreach _s lb_text
,,,str regx="^\["
,,,if(findrx(_s regx)>=0)
,,,,t_act[]=dark_orange
,,,else
,,,,t_act[]=dark_grey

,,;; FILL THE LISTBOX
,,ARRAY(str) a.create(1)        
,,a=lb_text
,,int i
,,for(i 0 a.len) LB_Add lb a[i]

,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
#10
Added parameter: aFont.

Function DT_LbCbOwnerDraw
Code:
Copy      Help
;/
function! hDlg message wParam lParam [ctlId] [flags] [ARRAY(int)&aColorText] [ARRAY(int)&aColorBack] [selColorText] [selColorBack] [ARRAY(int)&aFont] ;;flags: 1 wrap lines, 2 draw separators

;Draws items in owner-draw listbox or combobox control.
;Items can have multiple lines.
;Call this function from a dialog procedure, like in dlg_listbox_multiline.
;Returns 1 if draws, 0 if not.

;hDlg message wParam lParam - hDlg message wParam lParam.
;ctrlId - control id. If 0, draws all owner-draw listbox and combobox controls.
;aColorText, aColorBack - arrays containing colors of item text and background. The variables should have thread scope. If omitted or 0, uses default colors.
;selColorText, selColorBack - colors of selected item text and background. If omitted or 0, uses default selection colors.
;aFont - array containing font handles of item text. The variable should have thread scope. Can be set only some elements, others can be 0 (default font).


sel(message) case [WM_MEASUREITEM,WM_DRAWITEM] case else ret

int ct cid msg1 msg2

sel message
,case WM_MEASUREITEM
,MEASUREITEMSTRUCT& mi=+lParam
,ct=mi.CtlType
,cid=mi.CtlID
,
,case WM_DRAWITEM
,DRAWITEMSTRUCT& di=+lParam
,ct=di.CtlType
,cid=di.CtlID

if(ctlId and cid!ctlId) ret
sel ct
,case ODT_LISTBOX msg1=LB_GETTEXT; msg2=LB_GETTEXTLEN
,case ODT_COMBOBOX msg1=CB_GETLBTEXT; msg2=CB_GETLBTEXTLEN
,case else ret

int hwnd i hdc fl
RECT rt
hwnd=id(cid hDlg)

sel message
,case WM_MEASUREITEM
,i=mi.itemID
,hdc=GetDC(hwnd)
,RECT rc; GetClientRect hwnd &rc; rt.right=rc.right
,fl=DT_CALCRECT
,
,case WM_DRAWITEM
,i=di.itemID
,if(i<0) ret
,hdc=di.hDC
,rt=di.rcItem
,
,int colB colT colB_used colT_used
,if(di.itemState&ODS_SELECTED)
,,colB=COLOR_HIGHLIGHT; colT=COLOR_HIGHLIGHTTEXT
,,if(selColorBack) colB=selColorBack; colB_used=1
,,if(selColorText) colT=selColorText; colT_used=1
,else
,,colB=COLOR_WINDOW; colT=COLOR_WINDOWTEXT
,,if(&aColorBack && i<aColorBack.len) colB=aColorBack[i]; colB_used=1
,,if(&aColorText && i<aColorText.len) colT=aColorText[i]; colT_used=1
,if(!colB_used) colB=GetSysColorBrush(colB); else colB=CreateSolidBrush(colB)
,if(!colT_used) colT=GetSysColor(colT)
,FillRect hdc &rt colB; if(colB_used) DeleteObject colB
,SetTextColor hdc colT
,SetBkMode hdc TRANSPARENT

int tl=SendMessageW(hwnd msg2 i 0)
if tl>0
,BSTR s.alloc(tl)
,tl=SendMessageW(hwnd msg1 i s.pstr)
,if tl>0
,,if(&di and di.itemState&ODS_COMBOBOXEDIT) fl|DT_SINGLELINE
,,else if(flags&1) fl|DT_WORDBREAK
,,
,,int font
,,if(&aFont && i<aFont.len) font=aFont[i]
,,if(!font) font=SendMessageW(hwnd WM_GETFONT 0 0)
,,int oldfont=SelectObject(hdc font)
,,DrawTextW(hdc s tl &rt fl|DT_EXPANDTABS|DT_NOPREFIX)
,,SelectObject hdc oldfont

sel message
,case WM_MEASUREITEM
,ReleaseDC hwnd hdc
,mi.itemHeight=rt.bottom
,
,case WM_DRAWITEM
,if(di.itemState&ODS_FOCUS) DrawFocusRect hdc &rt
,else if flags&2
,,int pen=CreatePen(PS_SOLID 1 0xc0c0c0)
,,int oldpen=SelectObject(hdc pen)
,,MoveToEx hdc 0 rt.bottom-1 0; LineTo hdc rt.right rt.bottom-1
,,DeleteObject SelectObject(hdc oldpen)

ret DT_Ret(hDlg 1)

example
Function dlg_listbox_colors_fonts_multiline
Code:
Copy      Help
\Dialog_Editor

str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 223 135 "Dialog"
;3 ListBox 0x54230161 0x200 0 0 108 114 ""
;4 ComboBox 0x54230262 0x0 118 14 102 215 ""
;5 ComboBox 0x54230263 0x0 118 54 102 215 ""
;6 Static 0x54000000 0x0 118 4 78 10 "Editable combo"
;7 Static 0x54000000 0x0 118 44 78 10 "Read-only combo"
;1 Button 0x54030001 0x4 120 116 48 14 "OK"
;2 Button 0x54030000 0x4 170 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2030300 "" "" ""

str controls = "3 4 5"
str lb3 cb4 cb5
;note: don't use dialog variable to add ownerdraw listbox/combobox items.

if(!ShowDialog(dd &sub.DlgProc &controls)) ret

;note: in dialog editor, select the listbox control and add styles LBS_OWNERDRAWVARIABLE and LBS_HASSTRINGS. Similar with combobox.


#sub DlgProc
function# hDlg message wParam lParam

;arrays for colors and fonts
ARRAY(int)-- t_act t_acb t_afont

;call this function before sel message
if(DT_LbCbOwnerDraw(hDlg message wParam lParam 0 1 t_act t_acb 0xffff 0x1 t_afont)) ret 1

sel message
,case WM_INITDIALOG
,;optionally set common font
,__Font-- t_f.Create("Comic Sans MS" 10 2)
,t_f.SetDialogFont(hDlg "3 4 5")
,
,;create arrays for colors
,t_act.create(4); t_act[0]=0xff; t_act[1]=0x8000; t_act[2]=0xff0000
,t_acb.create(4); t_acb[0]=0xffC0C0; t_acb[1]=0xC0FFff; t_acb[2]=0xC0ffC0; t_acb[3]=0xffffff
,
,;create array for fonts
,__Font-- t_f1.Create("Tahoma" 15 1) t_f2.Create("" 0 4 0 1 4)
,t_afont.create(4); t_afont[1]=t_f1; t_afont[2]=t_f2; t_afont[3]=t_f1 ;;and t_afont[0]=0 - default font
,
,;add items. Or can add/remove later. To remove all, send message LB_RESETCONTENT or CB_RESETCONTENT.
,ARRAY(str) a.create(4)
,a[0]="normal"
,a[1]="line[]line[]line"
,a[2]="wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap wrap"
,a[3]="last"
,int i h
,h=id(3 hDlg)
,for(i 0 a.len) LB_Add h a[i]
,h=id(4 hDlg)
,for(i 0 a.len) CB_Add h a[i]
,h=id(5 hDlg)
,for(i 0 a.len) CB_Add h a[i]
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1
#11
wow!!!
thank you!!!
#12
I seem to have the following problem:
When the DT_LbCbOwnerDraw has tooltip text, the tooltip does not dissapear after the user moves out of DT_Lb control area.
(I have set max time of 32seconds in dialog settings tooltip (time, s), it seems to dissapear after the 32 seconds are run out)

Is this an issue within DT_LbCbOwnerDraw?

(Maybe it is not an issue within DT_LbCbOwnerDraw, I do not know for sure).


EDIT:
It seems to happen when you sometimes move slow out of LB area or when moving fast out of LB area.
(Sorry, can not give more input on this).

Is there something I can add in the DT_Lb function to force kill tooltips if user mouse is out of LB area?
Maybe this issue may take to much time to solver properly, as I understand you are very busy with next "QM" so if this "issue" takes to long to resolve then by all means skip it.
#13
It seems it is a bug of tooltip controls. Not related to DT_LbCbOwnerDraw.
In this example, tooltip of listbox, edit and richedit has this bug.
Function Dialog3
Code:
Copy      Help
str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 224 186 "Dialog"
;3 ListBox 0x54230101 0x200 8 8 96 48 "" "tooltip"
;4 Button 0x54032000 0x0 8 60 48 14 "Button" "tooltip"
;5 Edit 0x54030080 0x200 8 80 96 12 "" "tooltip"
;6 ComboBox 0x54230243 0x0 8 96 96 213 "" "tooltip"
;7 RichEdit20A 0x54233044 0x200 8 112 96 16 "" "tooltip"
;8 SysListView32 0x54030000 0x0 8 132 96 48 "" "tooltip"
;END DIALOG
;DIALOG EDITOR: "" 0x2040800 "*" "" "" ""

str controls = "3 5 6 7"
str lb3 e5 cb6 re7
if(!ShowDialog(dd 0 &controls)) ret

Workaround: in dialog editor's Tooltip dialog check "Don't subclass controls". It adds "4":
0 "" 0x90C80AC8 0x0 0 0 224 186 "Dialog" "4"
#14
Thank you this works!


Forum Jump:


Users browsing this thread: 1 Guest(s)