Simple GUI

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

I have finished my small GUI project now. Short description and code: see http://www.freebasic-portal.de/projekte ... ui-98.html.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple GUI

Post by BasicCoder2 »

@Lothar Schirm,
Very nice examples with easy to read code.
May I suggest you update and add your link to the first post as that is where readers will look first.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Simple GUI

Post by dodicat »

I agree.
Are we done here, the simple GUI has been made.

One thing though Lothar S.
Shouldn't the default cursor position not be at the right end of the input text + one space, in order to easily edit the text?

e.g.
48.99977_

_ is the cursor.
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Simple GUI

Post by BasicCoder2 »

dodicat wrote:Are we done here, the simple GUI has been made.
I am still working on it including a graphical gui designer to make use of it.

Strictly speaking it was done a long time ago and has since then evolved into the GUI packages that exist today. The simple GUI is just a tutorial on how it can be done from scratch. It is an exercise in solving a programming problem.

The only reason I have rolled my own buttons etc in FreeBasic is because FreeBasic lacks a set of GUI commands itself and to learn to use some add on GUI is a bit of an overkill if all you need is a couple of simple controls.
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

BasicCoder2 wrote:@Lothar Schirm,
Very nice examples with easy to read code.
May I suggest you update and add your link to the first post as that is where readers will look first.
Done.
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

dodicat wrote: Shouldn't the default cursor position not be at the right end of the input text + one space, in order to easily edit the text?

e.g.
48.99977_

_ is the cursor.
Done. I have also done some further small improvements in the Sub EditText:
- The keys "Home" and "End" are now supported to move the cursor to the beginning or to the end of the text
- Editing is ended by a mouseclick only when the mouse position is outside of the textbox, so the cursor will not jump to the beginning or end of the text when the mouse is clicked within the textbox.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Simple GUI

Post by MrSwiss »

@Lothar S.
really nice job. However:
in your download at FreeBASIC-Portal.de you've changed the NAMING of the files.
(at least in the complete .ZIP)
This is a call for disaster with noob's/newbees. Specifically the "GUI.bas" include
file is NOT found by the compiler ...
You might want to change that, in order that the examples compile / run, out of
the box, so to speak.
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

Hallo MrSwiss,

thank you for your information. Unfortunately the file name "GUI.bas" has been changed automatically by the project file management due to the project name "simple gui". I have done a new download to FreeBasic Portal - Downloads - Bibliotheken. I have updated the download path in the first post.

Lothar
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

dodicat wrote:For your perusal (optional of course), here is a simplified Win Api of my previous code.

Code: Select all

#include "windows.bi"
freeconsole
Declare Sub OPERATE(flag As Integer)
Dim Shared As hwnd B1,B2,answer 'used in sub
Const MainWindow ="#32770"
Dim As MSG msg
'The window and boxes
Var hWnd= CreateWindowEx( 0,MainWindow, "CALCULATE", WS_OVERLAPPEDWINDOW Or WS_VISIBLE, 200, 200, 400, 600, 0, 0, 0, 0 )
B1      = CreateWindowEx( 0, "EDIT", "", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or ES_AUTOHSCROLL  , 50, 80, 200, 45, hWnd, 0, 0, 0 )
B2      = CreateWindowEx( 0, "EDIT", "", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or ES_AUTOHSCROLL , 50, 280, 200, 45, hWnd, 0, 0, 0 )
answer  = CreateWindowEx( 0, "EDIT", "", ws_border Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or ES_AUTOHSCROLL  Or ES_READONLY, 50, 480, 200, 45, hWnd, 0, 0, 0 )
Var label    =CreateWindowEx( 0, "STATIC", "ANSWER:",WS_VISIBLE Or WS_CHILD , 20, 450, 70, 30, hWnd, 0, 0, 0 )
Var ADDBUTTON= CreateWindowEx( 0,"BUTTON", "A+B", WS_VISIBLE Or WS_CHILD, 50,380 , 50, 30, hWnd, 0, 0, 0 )
Var minus    = CreateWindowEx( 0,"BUTTON", "A-B", WS_VISIBLE Or WS_CHILD, 110,380 , 50, 30, hWnd, 0, 0, 0 )
Var prod     = CreateWindowEx( 0,"BUTTON", "A*B", WS_VISIBLE Or WS_CHILD, 170,380 , 50, 30, hWnd, 0, 0, 0 )
Var divide   = CreateWindowEx( 0,"BUTTON", "A/B", WS_VISIBLE Or WS_CHILD, 230,380 , 50, 30, hWnd, 0, 0, 0 )
Var lblA     =CreateWindowEx( 0, "STATIC", "A = ",WS_VISIBLE Or WS_CHILD , 15, 85, 30, 30, hWnd, 0, 0, 0 )
Var lblB     =CreateWindowEx( 0, "STATIC", "B = ",WS_VISIBLE Or WS_CHILD , 15, 285, 30, 30, hWnd, 0, 0, 0 )
'loop
While GetMessage( @msg, 0, 0, 0 )
    TranslateMessage( @msg )
    DispatchMessage( @msg )
    Select Case msg.hwnd
    Case hWnd
        Select Case msg.message
        Case 273
            End
        End Select
        '__________________  
    Case AddButton
        Select Case msg.message  
        Case WM_LBUTTONDOWN
            OPERATE(1)'ADDUP
        End Select
        '____________________   
    Case minus
        Select Case msg.message  
        Case WM_LBUTTONDOWN
            OPERATE(2)'SUBTRACT
        End Select
        '______________________  
    Case prod
        Select Case msg.message  
        Case WM_LBUTTONDOWN
            OPERATE(3)' MULTIPLY
        End Select 
        '_______________________
    Case divide
        Select Case msg.message  
        Case WM_LBUTTONDOWN
            OPERATE(4)'DIVIDE
        End Select 
    End Select
