• Welcome to Theos PowerBasic Museum 2017.

Input-box replacement-SLL

Started by Theo Gottwald, January 24, 2012, 10:35:02 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Theo Gottwald

The question of a perfect input-box replacement was asked before, but it was never solved.

It must have:
- get immediately input focus
- take default text and
- place the cursor behind the default text
- also should be able to use %ES_PASSWORD
- and have the standard features of the PB-INPUTBOX$
- works with ansi and unicode,
- be  High DPI aware.
- don't uses any global variable!
- be of course thread safe.

and it must be just a snap to add it to any program. Just like a

#LINK "JR_Inputbox.sll"

Taking all this it must be something from Jose's window class "CWindow".

And now here is an example how i just copied some code out, modified it a bit and made it into an completely modular SLL.
This way, alll sorts of dialogs can be added to a program just as a SLL!


' ========================================================================================
' Input box dialog
' Parameters:
' - hParent = Handle of the parent window
' - x, y = The location on the screen to display the dialog. If both are 0, the dialog
'   is centered on the screem.
' - strCaption = Caption of the window
' - strPrompt = Prompt string
' - strText = Text to edit
' - nLen = Maximum length of the string to edit (default = 260 characters)
'   Note: The maximum length is 2048 characters.
' ========================================================================================

#COMPILE SLL "JR_Inputbox.sll"
#DIM ALL
#OPTIMIZE SIZE
#INCLUDE "Win32API.inc"
#INCLUDE "CWindow.inc"

' A01 0/1 - Password or not

#IF %DEF(%UNICODE)
FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS WSTRING, BYVAL strPrompt AS WSTRING, BYVAL strText AS WSTRING,OPT BYVAL A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) common AS WSTRING
#ELSE
FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS STRING, BYVAL strPrompt AS STRING, BYVAL strText AS STRING,opt A01 as long,opt BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) common AS STRING
#ENDIF

   LOCAL hEdit,T01 AS DWORD
#IF %DEF(%UNICODE)
   LOCAL szText AS WSTRINGZ * 2049
#ELSE
   LOCAL szText AS ASCIIZ * 2049
#ENDIF

if A01 THEN
   T01=%ES_Password or %ES_LEFT or %ES_AUTOHSCROLL or %WS_VISIBLE
else
   T01=-1
END IF

   ' // Create an instance of the class
   LOCAL pInputBox AS IWindow
   pInputBox = CLASS "CWindow"
   IF ISNOTHING(pInputBox) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD

   hwnd = pInputBox.CreateWindow(hParent, strCaption,x,y, 276, 142, _
          %WS_VISIBLE or %WS_CAPTION OR %WS_POPUPWINDOW, %WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT or %WS_EX_TOPMOST, _
          CODEPTR(CWindow_InputBox_WindowProc2))
   ' // Center the window
   IF x = 0 AND y = 0 THEN
      pInputBox.CenterWindow(hwnd, GetDesktopWindow)
   END IF
   AfxForceSetForegroundWindow hwnd

   ' // Add a label control
   pInputBox.AddLabel(hwnd, -1 , strPrompt, 21, 10, 240, 19, -1, -1)

   ' // Add a TextBox control  %ES_Password ?
   hEdit = pInputBox.AddTextBox(hwnd,_
                                 101,_
                                 "",_  ' Title
                                 21,33,_ ' x,y
                                 230, 19,_ ' With and height
                                 T01,_
                                  -1) ' Ext styles

   'SetWindowLong hEdit, %GWL_Style, (GetWindowLong(hEdit,%GWL_Style) Or %ES_Password )

   ' // Add the buttons
   pInputBox.AddButton(hwnd, %IDOK, "&Ok", 21, 72, 75, 22, -1, -1)
   pInputBox.AddButton(hwnd, %IDCANCEL, "&Cancel", 176, 72, 75, 22, -1, -1)

   ' // Set the text
   IF nLen = 0 THEN
      nLen = 260
   ELSE
      IF nLen < 1 OR nLen > 2048 THEN nLen = 2048
   END IF
   SendMessage hEdit, %EM_LIMITTEXT, nLen, 0
   IF LEN(strText) > nLen THEN strText = LEFT$(strText, nLen)
   SendMessage(hEdit, %WM_SETTEXT, 0, STRPTR(strText))
   SendMessage hEdit, %EM_SETSEL, len(strText), -1

   ' // Set the focus in the edit control
   SetFocus hEdit

   ' // Pointer to the allocated string to return the result
   SendMessage hwnd, %WM_USER + 1, VARPTR(szText), 0

   ' // Default message pump (you can replace it with your own)
   pInputBox.DoEvents

   ' // Enable the parent window
   'EnableWindow hParent, %TRUE

    SetFocus hEdit

   FUNCTION = szText

