Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Set/Reset Icon & Text to "OK" button
#1
I understand it is not easy to change the background color of a system button (OK, Cancel) (topic : Rich Edit on Toolbar Buttons and Text).

To overcome it, I wrote a simple-sample dialog to add an icon to "OK" button :

Function ColorButtonDlg_Reset
Code:
Copy      Help
;https://msdn.microsoft.com/en-us/library/windows/desktop/bb761822(v=vs.85).aspx
str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 214 78 "Dialog"
;3 Button 0x54032000 0x0 23 11 48 14 "Set"
;4 Button 0x54032000 0x0 89 11 48 14 "Reset"
;1 Button 0x54034040 0x4 66 59 48 14 "OK"
;2 Button 0x54030000 0x4 130 59 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040308 "*" "" "" ""

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


#sub DlgProc
function# hDlg message wParam lParam
int- handle
sel message
,case WM_INITDIALOG
,handle=GetFileIcon("%IconFol%\red_light.ico" 0 0)
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case 3
,out "set"
,out handle
,SendMessage(id(1 hDlg) BM_SETIMAGE IMAGE_ICON handle)
,
,case 4
,out "Reset"
,SendMessage(id(1 hDlg) BM_SETIMAGE IMAGE_ICON 0)
,
,case IDOK
,case IDCANCEL
ret 1

I would appreciate it if I could have any advice on the following issues :

1. How could I reset the "OK" button back to its default state? I found empirically that it can be done with a BM_SETIMAGE with handle=0. However, I am nt sure that this is right.

2. Is it possible to have both icon + text on the same button? There is relevant information in QM help, Dialog Editor, Styles, BS_ICON but I failed to set it up.

Many thanks in advance.
#2
I recommend to review all your macros that get icon and make sure that all icons are finally destroyed. Not destroying an icon is a serious memory leak that may affect all processes, not only QM, because icon handles are shared by all processes, and their allowed number is limited. If icon is assigned to an int or directly passed to a function, call DestroyIcon when it is not longer used. Or assign to a __Hicon variable, it will call DestroyIcon in destructor.
#3
example - function dlg_button_images in Archive.qml.
#4
Dear Gintaras,

Thank you for this useful recommendation. I will take care about it immediately. Do I understand well that if an icon is assigned to a __Hicon variable, then it will destroy itself automatically upon dialog exit?

I also thank you for the reference to the archive.qml thesaurus. I run dlg_button_images but I failed to display icon (bitmap) with text. I understand that this might due to my OS (XP SP3) or not?

Sorry for bothering. Best regards.
#5
Destructor is called when variable life time ends. For locals - when that function exits. For thread - when thread ends. For global - when unloading QM file. Dialog procedure function is called many times.

dlg_button_images should display images on all OS, if the image file exists.
#6
Thank you for this perfect explanation regarding destructor.

My reference to the OS was due to the facts (a) I cannot see on buttons image and text together (for example when running dlg_button_images control 4) although I see icons alone (control 6), in view of the comment :

Quote:note that BM_SETIMAGE does not work on OS before Vista if BS_BITMAP or BS_ICON style is not set

Please advise.
#7
Alternative for XP - control of class ToolbarWindow32.
#8
I understand that you mean :

(a) In the case of XP I cannot expect a button with both text & icon.

(b) In the case of XP and dlg_button_images, adding an item of class ToolbarWindow32. Could you please give an example?

Thank you!
#9
Macro Draw dialog button icon
Code:
Copy      Help
str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 224 136 "Dialog"
;1 Button 0x54030001 0x4 116 116 48 14 "OK"
;2 Button 0x54030000 0x4 168 116 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040308 "*" "" "" ""

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


#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,__Hicon- t_hi=GetFileIcon("$qm$\paste.ico")
,SetWindowSubclass(id(1 hDlg) &sub.WndProc_Subclass 1 0)
,
,case WM_DESTROY
,case WM_COMMAND goto messages2
ret
;messages2
sel wParam
,case IDOK
,case IDCANCEL
ret 1


