View Full Version : Creating Run Time Controls
gungadout
16-02-2010, 10:09
Hi Folks,
I've given thought to another idea with respect to communicating with "real world" legacy data bases.
The idea of having simple Windows-based front ends and leaving the logic processing in the database environment is not new.
However, instead of creating 50,000 (slight exaggeration) front ends (which would not solve the inter-process communication problem), I thought of having just one front-end process. That process would dynamically create display screens for data base programs containing the controls they need, based on parameters sent by each legacy program.
The process would work like this:
- The process establishes initial communications with the database;
- A menu program automatically fires up at the database end and sends display parameters to the front end; the front end process displays the menu screen;
- A database program is selected from the menu; the front end process dissolves the menu screen and is displays the screen for the selected program in its stead, based on parameters sent by that program;
- When that program terminates, the database menu program sends its parameters again; the front end process dissolves the program screen and the re-displays the menu screen.
If thinBasic allows that, I reckon I could automatically convert most of the legacy programs to interface with the front end. It would mean that thinBasic would have to permit controls to be created on the fly and destroyed on the fly.
As a proof of concept, I tried modifying one of the examples. I added a button dynamically. It displays OK, but I fail to detect it when it is clicked on.
I've been doing other things in the meantime, so I am coming at thinBasic again from scratch, to some extent.
If someone could point out what I'm doing wrong, it would be great.
Thanks,
Peter H. (Gungadout)
Source Code:
''''''''''''''''''''''''''
' Button Style control '
' '
' Not complete '
' Started by Abraxas '
' '
''''''''''''''''''''''''''
USES "UI"
%Button1 = 2000
%Button2 = 2001
%Label = 2002
dim hDLG1 as DWORD
Dim Msg As DWORD
Dim wparam,lparam As DWORD
Dim Win1Params as DWORD VALUE = %WS_POPUP Or %WS_VISIBLE Or %WS_CLIPCHILDREN Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX
DIm myloop as LONG
DIm Counter as LONG
DIALOG NEW 0, "window1", -1, -1, 400, 200, Win1Params, 0 To hDlg1
CONTROL ADD BUTTON, hDlg1, 2000, "Test Button 1", 100 , 100, 100, 40
CONTROL ADD BUTTON, hDlg1, 2001, "Test Button 2", 250 , 100, 100, 40
CONTROL ADD LABEL , hDlg1, 2002, "", 150 , 20, 100, 40
'***<<<
CONTROL Disable hDlg1, %Button2
'***>>>
DIALOG SHOW MODELESS hDlg1
While ISWINDOW(hDlg1) ' PEH this is the major loop. it keeps looping until the Exit While is triggered.
Msg = GETMESSAGE(hDlg1, wParam, lParam) ' PEH waiting for input
Select Case Msg
Case %WM_Command ' PEH check if it is an ordinary command, like a button press.
If wParam = %Button1 Then
CONTROL Disable hDlg1, %Button1 ' PEH don't allow button 1 to be pressed again (until after button 3 is pressed).
'***<<<
CONTROL Enable hDlg1, %Button2
'***>>>
myloop = NOTB myloop
WHILE (myloop)
Msg = GETMESSAGE(hDlg1, wParam, lParam) ' PEH waiting for input
Select Case Msg
Case %WM_Command ' PEH check if it is an ordinary command, like a button press while in the loop.
If wParam =%Button2 Then
'***<<<
' CONTROL ENable hDlg1, %button1 ' PEH allow button 1 to be pressed now (because button 2 has been pressed).
CONTROL Disable hDlg1, %Button2
%Button3 = 2003
CONTROL ADD BUTTON, hDlg1, 2001, "Test Button 3", 001 , 100, 100, 40
CONTROL ENable hDlg1, %Button3
'***>>>
myloop = NOTB myloop
ENDIF
'***<<<
If wParam =%Button3 Then
CONTROL ENable hDlg1, %Button1 ' PEH allow button 1 to be pressed now (because button 2 has been pressed).
CONTROL Disable hDlg1, %Button3
myloop = NOTB myloop
ENDIF
'***>>>
End Select
INCR Counter ' PEH increment the counter
CONTROL SET TEXT hDlg1, %Label, Counter ' PEH display the counter
WEND
ENDIF
Case %WM_SYSCOMMAND
If wParam = %SC_Close Then Exit While
End Select
Wend
DIALOG End hDlg1
Petr Schreiber
16-02-2010, 11:11
Hi Peter,
definitely possible. Here I arranged the code for you.
Instead of While/Wend mechanism, it uses much more ellegant callback function structure.
You will see the code is much shorter than your original, and works ok.
I added some comments to the code for you.
If you didn't do so yet, please update to the latest beta (http://community.thinbasic.com/index.php?topic=3195.msg23925#msg23925) to get the most out of thinBasic :)
''''''''''''''''''''''''''
' Button Style control '
' '
' Not complete '
' Started by Abraxas '
' '
''''''''''''''''''''''''''
Uses "UI"
' -- Use ControlID construction to create safe values for control identifiers
Begin ControlID
%Button1
%Button2
%Button3
%Label1
End ControlID
' -- I recommend to enter the main program body to TBMain function
' -- which is executed automatically
Function TBMain()
Dim hDlg1 As DWord
Dim Win1Params As DWord = %WS_POPUP Or %WS_VISIBLE Or %WS_CLIPCHILDREN Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX
Dialog New 0, "window1", -1, -1, 400, 200, Win1Params, 0 To hDlg1
' -- You can define own
Control Add Button, hDlg1, %Button1, "Test Button 1", 100 , 100, 100, 40
Control Add Button, hDlg1, %Button2, "Test Button 2", 250 , 100, 100, 40
Control Add Label , hDlg1, %Label1, "", 150 , 20, 100, 40
'***<<<
Control Disable hDlg1, %Button2
'***>>>
' -- For single dialog application, modal is the good choice
' -- Also note using callbacks provides much better performance
' -- and makes CPU breathe lightly
Dialog Show Modal hDlg1, Call cbDialog
End Function
' -- Callback function allocates everything you need (message, control clicked ... for you)
CallBack Function cbDialog()
Static counter As Long
Static Button3Added As Long
Select Case Callback_Message
Case %WM_COMMAND ' PEH check if it is an ordinary command, like a button press.
' -- Handling multiple buttons
Select Case Callback_Control
Case %Button1
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Disable Callback_Handle, %Button1 ' -- Callback_Handle = handle of dialog calling this function
Control Enable Callback_Handle, %Button2
End If
Case %Button2
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Disable Callback_Handle, %Button2
If Button3Added <> %TRUE Then
Control Add Button, Callback_Handle, %Button3, "Test Button 3", 001 , 100, 100, 40
End If
Control Enable Callback_Handle, %Button3
Button3Added = %TRUE
End If
Case %Button3
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Enable Callback_Handle, %Button1
Control Disable Callback_Handle, %Button3
End If
End Select
Case %WM_CLOSE
' -- Add here some de-initialization if needed
End Select
Incr Counter ' PEH increment the counter
Control Set Text Callback_Handle, %Label1, Counter ' PEH display the counter
End Function
ErosOlmi
16-02-2010, 11:21
gungadout,
please 100% avoid old message pump method inside WHILE/WEND.
Also 100% avoid using GETMESSAGE function that is first try of using windows messages inside thinBasic.
Please follow Petr suggestion and use dialogs/windows/controls callbacks.
You will find you will have huge set of possibilities.
In \thinbasic\SampleScripts\UI\ directory you will find many different examples.
Some are still using GETMESSAGE way of handling messages: avoid taking inspiration from those examples and use all the others. I will change soon all those old examples.
Ciao
Eros
gungadout
16-02-2010, 22:45
Thanks, Petr and Eros.
I've been away for a while and have forgotten most of what I'd learned before. Hence I picked an old example to play with.
I'll use the new example as a base for my experimentation.
Regards,
Peter H (gungadout)
gungadout
18-02-2010, 08:54
Hi Folks,
I'm stumped in two areas. (Refer to incuded source code below.)
First, in the Case %Button4 logic, the "Dialog End cbDialog" statement does not work if preceded by the "DisplayMessage()" statement. If the "DisplayMessage()" statement is commented out, the "Dialog End cbDialog" statement works. I do not understand why, nor do I understand how I should code a function call to make it harmless in this context.
Second, I have tried a number of ways to create a text box and permit input, at the same time as %Button3 is created. Each time I tried, thinBasic displayed no screen and no pop-up error notification, but the start of a (text) error message appeared in the very bottom left hand corner of the thinAir screen.
I found out later, when I pull up the task manager to find out why my computer was running so slowly, that I had multiple copies of thinBasic running, chewing up all the CPU. It looks like my talent for accidentally testing things to destruction has surfaced again.
Anyway, I would love to know how to create a text field at the same time as %Button3 is created, and permit text entry while %Button3 is active. When the text field loses focus for any reason (having got focus first), I would like the contents to be displayed in say, a message box, prior to any other action being taken (e.g. if %Button3 or %Button4 is clicked).
What I'm trying to do may seem strange, but it is all part of my grand master plan. :twisted:
There just may be as much method in my madness, as there is madness in my method.
All suggestions are welcome, including kindly worded implications that I am an idiot.
Thanks in advance,
Peter H (gungadout)
''''''''''''''''''''''''''
' Button Style control '
' '
' Modified Example '
' Ex Petr Schreiber '
' '
' Played with by '
' gungadout '
' '
''''''''''''''''''''''''''
' '
' Dynamic Control Creation - PEH Play - Version 10
'
Uses "UI"
' -- Use ControlID construction to create safe values for control identifiers
Begin ControlID
%Button1
%Button2
%Button3
%Button4
%Label1
End ControlID
' -- I recommend to enter the main program body to TBMain function
' -- which is executed automatically
Function TBMain()
Dim hDlg1 As DWord
Dim Win1Params As DWord = %WS_POPUP Or %WS_VISIBLE Or %WS_CLIPCHILDREN Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX
Dialog New 0, "window1", -1, -1, 400, 200, Win1Params, 0 To hDlg1
' -- You can define own
Control Add Button, hDlg1, %Button1, "Test Button 1", 100 , 100, 100, 40
Control Add Button, hDlg1, %Button2, "Test Button 2", 250 , 100, 100, 40
Control Add Button, hDlg1, %Button4, "Exit", 250 , 150, 100, 40
Control Add Label , hDlg1, %Label1, "", 150 , 20, 100, 40
'***<<<
Control Disable hDlg1, %Button2
'***>>>
' -- For single dialog application, modal is the good choice
' -- Also note using callbacks provides much better performance
' -- and makes CPU breathe lightly
Dialog Show Modal hDlg1, Call cbDialog
End Function
' -- Callback function allocates everything you need (message, control clicked ... for you)
CallBack Function cbDialog()
Static counter As Long
'***<<< PEH
' Static Button3Added As Long
Static CloseWindow As Byte = 0
'***>>> PEH
Select Case Callback_Message
Case %WM_COMMAND ' PEH check if it is an ordinary command, like a button press.
' -- Handling multiple buttons
Select Case Callback_Control
Case %Button1
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Disable Callback_Handle, %Button1 ' -- Callback_Handle = handle of dialog calling this function
Control Enable Callback_Handle, %Button2
Control Enable Callback_Handle, %Button4
'***<<< PEH
Incr Counter
Control Set Text Callback_Handle, %Label1, Counter
'***>>> PEH
End If
Case %Button2
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Disable Callback_Handle, %Button2
'***<<< PEH
' If Button3Added <> %TRUE Then
' Control Add Button, Callback_Handle, %Button3, "Test Button 3", 001 , 100, 100, 40
' End If
'***>>> PEH
Control Add Button, Callback_Handle, %Button3, "Test Button 3", 001 , 100, 100, 40
Control Enable Callback_Handle, %Button3
'***<<< PEH
' Button3Added = %TRUE
'***>>> PEH
End If
Case %Button3
' -- Test if it was clicked
If Callback_Control_Message = %BN_CLICKED Then
Control Enable Callback_Handle, %Button1
Control Disable Callback_Handle, %Button3
'***<<< PEH
Control Kill Callback_Handle, %Button3
'***>>> PEH
End If
Case %Button4
' -- Test if it was clicked
' CloseWindow = 1
DisplayMessage() ' if this is commented out, Dialog End works. if not, it doesn't.
' Dialog End hDlg1 ' this is invalid -> Dialog Show Modal hDlg1, Call cbDialog
Dialog End cbDialog
' If CloseWindow = 1 Then
' Dialog End cbDialog
' End If
End Select
Case %WM_CLOSE
' -- Add here some de-initialization if needed
End Select
'***<<< PEH
' Incr Counter
' Control Set Text Callback_Handle, %Label1, Counter
'***>>> PEH
End Function
Function DisplayMessage()
MsgBox (0,"Exit has been clicked.")
End Function
ErosOlmi
18-02-2010, 09:16
Hi Petr,
I will check better later but at first sight there is a problem in DIALOG END ... and how you call it.
DIALOG END ... expect a window handle as parameter and not a callback function so change from:
Dialog End cbDialog '---cbDialog is a function and not a variable containing the window handle
to
Dialog End Callback_Handle
to have the window ending.
I will check the rest of your requests later.
Ciao
Eros
ErosOlmi
18-02-2010, 09:37
I found out later, when I pull up the task manager to find out why my computer was running so slowly, that I had multiple copies of thinBasic running, chewing up all the CPU. It looks like my talent for accidentally testing things to destruction has surfaced again.
It can be related to DIALOG END ... problem I described above.
ErosOlmi
18-02-2010, 09:41
If Callback_Control_Message = %BN_CLICKED Then
If you are inside a window callback you will receive %WM_COMMAND only if button is pressed. So the above line (repeated in your code) is not necessary.
The above sentence is only needed if you create a callback specific for the button.
In this case the callback function will receive messages not only for button clicked but also for other events.
gungadout
18-02-2010, 10:03
Thanks for your help, Eros.
By the way, the Dialog End was a recent addition, and was not present in the attempts to create the text field. I'm not worried about the invisible running, because I know it won't happen when I know how to do things properly. (It was just information for you.)
Regards,
Peter H. (gungadout)
ErosOlmi
18-02-2010, 10:12
Here it is an example of what you asked.
Because you asked you want to work with FOCUS events, I've removed MSGBOX and used CONSOLE to display messages because MSGBOX stole the focus to whatever text field and can create uncontrollable events.
In this example, when you press BUTTON3 a new textbox is created and is connected to a specific callback in order to manage FOCUS events.
If textbox lose the focus it is destroyed and its text content is passed to a global variable
It also fire a personalized event (%WM_USER + 100) in order to tell it parent window that it is killing itself so the parent window must decide what to do.
It is just an example, not all possibilities have been covered but can give you a go.
Ciao
Eros
' Button Style control '
' '
' Modified Example '
' Ex Petr Schreiber '
' '
' Played with by '
' gungadout '
' '
''''''''''''''''''''''''''
' '
' Dynamic Control Creation - PEH Play - Version 10
'
Uses "UI"
Uses "Console"
' -- Use ControlID construction to create safe values for control identifiers
Begin ControlID
%Button1
%Button2
%Button3
%Button4
%Label1
'---Leave this as the last control ID. It will be used to increment dinamic control creation
%LastControl
End ControlID
Global gBuffer As String '---Used to return string buffers from callbacks
'-----------------------------------------------------------------
' -- I recommend to enter the main program body to TBMain function
' -- which is executed automatically
Function TBMain()
'-----------------------------------------------------------------
Dim hDlg1 As DWord
Dim Win1Params As DWord = %WS_POPUP Or %WS_VISIBLE Or %WS_CLIPCHILDREN Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX
Dialog New 0, "window1", -1, -1, 400, 200, Win1Params, 0 To hDlg1
' -- You can define own
Control Add Button, hDlg1, %Button1, "Test Button 1" , 100 , 100, 100, 40
Control Add Button, hDlg1, %Button2, "Test Button 2" , 250 , 100, 100, 40
Control Add Button, hDlg1, %Button4, "Exit" , 250 , 150, 100, 40
Control Add Label , hDlg1, %Label1, "" , 150 , 20, 100, 40
Control Disable hDlg1, %Button2
' -- For single dialog application, modal is the good choice
' -- Also note using callbacks provides much better performance
' -- and makes CPU breathe lightly
Dialog Show Modal hDlg1, Call cbDialog
End Function
'-----------------------------------------------------------------
' -- Callback function allocates everything you need (message, control clicked ... for you)
CallBack Function cbDialog()
'-----------------------------------------------------------------
Static CounterDynamicID As Long Value %LastControl
Select Case Callback_Message
Case %WM_COMMAND
' -- Handling multiple buttons
Select Case Callback_Control
Case %Button1
' -- Test if it was clicked
Control Disable Callback_Handle, %Button1 ' -- Callback_Handle = handle of dialog calling this function
Control Enable Callback_Handle, %Button2
Control Enable Callback_Handle, %Button4
' Incr Counter
' Control Set Text Callback_Handle, %Label1, Counter
Case %Button2
' -- Test if it was clicked
Control Disable Callback_Handle, %Button2
Control Add Button, Callback_Handle, %Button3, "Test Button 3", 001 , 100, 100, 40
'Control Enable Callback_Handle, %Button3
Case %Button3
' -- Test if it was clicked
Control Enable Callback_Handle, %Button1
Control Disable Callback_Handle, %Button3
Control Kill Callback_Handle, %Button3
'---Increment dynamic IDs counter and create a new textbox
Incr CounterDynamicID
Control Add Textbox, Callback_Handle, CounterDynamicID, "I'm control ID " & CounterDynamicID, _
10, 10, 200, 50, , , Call cbDynamicTextBox
Control Set Focus Callback_Handle, CounterDynamicID
Case %Button4
DisplayMessage("I'm closing this window. Bye !", %TRUE)
Dialog End Callback_Handle
End Select
Case %WM_USER + 100
DisplayMessage "-----------------------------------------------"
DisplayMessage "Text Control as died."
DisplayMessage "Text before the event was: " & gBuffer
DisplayMessage "-----------------------------------------------"
gBuffer = ""
Case %WM_DESTROY
' -- Add here some de-initialization if needed
End Select
End Function
'-----------------------------------------------------------------
CallBack Function cbDynamicTextBox()
'-----------------------------------------------------------------
Local sText As String
Select Case CBCTLMSG
Case %EN_KILLFOCUS
sText = Control_GetText(Callback_Handle, Callback_Control)
DisplayMessage("I'm loosing focus. The text I've in my box is:" & $CRLF & sText)
'---Save text buffer
gBuffer = sText
'---Send a personalized message to parent window telling I'm killing myself
Dialog Post Callback_Handle, %WM_USER + 100, 0, 0
'---Kill myself
Control Kill Callback_Handle, Callback_Control
Case %EN_SETFOCUS
DisplayMessage("I'm getting focus")
End Select
End Function
'-----------------------------------------------------------------
Function DisplayMessage(Optional ByVal sMsg As String, ByVal SetWaitKey As Long)
'-----------------------------------------------------------------
If Len(sMsg) Then
PrintL sMsg
If SetWaitKey Then
Beep
Beep
PrintL "---Press a key in console window to continue---"
WaitKey
End If
End If
End Function
gungadout
18-02-2010, 10:20
Thanks again, Eros.
I'll give this good attention.
Regards,
Peter H (gungadout)
ErosOlmi
18-02-2010, 11:27
I hope my example is close to what you asked.
Otherwise let me know.
Eros
gungadout
24-02-2010, 00:44
Hi Folks,
(Thanks, Eros. Your example was spot on.)
I have been having fun combining code from various examples from different releases of thinBasic, which were using different coding techniques. I am pleased with my progress.
But, I have one problem that has me tricked. (See code segment below.)
I am trying to place a multi-line string into a text box based on logic from a very good textbox example. I cannot get it to work.
If I activate the console and use Console_Writeline, the data displays perfectly.
I must be missing something simple, but I am missing it.
Would someone please enlighten me?
(A thought: If there happen to be some special characters, i.e. nondisplaying ascii characters, in the multi-line string, might that cause problems with text box displays but not with console displays?)
Thanks,
Peter H. (gungadout)
Function MainControlFunction()
' This will be the main control function, later
' I am just displaying a report at this stage
' When displaying the multi-line string to the console (commented out), it works very well
' When displaying the multi-line string in a text box, it does not work
' The variable CallbackHandle has been defined to preserve the current Callback_Handle value,
' which seemed to be getting lost in function calls
Control Set Text CallbackHandle, %lblStatus, "Creating a report display"
Control Add Textbox , CallbackHandle, %txtReportBody, "" , 5, 75, 185, 100, %WS_BORDER Or _
%WS_TABSTOP Or _
%ES_WANTRETURN Or _
%ES_MULTILINE Or _
%ES_AUTOHSCROLL Or _
%ES_AUTOVSCROLL Or _
%WS_VSCROLL Or _
%WS_HSCROLL, _
%WS_EX_CLIENTEDGE
Control Enable CallbackHandle, %txtReportBody
' Control set focus CallbackHandle, %txtReportBody
' Console_ShowWindow(%CONSOLE_SW_SHOW)
' Console_SetTitle("General Ledger Account List")
Command = "SORT ACDES = " + Chr$(34) + "650]" + Chr$(34) + "ACDES.DESC BAL HEADING " + Chr$(34) + "ACDES" + Chr$(34)
SendResult = TCP_Send(TCPFreeFile, Command+$CR)
Buffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024*24)
Buffer += InBuffer
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :")'
' Console_WriteLine("Buffer = " + Buffer)'
Control Set Text CallbackHandle, %txtReportBody, Buffer
' Control Append Text CallbackHandle, %txtReportBody, Buffer
Control Set Text CallbackHandle, %lblStatus, "Press <Enter> when finished viewing"
' WaitKey
' Console_ShowWindow(%CONSOLE_SW_HIDE)
End Function
ErosOlmi
24-02-2010, 01:38
Petr,
what is "CallbackHandle" ?
You use it in place of window handle (that is a variable) but (I can be wrong) in my mind it seems to me the name of a callback function.
If I'm guessing right, it is not the way it should be used.
For example in
Control Set Text CallbackHandle, %lblStatus, "Creating a report display"
what is "CallbackHandle"?
Control Set Text ... should be something like:
Control Set Text hWnd, %lblStatus, "Creating a report display"
where hWnd is the window handle returned by the
DIALOG NEW ... TO hWnd
when you created the parent window of %lblStatus control.
The same apply to all statements working on controls.
Is it possible to post 2 images of console and window so we can better understand what's going on?
gungadout
24-02-2010, 05:17
Hi Eros,
Thanks for your reply.
The working console-based program and the non-working screen-based programs are inserted below.
*** the message was too long. I'll post the source code separately. ***
The CallbackHandle variable is equated to the Callback_Handle variable in the callback function from which the sub-functions are called. The value of Callback_Handle seemed to be not preserved inside the sub-functions.
I used the construction involving Callback_Handle (CallbackHandle) because it was in an example I was looking at.
That construction works for the txtStatus control, and seems to work for the txtReportBody control as well.
I have since included logic to remove Chr$(1) to Chr$(9), Chr(11) to Chr(12), and Chr$(127) to Chr(255) by means of Replace$() statements. My method probably is not the most efficient, but I think it works. It made no difference.
(There were special characters in the transmitted string, but they appeared as symbols on the console display and did no harm.)
The display of each InBuffer (line 374, currently commented out) shows that the data is being received and is recognizable.
I have placed '<<< and '>>> comments around what seem to be the important areas.
Are there any characters on a normal keyboard that can cause problems when placed into txt and lbl controls?
Thanks again for your help,
Peter H (gungadout)
gungadout
24-02-2010, 05:19
Console-based program. This works.
USES "UI"
' Uses "FILE"
Uses "TCPUDP" ' For internet communication
Uses "INET" ' To get mine IP
Uses "Console"
Begin ControlID
%lblAccountId
%lblLoginId
%lblPassword
%lblStatus
%LblStatusH
%txtAccountId
%txtLoginId
%txtPassword
%btnLogin
%btnExit
%Portnumber = 2300
End ControlID
Dim ScreenId01 As String = "Login Screen 03"
Dim Msg As Long
Dim wParam As Long
Dim lParam As Long
Dim AccountId As String
Dim LoginId As String
Dim Password As String
Dim hDlg As Long
Dim TCPFreeFile As DWord
Dim TCPOpenError As DWord
Dim CloseResult As DWord
Dim SendResult As DWord
Dim InBuffer As String
Dim Buffer As String
Dim Command As String
Dim CallbackHandle As Long
Dim Massage As String
Dim LogOffFlag As Byte
'------------------------------------------------------------------------------------------------------
Function TBMain()
' Dim hDlg As DWord
Dim Win1Params As DWord = %WS_POPUP Or %WS_VISIBLE Or %WS_CLIPCHILDREN Or %WS_CAPTION Or %WS_SYSMENU Or %WS_MINIMIZEBOX
' Dialog New 0, "Login Screen 01", -1, -1, 195, 250, _
' Dialog New 0, ScreenId01, -1, -1, 595, 450, _
' %WS_DLGFRAME Or %DS_CENTER Or %WS_CAPTION Or %WS_SYSMENU Or %WS_OVERLAPPEDWINDOW, _
' 0 To hDlg
Dialog New 0, ScreenId01, -1, -1, 400, 200, Win1Params, 0 To hDlg
' Control Add Textbox , hDlg, 10, "GPAC.DEMO" , 5, 15, 185, 15, %WS_BORDER Or %WS_TABSTOP , %WS_EX_CLIENTEDGE
' Control Add Textbox , hDlg, 20, "PEH", 5, 30, 185, 15, %WS_BORDER Or %WS_TABSTOP Or %ES_CENTER , %WS_EX_CLIENTEDGE
' Control Add Textbox , hDlg, 30, "ABCD" , 5, 45, 185, 15, %WS_BORDER Or %WS_TABSTOP Or %ES_RIGHT , %WS_EX_CLIENTEDGE
'
' labels
'
Control Add Label , hDlg, %lblAccountId, "Account Id" , 55,17,55,12
Control Add Label , hDlg, %lblLoginId, "Login Id" , 55,32,55,12
Control Add Label , hDlg, %lblPassword, "Password" , 55,47,55,12
Control Add Label , hDlg, %lblStatusH, "Status:" , 55,160,125,12
Control Add Label , hDlg, %lblStatus, "Awaiting user input" , 85,160,600,12
' MsgBox(0,"Added labels")
'
' text boxes
'
Control Add Textbox , hDlg, %txtAccountId, "GPAC.DEMO" , 125, 15, 185, 12, %WS_BORDER Or %WS_TABSTOP , %WS_EX_CLIENTEDGE
Control Add Textbox , hDlg, %txtLoginId, "PEH", 125, 30, 185, 12, %WS_BORDER Or %WS_TABSTOP , %WS_EX_CLIENTEDGE
Control Add Textbox , hDlg, %txtPassword, "ABCD" , 125, 45, 185, 12, %WS_BORDER Or %WS_TABSTOP , %WS_EX_CLIENTEDGE
'
' buttons
'
Control Add Button, hDlg, %btnLogin, "Log In", 65 , 100, 100, 40
Control Add Button, hDlg, %btnExit, "Exit", 200 , 100, 100, 40
' CONTROL ADD TEXTBOX , hDlg, 40, "Text box: read only" , 5, 60, 185, 15, %WS_BORDER OR %WS_TABSTOP OR %ES_READONLY , %WS_EX_CLIENTEDGE
' CONTROL ADD TEXTBOX , hDlg, 50, "" , 5, 75, 185, 100, %WS_BORDER OR _
' %WS_TABSTOP OR _
' %ES_WANTRETURN OR _
' %ES_MULTILINE OR _
' %ES_AUTOHSCROLL OR _
' %ES_AUTOVSCROLL OR _
' %WS_VSCROLL OR _
' %WS_HSCROLL, _
' %WS_EX_CLIENTEDGE
' -- For single dialog application, modal is the good choice
' -- Also note using callbacks provides much better performance
' -- and makes CPU breathe lightly
' Dialog Show Modeless hDlg, Call cbDialog
Dialog Show Modal hDlg, Call cbDialog
End Function
'--------------------------------------------------------------------------------------------------------
' -- Callback function allocates everything you need (message, control clicked ... for you)
CallBack Function cbDialog()
Select Case Callback_Message
Case %WM_COMMAND ' PEH check if it is an ordinary command, like a button press.
' -- Handling multiple buttons
Select Case Callback_Control
Case %btnLogin
' -- Test if it was clicked - No need. It was - test only needed if special callback written for button
' If Callback_Control_Message = %BN_CLICKED Then
AccountId = Control_GetText(Callback_Handle, %txtAccountId)
LoginId = Control_GetText(Callback_Handle, %txtLoginId)
Password = Control_GetText(Callback_Handle, %txtPassword)
If Trim$(AccountId) = "" Or Trim$(LoginId) = "" Or Trim$(Password) = "" Then
MsgBox(hdlg, "Account Id, Login Id or Password missing.")
Else
Control Disable Callback_Handle, %btnLogin
CallbackHandle = Callback_Handle
LogOffFlag = 0
login()
If logoffflag = 1 Then
' SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
' TCP_Close(TCPFreeFile)
End If
End If
' Control_SetText Callback_Handle, %Label1, Counter
Case %btnExit
' -- Test if it was clicked - No need. It was - test only needed if special callback written for button
' If Callback_Control_Message = %BN_CLICKED Then
' MsgBox(0,"btnExit clicked")
SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
TCP_Close(TCPFreeFile)
Dialog End Callback_Handle
End Select
Case %WM_CLOSE
' -- Add here some de-initialization if needed
SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
TCP_Close(TCPFreeFile)
End Select
End Function
'-----------------------------------------------------------------------------------------------------
Function Login()
' MsgBox(0,"Entering Login")
' Stop
' Control_SetText (CallbackHandle, %lblStatus, "Entering Function Login")
' Console_WriteLine("Checking first free File")'
Control_SetText (CallbackHandle, %lblStatus, "Establishing database connection")
TCPFreeFIle = TCP_FreeFile
' Console_WriteLine("FreeFile number : "+ Str$(TCPFreeFile))'
'---Open a connection
' Console_WriteLine("Opening connection Port :"+ Str$(%Portnumber))
' TCPOpenError = TCP_Open(%PortNumber, "", TCPFreeFile, 1000)
TCPOpenError = TCP_Open(%PortNumber, "localhost", TCPFreeFile, 1000)
If TCPOpenError <> 0 Then
' Console_WriteLine("An error occured during connection. Error code is: " & TCPOpenError)
' WaitKey
Control_SetText (CallbackHandle, %lblStatus, "An error occured during connection. Error code is: " & TCPOpenError)
MsgBox(0,"An error occured during connection. Error code is: " & TCPOpenError)
' Stop
Exit Function
Else
' Console_WriteLine("Port opened returning : " + Str$(TCPOpenError))'
'---Send request
'
SendResult = TCP_Send(TCPFreeFile, $CR)
'---Receive request
' Console_WriteLine("Receiving data")'
'---Get back data in a loop
Buffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024*2)
Buffer += InBuffer
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :")'
' Console_WriteLine(Buffer)'
' Control_SetText (CallbackHandle, %lblStatus, Buffer)
'
If InStr(1, Buffer, "Logon") = 0 Then
'
' Console_WriteLine(Buffer)'
Control_SetText (CallbackHandle, %lblStatus, "Unable to obtain login prompt. Sorry. " + Buffer)
MsgBox (0,"Unable to obtain login prompt. Sorry. " + Buffer)
' SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
' TCP_Close(TCPFreeFile)
LogOffFlag = 1
' Stop
Exit Function
End If
'
'
' send account id
'
' Console_WriteLine("Sending account Id")'
Control_SetText (CallbackHandle, %lblStatus, "Sending Account Id")
SendResult = TCP_Send(TCPFreeFile, AccountId+".XB"+$CR)
' Console_WriteLine("Sending returned : " + Str$(SendResult))'
'---Receive request
' Console_WriteLine("Receiving data")'
'---Get back data in a loop
Buffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024)
Buffer += InBuffer
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :")'
' Console_WriteLine(Buffer)'
' Control_SetText (CallbackHandle, %lblStatus, Buffer)
'
' send login id
'
' Console_WriteLine("Sending User Id")'
Control_SetText (CallbackHandle, %lblStatus, "Sending Login Id")
SendResult = TCP_Send(TCPFreeFile, LoginId+$CR)
'---Receive request
' Console_WriteLine("Receiving data")'
'---Get back data in a loop - until we can suppress the character echo
Buffer = ""
InBuffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024*2)
Buffer += InBuffer
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :<")'
' Console_WriteLine(Buffer)'
' Control_SetText (CallbackHandle, %lblStatus, Buffer)
'
' now send password
'
' Console_WriteLine("Sending password request")'
Control_SetText (CallbackHandle, %lblStatus, "Sending Password")
SendResult = TCP_Send(TCPFreeFile, Password+$CR)
' Console_WriteLine("Sending returned : " + Str$(SendResult))'
'---Receive request
' Console_WriteLine("Receiving data")'
'---Get back data in a loop
Buffer = ""
InBuffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024)
Buffer += InBuffer
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :")'
' Console_WriteLine(Buffer)'
' Control_SetText (CallbackHandle, %lblStatus, Buffer)
If InStr(1, Buffer, "Welcome") = 0 Then
' If InStr(Buffer, "Welcome") = 0 And Buffer <> Password Then
'
' Console_WriteLine(Buffer)'
Massage = "Unrecognized response from server. " + Buffer
Control_SetText (CallbackHandle, %lblStatus, Massage)
MsgBox (0,Massage)
' SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
' TCP_Close(TCPFreeFile)
LogOffFlag = 1
' Stop
Exit Function
End If
End If
Control_SetText (CallbackHandle, %lblStatus, "Login established")
'---Try a command
' SendResult = TCP_Send(TCPFreeFile, "SORT ONLY ACDES"+$CR)
' SendResult = TCP_Send(TCPFreeFile, "LIST ONLY ACDES"+$CR)
MsgBox(0,"Trying a sort")
Control_SetText (CallbackHandle, %lblStatus, "Creating a console display")
Console_ShowWindow(%CONSOLE_SW_SHOW)
Console_SetTitle("General Ledger Account List")
Command = "SORT ACDES = " + Chr$(34) + "650]" + Chr$(34) + "ACDES.DESC BAL HEADING " + Chr$(34) + "ACDES" + Chr$(34)
SendResult = TCP_Send(TCPFreeFile, Command+$CR)
Buffer = ""
Do
InBuffer = TCP_Recv(TCPFreeFile, 1024*24)
Buffer += InBuffer
' Console_WriteLine("InBuffer = " + InBuffer + " InBuffer")'
' Console_WriteLine("Buffer = " + Buffer + " Buffer")'
Loop While ((Len(InBuffer) > 0) And (Err = 0))
' Console_WriteLine("Data Received :")'
Console_WriteLine("Buffer = " + Buffer)'
Control_SetText (CallbackHandle, %lblStatus, "Console display ready for viewing")
' Control_SetText CallbackHandle, %lblStatus, "Check: " + Buffer
WaitKey
Console_ShowWindow(%CONSOLE_SW_HIDE)
'---Close the channel
' SendResult = TCP_Send(TCPFreeFile, "OFF"+$CR)
' Console_WriteLine("Closing Port")'
' TCP_Close(TCPFreeFile)
' LogOffFlag = 1
' EndIf
End Function
gungadout
24-02-2010, 05:45
Textbox-Based program. This does not work. The problem seems to be associated with the Buffer variable.
ErosOlmi
24-02-2010, 09:10
Hi Petr,
thanks for posting your code. I'm sorry I cannot test it because I have not the server to where you are connecting so I can just guess.
Yes, I think there are limitations to what chars can be shown into a TEXTBOX control and those limitations come from the control itself and how it has been designed by Microsoft. I do not know what chars can be used inside it but I can check in Microsoft documentation. I think TEXTBOX and LABEL are mainly designed for user interaction so special chars I think can create some problems.
To show special chars or chars above CHR(127) usually programmers develop a HEX control control where to report HEX value of each char plus an ascii buffer but where special chars are substituted by something a visible one. See image on there: http://www.codeproject.com/KB/WPF/HexViewerControl.aspx
I will try to see if I can create a control like that native to UI module or at least create an example on how to create a HEX control
------
As initial indication on your code I can just say to avoid GLOBAL variables as much as possible.
For example you correctly said that pseudo variables "Callback_*" like Callback_Handle are available only inside a CallBack function and that is true. The reason this is in this way is because CallBacks functions are automatically executed by Windows Events and Windows pass pseudo variable info only when a callback is executed.
If you have to pass one or more of pseudo callback info you just pass the as parameter in your functions.
So for example change from
Function Login()
to
Function Login(BYVAL hWnd AS LONG)
inside Login function substitute CallbackHandle with hWnd
and inside your main CallBack call Login() as Login(Callback_Handle)
The same apply to MainControlFunction
------
I will study your source better this evening when back from work (today will be a quite heavy load at job so quite sure I will not have time to help you more, sorry)
Eros
gungadout
24-02-2010, 22:42
Hi Eros,
Once again, thanks heaps.
I really appreciate your help and advice.
(I have not forgotten the other people who helped me in the past, either. Thanks to all of you, too.)
I will double check my logic which is supposed to strip special characters.
Regards,
Peter H. (gungadout)
gungadout
25-02-2010, 08:24
Hi Eros,
I think I've found the problem.
I wondered if text box might be getting confused by Carriage Return (CHR$(13)) and Linefeed (CHR$(10)) characters, although the idea that it might, seemed illogical.
I did some manual testing. Aha!
Text box gets totally confused by the presence of simple Linefeed characters CHR$(10). Nothing appears in the textbox.
Carriage Returns cause the data to be displayed, but incorrectly (some parts blanked out).
On the Console display, the linefeed and/or carriage return characters trigger new lines, as they are supposed to.
I guess the CR and LF sensitivity is a Microsoft thing. (And I think I've made a dent in the wall from all my headbanging.)
Two things I need to ask now, if I may.
1. How do I progressively append new lines to a textbox? Without some form of line feed function, would Control Append Text work? Also, are the parameters used in the Control Add Textbox instruction in my program appropriate? (I don't pretend to understand what they all mean.)
2. The text box contents (when they are there) only display when I click on the textbox. If I focus on another task in the taskbar and then come back, the textbox contents have disappeared again. I must click on the textbox again to make the contents appear. Using Control Enable makes no difference. Is this related to the Control Add Textbox parameters?
(I did find what might have been an inconsistency in the Control Add Textbox instruction. I was combining code from a number of sources. Making the code consistent, however, seemed to make little difference, if any.)
Your help will be appreciated as always, as and when you have time to give it.
Regards,
Peter H.
Petr Schreiber
25-02-2010, 09:04
Hi Peter,
I didn't try your example, but you can allow CRLF to be interpreted as "new line", when you create textbox with this style:
Control Add Textbox, hDlg, %bClose, "Line 1"+$CRLF+"Line 2", 5, 5, 85, 110, %ES_MULTILINE Or %ES_AUTOHSCROLL Or %ES_LEFT Or %WS_BORDER Or %WS_TABSTOP, %WS_EX_CLIENTEDGE Or %WS_EX_LEFT
The %ES_MULTILINE style serves well for this.
Petr
gungadout
25-02-2010, 10:04
Thanks, Petr.
I'll try it.
Regards,
Peter H.
ErosOlmi
25-02-2010, 11:34
:grrrr:
Peter I replied this morning from home just before going out for work but got a phone call from job for an urgent matter and I forgot to click "Post" and my reply was still on video of my home computer. I wrote down 20 lines or so but unfortunately my wife switched off the computer so I lost my reply :oops:
I will reply this evening when back home.
Sorry.
gungadout
25-02-2010, 22:40
Thanks Eros and Petr.
I have found a solution to my second problem.
It would seem that all controls used by a dialog must be defined (Control Add) physically within the function where the Dialog New statement is issued. I was defining (Control Add) the textbox within a sub function called from the dialog function. The textbox appeared OK, but did not function properly.
I moved the Control Add from the sub function into the main dialog function, and the textbox functions as expected.
I am still working on the first problem. There appears to be something about or in the input Buffer that still confuses the textbox.
(Petr, the %ES_LEFT and %WS_EX_LEFT were the only parameters not already present. Adding them made no appreciable difference.)
Regards and thanks again,
Peter H. (gungadout)
ErosOlmi
25-02-2010, 22:50
Peter,
no, it is possible to add any control from anywhere in your code. Important is to have the handle of the window in which you want to create it.
So I think there must be something else.
Do you have latest thinBasic beta 1.7.10.3 installed?
In version 1.7.10.2 there was a problem in using CallBack_* pseudo variables bug when passed to functions as parameters.
So please be sure to have latest version
Do you think it is possible update again the source code of your script so I can double check it?
Thanks
Eros
gungadout
26-02-2010, 02:23
Thanks, Eros.
I was using version 1.7.10.1. I will update to the latest version.
I changed my code to test for valid characters instead of invalid ones. That fixed my first problem.
Everything now works OK. So I am happy.
I can now go on to the next step, which is playing with grids.
Once again, thanks for your help.
Regards,
Peter H. (gungadout)
gungadout
26-02-2010, 04:01
Sorry, Folks.
I have another question about (multi-line) textboxes.
Is there any way to suppress proportional character widths when displaying? Can we make the textbox give each character the same display width, i.e. fixed character widths?
I am receiving a pre-formatted, columnar, multi-line report from the database, and displaying it in a textbox.
The textbox is destroying the display of the columns by choosing to use proportional character widths. The columns end up all higgledy-piggledy. They do not line up.
I have looked at the textbox style equates in the documentation, but I did not notice anything to help.
I checked the label style equates as well.
Should I be using a different type of control? If so, please identify it for me.
(The display on the console works well, but does not have a professional look. I'm hoping I can use a non-console control.)
Thanks,
Peter H. (gungadout)
ErosOlmi
26-02-2010, 06:59
Everything now works OK. So I am happy.
I'm happy too :D
Regarding mono space font do something like the following just after creating the control:
Static hFont As DWord Resource '---With Resource you will instruct thinBasic to automatically release hFont resource when done
hFont = Font_Create("Courier New" , 10) '---Select a mono space font
Control Send CBHNDL, %ID_MYCONTROL, %WM_SETFONT, hFont, 0
gungadout
26-02-2010, 09:01
Hi Eros,
Brilliant!
The result is perfect.
Thanks,
Peter H. (gungadout)