END FUNCTION
' ========================================================================================

' ========================================================================================
' Editor options callback function.
' ========================================================================================
FUNCTION CWindow_InputBox_WindowProc2 (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL nLen   AS LONG
#IF %DEF(%UNICODE)
   STATIC pText AS WSTRINGZ PTR
#ELSE
   STATIC pText AS ASCIIZ PTR
#ENDIF

   SELECT CASE uMsg

      CASE %WM_CREATE
         ' // Disable the owner of the modal window
         EnableWindow GetWindow(hwnd, %GW_OWNER), %FALSE

      CASE %WM_USER + 1
         ' // Pointer to allocated string to return the result
         IF wParam THEN
            pText = wParam
            EXIT FUNCTION
         END IF

      CASE %WM_COMMAND

         SELECT CASE LO(WORD, wParam)

            CASE %IDCANCEL
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

            CASE %IDOK
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXTLENGTH, 0, 0)
                  IF nLen > 2048 THEN nLen = 2048
                  nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXT, nLen + 1, pText)
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

         END SELECT

      CASE %WM_CLOSE
         ' // The owner window is enabled in WM_CLOSE rather than WM_DESTROY to
         ' // prevent the application from losing the focus. In WM_DESTROY the
         ' // modal window has already been removed from the screen by the system.
         ' // Because the remaining windows are disabled, the system gives the
         ' // focus to another application.
         EnableWindow GetWindow(hwnd, %GW_OWNER), %TRUE

      CASE %WM_DESTROY
         ' // Close the main window
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

END FUNCTION




Frank Brübach

#1
I am not sure, but your example doesn't work theo. I haven't using SLL examples often yet, but if I look at the code example the statement and parameters for the inputbox aren't complete. I reduced your example to simple exe with cWindow include (why you're using "win32api.inc" too, I think that's no purpose for it if you are working with cWindow.inc". you're idea for another inputbox via SLL I like though :)

' ========================================================================================
' Input box dialog
' Parameters:
' - hParent = Handle of the parent window
' - x, y = The location on the screen to display the dialog. If both are 0, the dialog
'   is centered on the screem.
' - strCaption = Caption of the window
' - strPrompt = Prompt string
' - strText = Text to edit
' - nLen = Maximum length of the string to edit (default = 260 characters)
'   Note: The maximum length is 2048 characters.
' ========================================================================================

'#COMPILE SLL "JR_Inputbox.sll"
#COMPILE EXE
#DIM ALL
#OPTIMIZE SIZE
'#INCLUDE "Win32API.inc" 'you don't need that one
#INCLUDE "CWindow.inc"


'#IF 0
FUNCTION PBMAIN () AS LONG

LOCAL S01 AS STRING

'S01=CWindow_InputBox2(0,"Hallo","Headline","-")
s01 = CWindow_InputBox2(0, "Hello", "shows an alternative InputBox", "-", 50,50,250,300) 'frank's correction
'MSGBOX s01
END FUNCTION
'#ENDIF

' A01 0/1 - Password or not

'#IF %DEF(%UNICODE)
FUNCTION CWindow_InputBox2(BYVAL hParent AS DWORD, BYVAL strCaption AS WSTRING, BYVAL strPrompt AS WSTRING, BYVAL strText AS WSTRING,OPT A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) COMMON AS WSTRING
'#ELSE
'FUNCTION CWindow_InputBox2 (BYVAL hParent AS DWORD, BYVAL strCaption AS STRING, BYVAL strPrompt AS STRING, BYVAL strText AS STRING,OPT A01 AS LONG,OPT BYVAL x AS LONG, BYVAL y AS LONG, OPTIONAL BYVAL nLen AS LONG) COMMON AS STRING
'#ENDIF

   LOCAL hEdit,T01 AS DWORD
