Tip: InputBox

Share your advanced PureBasic knowledge/code with the community.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Tip: InputBox

Post by BackupUser »

Code updated For 5.20+

Restored from previous forum. Originally posted by PB.

Here's my own version of an input requester, which is superior to the
built-in InputRequester() command in these ways:

(1) It's "modal" (it locks the calling window until done).
(2) The prompt area is bigger and can have multi-line text.
(3) It has a Cancel button in addition to an OK button.
(4) It has a standard Windows look-and-feel about it.
(5) It plays the "question" audio prompt sound.

It works with or without a calling window, and here's how you call it:

a$=InputBox(title$,prompt$,default$)

Naturally prompt$ can include Chr(13) for multi-line text, and default$
can be empty (null) if you don't want a default entry placed in it.
I called it InputBox() so as not to clash with InputRequester(), and
because it emulates the Visual Basic InputBox() command.

Code edited out, see new v4.00 version below.
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by TronDoc.

I will try it at my first opportunity.
It sounds very well thought out.
Joe

elecTRONics DOCtor
{registeredPB}P150 32Mb w98/DOS/Linux NO DirX NO IE :wink:
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by redacid.

Very nice! Just what I´ve been searching for (because I was too lazy to do it myself)...

regards,
Redacid
---
Viva Los Tioz!
registered user of PB3.20 on WinXP
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by waffle.

i'm always amazed at how much work is invovled to do something so "simple" in windows :)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by Fangbeast.

I'm always amazed at PB's imagination. He not only comes up with some great solutions, he also explains them.

Good on ya mate !! :)

Fangles woz ear orright den?
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by TheBeck.

Thanks PB, I've added this to my IncludeFile stash. :)
BackupUser
PureBasic Guru
PureBasic Guru
Posts: 16777133
Joined: Tue Apr 22, 2003 7:42 pm

Post by BackupUser »

Restored from previous forum. Originally posted by PB.

Thanks for the kind words, everyone. :)


PB - Registered PureBasic Coder
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

Code updated For 5.20+

And here's an enhanced update that works with PureBasic v4.30, which now
supports a password flag and also returns Chr(1) if the InputBox is cancelled
by the user (which is great to know because just returning null won't tell you
if the requester was cancelled or an empty string entered). Enjoy! :)

Code: Select all