#sub WndProc_Subclass
function# hwnd message wParam lParam uIdSubclass dwRefData

int R=DefSubclassProc(hwnd message wParam lParam)

sel message
,case WM_NCDESTROY
,RemoveWindowSubclass(hwnd &sub.WndProc_Subclass uIdSubclass)
,
,case WM_PAINT
,int dc=GetDC(hwnd)
,__Hicon- t_hi ;;out t_hi
,DrawIconEx(dc 4 4 t_hi 0 0 0 0 DI_NORMAL)
,ReleaseDC hwnd dc

ret R
#10
It is Perfect! I really feel much obliged. I think that that you may link this post to Rich Edit on Toolbar Buttons and Text
#11
Function DT_SetButtonIcon
Code:
Copy      Help
;/
function hDlg imageList $buttons

;Sets to draw icons on dialog buttons using an imagelist.

;hDlg - dialog handle.
;imageList - imagelist. Don't destroy too early. You can create imagelists with the imagelist editor (floating toolbar -> more tools) or at run time (call t_il.Create).
;icons - list of buttonId=imageIndex like "3=0 4=1 7=0".

;REMARKS
;Buttons must have space at the left side for icons.

;EXAMPLE
;,case WM_INITDIALOG
;,__ImageList- t_il.Load("$qm$\il_qm.bmp")
;,DT_SetButtonIcon hDlg t_il "1=25 2=32"


ARRAY(str) a
int i w x y
tok buttons a -1 " ="
for i 0 a.len/2
,x=val(a[i*2]) ;;id
,y=val(a[i*2+1]) ;;image index
,w=id(x hDlg 1); if(w=0) end F"control id {x} not found" 8; continue
,POINT* p
,if !GetWindowSubclass(w &sub.WndProc_Subclass 815476901 +&p)
,,p._new
,,SetWindowSubclass(w &sub.WndProc_Subclass 815476901 p)
,p.x=imageList; p.y=y
,if(IsWindowVisible(w)) InvalidateRect w 0 1


#sub WndProc_Subclass
function# hwnd message wParam lParam uIdSubclass POINT*p

int R=DefSubclassProc(hwnd message wParam lParam)

sel message
,case WM_NCDESTROY
,RemoveWindowSubclass(hwnd &sub.WndProc_Subclass p)
,p._delete
,
,case WM_PAINT
,int dc=GetDC(hwnd)
,ImageList_Draw p.x p.y dc 4 4 ILD_TRANSPARENT
,ReleaseDC hwnd dc

ret R
#12
This is an integrated example to use dialog buttons with text & images :

Function Dialog_Button_Text
Code:
Copy      Help
;www.quickmacros.com/forum/viewtopic.php?p=31473

str dd=
;BEGIN DIALOG
;0 "" 0x90C80AC8 0x0 0 0 195 69 "Dialog"
;3 Button 0x54032000 0x0 18 7 48 14 "Reset"
;1 Button 0x54030001 0x4 65 47 48 14 "OK"
;2 Button 0x54034040 0x4 139 46 48 14 "Cancel"
;END DIALOG
;DIALOG EDITOR: "" 0x2040308 "*" "" "" ""

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

#sub DlgProc
function# hDlg message wParam lParam

sel message
,case WM_INITDIALOG
,__ImageList- t_il.Create("$qm$\copy.ico[]$qm$\paste.ico")
,DT_SetButtonIcon hDlg t_il "1=0 2=1"
,case WM_DESTROY
,case WM_COMMAND goto messages2

ret
;messages2
sel wParam
,case 3
,DT_SetButtonIcon hDlg t_il "1=1 2=0"
(`c);,www.quickmacros.com/forum/viewtopic.php?p=21390

I cannot understand why in the case of "messages2" change of buttons (at execution time) it was necessary to use InvalidateRect to fix the display. Any idea or advice is - as always - welcome.
#13
Please use the updated version of DT_SetButtonIcon.


Forum Jump:


Users browsing this thread: 1 Guest(s)