'#IF %DEF(%UNICODE)
   LOCAL szText AS WSTRINGZ * 2049
'#ELSE
'   LOCAL szText AS ASCIIZ * 2049
'#ENDIF

IF A01 THEN
   T01=%ES_PASSWORD OR %ES_LEFT OR %ES_AUTOHSCROLL OR %WS_VISIBLE
ELSE
   T01=-1
END IF

   ' // Create an instance of the class
   LOCAL pInputBox AS IWindow
   pInputBox = CLASS "CWindow"
   IF ISNOTHING(pInputBox) THEN EXIT FUNCTION

   ' // Create the main window
   LOCAL hwnd AS DWORD

   hwnd = pInputBox.CreateWindow(hParent, strCaption,x,y, 276, 142, _
          %WS_VISIBLE OR %WS_CAPTION OR %WS_POPUPWINDOW, %WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT OR %WS_EX_TOPMOST, _
          CODEPTR(CWindow_InputBox_WindowProc2))
   ' // Center the window
   IF x = 0 AND y = 0 THEN
      pInputBox.CenterWindow(hwnd, GetDesktopWindow)
   END IF
   AfxForceSetForegroundWindow hwnd

   ' // Add a label control
   pInputBox.AddLabel(hwnd, -1 , strPrompt, 21, 10, 240, 19, -1, -1)

   ' // Add a TextBox control  %ES_Password ?
   hEdit = pInputBox.AddTextBox(hwnd,_
                                 101,_
                                 "",_  ' Title
                                 21,33,_ ' x,y
                                 230, 19,_ ' With and height
                                 T01,_
                                  -1) ' Ext styles

   'SetWindowLong hEdit, %GWL_Style, (GetWindowLong(hEdit,%GWL_Style) Or %ES_Password )

   ' // Add the buttons
   pInputBox.AddButton(hwnd, %IDOK, "&Ok", 21, 72, 75, 22, -1, -1)
   pInputBox.AddButton(hwnd, %IDCANCEL, "&Cancel", 176, 72, 75, 22, -1, -1)

   ' // Set the text
   IF nLen = 0 THEN
      nLen = 260
   ELSE
      IF nLen < 1 OR nLen > 2048 THEN nLen = 2048
   END IF
   SendMessage hEdit, %EM_LIMITTEXT, nLen, 0
   IF LEN(strText) > nLen THEN strText = LEFT$(strText, nLen)
   SendMessage(hEdit, %WM_SETTEXT, 0, STRPTR(strText))
   SendMessage hEdit, %EM_SETSEL, LEN(strText), -1

   ' // Set the focus in the edit control
   SetFocus hEdit

   ' // Pointer to the allocated string to return the result
   SendMessage hwnd, %WM_USER + 1, VARPTR(szText), 0

   ' // Default message pump (you can replace it with your own)
   pInputBox.DoEvents

   ' // Enable the parent window
   'EnableWindow hParent, %TRUE

    SetFocus hEdit

   FUNCTION = szText

END FUNCTION
' ========================================================================================

' ========================================================================================
' Editor options callback function.
' ========================================================================================
FUNCTION CWindow_InputBox_WindowProc2 (BYVAL hwnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG

   LOCAL nLen   AS LONG
#IF %DEF(%UNICODE)
   STATIC pText AS WSTRINGZ PTR
#ELSE
   STATIC pText AS ASCIIZ PTR
#ENDIF

   SELECT CASE uMsg

      CASE %WM_CREATE
         ' // Disable the owner of the modal window
         EnableWindow GetWindow(hwnd, %GW_OWNER), %FALSE

      CASE %WM_USER + 1
         ' // Pointer to allocated string to return the result
         IF wParam THEN
            pText = wParam
            EXIT FUNCTION
         END IF

      CASE %WM_COMMAND

         SELECT CASE LO(WORD, wParam)

            CASE %IDCANCEL
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

            CASE %IDOK
               IF HI(WORD, wParam) = %BN_CLICKED THEN
                  nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXTLENGTH, 0, 0)
                  IF nLen > 2048 THEN nLen = 2048
                  nLen = SendMessage(GetDlgItem(hwnd, 101), %WM_GETTEXT, nLen + 1, pText)
                  SendMessage hwnd, %WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF

         END SELECT

      CASE %WM_CLOSE
         ' // The owner window is enabled in WM_CLOSE rather than WM_DESTROY to
         ' // prevent the application from losing the focus. In WM_DESTROY the
         ' // modal window has already been removed from the screen by the system.
         ' // Because the remaining windows are disabled, the system gives the
         ' // focus to another application.
         EnableWindow GetWindow(hwnd, %GW_OWNER), %TRUE

      CASE %WM_DESTROY
         ' // Close the main window
         PostQuitMessage 0
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProc(hwnd, uMsg, wParam, lParam)