Wend

Sub OPERATE(flag As Integer)
    Dim As String outtext1,outtext2,result
    Dim As Integer charcount1,charcount2
    charcount1 = GetWindowTextLength(B1)
    charcount2 = GetWindowTextLength(B2)
    outtext1 = String(charcount1," ")
    outtext2 = String(charcount2," ")
    GetWindowText(B1,outtext1,charcount1+1)
    GetWindowText(B2,outtext2,charcount2+1)
    Select Case As Const flag
    Case 1:result= Str(Val(outtext1)+Val(outtext2))
    Case 2:result= Str(Val(outtext1)-Val(outtext2))
    Case 3:result= Str(Val(outtext1)*Val(outtext2))
    Case 4:result= Str(Val(outtext1)/Val(outtext2))
    End Select
    setWindowText(answer,result)
End Sub

 
I found further code examples written here: http://freebasic.net/forum/viewtopic.php?f=7&t=13451. This seems to be a rather simple way to write code for a windows GUI, so I begin to write a WinAPI library for myself in a similiar way as I did it with "Simple GUI" project, because I feel that I have to write very many lines of code if I want to add more featues into my project.

But it in this link it is also said that this simple method of writing WinAPI GUI is not "safe", "because you need to register window class and process window messages in window procedure. Tutorial: http://www.freebasic.net/wiki/wikka.php ... ssageIntro ". But it works. I am a hobby progrmmer and do not develop commercial software, so for me this method seems to be sufficient. What do you say? Can I run into problems?
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Simple GUI

Post by dodicat »

Hi Lothar S.

That's a nice link (further examples).
Didn't see it before.
Nice easy fonts examples.

Safety ??
Yea, safe enough I would say.
Depends how pernickety you are!
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

If it works, it's ok. This is my first attempt:

Code: Select all

'===============================================================================
' AddNumbers.bas
' Erstellt am 27.01.2015
'===============================================================================

#Include "WinGUI.bas"

Dim Shared As HWND Window_Main, Edit_a, Edit_b, Edit_result, Button_Add, Button_Close  
Dim As MSG msg


Sub OpenWindow_Main()
' Fenster

	Window_Main = Window_New						(100, 100, 300, 300, "Add two numbers")
	Button_Add = Button_New							(100, 20, 60, 20, "Add", Window_Main)
	Var Static_a = StaticText_New				(20, 50, 60, 20, "a:", Window_Main)
	Var Static_b = StaticText_New				(20, 80, 60, 20, "b:", Window_Main)
	Var Static_result = StaticText_New	(20, 110, 60, 20, "a + b:", Window_Main)
	Edit_a = EditBox_New								(100, 50, 150, 20, "0", 0, 0, Window_Main)
	Edit_b = EditBox_New								(100, 80, 150, 20, "0", 0, 0, Window_Main)
	Edit_result = EditBox_New						(100, 110, 150, 20, "0",0, 1, Window_Main)
	Button_Close = Button_New						(100, 170, 60, 20, "Close", Window_Main)
		
End Sub


Sub Add()
'Werte a und b auslesen, addieren, Resultat anzeigen

	Dim As Single a, b, result
	
	a = Val(EditBox_GetText(Edit_a))
	b = Val(EditBox_GetText(Edit_b))
	result = a + b
	EditBox_SetText(Edit_result, Str(result))

