Thanks for this idea Areilius. I've been using custom Msgboxes a lot (because they just look nicer and can be centered on the main Gui) but up until now they all only had an "OK" button
Meh it was just an example. You can add to it if you want
Done.
It got a bit crazy with all the options (I can't remember the order of 5 parameters, let alone 20...), so all the options just go in one big Options parameter. Zero or more of the following strings may be present in Options :wink: :
ButtonsXXXX: The Msgbox can have up to three buttons. Either just Buttons1 (Okay), Buttons2 (Okay|Cancel), Buttons3 (Yes|No|Cancel) or specify custom button names, like this: ButtonsSave|Discard. Note: You have to replace spaces with "_": Save_and_Exit.
The Msgbox() function returns the name of the button the user clicked (note that ampersands are omitted. &Okay -> Okay).
Default*: Specifies which button should be the default button. If this option is not present, it's always the last button. To have no default button, specify Default0.
Icon*: can be one of the following: !,?,X,i; Should be self-explanatory...
Checkbox*: Adds a checkbox at the bottom left corner, for instance: CheckboxDon't_ask_me_again. The funtion sets ErrorLevel to 1 if the user checked the checkbox.
w*: The width of the Msgbox. This is useful because the text will be word-wrapped automatically. Ex: w300
c*: The text color. Ex: cGreen
Background*: Background color.
s*: Size of font.
bold, italich*: This is a bit confusing - this is the height of the button(s), not the window. The default is 20.
Owner*: For instance "Owner14". By default the Msgbox is owned and modal. If the owner is unspecified, the function used A_Gui, or simply 1 when A_gui is blank (though in any case it checks if the owner exists; if it doesn't, the Msgbox is simply shown normally).
-Owner: If you don't want the the Msgbox to be owned (in this case it isn't modal either, of course).
-Modal: The Msgbox can still be owned, but the user can interact with the owner while the Msgbox is beeing displayed.
-Toolwindow: By default it's a toolwindow because I like toolwindows.
+AlwaysOnTop: Guess what.
-Caption: I like to use this in combination with...
+0x800000: ...sometimes. (+0x800000 is a thinline border).
FontName has to be an extra param because it contains spaces...
Note that I used "FFFACD" as the default for Background and Comic Sans MS as the default FontName... you can change that to suit your needs.
I figured GuiNumber should be an extra param because that way it can be an expression (and the only reason I can think of to not use the default is when you're dynamically keeping track of Gui numbers...).
Note that because of the way the Options param works I added a small helper funtion to keep the code at least somewhat tidy. Make sure you include it along with the main function.
One thing that should be mentioned is that we have to turn Critical off before "WinWaitClose" in case the thread that called the function was critical. Otherwise the button subroutines are buffered until the Gui closes, which never happens because the button subroutines are buffered...
I don't think it matters much in most cases, but if it's really critical that the thread be critical, better don't use this function in it, or at least turn on Critical after the function returns.
I just used preview - I'll better shut up. Just try it.
Gui,10: Color, FFFACD
Gui,10: Font, s14 bold, Comic Sans MS
Gui,10:Add, Text, c00008B, Msgbox(message="",Options="",Title="",FontName="",GuiNumber=66)
Gui,10:Font, cCC0000 s12
Gui,10: Add, Text,
, Options: Buttons* Default* Icon* Checkbox* w* c* Background* s* bold italic h* Owner*`n -Toolwindow -Modal -Owner +AlwaysOnTop -Caption +0x800000
Gui,10:Font, s10 cblack
message1 = Do you really want to delete these files?
message2 = The changes you made have been saved. Do you wish to continue?
message3 =
(
Sorry, an error occured. Error code: 66.
(Note: Press Ctrl+C to copy this message to the clipboard).
Do you wish to continue?
)
message4 =
(
Note: If you tried out Example #5, this Msgbox is will be owned by that Gui (which you couldn't close because it has no buttons:))
Therefore we use a different Gui numer and set the owner manually.
)
ex1 = Msgbox()
ex2 = Msgbox(message1,"Buttons&Yes|&No Icon! w150 cGreen s11 BackgroundFFFACD bold","Warning","Times New Roman")
ex3 = Msgbox(message2,"ButtonsYes|I_don't_know|Discard Icon? bold c6495ED BackgroundFFF8DC s10 w300 -Modal","Save changes?","Matisse ITC")
ex4 = Msgbox(message3,"ButtonsYes|No IconX w250 s8 bold c8B0000 BackgroundF5DEB3 CheckboxDon't_ask_me_again.","Invalid Entry", "Comic Sans MS")
ex5 = Msgbox(message3,"Buttons IconX w300 s10 bold c8B0000 BackgroundF5DEB3 -Toolwindow +AlwaysOnTop -Caption +0x800000 -Owner h25","Invalid Hotkey", "Comic Sans MS")
ex6 = Msgbox(message4, "ButtonsDestroy_Gui66|Don't_destroy_owner IconI w250 s8 bold cGreen BackgroundFFFACD Owner66","Gui67","Comic Sans MS",67)
Loop 6
{
If a_index = 1
Gui,10: Add, Button, vbutton%a_index% h20 Section gG, Example %a_index%
else
Gui,10: Add, Button, vbutton%a_index% xs Section h20 gG, Example %a_index%
Gui, 10: Add, Text, vtxt%a_index% ys w500, % ex%a_index%
}
Gui,10: Show, Autosizex100 y100, Gui 10
return
10GuiClose:
ExitApp
return
G:
If a_guicontrol = button1
t := Msgbox()
else if a_guicontrol = button2
t := Msgbox(message1,"Buttons&Yes|&No Icon! w150 cGreen s11 BackgroundFFFACD bold","Warning","Times New Roman")
else if a_guicontrol = button3
t := Msgbox(message2,"ButtonsYes|I_don't_know|Discard Icon? bold c6495ED BackgroundFFF8DC s10 w300 -Modal","Save changes?","Matisse ITC")
else if a_guicontrol = button4
t := Msgbox(message3,"ButtonsYes|No IconX w250 s8 bold c8B0000 BackgroundF5DEB3 CheckboxDon't_ask_me_again.","Invalid Entry", "Comic Sans MS")
else if a_guicontrol = button5
{
t := Msgbox(message3
,"Buttons IconX w300 s10 bold c8B0000 BackgroundF5DEB3 -Toolwindow +AlwaysOnTop -Caption +0x800000 -Owner h25"
,"Invalid Hotkey", "Comic Sans MS")
}
else if a_guicontrol = button6
{
t := Msgbox(message4
, "ButtonsDestroy_Gui66|Don't_destroy_owner IconI w250 s8 bold cGreen BackgroundFFFACD Owner66","Gui67"
,"Comic Sans MS",67)
If t = Destroy Gui66
Gui, 66: Destroy
}
Tooltip, ReturnValue: %t%`nErrorLevel: %ErrorLevel%
SetTimer, Tip, 2500
return
Tip:
Tooltip
return
Msgbox(message="",Options="",Title="",FontName="",GuiNumber=66) {
global MessageBoxIcon,MessageBoxText,MessageBoxButton1,MessageBoxButton2
,MessageBoxButton3,MessageBoxButtonName1,MessageBoxButtonName2,MessageBoxCheckbox
Gui, %GuiNumber%:Default
Gui, Destroy
autotrim = %a_autotrim% ;store it so we can reset it later
AutoTrim Off ;necessary because of the "Options" param
Options = %a_space%%Options%%a_space% ;leading and trailing spaces (for StrEnd())
If message =
message = Press okay to continue. ;this is the default for the normal Msgbox command also
;the "Buttons" option can be numeric (1-3) or a string seperated by pipes (|).
;the default is "Okay"
If (InStr(Options, "Buttons") = 0 OR InStr(Options, "Buttons1"))
buttons = Okay
else IfInString, Options, Buttons2
buttons = Okay|Cancel
else IfInString, Options, Buttons3
buttons = Yes|No|Cancel
else
buttons := StrEnd(Options,"buttons")
;If Owner is unspecified, use A_Gui (if non-blank)
;else, use Gui#1 as owner (unless -Owner" is present in Options)
;in any case, we check if the owner exists before using it
If ! InStr(Options, "-Owner") {
owner := StrEnd(Options,"owner")
If ! owner {
If a_gui <>
owner = %a_gui%
else
owner = 1
}
Gui, %owner%: +LastfoundExist
If WinExist() {
;unless specified otherwise, disable the owner.
;note that this causes that neat flickering when
;the user tries to interact with the owner
IfNotInString, Options, -Modal
Gui, %owner%: +Disabled
Gui, +Owner%owner%
WinGetPos, x, y, w, h ;get the position of the owner
}
else
owner =
}
IfNotInString, Options, -Toolwindow
Gui, +Toolwindow
IfInString, Options, +AlwaysOnTop
Gui, +AlwaysOnTop
IfInString, Options, -Caption
Gui, -Caption
IfInString, Options, +0x800000
Gui, +0x800000
Gui, +lastfound -SysMenu
GuiID := WinExist() ;used later in the Hotkey command
;get BackgroundColor and TextColor, as well as bold/italic
BgColor := StrEnd(Options, "Background")
color := StrEnd(Options, "c")
IfInString, Options, %a_space%bold%a_space%
bold = bold
IfInString, Options, %a_space%italic%a_space%
italic = italic
size := StrEnd(Options, "s")
;change these default values to whatever you prefer
If FontName =
FontName = Comic Sans MS
If BgColor =
BgColor = FFFACD
If color =
color = black
If size =
size = 8
Gui, Color, %BgColor%
Gui, Font, s%size% %bold% %italic% c%color%, %fontName%
Gui, Margin, 5, 5
icon := StrEnd(Options, "Icon")
;the corresponding icon #'s
If Icon = !
i = 2
else if icon = ?
i = 3
else if icon = x
i = 4
else if icon = i
i = 5
;it gets a bit ugly now because of the sectioning with/without the icon...
If icon {
Gui, Add, Picture, vMessageBoxIcon Section Icon%i%, User32.dll
ys = ys
xs = xs
}
width := StrEnd(Options, "w")
Gui, Add, Text, vMessageBoxText %ys% w%width%, %message%
Gui, Font, norm ;I think buttons with bold font are ugly ;)
button_h := StrEnd(Options, "h") ;just in case anyone wants to specify the button height...
If button_h =
button_h = 20
If button_h not integer
button_h = 20
;add the buttons:
Loop, Parse, buttons, |
{
StringReplace, b, a_loopfield, _, %a_space%,1
numButtons++ ;for the subroutine that positions the buttons
If a_index = 1
Gui, Add, Button, vMessageBoxButton%a_index% Section h%button_h% %xs% gMessageBox_MessageBoxButtonPushed, %b%
else
Gui, Add, Button, vMessageBoxButton%a_index% ys h%button_h% gMessageBox_MessageBoxButtonPushed, %b%
}
checkboxText := StrEnd(Options,"Checkbox")
StringReplace, checkboxText, checkboxText, _, %a_space%,1
If checkboxText <>
Gui, Add, Checkbox, vMessageBoxCheckbox %xs%, %checkboxText%
default_button := StrEnd(Options, "Default")
;if default_button is unspecified, use the last button
If default_button =
default_button = %numButtons%
;to have NO default button, specify Default0
If default_button <> 0
GuiControl, +Default, MessageBoxButton%default_button%
GuiControl, Focus, MessageBoxButton%default_button%
;this works for the real Msgbox, so we need it too :)
Hotkey, IfWinActive, ahk_id%GuiID%
Hotkey, ^c, MessageBox_CopyMessageBoxTextToClipboard
Gui, Show, Autosize Hide, %title%
Gosub, MessageBox_MoveMessageBoxButtons ;move the buttons
;if we have no owner, just show the Gui in the middle of the screen
;else, position is in the middle of its owner
If owner {
Gui, +Lastfound
WinGetPos,,,msg_w,msg_h
msg_x := x + w/2 - msg_w/2
msg_y := y + h/2 - msg_h/2
Gui, Show, x%msg_x% y%msg_y%, %title%
} else
Gui, Show,, %title%
;this thread can't be critical (otherwise the MessageBox_ButtonPushed thread
;would be buffered endlessly...)
Critical Off
WinWaitClose ;wait until the user clicks one of the buttons
;turn off the hotkey and reset autotrim
Hotkey, ^c, MessageBox_CopyMessageBoxTextToClipboard, Off
Autotrim %autotrim%
If MessageBoxCheckbox = 1
ErrorLevel = 1
else
ErrorLevel = 0
If owner
Gui %owner%:Default
else
Gui, 1:Default
return return_value ;return the return value set by the ButtonPushed thread
MessageBox_MessageBoxButtonPushed:
;if we've been asked to redraw:
StringRight, num, a_guicontrol, 1 ;the button #
GuiControlGet, return_value,,%a_guicontrol%
StringReplace, return_value, return_value, & ;get rid of the ampersand
Gui, Submit
If owner
Gui, %owner%: -Disabled
Gui, Destroy
return
;the hotkey thread
MessageBox_CopyMessageBoxTextToClipboard:
clipboard = %message%
return
;center the buttons:
MessageBox_MoveMessageBoxButtons:
Gui %GuiNumber%:Default
WinGetPos,,,gw
gw -= 6
GuiControlGet, txt, Pos, MessageBoxText
If ! icon
GuiControl, Move, MessageBoxText, % "x" gw/2 - txtW/2
Loop 3
GuiControlGet, p%a_index%, Pos, MessageBoxButton%a_index%
If numButtons = 1
GuiControl, Move, MessageBoxButton1, % "x" gw/2 - p1w/2
else if (numButtons = 2) {
GuiControl, Move, MessageBoxButton1, % "x" gw/2 - ((p1w + p2w + 5)/2)
GuiControl, Move, MessageBoxButton2, % "x" gw/2 - ((p1w + p2w + 5)/2) + p1w + 5
} else if (numButtons = 3) {
GuiControl, Move, MessageBoxButton1, % "x" gw/2 - ((p1w + p2w + p3w + 10)/2)
GuiControl, Move, MessageBoxButton2, % "x" gw/2 - ((p1w + p2w + p3w + 10)/2) + p1w + 5
GuiControl, Move, MessageBoxButton3, % "x" gw/2 - ((p1w + p2w + p3w + 10)/2) + p1w + p2w + 10
} return
}
;########## this small helper funtion also has to be present ############
;this function extracts the trailing characters of a string
;(for instance "White" from BackgroundWhite etc.)
StrEnd(O,str) {
IfNotInString, O, %a_space%%str%
return
StringMid, e, O, InStr(O, " " str) + StrLen(str) + 1
, InStr(O, a_space, "", InStr(O, " " str) + 1) - InStr(O, " " str) - StrLen(str) - 1
return e
}