END FUNCTION


and for newbies or beginners with SLL ( like me) shows whole code example with a) SLL building and b) test example how to use it (like handy DLL and test-DLL examples. btw: I've tested your code example and got an error when testing your SLL file with

#COMPILE EXE
#DIM ALL
#INCLUDE "cWindow.inc"

#LINK "JR_Inputbox.sll"

FUNCTION PBMAIN () AS LONG

LOCAL S01 AS STRING
S01=CWindow_InputBox2(0,"Hallo","Headline","-")
'MSGBOX s01


END FUNCTION

'ERROR 632: COMMON name is a duplicate: CWINDOW   


best regards, frank

Paul Elliott

#2
Theo,

Does the error 'ERROR 632: COMMON name is a duplicate: CWINDOW
mean that we can't use it in a program that uses CWindow for other forms?

You should have included a complete test program source. I kept getting the memory error
until I added Frank's extra parameters.
Well, almost.  You need to check ISMissing(A01) instead of just testing contents of A01.


Frank,

The last 4 parameters are use Password, x loc, y loc, max len.

Sorry, I can't count.








Paul Elliott


Theo Gottwald

Frank and Paul, yes you are right, i have done the change.
An optional Parameter must be BYVAL to be able to just check for zero.
Otherwise it may lead to an GPF.

Also the example was from Jose's original Input-Box which is at the end of CWindows.INC.
I took it out and did only few modifications.

Paul, about the Error 632 i can't comment, because i did not get this error here.
Maybe Jose can comment on this?

For what i needed the SLL it works fine, as it is.
If this error would be there it would prevent to have more CWindows Elements linked as SLL's.

José Roca

Quote
Paul, about the Error 632 i can't comment, because i did not get this error here.
Maybe Jose can comment on this?

I don't use SLLs. If you want to make an input box based in mine, the easiest way is to put the code in an include file. It doesn't take less work to use #LINK "JR_Inputbox.sll" than #INCLUDE "JR_Inputbox.inc". Besides, whereas my input box works both in ansi and unicode thanks to conditional compilation, your SLL won't. Which is the purpose of such a SLL?

Paul Elliott

Theo,

I'm curious.  What benefit does your version of cwindow_inputbox have over the one in
Jose's CWindow.inc ?  Aside from being in a SLL which you can't use with a main program
that uses his CWindow.inc .


José Roca

None. It would have to use a modified version of CWindow with the COMMON keyword added, which will bloat the code. My version was designed to be used as a simple replacement of the input box built in the compiler, that is quite ugly, and to be used modal, not to show a dozen of them at the same time, or to be used in different threads (it uses an static variable; therefore it is not thread safe). Don't you think that if there was any advantage of converting it into a SLL I already would have done it?

Besides, if you compile the SLL without the %UNICODE constant defined, it will be only ansi, and if you define it, it will be only unicode. And it won't be High DPI aware if used with an application that it isn't, or maybe something worse.

Theo Gottwald

#8
Here are the changes to the original version:

I have added this statement:

SendMessage hEdit, %EM_SETSEL, LEN(strText), -1

which is missing in the original version to my knowledge.
Using this, the cursor is behind the default text, not in front of it as in the original version.

Also i have added a way to use a %ES_Password-Textbox if the user should input an password.
For this to be activated i have added an parameter.

Finally i did the great thing and added the word "common" as you know.

As I did not want to change the original thing (because otehrwise any update would destroy my changes) i have copied it and changed the name, added a "2".
I would wish to have a greater choice of predefined dialogs in CWindows.

Like a:

  • Timed Textbox
  • Textbox with something like "check this, to not show this message again."

and other often used dialogs.