End Sub


'Hauptprogramm:

OpenWindow_Main()

While GetMessage( @msg, 0, 0, 0 )

	TranslateMessage( @msg )
	DispatchMessage( @msg )
	
	Select Case msg.hwnd
		Case Window_Main
			If msg.message = 273 Then End
		Case Button_Add
			If msg.message = WM_LBUTTONDOWN Then Add()
		Case Button_Close
			If msg.message = WM_LBUTTONDOWN Then End
	End Select
	
Wend

Code: Select all

'===============================================================================
' WinGUI.bas
' Kleine WinAPI GUI-Bibliothek
' Erstellt am 27.01.2015
'===============================================================================

#Include Once "windows.bi"


Function Window_New(x As Integer, y As Integer, w As Integer, h As Integer, _
										Title As String) As HWND
	'Neues Fenster. Parameter:
	'- x, y = Ecke links oben
	'- w = Breite
	'- h = Höhe
	'- Title = Titel 
	
	Return CreateWindowEx(0, "#32770", Title, WS_OVERLAPPEDWINDOW Or WS_VISIBLE, _
												x, y, w, h, 0, 0, 0, 0)
	
End Function


Function Button_New(x As Integer, y As Integer, w As Integer, h As Integer, _
										Label As String, hwnd As HWND) As HWND
	'Neuer Button. Parameter:
	'- x, y = Ecke links oben
	'- w = Breite
	'- h = Höhe
	'- Label = Beschriftung
	'- hwnd = Handle des Fensters	
	
	Return CreateWindowEx(0, "BUTTON", Label, WS_VISIBLE Or WS_CHILD, x, y, w, h, _
												hWnd, 0, 0, 0 )
End Function


Function StaticText_New(x As Integer, y As Integer, w As Integer, h As Integer, _
										text As String, hwnd As HWND) As HWND
	'Neuer Static Text. Parameter:
	'- x, y = Ecke links oben
	'- w = Breite
	'- h = Höhe
	'- text = Text
	'- hwnd = Handle des Fensters
	
	Return CreateWindowEx(0, "STATIC", Text, WS_VISIBLE Or WS_CHILD, x, y, w, h, _
												hWnd, 0, 0, 0 )
												
End Function


Function EditBox_New(x As Integer, y As Integer, w As Integer, h As Integer, _
										Text As String, MultiLine As UInteger = 0, ReadOnly As UInteger = 0, _
										hwnd As HWND) As HWND
	'Neue Editbox. Parameter:
	'- x, y = Ecke links oben
	'- w = Breite
	'- h = Höhe
	'- Text = Text
	'- MultiLine: 0 = Singleline, 1 = Multiline
	'- ReadOnly: 0 = editierbar, 1 = nicht editierbar (nur lesen)
	'- hwnd = Handle des Fensters
	
	Dim Style As UInteger
	
	Select Case MultiLine
		Case 0
			If ReadOnly = 0 Then 
				Style = WS_BORDER Or WS_VISIBLE Or WS_CHILD OR ES_AUTOHSCROLL
			Else
				Style = WS_BORDER Or WS_VISIBLE Or WS_CHILD Or ES_AUTOHSCROLL Or ES_READONLY
			End If
		Case 1
			If ReadOnly = 0 Then 
				Style = WS_BORDER Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL _
								Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE
			Else
				Style = WS_BORDER Or WS_VISIBLE Or WS_CHILD Or WS_HSCROLL Or WS_VSCROLL _
								Or ES_AUTOHSCROLL Or ES_AUTOVSCROLL Or ES_MULTILINE Or ES_READONLY
			END IF
	End Select
	
	Return CreateWindowEx(0, "EDIT", Text, Style, x, y, w, h, hWnd, 0, 0, 0 )
	
End Function


Sub EditBox_SetText(hWndControl As HWND, Text As String)
	'Text in die Editbox setzen. Parameter:
	'- hWndControl = Handle der Textbox
	'- Text = Text
    
  SetWindowText(hWndControl, Text)

End Sub


Function EditBox_GetText(hWndControl As HWND) As String
	'Gibt den Text aus der EditBox aus. Parameter:
	'- hWndControl = Handle der Textbox
    
	Dim nBufferSize As Long
	Dim nBuffer     As String
    
	'Textlänge ermitteln
	nBufferSize = GetWindowTextLength(hWndControl)
	If nBufferSize = 0 Then 
		Function = ""
		Exit Function
	End If                       
	 
	'Ein Zeichen dranhängen - nullterminierter String:
	nBufferSize = nBufferSize + 1
	 
	'Speicher erzeugen:
	nBuffer = Space(nBufferSize)
	 
	'Text abholen:
	GetWindowText(hWndControl, StrPtr(nBuffer), nBufferSize)  
	 
	'Null entfernen:
	nBuffer = RTrim(nBuffer, chr(0))
		 
	Return nBuffer
         