Procedure.s InputBox(title$,prompt$,def$,password)
  box=OpenWindow(999,0,0,500,145,title$,#PB_Window_ScreenCentered)
  If box<>0
    TextGadget(996,6,8,487,70,prompt$)
    If password=0 : flags=#ES_MULTILINE|#ES_AUTOVSCROLL : Else : flags=#PB_String_Password|#ES_AUTOVSCROLL : EndIf
    StringGadget(997,6,85,487,20,def$,flags) : ButtonGadget(998,365,114,60,23,"OK") : ButtonGadget(999,433,114,60,23,"Cancel")
    SendMessage_(GadgetID(997),#EM_SETSEL,0,Len(def$)) : GetAsyncKeyState_(#VK_RETURN) : GetAsyncKeyState_(#VK_ESCAPE)
    StickyWindow(999,#True) : SetForegroundWindow_(WindowID(999)) : SetActiveGadget(997) : MessageBeep_(#MB_ICONQUESTION)
    Repeat
      ev=WaitWindowEvent(1) : id=EventGadget() : ret=GetAsyncKeyState_(#VK_RETURN) : esc=GetAsyncKeyState_(#VK_ESCAPE)
      a=GetForegroundWindow_()
      If a<>box
        thread1=GetWindowThreadProcessId_(@a,0) : thread2=GetWindowThreadProcessId_(@box,0)
        If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#True) : EndIf
        SetForegroundWindow_(box) : Sleep_(1)
        If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#False) : EndIf
        SetActiveGadget(997) : MessageBeep_(#MB_ICONQUESTION)
      EndIf
    Until (ev=#PB_Event_Gadget And (id=998 Or id=999)) Or ret<>0 Or esc<>0 Or ev=#PB_Event_CloseWindow
    If id=998 Or ret<>0 : text$=GetGadgetText(997) : Else : text$=Chr(1) : EndIf
    CloseWindow(999)
  EndIf
  ProcedureReturn text$
EndProcedure

a$=InputBox("Test","Enter something:","default",0) ; Use 1 at end for passwords.
If a$=Chr(1) : Debug "InputBox cancelled" : Else : Debug a$ : EndIf
Last edited by PB on Sat Mar 28, 2009 2:35 pm, edited 4 times in total.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

nice..
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Same as the cool code above,
only the return value/text is slightly differently handled.
And if your lazy this means you do not really have to check at all if the user clicked cancel, the code will handle that itself :)

Code: Select all

Procedure.s InputBox(title$,prompt$,def$,password)
  box=OpenWindow(999,0,0,360,145,#PB_Window_ScreenCentered,title$)
  If box<>0 And CreateGadgetList(WindowID(999))<>0
    TextGadget(996,6,8,347,70,prompt$)
    If password=0 : flags=#ES_MULTILINE|#ES_AUTOVSCROLL : Else : flags=#PB_String_Password|#ES_AUTOVSCROLL : EndIf
    StringGadget(997,6,85,347,20,def$,flags) : ButtonGadget(998,225,114,60,23,"OK") : ButtonGadget(999,293,114,60,23,"Cancel")
    SendMessage_(GadgetID(997),#EM_SETSEL,0,Len(def$)) : GetAsyncKeyState_(#VK_RETURN) : GetAsyncKeyState_(#VK_ESCAPE)
    StickyWindow(999,#True) : SetForegroundWindow_(WindowID(999)) : SetActiveGadget(997) : MessageBeep_(#MB_ICONQUESTION)
    Repeat
      ev=WaitWindowEvent(1) : id=EventGadget() : ret=GetAsyncKeyState_(#VK_RETURN) : esc=GetAsyncKeyState_(#VK_ESCAPE)
      a=GetForegroundWindow_()
      If a<>box
        thread1=GetWindowThreadProcessId_(@a,0) : thread2=GetWindowThreadProcessId_(@box,0)
        If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#True) : EndIf
        SetForegroundWindow_(box) : Sleep_(1)
        If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#False) : EndIf
        SetActiveGadget(997) : MessageBeep_(#MB_ICONQUESTION)
      EndIf
    Until (ev=#PB_Event_Gadget And (id=998 Or id=999)) Or ret<>0 Or esc<>0 Or ev=#PB_Event_CloseWindow
    If id=998 Or ret<>0 : text$=GetGadgetText(997) : Else : text$=def$ : EndIf
    CloseWindow(999)
  EndIf
  ProcedureReturn text$
EndProcedure


;Will automaticaly return the default value if the user hit cancel
a$=InputBox("Test","Enter something:","default",0)
Debug a$

;and if you wish to "know" if the user actualy pressed cancel

If a$="default" : Debug "InputBox cancelled" : Else : Debug a$ : EndIf
User avatar
bingo
Enthusiast
Enthusiast
Posts: 210
Joined: Fri Apr 02, 2004 12:21 pm
Location: germany/thueringen
Contact:

Post by bingo »

simple ... but effective :lol:

Code: Select all

Procedure.s Uni2Ansi(*Unicode.l) 
size.l = WideCharToMultiByte_(#CP_ACP, 0, *Unicode, -1, #Null, #Null, #Null, #Null) 
ansi.s=Space(size) 
WideCharToMultiByte_(#CP_ACP, 0, *Unicode, -1, @ansi, size, #Null, #Null) 
ProcedureReturn ansi  
EndProcedure

Procedure.l Ansi2Uni(ansi.s) ;short way to unicode
SHStrDup_(@ansi,@memtarget)
ProcedureReturn memtarget
EndProcedure

Structure VARIANT 
  vt.w 
  wReserved1.w 
  wReserved2.w 
  wReserved3.w 
  StructureUnion 
     cVal.b                                        
     iVal.w                                       
     lVal.l                                          
     bstrVal.l                                  
     pdispVal.l                           
  EndStructureUnion 
EndStructure 

Global VarResult.VARIANT

Procedure showhtmlwin(source.s)
*pMoniker.IMoniker
res = CreateURLMoniker_(0, Ansi2Uni(source),@*pMoniker)
If res = 0
OpenLibrary(1,"mshtml.dll")
CallFunction (1, "ShowHTMLDialog",FindWindow_("Progman", "Program Manager"), *pMoniker,0 ,ansi2uni("help:no;status:0;unadorned:1") ,@VarResult)
*pMoniker\release()
CloseLibrary(1)
EndIf
EndProcedure

showhtmlwin("res://" + GetFilePart(ProgramFilename()) + "/input.htm")

MessageRequester("input return ...",uni2ansi(VarResult\pdispVal),#PB_MessageRequester_Ok)

End
input.htm for pb-resources

Code: Select all

<HTML id=dlgAbout  STYLE="width: 200; height: 100;">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<HEAD>
</HEAD>
<SCRIPT LANGUAGE="JavaScript">
function testResults (form) {
window.returnValue = form.inputbox.value;
window.close()
}
</SCRIPT>
<BODY onload="self.focus(); document.inputform.inputbox.focus();">
<FORM NAME="inputform" ACTION="" METHOD="GET">
<table border="10" cellpadding="0" cellspacing="0" width="200" height="100" bgcolor="#CCCCCC" bordercolordark="blue" bordercolorlight="red">
<tr>
<td align="center" valign="middle">
<p><b>your INPUT:</b><br>
<br>
<INPUT TYPE="text" NAME="inputbox" VALUE="" maxlength="10" size="10" style="color:white; background-color:blue;"> &nbsp;<INPUT TYPE="button" NAME="button" Value="-- ok --" onClick="testResults(this.form)" style="color:yellow; background-color:blue;">
</p>
</td>
</tr>
</table>
</FORM>
</BODY>
</HTML>
inputbox with html

Image

a replacement for the "lifeless" InputRequester...
["1:0>1"]
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Now now, you can do bette than that! Like this for example :P

Use same PB code as above,
but this html instead :twisted:

Code: Select all

<HTML id=dlgAbout  STYLE="width: 250; height: 150;">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<HEAD>
</HEAD>
<SCRIPT LANGUAGE="JavaScript">
function testResults (form) {
window.returnValue = form.inputbox.value+'\n'+form.inputbox2.value;
window.close()
}
</SCRIPT>
<BODY onload="self.focus(); document.inputform.inputbox.focus();">
<FORM NAME="inputform" ACTION="" METHOD="GET">
<table border="10" cellpadding="0" cellspacing="0" width="250" height="150" bgcolor="#CCCCCC" bordercolordark="blue" bordercolorlight="red">
<tr>
<td align="center" valign="middle">
<p><b>your INPUT:</b><br>
<br>
<INPUT TYPE="text" NAME="inputbox" VALUE="" maxlength="10" size="10" style="color:white; background-color:blue;">
<INPUT TYPE="text" NAME="inputbox2" VALUE="" maxlength="10" size="10" style="color:white; background-color:blue;"> &nbsp;<INPUT TYPE="button" NAME="button" Value="-- ok --" onClick="testResults(this.form)" style="color:yellow; background-color:blue;">
</p>
</td>
</tr>
</table>
</FORM>
</BODY>
</HTML>
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post by PB »

@Rescator: Your example is majorly flawed in two ways:

(1) If I click Okay, I get told that I cancelled, which is definitely not true.
(2) If I enter "123" and click Cancel, the value returned is still the default.

Back to the ol' drawing board for you. :)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Redo the last line to:

Code: Select all

If a$="default" : Debug "No change!" : Else : Debug a$ : EndIf

:lol:
akj
Enthusiast
Enthusiast
Posts: 665
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

I thought I would add my own twopennyworth to this thread by making a few changes that seemed useful:

1. Width and height parameters added. These are not the dimensions of the overall input box, but those of the text box containing the prompt string. If the width and height are both specified as zero, they default to 128 x 20, which is about the smallest useful size.

2. Instead of just being able to set the password flag, any #PB_String_xxx flag can now be set.
For example: #PB_String_UpperCase

3. The OK button has been moved further to the left (because I preferred the appearance of the input box to be symmetrical).

4. The input box no longer beeps each second when it loses the input focus (because the beeps annoyed me).

5. All gadget numbers are now generated by #PB_Any instead of being hardcoded as arbitrary numbers such as 997.

6. All variables are now declared in order to be EnableExplicit compliant.

Code: Select all

Procedure.s InputBox(txtw, txth, title$, prompt$, def$="", flags=0)
; A version of InputRequester() by BackupUser
; Modified by AKJ 18-Oct-06
; Downloaded: www.purebasic.fr/english/viewtopic.php?t=2412
; textw and txth are the outer dimensions of the prompt text gadget
; Available flags are:
;   #PB_String_{BorderLess  LowerCase  Numeric  Password  ReadOnly  Uppercase}
; Features:
; (1) Modal (locks the calling window until done)
; (2) Prompt area is larger
; (3) Prompt area supports multi-line text with Chr(13)
; (4) Cancel button in addition to OK button
; (5) Returns the default string (def$) if the Cancel button is pressed
; (6) Returns "" if an error occurs
; (7) Standard Windows look-And-feel
; (8) Plays the "question" prompt sound
; (9) Works with or without a calling window
;(10) Emulates the Visual Basic InputBox() command
;(11) Supports all #PB_String_xxx flags
Protected winBox, txtPrompt, strInput, butOK, butCancel ; Gadgets
Protected box, ev, id, ret, esc, a, thread1, thread2, text$=""
If txtw<128 : txtw=128 : EndIf ; To show buttons correctly
If txth<20 : txth = 20 : EndIf ; Height of a normal text line
winBox=OpenWindow(#PB_Any,0,0,txtw+13,txth+20+23+8*4,title$,#PB_Window_ScreenCentered)
box=WindowID(winBox)
If winBox And CreateGadgetList(box)
  txtPrompt=TextGadget(#PB_Any,6,8,txtw,txth,prompt$)
  If flags&#PB_String_Password=0 : flags|#ES_MULTILINE : EndIf
  strInput=StringGadget(#PB_Any,6,txth+8*2,txtw,20,def$,flags|#ES_AUTOVSCROLL)
  butOK=ButtonGadget(#PB_Any,6,txth+20+8*3,60,23,"OK") ; Set x=txtw-122 for button to be on the right
  butCancel=ButtonGadget(#PB_Any,txtw-54,txth+20+8*3,60,23,"Cancel")
  SendMessage_(GadgetID(strInput),#EM_SETSEL,0,Len(def$))
  GetAsyncKeyState_(#VK_RETURN) : GetAsyncKeyState_(#VK_ESCAPE)
  StickyWindow(winBox,#True) : SetForegroundWindow_(box) : SetActiveGadget(strInput) : MessageBeep_(#MB_ICONQUESTION)
  Repeat
    ev=WaitWindowEvent(1) : id=EventGadget() : ret=GetAsyncKeyState_(#VK_RETURN) : esc=GetAsyncKeyState_(#VK_ESCAPE)
    a=GetForegroundWindow_()
    If a<>box
      thread1=GetWindowThreadProcessId_(@a,0) : thread2=GetWindowThreadProcessId_(@box,0)
      If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#True) : EndIf
      SetForegroundWindow_(box) : Sleep_(1)
      If thread1<>thread2 : AttachThreadInput_(thread1,thread2,#False) : EndIf
      SetActiveGadget(strInput); !!! : MessageBeep_(#MB_ICONQUESTION)
    EndIf
  Until (ev=#PB_Event_Gadget And (id=butOK Or id=butCancel)) Or ret<>0 Or esc<>0 Or ev=#PB_Event_CloseWindow
  If id=butOK Or ret<>0 : text$=GetGadgetText(strInput) : Else : text$=def$ : EndIf
  CloseWindow(winBox)
EndIf
ProcedureReturn text$
EndProcedure

; Example using BackupUser's dimensions for the prompt text gadget
Debug InputBox(487, 70, "Test", "Enter something:", "default", #PB_String_UpperCase)
Anthony Jordan
Post Reply