End Function

	
Function ListBox_New(x As Integer, y As Integer, w As Integer, h As Integer, _
										hwnd As HWND) As HWND
	'Neue Listbox. Parameter:
	'- x, y = Ecke links oben
	'- w = Breite
	'- h = Höhe
	'- hwnd = Handle des Fensters
	
	Return CreateWindowEx(0, "LISTBOX", "", WS_BORDER Or WS_VISIBLE Or WS_CHILD _
												Or WS_HSCROLL Or WS_VSCROLL OR LBS_NOTIFY, x, y, w, h, _
												hWnd, 0, 0, 0 )
												
End Function


Sub ListBox_AddString(hWndControl As HWND, Text As String) _
  'Eine Textzeile hinzufügen.  Parameter:
	'- hWndControl = Handle der Listbox
	'- Text = Text
	
  SendMessage(hWndControl, LB_ADDSTRING, 0, Cast(LPARAM, StrPtr(Text)))
    
End Sub


Function ListBox_GetCount(hWndControl As HWND ) As Integer
	'Gibt die Zahl der Einträge in der Listbox aus. Der höchste Index ist um 1 kleiner,
	'da die die Indizierung mit 0 beginnt. Parameter:
	'- hWndControl = Handle der Listbox
    
  Return SendMessage(hWndControl, LB_GETCOUNT, 0, 0)
    
End Function
Listbox is not yet tested/finished. I try to put all that ugly WinAPI stuff with a lot of cryptical parameters (CreateWindowEx, SendMessage, creating and handling of buffers) into the include library WinGUI.bas so that the main program can be kept rather simple.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Simple GUI

Post by dodicat »

Thanks Lothar S.
Seems good.

Other window functions can be combined with a standard FB screen.
So, not a GUI here, but something I posted a while ago, but with some additions.

The FB mouse hovers over any point on your desktop and the colour it points to is shown in a little window.

Keep that little window active, and press spacebar to save that colour to the clipboard (optional)

Code: Select all

#include "Windows.bi"
Dim Shared As Integer xres,yres
Dim Shared As Any Ptr MyScreen 
MyScreen=GetDC(0)

Sub SetClipBoard(Text As String)       'write Text to the clipboard
    Dim Num  As HANDLE
    Dim Chars As LPSTR
    Num=GlobalAlloc(0,Len(Text)+1)
    Chars=GlobalLock(Num)
    Chars= @text[0]
    GlobalUnlock(Num)
    OpenClipboard(0)
    EmptyClipboard()
    SetClipboardData(CF_TEXT,Chars)
    CloseClipboard()
End Sub

Function HTML(v As Uinteger) As String 'HTML format
    Dim As String hx=Hex(v)
    hx=String(6-Len(hx),"0")+hx
    Swap hx[0],hx[4]
    Swap hx[1],hx[5]
    Return hx
End Function

Function StringForClipboard(Byref counter As Integer,r As Ubyte,g As Ubyte,b As Ubyte,v As Uinteger) As String
    Static As Integer ct
    Static As String ans
    ct+=1: counter=ct
    var bb=String(3-Len(Str(b)),"0")+Str(b),rr=String(3-Len(Str(r)),"0")+Str(r),gg=String(3-Len(Str(g)),"0")+Str(g)
    var sp=String(6-Len(Hex(v))," ")
    var s= "RGB (" & bb &"," & gg &"," & rr &")"+ "   HEX &h"+Hex(v)+sp+"   HTML #"+HTML(v) +Chr(13)+Chr(10)
    ans+=s
    Return ans
End Function

Sub ShowWindowOutput(m As Point,Byref r As Ubyte,Byref g As Ubyte,Byref b As Ubyte,Byref v As Uinteger,msg As String)
    v=GetPixel(MyScreen,m.x,m.y)
    Screenlock
    Cls
    Locate 1,1
    Color 0
    Print "X,Y   ";Str(m.x);",";Str(m.y)
    Print "Red   ";b
    Print "Green ";g
    Print "Blue  ";r
    Print
    Locate 10,1
    Print "HEX   &h";Hex(v,6)
    Draw String(0,180),msg,Rgb(0,0,0)
    Print "HTML   #";HTML(v)
    Line(100-30,100-30)-(100+30,100+30),Rgb(b,g,r),bf
    Line(100-30,100-30)-(100+30,100+30),Rgb(0,0,0),b
    r= Cptr(Ubyte Ptr,@v)[2] 'Or just use the standard r,g,b extract method
    g= Cptr(Ubyte Ptr,@v)[1] 'but this method is a tad faster
    b= Cptr(Ubyte Ptr,@v)[0]
    Screenunlock
    Sleep 1,1
End Sub

Sub PrepareClipBoard(counter As Integer,s As String)
    Screen 0
    AllocConsole
    Print counter; " Colours have been copied to the clipboard"
    Print "Press Edit then Paste in notepad"
    setclipboard(s)
    Shell "notepad" 
End Sub

Function MouseInWindow(m As Point) As Integer
    Dim As Integer x,y
    screencontrol 0,x,y
    Return m.x>x And m.x<x+xres And m.y>y And m.y<y+yres 
End Function
'=======================================
Screenres 200,200,32,,&h20 
Windowtitle "Colour finder"
Screeninfo xres,yres 
Width xres\8,yres\16           'make Window font larger
Color ,Rgb (236,233,216)

FreeConsole                    'Hide the console

Dim As Uinteger v              'The whole colour
Dim As Ubyte r,g,b             'r,g,b split 
Dim As Point m                 'mouse point
Dim As String key,s,msg 
Dim As Integer  counter

Do
    key=Inkey
    If key=" "  Then s=StringForClipboard(counter,r,g,b,v):messagebeep(0)
    GetCursorPos @m
    If MouseInWindow(m) Then msg="<space> to save a colour" Else msg="" 
    ShowWindowOutPut(m,r,g,b,v,msg)
Loop Until key=Chr(255,107) Or key=Chr(27)

If Len(s) Then PrepareClipBoard(counter,s) 'if space has been pressed

 
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

Nice example! When I select a color with the spacebar and leave the program with ESC, the console window shows an error:
Aborting due to runtime error 12 ("segmentation violation signal") in ColorFinder.bas::SETCLIPBOARD.

My small WinAPI library works fairly well now, except for the combobox. I request the selection from a dropdown combobox (CBS_DROPDOWNLIST) in the following way:

Code: Select all

While GetMessage(@msg, 0, 0, 0)
	
	TranslateMessage(@msg )
	DispatchMessage(@msg )

	Select Case msg.hwnd
		Case Window_Main
			If msg.message = 273 Then End
		Case Combo
			'If msg.message = WM_LBUTTONDOWN Then		<--- both does not work properly!
			If msg.wParam = CBN_SELCHANGE Then
				index = ComboBox_GetCurSel(Combo)
				Print "Selected: Index Number "; index
			End If
	End Select
	
Wend
The index is always printed twice and is not the selected index from the opened combobox, but from the upper window of the combobox. Can you help me how to modify the code?

The same example for the listbox works well (LBN_SELCHANGE instead of CBN_SELCHANGE).
PaulSquires
Posts: 1002
Joined: Jul 14, 2005 23:41

Re: Simple GUI

Post by PaulSquires »

Lothar Schirm wrote: The index is always printed twice and is not the selected index from the opened combobox, but from the upper window of the combobox. Can you help me how to modify the code?

The same example for the listbox works well (LBN_SELCHANGE instead of CBN_SELCHANGE).
[/quote]

Hi Lothar, both of those messages are "notifications" as evidenced by the "LBN_" and "CBN_" prefixes to the message name. Notifications get sent to the parent window of the control (most often the form or dialog that the listbox or combobox was created on). The notification arrives through WM_COMMAND or WM_NOTIFY. For those two messages you would process WM_COMMAND and decode wParam for the notification message (e.g. LBN_SELCHANGE) and the lParam for the handle of the control sending the notification (e.g. HWND of the ListBox).
Lothar Schirm
Posts: 437
Joined: Sep 28, 2013 15:08
Location: Germany

Re: Simple GUI

Post by Lothar Schirm »

I intended to write my code in a very simple manner, as shown in my first draft "AddNumbers.bas" (above, Jan 28, 2015), but this seems not to be possible in any cases. It is the first time that I try to write code with WinAPI, but I am not sure whether it is useful for me to go further. For the moment, I have a small ibrary with labels, editboxes (singleline and multiline) and buttons, that is sufficient for most of my simple projects. Even listbox works with this simple concept. Alternatively, I am quite happy with FLTK or FireFly. I think I stop my "Simple (WinAPI) GUI" here.

Thanks to all who have helped me with their knowledges and ideas!
Post Reply