Getting Started With Gambas Tutorial
Getting Started With Gambas Tutorial
com
Page1of110
GettingStartedwithGambas Version2:ATutorial
Subject: Author: FileName: Version: LearningVisualBasicwithLinuxandGambas TimothyMarshalNichols GettingStartedwithGambasTutorial.odt 1.0(Revision:193) Sunday28May2006
Contents
1:Introduction.....................................................................................................................................2 1.1:GAMBasAlmostMeansBasic.................................................................................................2 1.2:Projects......................................................................................................................................4 1.3:GambasResources....................................................................................................................5 1.4:License......................................................................................................................................6 1.5:Acknowledgments.....................................................................................................................6 2:YourFirstGambasProject:SimpleEdit...........................................................................................7 2.1:Creatingtheproject...................................................................................................................7 2.2:Creatingtheuserinterface......................................................................................................13 2.3:Addingthecode......................................................................................................................18 2.4:Runningtheproject.................................................................................................................23 3:DrawingProject:ImageShow........................................................................................................28 3.1:Creatingtheproject.................................................................................................................28 3.2:Creatingtheuserinterface......................................................................................................29 3.3:AddingtheCode.....................................................................................................................37 3.4:Runningtheproject.................................................................................................................52 4:DatabaseProject:Notations..........................................................................................................56 4.1:Creatingtheproject.................................................................................................................59 4.2:Creatingtheuserinterface......................................................................................................64 4.3:CheckingouruserinterfaceforCRUD...................................................................................75 4.4:Addingthecode......................................................................................................................77 4.5:Runningtheproject.................................................................................................................99 4.6:SwitchingtoaMySQLorPostgreSQLDatabase.................................................................102 5:Appendix1:DatabaseCommandswithExecandSQL..............................................................104
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page2of110
1:
Introduction
ThisisasimpleGettingStartedwithGambasTutorial.Itisintendedforfirsttimeprogrammerswho wanttogainsomeideaofthecapabilitiesofGambas.Youcanthenseeifthisisthedevelopment environmentthattheywouldliketolearnmorefully.ItwillalsobeusefulforVisualBasic programmerswhoaremovingfromWindowstoLinux. TraditionallyonUnixbasedsystemslikeLinuxyouusedanumberoftoolstodevelopan application.Soyouusedacodeeditor,possiblyauserinterfacedesigner,acompilerandothertools. Youpreformedeachstageofthedevelopmentprocesswiththerelevanttool.Thisprocesscanwork, afterallmuchofLinuxwasbuiltthisway.Itdoeshavetheadvantagethatifyoudonotlikeonetool thenyoucanreplacejustthattoolwithsomethingyoudolike.Butitcanalsohavethedisadvantage ofcompatibilityissueswhentheoutputofonetooldoesnotfittherequiredinputforanothertool.It alsomakesitdifficultfornewdeveloperstolearntherequiredstepstoproduceprofessionallooking application.ToovercometheseproblemstherearenowanumberofIntegratedDevelopment Environment(IDE)forLinux.IDE'sincludeallthetoolsyouneedtodevelopapplicationswithin oneframework.Theyhavebeenverypopularonotheroperatingsystemsanddevelopersmovingto LinuxexpecttofindsimilarIDE's.TwoofthemostusedIDE'sonLinuxareKDevelopand MonoDevelop.KDevelopisanIDEforcreatingCandC++applicationsandforusingscripting languages.MonoDevelopisanIDEfordeveloping.NETapplicationusinglanguageslikeC#and VisualBasic.NETandothers. GambasisaIDEforVisualBasiconLinux.YoucanbuildmostkindsofLinuxapplicationwith Gambas.HoweverGambasisespeciallystrongatprovidingGraphicalUserInterfaces(GUI)types ofapplications.Theycanbestandaloneapplicationsorfrontendstoaserverordatabase.Gambas providesallthetoolsyouwouldnormallyexpectinaIDE.Ithasaformdesignerwhereyoucan dragcontrolsandcomponentsontoyourformstodevelopyouruserinterface.Italsohasaproject manager,acodeeditor,acodeexplorerandanintegratedhelpsystem.Youcanalsocompile,run anddebugyourapplicationsfromwithinGambas.ItisopensourceandsofitsinwiththeLinux philosophy. Gambasalsohasastrongusercommunity.Thereareanumberofusefulforumswherenewusers cangethelp.ThereisanactiveGambasmailinglist.IftherearebugswithGambasthen,inmy experience,theyarerapidlycorrected.SeetheGambasResourcessectionbelow. GambasisdefinitelyaVisualBasicforLinux.ItisnotsimplyaportofMicrosoftVisualBasicto Linux.HoweverWindowsusersofVisualBasic(atleastuptoversion6)willfindmuchinthis environmentthatisfamiliar.
1.1: GAMBasAlmostMeansBasic
BASICstandsforBeginner'sAllPurposeSymbolicInstructionCode.Thislanguagewasdeveloped byJ.KemenyandT.KurtzatDartmouthCollegetoteachbeginnerprogrammers.Eversinceithas
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page3of110
provedtoausefulfirstlanguageforbeginnerstolearn.BASICbecameverypopularwhenpersonal computers(PC's)firstappearedinthe1970's.Thesmalloverheadsofthelanguageandtheeaseof learningmadeitthelanguageofchoicefornewprogrammerswiththeirfirstPC.Microsoft understoodthisandshippedQuickBASICforMSDOS. AlanCooperiscreditedasthe'father'ofVisualBasicandsoldtheideatoMicrosoft.Microsoftalso learnedfromHyperCardontheMacandin1991launchedVisualBasic1.0.Butitwasnotuntil Windows3.0andVisualBasic3.0thatthisreallybecamepopular.Sincethenithasbecameoneof themostdominantdevelopmentenvironment,bothinthehomeandinindustry. TherehavebeenversionsoftheBASIClanguageforalmostalloperatingsystemsandLinuxisno exception.TherehavebeenQuickBASIClikeUnix/Linuxversions.Therearealsoversionsof VisualBasicforLinuxlikeHBasicandKBasic.Formoreinformationandexamplessee http://www.thefreecountry.com/compilers/basic.shtml.Arguablythemostdevelopedandusableof theVisualBasicsforLinuxisGambas. GambaistheSpanishforprawn.GambasisalsoanVisualBasicIDEdesignedbyBenoit Minisini.ThefirstpublicreleaseofGambaswasVersion0.20inFebruary2002.Therethen followedagreatdealofdevelopmentworkandreleases.ThefirststablereleaseofGambaswas Version1.0inJanuary2005.Sincethentherehavebeenanumberofbugfixestothestableversion. AlsoinJanuary2005camethereleaseofthenewdevelopmentversionofGambas(verion1.9.1). Thisversionwilleventuallybecomethestableversion2.0. AllversionofGambasareissuedundertheGNUGeneralPublicLicenseandarefreetouse.Italso meanstheGambasruntimeisfreetouseifyouneedtoinstallitonacustomersworkstation.As Gambasisopensourceyoucanobtain,lookatand,ifyouneedto,modifythesourcecode.Alsothe GambasIDEiswritteninGambas. InthistutorialweareusingthelatestdevelopmentversionofGambas.Atthetimeof writingthelateststableversionis1.0.16(2May2006)andthelatestdevelopment versionis1.9.28(29April2006). MostofwhatiswrittenhereshouldworkonthestableversionofGambas.Where changesareneededyoushallseeanotelikethis.Lookforthesymbolontheleft. AlsointheexampleprojectsthatarepartofthistutorialthereareversionsforGambas1 and2. AllofthescreenshotsinthistutorialarefromGambasversion2.Someofthescreens maylookslightlydifferentinGambasversion1ornewerinstallsofversion2. IhavebeenusingthedevelopmentversionofGambasforaboutsixmonthsatthetimeofwriting thistutorial.IwouldsaythatGambasismorestablethanMicrosoftVisualBasic6.Ihavehadfewer crasheswiththedevelopmentversionofGambasthanwithproductionreleaseofVB6.Itisproperly justasstableasMicrosoftVisualBasic.NET(boththe.NETruntimes1.0and1.1)whichIhave alsousedquiteextensively.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page4of110
1.2: Projects
Inthistutorialweshalldevelopthreeprojectsthatdemonstratesomeofthetypesofapplications thatcanbebuiltwithGambas.
SimpleEdit .Asimpletexteditor.Thisisasimplefirstapplicationtodemonstrateusingthe developmentenvironment.Itwillshowhowbyusingsomeofthecomponentsfromthetool boxandwithalittlecodingyoucanbuildausableapplication. ImageShow. Aimagedisplayprogramforplayingaslideshowofimagesfromaselected directory.ThisapplicationdemonstratssomeofthedrawingfunctionsinGambas. Notations. Aprojectforeditingandstoringusernotes.Thisprojectdemonstrateshowto createauserinterfacetoadatabase.Theapplicationwillalsocreatethedatabaseifitdoes notexist.Youcanthencreate,read,updateanddeleterecordsinthedatabase.
Thefollowingscreenshotshowsallthreeapplicationsinaction.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page5of110
1.3: GambasResources
ThesearesomeofthewebsiteswhereyoucanfindmoreinformationaboutGambas.Youmayneed someoftheselinkstocompletethistutorialifyourLinuxdistributionhasnotincludedallthe requiredresources.NewsourcesofinformationaboutGambasarecomingonlineallthetime. IndeedIhavehadtoadditemstothislistanumberoftimeswhilewritingthistutorial.Ijustkeep discoveredmoreinformationaboutGambasontheweb.Asalwayswithweblinkstheycanbecome outofdatefastthesewerevalidinMay2006.
Gambas: TheGambasshrine SourceforgepageforGambasdownload TheGambashelpWiki GambasWikiBooktextbook GermanGambasWikiBook http://gambas.sourceforge.net/ http://gambas.sourceforge.net/download.html http://www.gambasdoc.org/ http://en.wikibooks.org/wiki/Gambas http://de.wikibooks.org/wiki/Gambas
YoucansubscribetotheGambasmailing https://lists.sourceforge.net/lists/listinfo/gambasuser listhere: ItalianGambassite GambasForums: LinuxBasic MyGambasCommunity GermanGambasClub SitiowebdeGambas(InSpanish) MoreLinks: SQLite MySQL PostgreSQL TangoDesktopProject GNULicenses MonoVisualBasic.NET FreeBASICCompilersandInterpreters http://www.sqlite.org/ http://www.mysql.org/ http://www.postgresql.org/ http://tangoproject.org/ http://www.gnu.org/licenses/ http://www.monoproject.com/Language_BASIC http://www.thefreecountry.com/compilers/basic.shtml http://www.linuxbasic.net/ http://forum.stormweb.no/ http://gambasclub.de/ http://gambas.gnulinex.org/ http://www.gambas.it/
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page6of110
1.4: License
Youarefreetousethecontentofthistutorialandexamplesourcecodeasyouwish.Alsoyoucan distributethistutorialtowhoeveryouwish.Iwouldrequestthatyouacknowledgetheauthorand alsomakesurethesourcecodeforexampleapplicationsisfreelyavailable(bothforVersions1and 2ofGambas).Butyouarenotforcedtothis.ThetextofthistutorialisissuedundertheTheGNU FreeDocumentLicense.Alloftheapplicationsandcodeexamplesfromthistutorialareissued undertheTheGNUGeneralPublicLicense2.Fordetailsseehttp://www.gnu.org/licenses/.
1.5: Acknowledgments
ManythankstoRohnnyStormoatMyGambasCommunityforcheckingoverthistutorial.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page7of110
2:
YourFirstGambasProject:SimpleEdit
Outfirstprojectisgoingtobeasimpletexteditor.Asastartingpointthismayseemalittle ambitiousforsomeonewhohasneverprogrammedinGambasbefore.Admittedlyourtexteditoris notgoingtobeasfullfeaturedassomeeditorsyoumayhaveused.Butstillitwillbeausabletext editor.Thisprojectshowsthepowerofamoderndevelopmentenvironment.Byusingthe functionalityofprebuiltcomponentsitiseasytobuildsomeusableapplicationsquickly. WithSimpleEdityoucandomanyofthethingsyoucandowithanyothertexteditor.Youcanopen andsavetextdocuments.Youwillhavetowriteabitofcodetoachievethis.ButtheTextArea componentwearegoingtousealsogivesusalotoffunctionality.Thisincludesbeingabletocut, copyandpastefromtheclipboard.Italsogivesusanundofacility.Andwedonothavetowriteany codetoincludethisfunctionalityinourapplication. InthisfirstprojectforGambaswearegoingtoprovidedetailedscreenshotsformostofthesteps. Inthelaterexampleprojectsweshallassumeyoudonotneedsomanyscreenshots.Youcanalways referbacktothisproject.
2.1: Creatingtheproject
ThefirststepistocreateanewGambasproject.SoopenGambasandandselectNewproject.... Thiswillstartthenewprojectwizard.Thefirstpageofthewizardsimplyshowsawelcomescreen withdetailsofhowtousethenewprojectwizard.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page8of110
ClicktheNext>>buttonforthenextpageofthewizard.Thisshowsapagewereyoucanselectthe typeofGambasprojectyouwanttobuild.Thetypesofprojectsinclude:
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page9of110
Wearegoingtousethedefaultoptionofagraphicalproject.SoclicktheNext>>button.This showsapagewhenyouenterthenameandtitleforyourprojectwearegoingtocreate.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page10of110
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page11of110
Selectthelocationwhereyouwanttosavetheproject.ThenclicktheNext>>button.Thisfinal pageofthewizardliststheoptionsyouhaveselectedfortheproject.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page12of110
Checkthroughtheoptionsandthenclickthe OKbutton.WehavecreatedanewVisualBasic projectandGambaswillopenshowingthe Gambasprojectmanager. Gambaswillalsoopentwootherwindows.One isaToolbox.Thisshowssomeofthecontrols wecanuseinourprojects.Theotheristhe Propertieswindow.Thisiswheretheproperties ofcontrolsinyourprojectcanbeedited.Aswe havenotcreatedanycontrolsyetitwillbe blank.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page13of110
2.2: Creatingtheuserinterface
NowwehaveaGambasproject.Thenextstepistoaddsomeelementstotheprojecttogiveusa userinterface.Thisprojectwillhaveonewindow.Mostofthiswindowwillbetakenupwitha TextAreacontrol.Byusingthiscontrolwegetmostofthefunctionsforourtexteditor.Thewindow willalsohavetwobuttonatthetopofit.Withthesebuttonsyouwillbeabletoopenandsave documentsfromtheTextArea. RightclickintheGambasproject manager.Thisbringsupapopup menu.FromthelistselectNew.This showsasubmenuwiththeitemswe canaddtoourproject.Weneedtoadd aFormtoactasthemainwindowto ourapplication.SoselectForm...from thismenu.
Thismenuoptionshowsadialoguewherewecandefinesomeofthepropertiesoftheformweare goingtocreate.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page14of110
GivetheformthenameofFormMain andaccepttheotherdefaultoptions. Thestartupclassistheclassthe Gambasruntimewillfirstloadwhen theapplicationisstarted.Therecan onlybeonestartupclassinyour project.Wewantthisformtobethe startupclasssomakesurethisoptionis checked.Leavealltheotheroptions unchecked.NowclicktheOKbutton tocreatetheform.TheGambasproject managershouldnowlooklikethe screenshotontheleft.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page15of110
Wenowneedtoaddsomecontrolsontotheformwehavejust created.Firstweshalladdtwobuttons.Makesuretheformwe havejustcreatedisvisible.Ifitisnotthendoubleclickontheform intheprojectmanager.AlsomakesuretheToolboxisvisible.Ifit isnotthenselecttheprojectmanagerViewmenthenToolboxsub menuorpresstheF6key. Thetoolboxhasseveraltabsthatgroupthekindsofcontrolswe canuse.MakesuretheFormtabisselected.Whenyoumovethe mouseoveritemsinthetoolboxthetooltipchangestoshowthe typeofobject.SelecttheButtoncontrolinthetoolbox. PlacetwoButtonsatthetopoftheformwindow.Youcandrag anddropitemsfromthetoolboxontoaformdesignerwindow.It ismucheasiertodothanitistodescribehowtodoit!
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page16of110
YourFormMainshouldnow looksomethinglikethescreen shotoftheleft.Theexactsize oftheTextAreadoesnotmatter solongasthetop,leftposition iscorrect.Thisisbecausewe aregoingtoresizethis TextAreaatruntime. Thecontrolswillhavetheir defaultname.Howeverthese defaultnamesdonotgiveand informationabouthowwe intendtousethem.Itisgood programmingpracticeto changetheirnamesto somethingmeaningfulforour application.Thiswaywewill writeselfdocumentingcode.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page17of110
Wearenowgoingtochangesomeoftheproperties ofthesecontrols.Ifthepropertieswindowisnot visiblethenselecttheprojectmanageViewmenu thenthePropertiessubmenuorpresstheF4key. NowclickonButton1intheformdesigner.Thiswill showthepropertiesforthisbutton.Wearegoingto changetheNamepropertytoButtonOpenandthe TextpropertytoOpen... Nowweshallchangethesomepropertiesforthe othercontrolsontheform.ClickonButton2inthe formdesigner.Thiswillshowthepropertiesfor Button2.WearegoingtochangetheNameproperty toButtonSaveandtheTextpropertytoSave... FinallyclickonTextArea1intheformdesigner.We aregoingtochangetheNamepropertyto TextAreaEditandthendeletethetextintheText property.InotherwordsmaketheTextproperty empty.
FinallyweshallchangeonepropertyontheForm.ClickontheformthenchangetheBorder propertytoResizeable.Thefollowingtablelistthepropertieswehavechanged. DefaultName FormMain Button1 Button2 TextArea1 Property Border Name Text Name Text Name Text NewValue Resizeable ButtonOpen Open... ButtonSave Save... TextAreaEdit <none>
Ourformshouldnowlooklikethefollowingscreenshotwhenviewedintheformdesigner.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page18of110
Thatallweneedtodowiththeformdesigner.Inmanywaysitishardertodescribewhattodothan doit.WecanseehoweasyitistobuildauserinterfaceinGambas.
2.3: Addingthecode
Itisnowtimetoaddsomecode.Infactwewedonotneedtoaddverymuchcode.Allweneedto handleareresizingtheTextAreawhentheformisresized.Wealsoneedtohandleopeningand savingatextfilewhentheuserclicksononeofthebuttons. InVisualBasicyouwritecodetohandleevents.Eventsoccurwhensomethinghappenstoacontrol orobject.Thecontrolorobjectfirestheeventtoallowothercontrolsorobjectstorespondanddo somethingwhentheeventhappens.Foraformobjectpossibleeventsinclude:
Alongwithmanyotherevents.Forabuttonpossibleeventsincludewhenitisclickedbytheuser
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page19of110
andwhenitisdoubleclicked.InVisualBasicyouwritecodetohookuptheeventsfiredbycontrols orobjectstotheactionsyouwantyourapplicationtoperform. WhenyoudoubleclickonacontrolorformintheFormdesigneritshowsthedefaulteventhandler forthatobjectinthecodeeditor.Ifthecodedoesnotexistforthedefaulteventhandleritiscreated foryou.ForaformthedefaulteventisForm_Open.Forthisapplicationwedonotneedtodo anythingwhenthiseventisfired.Howeverwedoneedtoaddaneventhandlerforthe Form_Resizeevent. Toaddtheformresizingevent handlerrightclickontheform. (Makesureyourightclickon theform,notontheTextArea oroneoftheButtons.)This willshowapopupmenu.From thismenuselectEvent.This willshowasubmenuofallthe eventsyoucouldhandlethat aregeneratedbytheform. SelectResizefromthissub menu. Thiswilladdastubforthe Form_Resizeeventtothe codeintheformsclass.Now weshalladdtheeventhandlers forthebuttonclickevents.As theclickeventisthedefault eventforthebuttonitismuch simplertoadd.IntheGambas formdesignerDoubleclickon theButtonOpenbuttontoadd theButtonOpen_Click event.Finallydoubleclickon theButtonSavebuttontoadd theButtonSave_Click event. Thesearealltheeventswewanttohandleinthisapplication.Attheendofcreatingtheevent handlestheGambascodeeditorshouldlooksomethinglikethefollowingscreenshot.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page20of110
Nowweshalladdthecodefrom thefollowinglistingtotheseevent stubs.Notethat iconinthe followinglistingmeansthatthisis acontinuationofthepreviousline. HencefortheForm_Resize eventneedonlyaddonelineof code.Soenterthefollowingcode intothecodeeditor.
FormMain.class 'Gambasclassfile PUBLICSUBForm_Resize() TextAreaEdit.Resize(ME.ClientWidth,ME.ClientHeight TextAreaEdit.Top) END PUBLICSUBButtonOpen_Click() IFDialog.OpenFile()THENRETURN TextAreaEdit.Text=File.Load(Dialog.Path) CATCH Message.Error(Error.Text) END PUBLICSUBButtonSave_Click() IFDialog.SaveFile()THENRETURN
Page21of110
SoherewearesayingwearegoingtohandletheResizeeventontheFormobject. PUBLICSUBForm_Resize() WethencalltheResizemethodontheTextArea.HerewetelltheTextAreawhatsizewewantitto be. TextAreaEdit.Resize(ME.ClientWidth,ME.ClientHeight TextAreaEdit.Top) TheResizemethodtakesparametersthatsetthewidthandheightoftheTextArea.Wecalculatethe sizebaseduponthesizeofthecurrentform.MEstandsforthecurrentobject,inthiscasethecurrent form.NotethatweuseClientWidthandClientHeightwhenwegetthesizeofthecurrent form.TheClientXXXpropertiesalwaysgivethecorrectsize.TheformalsohasWidthand Heightproperties.Butthevaluetheyreturndependsonwhethertheformismaximised.Sothey mightnotreturnthevalueyouexpect.Alsowewanttoleavespaceatthetopoftheformsothatour buttonsarevisible.SowehavetodeductthevalueforthetopoftheTextAreafromtheheightofthe form. Thefinallinefortheproceduresignalswherethecodefortheeventends. END Thenextlinetellsuswearehandlingtheclickeventfortheopenfilebutton. PUBLICSUBButtonOpen_Click() Thefirstthingweneedtodointhisprocedureisgetthepathofthefiletheuserwantstoopen.The GambasDialogobjecthasanumberofmethodswithwhichyoucandisplayanumberofcommon dialogs.Amongtheseisaopenfiledialogue.Alsoiftheusercancelsthedialogueweshouldexit ourprocedureandnonothingfurther.Givingtheuserthechancetocancelanactionisgood
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page22of110
programmingpractice.TheOpenFilemethodreturnsFALSEwhentheuserclicksontheOK buttonandTRUEotherwise.ByplacingthisstatementinsideanIFwecancheckthereturnvalueof theOpenFilemethod.TheRETURNstatementcausestheproceduretoquitimmediately.Soifthe userdoesnotclickontheOKbuttonafterselectingafilenamewethenweexitfromthis procedure.Atfirstthislinelookssomewhatcounterintuitive.Butthiswayofcallingthedialogdoes worksverywellwhenyougetusedtoit. IFDialog.OpenFile()THENRETURN WhenwereachthenextlineweknowtheuserhasclickedontheOKbuttonandselectedafile.The DialogobjecthasapropertycalledPathwhichwecanusetogetthefullpathtotheselectedfile. YouusetheFileobjectwhenperformingfileinputandoutput.TheFileobjectalsohasuseful methodsforquicklyreadingatextfile.HereweusetheFile.Load()method.Ittakesas parameterthepathtoourfileandthenreturnsthecontentofthefileasatextstring.Thisfunction handlesalltheopening,readingandclosingofthefileforus.Itiseasytousethisfunctionwhenwe wanttheentirecontentofaplaintextfile.WepassthecontentofthetextfileTextArea'sText property.ThisreplacestheentirecontentoftheTextAreawiththecontentofthefilewehave opened. TextAreaEdit.Text=File.Load(Dialog.Path) Wealsoneedtohandleanypossibleerrorsinourapplication.Thisisespeciallytruewhenyou communicatewithanythingoutsideyourapplication.Herewehaveadialoguewheretheuserenters input.Wealsohaveafilethatcouldcontainalmostanything.Withoutthefollowingerrorhandler ourprogramwouldcrashiftheuserselectedaninvalidfileorafilewheretheydidnothaveread permission.IfanyerroroccursthentheGambasruntimejumpstothisCATCHstatement.Herewe willjustdisplayamessagetotheuser.ByusingtheErrormethodontheMessageobjectwe displayaerroriconinthemessagebox.Herewehavekeptthemessageassimpleaspossible.We simplyshowthetextfromtheerrorthatwascreated. CATCH Message.Error(Error.Text) END CodeafteraCATCHstatementisnotexecutedwhennoerroroccurs.Sowithvalidfilestheuserwill neverseethemessagebox. Thecodeforthesavefilebuttonisverysimilartothatoftheopenfilebutton.Thefirstlinetellsus wearehandlingtheclickeventforthesavebutton. PUBLICSUBButtonSave_Click() Thistimewecallthesavefiledialogwhichisverysimilartotheopenfiledialogweusedabove. Butthisdialoghasfunctionalitymoreappropriatetosavingafile.AgainthisdialogreturnsFALSE whentheuserclicksontheOKbuttonandTRUEotherwise.SoiftheuserdoesnotclickontheOK buttonafterselectingafilenameweexitfromtheprocedure. IFDialog.SaveFile()THENRETURN
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page23of110
2.4: Runningtheproject
That'severythingweneedforthisproject.So letsrunit.Youruntheprojectbyclickingon thegreenRunbuttonintheprojectmanager windoworbypressingtheF5key.
Iftheprojectdoesnotrunthemostlikelycauseisamisspellinginthecodeweentered. LookasthelinethatGambashighlightswhenfindinganerrorandcheckthenames matchthenamesofthecontrolsontheform.Alsocheckthesyntaxofthehighlighted linematchesthecodeexample. Hereisascreenshotofthefinalrunningapplicationafterwehaveopenedthecodefileforthis project.Asyoucanseethecodeisthesameasabove,butthereareextracommentsinthisfile. Thesecommentsareintheexamplesthatcomewiththistutorial.Thescreenshotalsoshowsapop upmenuwithoptionsforeditingthetext.ThismenuispartoftheTextAreacontrol.Yougetthis menuforfreebyusingthiscontrol.TryrightclickingontheTextAreainyourapplicationwhenitis running.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page24of110
Yourcode.Yourtestsshouldcovereverylineofcodeintheapplication.Thisincludesall branchesisaselection.Alsoeveryloopshouldbetestedforzero,oneandmanyiterations. Interactionbetweenobjects.Itisoftenintheinteractionbetweenobjectswhereerrors occur.Thereshouldbeatestforeveryachievableinteractionbetweenobjects(interaction thatareonlytheoreticalneednotbetested). Interfacestotheworldoutsideyouapplication.Anyusefulapplicationhasto communicatewithsomethingoutsideofitself.Yourapplicationshouldnottrustanydata fromoutsideofitselfuntilithasbeenvalidatedinsidetheapplication.Thisincludesuser inputaswellandcommunicationstoanydevices.Youalsoneedtotestforanymixof otherwisevalidinputsthattogetherareinvalid.Alsoanyinvaliddatashouldbehandled appropriately.
Normallyyouwouldnottestthefollowingitems(exceptwhenbuildingacriticalsystemsuchas applicationforuseisahospital):
Operatingsystemfunctions.Thesecouldbesystemcallsorshellcommands.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page25of110
Inbuiltcontrolsforyourprogrammingenvironment. Anythirdpartycomponentsinyourapplication.
Theseareitemsyouhavelesscontrolover.Iftherearefaultswithanyoftheseitemsthenyouwould properlyhavetochangeyourapplicationtoworkaroundthefault. Agoodwaytototestyouapplicationistoproduceatableoftests.Ideallyyouwouldproducethis tablebeforeyoustartedcodingtheapplication.Ifnewfeaturesarelateraddedtotheapplication thenaddmoreteststothetable.Inthetableyouwouldwritedowneachofthetestandtheresult youexpectforthetesttopass.Youneedtostatetheexpectedresultsothereisnoambiguityifyour applicationdoessomethingdifferent.Thefinalcolumnisforyoutorecordtheresultsofthetesting process.Ourfirstsetoftestsdealwithresizingtheapplicationwindow. FormResizingTests Test Resizethewindowusingrightedge Resizethewindowusingbottomedge Resizethewindowusingleftedge Resizethewindowusingtopedge ExpectedResult Windowshouldberesizeandthetextarea resizedtofitinthewindow. Asabove. Asabove. Asabove. Pass/Fail
Resizethewindowusingnorth/westcorner Asabove. Resizethewindowusingsouth/westcorner Asabove. Resizethewindowusingsouth/eastcorner Asabove. Resizethewindowusingsouth/eastcorner Asabove. Minimizethewindowandrestoreit Maximisethewindowandrestoreit Thewindowshouldbecorrectlyresize whenrestored. Windowshouldresizeandthetextarea resizetofitinthemaximisedwindow. Thewindowshouldbecorrectlyresize whenrestored.
Thenextsetoftestsareforthebuttonwhichopensatextfile.
GettingStartedwithGambasVersion2:ATutorial [email protected] OpenFileTests Test Opentextfile Openanemptytextfile Openaverylargetextfile Openabinaryfile Trytoopenafilethatdoesnotexist Trytoopenafilewhereyoudonothave readpermission ExpectedResult Filedisplayedintextarea Textareaempty Filedisplayedintextarea. Filedisplayedintextarea.Contentis properlynotverymeaningful Errormessage Errormessage
Page26of110
Pass/Fail
Thefinalsetoftestsareforthebuttonwhichsavesatextfile.Whenpreformingthesavefiletests makesureyoudonotoverwriteanyfilesyouneedoranysystemfiles. SaveFileTests Test Entersometextinthetextareaandsavea Filesaved newtextfiletoyourHomedirectory Entersometextinthetextareaandsaveto Filesaved anexistingfileinyouHomedirectory. Withnotextinthetextareasaveanempty Filesaved filetoyourHomedirectory Openanbinaryfileandsavethisasanew Filesaved file Trytosavethefiletoadirectorywhere youdonothavewritepermission Errormessage ExpectedResult Pass/Fail
Trytosavethefiletoadirectorythatdoes Errormessage notexist Wehaveendedupwithmoreteststhanlinesofcodeinourapplication.Thismayseemoverkillfor yourfirstproject.Butthemorethoroughyouareattestingthemoreusefulyourapplicationswillbe tootherusers.Gettingusedtoatoughtestingregimefromthestartwillpaydividendsinthelong run.Therealproblemisbeingasmeticulousasyoucaninyourtests.Youneedtocoveranymany optionsaspossibleandmakesureallcodeiscovered.Onehundredpercentcoverageisnotpossible, butyoushouldaimforthis. Soworkthroughthelistoftextandmakesureyourecordiftheypassorfail.Ifanytestfailsyou willneedtodebugthecodetofindthefault.Alsoarethereanyteststhatshouldbeaddedtothe
Page27of110
Ifyoubuildapaintprogramthenuseitforallyourdrawingtasks.Thatwayyoufind whatfeaturesyouneedtoadd.(Andalsowhatfeaturesseemedagoodideaat developmenttime,butarelittleused.)Alsoafterafewweeksmakesureyouthinkagain abouthoweasyitisforanewusertolearnyourapplication. Thatwasnottohard.Wehavecreatedabasicbutperfectlyfunctionaltexteditor.Wehaveachieved thisbyusingthepowerofexistingcomponents.Thecorefunctionalityforourtexteditorwas alreadycontainedintheTextAreacontrol. Youcouldgoonaddingfeaturestothisprojectanddevelopitasyourowntexteditor.Forexample youcouldaddsomebuttonstocut,copyandpastetext.Thenhooktheseuptothemethodsonthe TextAreacontroltohandlethisfunctionality.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page28of110
3:
DrawingProject:ImageShow
Withthisprojectwearegoingtocreateasimpleslideshowapplication.Wewanttheprojecttohave thefollowingfunctionality:
Theapplicationshoulddisplayimagesfromaselecteddirectory. Thedisplayshouldbefullscreen. Imagesshouldbedisplayedfullsizeandcentredonthescreen. Ifanimageislargerthenthescreenthenitshouldbescaledtofitonthescreenkeepingthe aspectratiooftheimage. Onceadirectoryisselectedtheapplicationwillscrollthroughtheimagesdisplayingone every15seconds. PressingtheEscapekeywillquittheapplication. PressingF1willdisplayabriefhelpscreen. Pressingspacebarorrightarrowwillscrolltothenextimage. Pressingthebackspacekeyorleftarrowwilldisplaythepreviousimage. Pressingthe'D'keywillallowtheusertochangetheimagedirectory. Pressingthe'S'willstartorpausetheslideshow Pressingthe'I'keywilldisplayinformationabouttheimage/show. Themouseshouldbehiddenwhenimagesaredisplayed.
Thislookslikealonglistbutasweshallseethefinalapplicationisnotthatcomplex.
3.1: Creatingtheproject
ThefirststepistocreateanewGambasproject.SoopenGambasandandselectNewproject.... Thiswillstartthenewprojectwizard.Thefirstpageofthewizardsimplyshowsawelcomescreen withdetailsofhowtousethenewprojectwizard.ClicktheNext>>buttontoforthenextpageof thewizard.ThisshowsapagewerewecanselectthetypeofGambasprojectwewanttobuild.We aregoingtousethedefaultoptionofagraphicalproject.SoclicktheNext>>button.Thisshowsa pagewhenyouenterthenameandtitleforyourprojectwearegoingtocreate.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page29of110
3.2: Creatingtheuserinterface
NowwehaveaGambasproject.Thenextstepistoaddsomeelementstotheprojecttogiveusa userinterface.Thisprojectwillhaveonewindowthatwillbedisplayedfullscreen.Allofthis windowwillbetakenupwithaDrawingAreacontrol.Wecoulddrawtheimagedirectlyontheform butusingaDrawingAreagivesussomeextrafunctionality.Wewillalsoputatimerontheform. Thisissowecanfireeventstochangeimagesassetintervals.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page30of110
RightclickintheGambasprojectmanager. Thisbringsupapopupmenu.Fromthelist selectNew.Thisshowsasubmenuwiththe itemswecanaddtoourproject.Weneedto addaFormtoactasthemainwindowtoour application.SoselectForm...fromthis menu. Thismenuoptionshowsadialoguewherewe candefinesomeofthepropertiesoftheform wearegoingtocreate.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page31of110
Wenowneedtoaddsomecontrolsontotheformwehavejust created.FirstweshalladdaTimer.Makesuretheformwehave justcreatedisvisible.Ifitisnotthendoubleclickontheformin theprojectmanager.AlsomakesuretheToolboxisvisible.Ifitis notthenselecttheprojectmanagerViewmenuthenToolboxsub menuorpresstheF6key. Thetoolboxhasseveraltabsthatgroupthekindsofcontrolswe canuse.MakesuretheSpecialtabisselected.Whenyoumove themouseoveritemsinthetoolboxthetooltipchangestoshow thetypeofobject.SelecttheTimercontrolthethetoolbox. PlaceaTimerontheformwindow.Youcandraganddropitems fromthetoolboxontoaformdesignerwindow.Itdoesnotmatter whereyouputthetimerasitwillnotbevisiblewhentheprogram isrun.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page32of110
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page33of110
ClickontheDrawingAreaobjectandchangetheName propertytoDrawingAreaImage. Thatallofthepropertieswearegoingtochangeinthe Formdesigner.Someotherpropertiesoftheseobjectswill bechangedinthecode. Wewanttoshowsomehelpinformationstotheuserwhen theypresstheF1key.Themethodwearegoingtouseis suitablewhentherequiredamountofhelpissmallandwill fitononepage.TheGambasMessageboxisquitea flexibleclassandwilltakeaHTMLformattedmessage. Sowiththesinglelineofcode: Message.Info(File.Load("help.htm")) wecandisplayaHTMLfile.
Thisshowsadialoguewherewegivethetextfileaname.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page34of110
Givethefilethename help.htmandpressthe OKbuttontosaveit.This willaddthefiletothe datasectionofyour projectandwillopenthe newtextfileinthe Gambastexteditor window.Thescreenshot ontheleftshowsthe Gambastexteditor windowafterwehave enteredsomeHTMLinto it.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page35of110
ThisisnotatutorialaboutHTMLthereareplentyofthoseontheinternet.Sowearenotgoingto saymuchaboutthisfile.JustenterthefollowingHTMLintothetexteditor.Notethat,asbefore,the iconinthefollowinglistingmeansthislineisacontinuationofthepreviousline. help.htm <html> <head> <title>ImageShowHelp</title> </head> <body> <h2><fontcolor='Blue'>ImageShowHelp</font></h2> <hr> <p>ImageShowpresentsaslideshowofimagesfromadirectory youselect. </p> <p>Thefollowingkeyscanbeusedwhileviewingimages: </p> <p>The<b><fontcolor='Blue'>Spacebar</font></b>or<b><font color='Blue'>RightArrow</font></b>keystoshowthenextimage <br>The<b><fontcolor='Blue'>Backspace</font></b>or<b><font color='Blue'>LeftArrow</font></b>keystoshowtheprevious image <br>The<b><fontcolor='Blue'>D</font></b>keytoselectanew picturedirectory <br>The<b><fontcolor='Blue'>I</font></b>keytoshow informationabouttheimage <br>The<b><fontcolor='Blue'>S</font></b>keytoggles startingandpausingtheshow <br>The<b><fontcolor='Blue'>Esc</font></b>keytoquit <br>The<b><fontcolor='Blue'>F1</font></b>keyforhelp </p> <hr> <p>ImageShowv.0.0.1wasdevelopedbyTimothyMarshalNichols inMay2006.Itisissuedunderthe<b>TheGNUGeneralPublic License2</b>.
Page36of110
Thatalloftheelementsweneedfortheuserinterface.Alltherestoftheapplicationsfunctionality isgoingtobedoneincode.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page37of110
3.3: AddingtheCode
Therearethreeeventweneedtohandleinthisapplication.Weneedsomesetupcodewhenthe applicationopens.Whentheuserpressesakeyonthekeyboardweneedtocheckthekeypressand, ifrequired,respond.Wealsoneedtoupdatethescreenimageevery15secondswhentheslideshow isrunning. Soletsaddtheseeventstoourapplication.Thefirsteventiseasydoubleclickonthe FormImageShowintheformdesigner.ThiswilladdtheeventForm_OpentotheFormImageShow class. Nextweshalladdtheeventforauserkeypress.RightclickontheontheFormImageShowinthe formdesigner.Thiswillshowapopupmenu.SelecttheEventsoptionandthenfromthesubmenu selectKeyPress.ThiswilladdtheeventForm_KeyPresstotheFormImageShowclass.Finally doubleclickontheTimerShowobjectontheFormImageShow.Thiswilladdtheevent TimerShow_TimereventtoFormImageShowclass. Whenyouhaveaddedtheseevents theFormImageShowclassshould looklikethisscreenshot.
NowweshalladdcodetotheFormImageShowclass.Inthistutorialchapterweshallsplitthecode intochuckssothatwecandescribeeachsection.Weneedtwovariablestostoreinformationabout
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page38of110
ourslideshow.ThefirstvariableisaarrayofstringscalledpictureFiles.Hereweshallstore thefilepathstoallinimagesinourslideshow.ThenextvariableispictureNumberwhichwill holdtheindexnumberofthecurrentlydisplayedimage. FormImageShow.class PRIVATEpictureFilesASNEWString[] PRIVATEpictureNumberASInteger ContinuedBelow NoticethatwedeclarethesevariablesasPRIVATE.Lateronyouwillseethatvariablesdeclared insideaprocedureorfunctionaredeclaredusingtheDIMstatement.HoweverinGambaswhen declaringvariablesatmoduleorclasslevelyouneedtousethePUBLICorPRIVATEkeywords. WeshalladdcodetotheForm_Openeventwecreatedearlier.Thiseventfireswhentheformis firstshownandonlyfiresonce.Itisausefulplacetoputanysetupcodeyouneedforaform.We startbysettingtheformsbackgroundtoblackandmakingtheformfullscreen.(Gambasversion1 usersseethenotebelow.) WethensetthechangesweneedtotheDrawingArea.WeresizetheDrawingAreawiththemove statement.NormallywewouldusetheME.ClientWidthandME.ClientHeightproperties togetthesizeofthecurrentform.Inmostcasesthesearethepropertiesyoushoulduse.Buthere theyarestillsettotheoldformsize.Theydonotappeartobecomesettothevalueswewantuntil theformresizeeventiscalled.AswewanttheformtobefullscreenwecanusetheDesktopobject togetthevaluesweneed.TheDesktopobjectgivesussomeusefulinformationaboutthescreen. AlsofortheDrawingAreawesettheCashedpropertytoTRUE.Whenthispropertyissetthe DrawingAreawillautomaticallyhandlerefreshingofitselfifthecurrentpictureneedstobe redrawn.ThismeanswelettheDrawingArearedrawthecurrentpicturewhenneeded.Weonlyneed tothinkaboutdrawingwhenwewanttochangethepicture. Wethencalltwofunctions.Thefirstallowstheusertoselectadirectoryfromwhichtobuildalist ofimages.Thenextfunctionwilldisplayanimage.Thecodeforthesefunctionsisdescribedlater on.Aftercallingthesefunctionswehidethemousesoitdoesnotdetractfromtheimage. Finallywesetuptheshowtimer.Wesetthedelaytimebetweenimagesto15seconds.Butweonly starttheshowtimerifwehavesomeimages. FormImageShow.classContinued
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page39of110
PUBLICSUBForm_Open() 'Setformproperties ME.BackColor=Color.Black ME.FullScreen=TRUE 'Setdrawingareaproperties DrawingAreaImage.Move(0,0,Desktop.Width,Desktop.Height) DrawingAreaImage.Cached=TRUE 'Selectimagedirectory Dialog.Path=User.Home SelectImages() NextPicture() 'Hidemouse DrawingAreaImage.Mouse=Mouse.Blank 'Startshowtimer TimerShow.Delay=15000'15seconds TimerShow.Enabled=(pictureFiles.Count>0) END ContinuedBelow InGambasversion1youuseaslightlydifferentmethodofdisplaystheformfullscreen. TheME.FullScreen=TRUElineintheabovelistingneedstobechangedtothe following: ME.State=Window.Fullscreen AlsotoselecttheusershomedirectoryyouusetheSystemobject. Dialog.Path=System.Home
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page40of110
keyboardcodeandwecancomparethiswithconstantsintheKeyobjectinourSELECTstatement. WhentheEscapekeyispressedweuseME.Close()toendtheapplication.IftheF1keyis pressedweholdtheimageshowandthendisplayourHTMLhelpfileinamessagebox.Whenthe userclosesthemessageboxtheimageshowstateissettothesavedstate. InGambasversion1themessageboxgetslostbehindtheformwhentheformisfull screen.SoamendthecodefortheF1buttontothefollowing: TimerShow.Enabled=FALSE DrawingAreaImage.Mouse=Mouse.Default ME.State=Window.Normal ME.Border=Window.Resizable Message.Info(File.Load("help.htm")) ME.State=Window.FullScreen DrawingAreaImage.Mouse=Mouse.Blank TimerShow.Enabled=timerState Thehelpmessagedoesnotlookasgoodasinversion2ofGambas.Butatleastitdoes notgetlost. Thenexttwocaseshandletheusermanuallyadvancingthecurrentimage.Whentheuserpresses theRightArroworBackspacekeywedecrementthecurrentimagecounterandthencallour proceduretodrawtheimage.SimilarlyiftheuserpressestheLeftArroworSpacebarkeywe incrementthecurrentimagecounterandthencallourproceduretodrawtheimage. WhentheDkeyispressedwehandletheuserchangingtheselecteddirectoryforimages.Firstwe pausetheslideshow.Thenweshowthemousebysettingittoitsdefaultcursor.Itcouldbe confusingtotheusertokeepthemousehidden.Wethencalltwofunctionsthatweusedinthe Form_Openevent.Thefirstallowstheusertoselectadirectoryfromwhichtobuildalistofimages. Thenextfunctionwilldrawanimage.Wehidethemouseagainandstarttheshowtimerifwehave someimages. TheSkeytogglespausingtheslideshoworstartingitrunningagain.Whenpausingtheslideshow wesimplydisabletheslideshowtimer.Weonlyallowtheslideshowtostartiftherearesome imagestodisplay.Iftherearesomeimagesweincrementthecurrentimagecounteranddisplaythe nextimage.Thisgivesavisualconfirmationtotheuserthattheslideshowhasstartedrunning again.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page41of110
WhentheIispressedwecallaprocedurethatdrawssomeinformationonthescreenaboutthe currentstateoftheslideshowandthecurrentimage.Thisprocedureisdescribedlater. FormImageShow.classContinued PUBLICSUBForm_Press() DIMtimerStateASBoolean timerState=TimerShow.Enabled SELECTCASEKey.Code CASEKey.Esc 'Closetheslideshow ME.Close() CASEKey.F1 'ShowHTMLhelp TimerShow.Enabled=FALSE DrawingAreaImage.Mouse=Mouse.Default Message.Info(File.Load("help.htm")) DrawingAreaImage.Mouse=Mouse.Blank TimerShow.Enabled=timerState CASEKey.BackSpace,Key.Left 'Showpreviouspicture TimerShow.Enabled=FALSE DECpictureNumber NextPicture() TimerShow.Enabled=timerState CASEKey.Space,Key.Right 'Shownextpicture TimerShow.Enabled=FALSE INCpictureNumber NextPicture() TimerShow.Enabled=timerState CASEKey["D"] 'Getanewslideshowfromadirectory TimerShow.Enabled=FALSE DrawingAreaImage.Mouse=Mouse.Default SelectImages()
GettingStartedwithGambasVersion2:ATutorial [email protected] NextPicture() DrawingAreaImage.Mouse=Mouse.Blank TimerShow.Enabled=(pictureFiles.Count>0) CASEKey["S"] IFTimerShow.EnabledTHEN 'Iftheshowisrunningthenstopit TimerShow.Enabled=FALSE ELSEIFpictureFiles.Count>0THEN 'Iftheshowisnotrunningandwehavepictures 'thenstarttheshowwiththenextpicture INCpictureNumber NextPicture() TimerShow.Enabled=TRUE ENDIF CASEKey["I"] 'Showsomeinformationabouttheshow ShowMessage() DEFAULT 'Nothing ENDSELECT END ContinuedBelow
Page42of110
Whentheimageshowisrunningatimereventwillbefired.Hereweincrementthecounterwehave fortheimagenumberby1andthencallourfunctiontodrawtheimage.Wewrapthedrawingcall withEnablingandDisablingatimer.Thisisproperlynotneededandisahangoverfromcodingin anotherVisualBasic.Ihaveputthisinsoweresetthetimerafterhavingcompleteddrawingthe image. FormImageShow.classContinued PUBLICSUBTimerShow_Timer() TimerShow.Enabled=FALSE 'Gotothenextimage INCpictureNumber
Page43of110
Wehavecalledthisnextprocedureseveraltimesabove.Itallowstheusertoselectanewimage directoryandloadsthepathsoftheimagefilesintopictureFilesarray.Firstwecallastandard dialoguethatallowstheusertoselectadirectory.Callingthisdialogueissimilarthewayweopened andsavedfilesintheSimpleEditprojectabove.IftheuserdoesnotselectatheOKbuttonanda directorywereturnfromtheprocedure.TheDialog.Pathpropertyreturnsthenameandpathof theselecteddirectory.Iftheuserselectsadirectorywecleartheoldlistofimagefiles. UsingtheDirfunctionwecanobtainalistofallfilesinadirectory.Asthislistisnotsortedwe usetheSort()methodonastringarraytosortthefilelist.WethenuseaFORNEXTconstructto loopthrougheachofthefiles.TheFileclassprovidessomeusefulmethodforextractingelements fromafilepath.HerewewanttotestthefileextensionforeachfilesoweusetheFile.Ext method.Inordertoprovideacaseinsensitivesearchforimagesweconverttheextensiontolower case.WethentestthefileextensionfortheimagefiletypessupportedbyGambas.Ifwehavefound aavalidimagefilenamethenweaddthefullfilenameandpathtoourimagefilelist. Whenwehavecompletedtheloopwechecktoseeifwehavefoundanyimagefilesinthedirectory. Ifwehavenotwedisplayamessagetotheuser.Wethensetthecurrentimageindextothefirst image.WehaveaCATCHherebecauseweareinterfacingwiththefilesystemandthereisthe possibilityoffileI/Oerrors.Hopefullytheuserwillneverseethiserrormessage. Wehavebuiltalistofimagesbasedupontheextensionofthefile.Inmostcasesthiswillproducea validlist.Howeverjustbecauseafilehasanextensionofjpgdoesnotmeanitisavalidjpgimage file.Ausercangiveafileanynametheywant.Hencewhenwedisplaytheimagesweshallstill needsomeerrorcheckingcode. FormImageShow.classContinued PRIVATESUBSelectImages() DIMfileNameASString DIMfileListASString[] DIMfileExtensionASString 'Getthedirectorynamefromtheuse
GettingStartedwithGambasVersion2:ATutorial [email protected] IFDialog.SelectDirectory()THENRETURN pictureFiles.Clear() fileList=Dir(Dialog.Path) fileList.Sort() FOREACHfileNameINfileList fileExtension=Lower(File.Ext(fileName)) 'Onlyselectimagefiles IFfileExtension="png"ORfileExtension="jpeg"OR fileExtension="jpg"ORfileExtension="bmp"OR fileExtension="gif"OR fileExtension="xpm"THEN 'Thisisaimagesoaddtoimagelist pictureFiles.Add(Dialog.Path&/fileName) ENDIF NEXT IFpictureFiles.Count=0THEN
Page44of110
Message.Info("Noimagesfoundinthedirectory:\n\n"& Dialog.Path) ENDIF pictureNumber=0 CATCH Message.Warning("Errorselectingimagesfrom:\n\n\t"& Dialog.Path&"\n\n"&ERROR.Text) END ContinuedBelow AlthoughwecalltheNextPictureprocedureseveraltimeitisnotwherewedotherealworkof drawingthecurrentimageisdone.Ratherthisprocedurecheckswehavevalidinputforthe DisplayImageprocedure.Firstwemakesurewehavesomeimagestodisplay.The pictureFilesarrayholdsthepathstotheimagesfilesinourshow.BymakingsuretheCount propertyisgreaterthanzeroweensurethereissomethingtodisplay.Wethenmakesureourindex forthecurrentpictureiswithinavalidrange.Ifourindexisgreaterthannumberofimages availablethenwesetittothestartoftheshow.Similarlyifourindexislessthanzerothenwesetit totheendoftheshow.ThiswaywecansafelyincrementanddecrementthepictureNumber indexintheproceduresabove.Weknowthathereweshallwraptheindexaroundtheendsofthe array.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page45of110
Rememberthattheindexinaarraystartsatzeroandthefinalelementofanarrayisonelessthen theCountproperty.WhenwehaveavalidindexwecalltheDisplayImageprocedurethatdoes alltheactualdrawingwork. FormImageShow.classContinued PRIVATESUBNextPicture() 'Checkwehavesomeimagefilepaths IFpictureFiles.Count>0THEN 'Limittheimagenumbertothenumberof 'filesinourarrayoffilepaths IFpictureNumber>=pictureFiles.CountTHEN pictureNumber=0 ELSEIFpictureNumber<0THEN pictureNumber=pictureFiles.Count1 ENDIF 'Nowdrawtheimage DisplayImage(pictureFiles[pictureNumber]) ENDIF END ContinuedBelow DrawingtheimageontheDrawingAreaisveryeasy.Threeobjectsareinvolvedinthisprocess.The Imageobject,theDrawobjectandtheDrawingAreacontrol.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page46of110
Draw:Youdrawonadevice.Thedevicecanbeaanyof thefollowingobjects:Picture,Window(i.e.aForm),the Printer,aDrawing,oraDrawingArea.Youstartdrawing byinitializingthedeviceyouwanttodrawon.Thisis donepassingthedrawingdevicetotheBeginmethod. Youthensetthepropertiesrequiredforthenextdrawing action.Thisincludespropertieslikeselectingcolors, fontsorlinestyles.Youthencallthemethodtoperform thedrawingaction.Thedrawingmethodsinclude drawinglines,rectangles,textandimages.Theprocess ofsettingdrawingpropertiesandcallingdrawing methodsiscontinueduntilthedrawingisfinished. FinallyyoucalltheEndmethodtocompletethe drawing.
Begin(Device)
Setdrawing properties
End
Thisdiagramshowstherelationshipbetweenthedrawingobjectsinourapplication.
ImageFile
jpg,png, bmporgif
LoadImage fromdisk
Image
Whenwefirstloadtheimagefromfile.Weneedtoputsomeerrorhandlingonthis.Theload
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page47of110
methodusesthefileextensiontodeterminewhatkindofimagetoload.Ifthefilecontentdoesnot matchthefileextensionthenwehaveanderror.Eveniftheuserselectedsomevalidimagesitis possiblewemaynothavereadpermissiononthefile.Thisagaincouldgiveuseanerror.Ifweget anerrorwesimplyreturnfromtheprocedure. Wethencheckthesizeoftheimage.Iftheimageislargerthenthesizeofthescreenthenwewant toscaleittofitonthescreen.Whenscalingwewanttoscaleisotropicallywhichmeansscalingthe imagebythesamefactorinbothdirections.Thiswillkeeptheaspectratiooftheimage.Thereare twopossiblescalingfactorswecoulduse.Scalingtomakethewidthfitonthescreenorscalingto maketheheightfitonthescreen.Wetakethesmallestoftheseandapplythemtoboththewidth andtheheightoftheimage. Amoreinterestingproblemismakingsurethepreviousimageiscleared.Whenanewimageis drawnitmaynotbethesamesizeasthepreviousimage.Eitherinthewidthdirectionoftheheight direction.Ifallwedoisdrawthenewimagewecouldleavebitsoftheoldimageonthescreen. Thiswouldnotlookverygood. ThefirstsolutionItriedwassimplytousetheClearmethodontheDrawingAreaandthendrawthe image.Inmanycasesthisworksfine.TheClearmethodclearstheDrawingAreausingthe Backgroundcolor.Theproblemwasfordrawinglargeimagesthescreenproducedanoticeable 'flash'eachtimeanimagechanged.Yousawthebackgroundcolorflashovertheentirescreenfora fractionofasecond.ThisdidnotlookverygoodsotheClearmethodhadtogo. ThenextsolutionItriedwastodrawasolidrectangleovertheentireDrawingAreausingthe backgroundcolor.ThenIwoulddrawtheimagecentredonthescreen.Thisworkedbetter.Butyou stillsawanoticeable'flash'whenalargeimagewasdrawn. ThenextsolutionItriedwastodrawthenewimagefirst.Thentodrawovertherestofthescreen withthebackgroundcolortoclearanypartsoftheoldimageleftbehind.Todothisweneedto draw4solidrectanglesinthebackgroundcoloroneachedgeoftheimage.Thefollowingdiagram willhelpuscalculatethesizeoftherectanglesweneedtodraw.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page48of110
x1
x2
x3
y1 Image y2
Height
y3
Width
Usingthisthiswecanseetherectanglesweneedtodrawtoclearanypossiblefragmentsofthe previousimage. Rectangle Top Bottom Left Right StartPoint 0,0 0,y2 0,0 x2,0 x3 x3 x1 x3x2 Width y1 y3y2 y3 y3 Height DrawRectangle Rect(0,0,x3,y1) Rect(0,y2,x3,y1) Notethat:y1=y3y2 Rect(0,0,x1,y3) Rect(x2,0,x1,y3) Notethat:x1=x3x2
(Ourrectanglesoverlapinthecorners.Youcouldmaketheapplicationmoreefficientbyreducing thesizeofsomeoftherectangle.ButIdonotthinkitisworthit.Idoubttheuserwouldevernotice aspeeddifference.Comparedwiththetimetakentoload,scaleanddrawtheimage,drawingthe rectanglesisveryfast.Alsoyouruntheriskofleavinglinesthathavenotbeenclearedacrossthe screenatthejoinsofrectangles.Thiscouldoccureifthereareanyroundingerrorsinyour calculations.) ThefinalmethodthatmightbetriedistouseaPictureobjectasadrawingbuffer.Withthismethod youwouldcreateaPictureobjectthesizeoftheDrawingArea.SetthePictureobjectsbackgroundto theDrawingAreasbackgroundcolor.ThendrawtheimagecentredonthePictureobject.Thefinal stepwouldbetodrawthePictureobjectontotheDrawingArea.Againthisworks.Butitdidnot provideasolutionanybetterthanthepreviousmethodwelookedat.Soforthefinalversionofthe
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page49of110
codewehaveusedthatmethodofclearinganypreviousimage.Thecodelistingfordrawingand imagefollows. SomeversionofGambasmayrequirethetheline: TRYcurrentImage.Load(ImagePath) tobe: TRYcurrentImage=Image.Load(ImagePath) asthesyntaxoftheloadfunctionhaschanged. FormImageShow.classContinued PRIVATESUBDisplayImage(ImagePathASString) DIMcurrentImageASNEWImage DIMscaleASFloat DIMx1ASInteger DIMx2ASInteger DIMx3ASInteger DIMy1ASInteger DIMy2ASInteger DIMy3ASInteger 'Loadtheimage 'SomeversionofGambasmayrequirethislinetoread 'TRYcurrentImage=Image.Load(ImagePath) TRYcurrentImage.Load(ImagePath) IFERRORTHENRETURN'Ifwecannotloadtheimagethengiveup 'Checkiftheimageislargerthanthescreen IF(currentImage.Width>DrawingAreaImage.ClientWidth)OR (currentImage.Height>DrawingAreaImage.ClientHeight)THEN 'Scaleimagetofitonthescreen scale=Min(DrawingAreaImage.ClientWidth/currentImage.Width, DrawingAreaImage.ClientHeight/currentImage.Height) currentImage=currentImage.Stretch(currentImage.Width* scale,currentImage.Height*scale) ENDIF 'Calcrectanglespoints x1=(DrawingAreaImage.ClientWidthcurrentImage.Width)/2
Page50of110
y1=(DrawingAreaImage.ClientHeightcurrentImage.Height)/2 y2=y1+currentImage.Height y3=DrawingAreaImage.ClientHeight 'Drawimage Draw.Begin(DrawingAreaImage) Draw.Image(currentImage,x1,y1) 'Drawrectanglesovertheareanotcoveredbythenewimage Draw.BackColor=DrawingAreaImage.BackColor Draw.ForeColor=DrawingAreaImage.BackColor Draw.FillColor=DrawingAreaImage.BackColor Draw.FillStyle=Fill.Solid 'Drawtoprectangle Draw.Rect(0,0,x3,y1) 'Drawbottomrectangle Draw.Rect(0,y2,x3,y1) 'Drawleftrectangle Draw.Rect(0,0,x1,y3) 'Drawrightrectangle Draw.Rect(x2,0,x1,y3) Draw.End END ContinuedBelow Thefinalprocedurewehavedrawsaninformationmessageabouttheslideshow.Thisiscalled whentheuserpressestheIkey.Firstwebuildthestringforthemessage.Weaddsomeinformation aboutiftheshowisrunningorpaused.Ifitisrunningweaddinformationaboutthetimeinterval betweenimages.Wethenshowsomeinformationaboutthecurrentimage.Weshowthecurrent picturenumberandthetotalnumberofimagesaswellastheimagepath.Notethatweaddoneto thecurrentimageindexbecausethestringarrayindexfortheimagepathsstartsatzero. Nextwecalculatethescreenpositionforthemessage.Wewanttoplacethemessageatthebottom ofthescreenandinthecentre.Wewilldrawthismessageusingthedefaultfont.Weusethe TextWidthandTextHeighmethodsontheDrawobjecttogetthesizeofthetext.Wecanthen calculatethepositionforthetext.Theleftpositionforthetextwillbehalfthewidthofthescreen
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page51of110
minusthewidthofthetextmessage.Thetoppositionforthetextwillbetheheightofthescreen minustheheightofthetext. Wewanttomakesurethetextisvisible.Ifwesimplydrewthetextitcouldbeoveranycolorthat formsthebackground.Sofirstwedrawafilledrectangleasthebackground.Thenwedrawthetext ontopofthisrectangleatthepositionwehavecalculated. FormImageShow.classContinued PRIVATESUBShowMessage() DIMmessageASString DIMx1ASInteger DIMy1ASInteger DIMmessageWidthASInteger DIMmessageHeightASInteger 'Gettheinformationmessage IFTimerShow.EnabledTHEN message="ShowRunning(Every"&CInt(TimerShow.Delay/ 1000)&"seconds)" ELSE message="ShowPaused:" ENDIF IFpictureFiles.Count>0THEN message&="Picture:("&(pictureNumber+1)&"/"& pictureFiles.Count&")"&pictureFiles[pictureNumber] ELSE message&="Nopictures" ENDIF 'Drawtheinformationmessage Draw.Begin(DrawingAreaImage) 'Calcmessageposition messageWidth=Draw.TextWidth(message) messageHeight=Draw.TextHeight(message) x1=(DrawingAreaImage.ClientWidthmessageWidth)/2'Center ofscreen y1=DrawingAreaImage.ClientHeightmessageHeight'Bottomof
GettingStartedwithGambasVersion2:ATutorial [email protected] screen 'Drawthemessagebackground Draw.ForeColor=Color.LightGray Draw.FillColor=Color.LightGray Draw.FillStyle=Fill.Solid Draw.Rect(x1,y1,messageWidth,messageHeight) 'Drawthemessagetext Draw.ForeColor=Color.Black Draw.Text(message,x1,y1) Draw.End END
Page52of110
3.4: Runningtheproject
Theprojectisnowcompletesoletsrunit.YouruntheprojectbyclickingonthegreenRunbutton intheprojectmanagerwindoworbypressingtheF5key.Adialogueshouldopenaskingyouto selectadirectory.Selectadirectorywithsomeimagesinpngorjpgformat.Watchtheshow! Wenowneedtotesttheapplicationworksasexpected.Soruntheapplicationandselectaimage directory.ThenpresstheDkeytochangetheimageshowdirectory.Testtheapplicationwiththe followingkindsofdirectories: OpenImageDirectoryTests Test Openadirectorywithimagesinit. Tryanemptydirectory. Tryadirectorywithnoimagesbutsome otherfiletypes. Adirectorywithsomejpgimagefiles. Adirectorywithsomejpegimagefiles. Adirectorywithsomepngimagefiles. Adirectorywithsomegifimagefiles. Adirectorywithsomebmpimagefiles. ExpectedResult Imageshowdisplayed. Anoimagesfoundmessage. Anoimagesfoundmessage. Imageshowdisplayed. Imageshowdisplayed. Imageshowdisplayed. Imageshowdisplayed. Imageshowdisplayed. Pass/Fail
Page53of110
Pass/Fail
Makesureinalloftheaboveteststhattheapplicationdoesnottrytoopenanyfilesthatarenot imagesandthatalltheimagesareshown.Theapplicationshouldnotcrashandyoushouldbeable toselectanotherdirectory.Wenowwilltestalltheotherkeysperformthecorrectaction. KeyPressTests Test Withanimageshowpressthespacebar. Withanimageshowpressthebackspace key. Withanimageshowpresstheleftarrow. WiththeshowrunningpresstheSkey. WiththeshowpausedpresstheSkey. WiththeshowrunningpresstheIkey. ExpectedResult Nextimageshouldbedisplayed. Previousimageshouldbedisplayed. Previousimageshouldbedisplayed. Theshowshouldpause.(Waitmorethan 15secondstomakesure.) Thenextimageshouldbedisplayedand theshowstartrunning. Aninformationlineshouldbeshown.It shouldsaytheshowisrunningandgive thecurrentimagename. Aninformationlineshouldbeshown.It shouldsaytheshowispausedandgivethe currentimagename. Ahelpmessageshouldbedisplayedand alsothemouse.Whenthemessageis clearedthemouseshouldbehidden. Theapplicationshouldclose. Pass/Fail
Withanimageshowpresstherightarrow. Nextimageshouldbedisplayed.
WiththeshowpausedpresstheIkey.
WiththeshowrunningpresstheF1key.
PresstheEsckey.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page54of110
InUnix/Linuxtheyourhomebindirectoryisagoodplacetostoreyourpersonalapplicationsand scripts.OnmostsystemthisdirectoryisinyourPATHsoitwillbesearchedwhenyouenter commandsfromaterminal.MovethefileImageShow.gambasthatwehavejustcreatedinyour projectdirectorytoyour$HOME/bindirectory. Nowopenaterminalwindowandtype ImageShow.gambas&andour applicationshouldstart.The&afterthe commandissotheterminaldoesnot waitfortheImageShowprocesstoend. ItisnotrequiredtostartImageShow.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page55of110
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page56of110
4:
DatabaseProject:Notations
MicrosoftVisualBasicbecameverypopularontheWindowsplatform.Onereasonforthissuccess isthatMicrosoftVisualBasicwasagoodfrontendfordatabaseapplications.Manyusers,like myself,comingfromtheWindowsworldtoLinuxwillhaveexperienceofdevelopingapplications withVisualBasictoactasauserinterfacetoadatabase.Theywillwanttotransfertheseskillsto Linux.Inthisexamplewearegoingtogetyoustartedwithasmallprojecttocommunicatewithan SQLite2database.WithGambasyoucanusealmostthesamecodetocommunicatewithaMySQL orPostgreSQLdatabase.WithlaterversionsofGambasyoucanalsoconnecttoaSQLite3,ODBC orFirebirddatabase. AswithinstallingGambasthistutorial willnotcoverinstallingSQLite.SQLite shouldbeinstalledwithmostLinux distributions.Inordertocheckyouhave SQLiteinstalledonyourworkstation openaterminalandtypesqlite version.Ifaversionnumberis returnedthenSQLiteisinstalled.
Page57of110
AddingrecordswouldbethroughtheResultobject.YouwouldcreatetheResultobject usingtheCreatemethodonaconnection. Youareabstractedfromthedatabaselayer. YoudonotneedtoknowmuchSQL(StructuredQueryLanguage). YourcodeisportablebetweenthedatabasessupportedbyGambas.Youshouldonlyneedto changetheconnectionparameterstoswitchdatabasetypes. Searchandfilteringdataismoreawkwardandislesswellsupportedthandirectlyusing SQL. Viewsanddatabasequeriesrequiringmorethanonetablearenotaswellsupportedasin directlyusingSQL. Therearesomefeaturesoftheunderlyingdatabasethatyoucannotaccess.
Thisapproachhasthefollowingadvantages:
Italsohasafewdisadvantages:
Therearetwopossiblemethodyoucouldusetocreatethedatabase.
YouwouldreaddatafromthedatabaseusingtheExecconnectionmethodusingaSQL queryandreturnthisdatatoareadonlyResultobject. Update,InsertandDeleteshouldalsobepreformedusingtheSQLstatementssenttothe Execconnectionmethod. Yougainfinegrainedcontroloverthedatabase.YoucontrolthedetailofeachSQLqueryor command. MostdatabasessupportmorefieldtypesfortablesthanaresupportedbyGambas. FeaturesinthedatabasenotsupportedinGambasareeasilyaccessible. Itiseasytoaccessdatabaseviewsandmultitablequeries. YouneedagoodknowledgeofSQLforyourtargetdatabase.
Theadvantagesare:
Possibledisadvantagesare:
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page58of110
Whichmethodshouldyouchose?Mygeneraladvicewouldbe:
Iwouldnotmixthetwoapproaches.Ofcoursethereisnothingtostopyouifyoureallywantto.But youcouldendupwithnoneoftheadvantagesofeithermethodandallofthedisadvantages. Inthistutorialwearegoingtodemonstratethefirstofthesemethods.Thisisafterallatutorial aboutGambasandnotSQL.AlsowecanthendemonstratemoreoftheGambasdatabaseobjects youmightwanttouse. InaAppendixtothistutorialweshalllookathowtoconvertthisNotationsexampleto thesecondapproachusingExecandSQLstatements. AcommonformofinterfacedesignforadatabaseistheMaster/Detaildesign.Hereyouhavealist ofrecordsinawindow.Thereissomefieldfromthedatabasethatsummarisesthedatabaserecords andthisisusedtocreatealist.Whenarecordfromthelistisselecteditsdetailsaredisplayedinthe restofthewindow.Ifrequiredthedetailscanbeupdatedandsavedtothedatabase.Therewillalso besomemechanismforaddinganddeletingrecords.ThisNotationsexamplewillfollowthisbasic interfacedesigntoadatabaseapplication. Withthisexamplewearegoingtocreateanotetakingapplication.Weshallstorethenotesina SQLitedatabase.Theusershouldbeableto:
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page59of110
Viewalistofnotetitles.Youcanthenclickonanotetitletoviewthecompletenote. Searchthetextinnotetitlesandnotesforagivensearchtext.
Weshallkeepourdatabaseverysimple.Thedatabasenameisgoingtobethesameasthe applicationname.WeshallonlyneedonetableandthiswillbecalledNotes.Thefollowingentry liststhefieldsinthetable. FieldName CreateDate LastModified Type DATETIME DATETIME Comment PrimaryKey.Whenanewnoteisfirstcreatedthiswillbe settothecurrentdateandtime. Whenanoteisfirstcreatedthiswillhavethesamevalue aretheCreateDatefield.Eachtimeanoteisupdatedthis fieldwillbesettothecurrenttime. Length0foraunlimitedstring Length0foraunlimitedstring Priorityencodedasaninteger.0islow,1ismediumand3 ishighpriority.
4.1: Creatingtheproject
ThefirststepistocreateanewGambasproject.SoopenGambasandandselectNewproject.... Thiswillstartthenewprojectwizard.Thefirstpageofthewizardsimplyshowsawelcomescreen withdetailsofhowtousethenewprojectwizard.ClicktheNext>>buttontoforthenextpageof thewizard.ThisshowsapagewerewecanselectthetypeofGambasprojectwewanttobuild.We aregoingtousethedefaultoptionofagraphicalproject.SoclicktheNext>>button.Thisshowsa pagewhenyouenterthenameandtitleforyourprojectwearegoingtocreate.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page60of110
GivetheprojectthenameNotationsandthetitleNotationsanotetaking application.Leavetheotheroptionsblank.ClickontheNext>>button.Selectthelocation whereyouwanttosavetheproject.ThenclicktheNext>>button.Thisfinalpageliststheoptions youhaveselectedfortheproject.CheckthroughtheoptionsandthenclicktheOKbutton.Wehave createdanewVisualBasicprojectandGambaswillopenshowingtheGambasprojectmanager. Withthisprojectwearegoingtouseatoolbartodisplaysomebuttons.Toolbarscanprovideanice lookinginterfacetotheuserandtakeuplittlespace.Soweshallneedsomeiconsforthesebuttons. TheTangoprojectaimstoprovideacommonlookandfeeltothedesktop.Italsoprovideagood iconsetforuseinyourapplications.Youcangettherequirediconsfromtheexampleapplications thatcomewiththistutorialortheTangowebsitehttp://tangoproject.org/.Thissitealsoprovides usefulinformationaboutdesigningandusingicons. GototheprojectdirectoryandcreateasubdirectorycalledImages.Inthisdirectoryplacethe followingiconsfromtheTangoiconset.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page61of110
Thetangoiconsaregroupedintosizeandthencategory,Selectthe iconsshowninthefollowingtableandplacethemintheImages directory. IconSize 16x16 16x16 22x22 IconCategory actions status actions IconName dialog.information.png mediarecord.png documentnew.png documentsave.png editfind.png viewrefresh.png accessoriestexteditor.png helpbrowser.png xdirectorytrash.png
22x22 22x22
apps mimetypes
ThefollowingscreenshotshowshowtheImagesdirectoryshould lookaftercopyingtheseicons.
FromtheprojectmanagerwindowopentheProjectmenuandthentheProperties...submenu.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page62of110
ClickontheOKbutton.TheProjectPropertiesshouldnowshowtheaccessoriestext editor.pngicon.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page63of110
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page64of110
Makesurethegb.dbDatabaseaccesscomponentanditemischecked.ThenclicktheOKbutton toacceptthisdialog.
4.2: Creatingtheuserinterface
Thisapplicationisonlygoingtohaveonewindowastheinterface.Thisinterfaceisgoingtobe slightlymorecomplexthantheprevioustwoexamples.Inordertogiveussomeideaofwhatweare workingtowardshereisascreenshotofthelookoftheformwhenwehaveaddedallthecontrols anditisindesignmode.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page65of110
Clickintheprojectmanagerwindowandcreateanewform.CalltheformFormNotationsand accepttheoptionforthistobeastartupclass.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page66of110
Wearefirstgoingtocreatesomebuttonsinatoolbartogoacrossthetopoftheform.Soselectthe ContainertabintheGambastoolbox.FromthisselecttheHPanelandaddthistothetopofthe form.Resizethiscontrolsoitis42pixelsheighandthewidthisabitlessthanthewidthofthe form.Theexactwidthdoesnotmatterasthiswillbecontrolledatruntime. Toresizecontrolsfirstclickontherequiredcontrol.Thiswillshoweightresizingboxes.Thenclick anddragoneoftheseresizingboxeswiththemouse.IfyouhavetheGambaspropertieswindow openyouwillseetheHeightandWidthpropertieschange.Youcanalsoedittheseproperties directlyinthiswindow. Inthisprojectwearegoingtoaddquiteafewcontrolsthatneedtobeplaceinsidea parentcontrol.Italltoeasytoplacethenewcontrolabovetheparentcontainerrather thaninsidetheparentcontainer.Theformwillstilllookcorrectindesignmodebut unfortunatelythecontrolswillnotresizecorrectlyatruntime.Trytofollowthislittle sequenceeachtimeyouaddachildcontroltoaparentcontainercontrol: Clickontheparentcontrol.Makesureitishighlightedanditseightresizing boxesasvisible. Thenclickonthetoolboxcontrolyouaregoingtoadd. Whenyouclickanddragthemousetoaddthecontrolmakesureyouareinside therequiredparentcontrol.Alsomakesuretheeightresizingboxesarestill
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page67of110
visible. Itisagoodideaeverysooftentomovetheparentcontrolyouareaddingchildcontrols to.Thenmoveitbacktoitsdesiredpositionontheform.Whenyoudothischeckall childcontrolsmovewiththeparent.Ifanychildcontroldoesnotmovewithitsparent thenitisproperlynotplacedcorrectlyinsidetheparentcontrol.Tryaddingthethe misplacedchildcontrolagain. Thenextstepistoaddthebuttonswewantinourtoolbar.SelecttheFormtabintheGambas toolbox.Thefirstbuttonisgoingtobeournewnotebutton.NowclickontheToolButtonandadd thistotheHPanelwehavejustadded.MakesurethisbuttonisinsidetheHPanelandnotabovethe HPanel.MovethisbuttonsoitisatthefarleftoftheHPanelandis42pixelsheighand42pixels wide.NowaddtwomoreToolButtontotheHPanelthesearegoingtobeourDeletebuttonandour Refreshbutton.Moveeachbuttonsoitis42pixelsheighand42pixelswideandplacednexttothe previouslyaddedbutton.WeshouldnowhavethreebuttonsintheHPanel. ThenextbuttontoaddistheSearchbutton.WearealsogoingtoaddaTextBoxnexttothisbutton inwhichtoplacethenotessearchtext.WhentheHPanelisresizedatruntimeitwillmovecontrols ontoanadditionallineiftheydonotfitonthewidthofthecontrol.Thisisnicebehaviourand meanswecankeepallofourbuttonsvisiblenomatterhowwidetheuserresizesourformwindow. WhatwouldalsobeniceisiftheSearchbuttonandTextBoxwerealwaysnexttoeachotherwhen thisresizingtakesplaceatruntime.Wecanachievethisbyplacingthesetwocontrolsinsidea PanelwhichisinsideourHPanel.Thissearchpanelwillnotbevisibleatruntime. SoletsaddtheseSearchcontrols.SelecttheContainerstabintheGambastoolbox.Fromthis selectthePanelandaddthistotheHPanel.MovethisPanelnexttoourRefreshbuttonandsetits heightto42pixelsanditswidthtoabout224pixels.SelecttheFormtabintheGambastoolbox. AddaToolButtoninsidethissearchPanel.MoveittotheleftofthesearchPanelandresizethe buttonsoitis42pixelsheighand42pixelswide.NowaddaTextBoxtothesearchPanel.Resize thistextboxsoitisheightis21anditswidthis168.AlsomakesureitsXvalueis42anditsY valueis14.YoumayneedtousetheGambaspropertieswindowtochangesomeofthesevalues. Thefinalpartofourtoolbaristwomorebuttons.Thesewillbeforupdatinganoteandahelp dialogbutton.SelecttheFormtabintheGambastoolbox.PlacetwoToolButtonsinsidethe HPanelnexttothesearchPanel.Resizeeachbuttonsoitis42pixelsheighand42pixelswide. Thathasaddedallthecontrolsweneedforourtoolbar.Nowweshalladdthecontrolsthatformthe mainpartofourwindowanddisplayournotes.Ontheleftsideoftheformwindowwearegoingto havealistofnotes.Ontherightsidewearegoingtohavethedetailsofthecurrentlyselectednote inthelist.InorderfortheusertoresizeeachhalfofourformwindowwearegoingtouseaHSplit control.SelecttheContainerstabintheGambastoolbox.AddaHSplittotheformunderthe HPanel.WeshallbeaddingmorecontrolstotheHSplitsomakeitlargeenoughforthis.Itsexact sizedoesnotmatterasitwillberesizedatruntime.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page68of110
InGambasversion1theHSplitcontrolisnotavailablesoweshallhavetomissitout. Thismeanstheuserwillnotbeabletoresizethetwohalf'softhewindowwiththe centralbar.PlacetheColumnViewweaddnextdirectlyontheform.Alsowedirectly placesecondpanelweaddlaterdirectlyontotheform. WearegoingtouseaColumnViewtoprovidethelistofnotes.Atruntimeweshallsetthecolumn titlesandcontentforthislist.SoselecttheFormtabintheGambastoolbox.Thenadda ColumnViewtotheHSplitandmakesureitisinsidetheHSplit.PushtheColumnViewtothetop leftcorneroftheHSplitandmakeitswidthaboutaquarteroftheHSplit.Oneofthenicethings aboutusingtheHSplitcontrolisthattheresizingoftheColumnViewwillbehandledbytheHSplit controlwhenitisresized.Weshallnothavetoaddandcodeforthis. Thisnextgroupofcontrolsiswhereweshalldisplayaparticularnote.Wefirstneedtoaddanother PanelsotheHSplitgroupsthesecontrolstogetheratruntime.SelecttheContainerstabinthe Gambastoolbox.ThenaddaPaneltotheHSplit.PushthepaneltothetopoftheHSplitandnextto theColumnView.MakethesizeofthePanelcoversmostoftheareaoftheHSplitnotoccupiedby theColumnView. Thefinalsetofcontrolstoaddwillshowthedetailsforaparticularnote.Allthesecontrolsgo insidethePanelwehavejustadded.SelecttheFormtabintheGambastoolbox.Nowaddthese controlstoourPanel. Thesenextcontrolsareforthetitleofthenote.AddaLabeltothetopofthePanel.Underthe LabelplaceaTextBox. Nowaddsomecontrolswheretheusercanselectthepriorityofanote.AddanotherLabelunder theTextBoxandthenalongsidethisaddthreeRadioButtons. Thesenextcontrolsareforthecontentofthenote.AddanotherLabelunderthePriorityLabeland thenaTextAreaunderthisLabel. Wearenotdonewiththesecontrolsyet.Weneedtochangesomeoftheirproperties.Somakesure theGambaspropertieswindowisdisplayed.Clickoneachcontrolinturnandchangetherequired properties.Thisisalistofallthepropertiesweneedtochange.(Gambas1usersshouldskipthe HSplit1control.)
GettingStartedwithGambasVersion2:ATutorial [email protected] DefaultName FormNotation Property Icon Border HPanel1 ToolButton1 Name Name ToolTip Picture ToolButton2 Name ToolTip Picture ToolButton3 Name ToolTip Picture Panel1 ToolButton4 Name Name ToolTip Picture TextBox1 ToolButton5 Name Text Name ToolTip Picture ToolButton6 Name ToolTip Picture HSplit1 ColumnView1 Panel2 Label1 TextBox2 Name Name Sorted Name Name Text Name Text NewValue
Page69of110
Images/accessoriestext editor.png Resizeable HPanelTools ToolButtonNew Createanewnote Images/documentnew.png ToolButtonDelete Deletetheselectednote Images/xdirectorytrash.png ToolButtonRefresh Refreshthenoteslist Images/viewrefresh.png PanelSearch ToolButtonSearch Searchnotesfortext Images/editfind.png TextBoxSearch <blank> ToolButtonUpdate Updatecurrentnote Images/documentsave.png ToolButtonHelp Displayhelp Images/editundo.png HSplitWindow ColumnViewNotes True PanelNote LabelNoteTitle Title: TextBoxTitle <blank>
GettingStartedwithGambasVersion2:ATutorial [email protected] DefaultName Label2 RadioButton1 Property Name Text Name Group Text RadioButton2 Name Group Text RadioButton3 Name Group Text Value Label3 TextArea1 Name Text Name Text NewValue LabelNotePriority Priority: RadioButtonHigh
Page70of110
RadioButtonPriority High RadioButtonMedium RadioButtonPriority Medium RadioButtonLow RadioButtonPriority Low True LabelNoteText Note: TextAreaNote <blank>
Inordertotestourworksofarletsaddasmallamountofresizingcodecodetotheproject.Right clickontheformandaddaForm_Resizeevent.NowrightclickontheHSplitWindowobject andaddaHSplitWindow_Resizeevent.Inthesetwoeventhandlersaddthefollowingcode. Gambasversion1userswouldonlyaddtheForm_Resizeevent.Alsotheresizing codeisalittledifferentseebelow. FormNotations.class PUBLICSUBForm_Resize() HPanelTools.Width=ME.ClientWidth HSplitWindow.Move(0,HPanelTools.Height,ME.ClientWidth, ME.ClientHeightHPanelTools.Height) END PUBLICSUBHSplitWindow_Resize() TextBoxTitle.Width=PanelNote.ClientWidth
Page71of110
OurresizingcodeisslightlydifferentforGambasversion1.Thisisbecausewehadto omittheHSplitcontrol. FormNotations.class PUBLICSUBForm_Resize() HPanelTools.Width=ME.ClientWidth ColumnViewNotes.Top=HPanelTools.Height ColumnViewNotes.Height=ME.ClientHeight ColumnViewNotes.Top PanelNote.Top=ColumnViewNotes.Top PanelNote.Width=ME.ClientWidthPanelNote.Left PanelNote.Height=ColumnViewNotes.Height TextBoxTitle.Width=PanelNote.ClientWidth TextAreaNote.Resize(PanelNote.ClientWidth, PanelNote.ClientHeightTextAreaNote.Top) END
GettingStartedwithGambasVersion2:ATutorial [email protected] Youshouldalsobeabletoresizetheformwindow andthecontrolswillresizethemselves.Iftheydonot thenthemostlikelyreasonisthatsomecontrolsare notcorrectlyinsidetheircontainers. YoucancheckthisusingtheGambasHierarchytool. Indesignmodeselecttheform.Nowfromthe GambasprojectmanagerselecttheViewmenuand thentheHierarchyoptionorpressCtrl+H.Check thecontrolshierarchyonyourformmatchesthe screenshotontheright. Ifacontrolisnotattherightlevelinthehierarchy thenclickontheoffendingcontrol.PressCtrl+Xto cutthecontrol.Thenselectthecorrectparentcontrol andpressCtrl+Vtopastethecontrolintoitscorrect container.
Page72of110
Ifacontrolisattherightlevelinthe hierarchybutnotintherightorderthen Rightclickontheparentcontroland thiswillshowapopupmenu.Selectthe Arrangementoptionandthiswillshow asubmenu.InthismenuselectLeftto right.Thiswillreorderthechildcontrol intheordertheyareontheform. Wewanttoshowsomehelpinformationstotheuserwhentheyclickonthehelpbutton.Weare goingtousethesamemethodasthepreviousproject.Thismethodissuitablewhentherequired amountofhelpissmallandwillfitononepage.TheGambasmessageboxisquiteaflexibleclass andwilltakeaHTMLformattedmessage.Sowiththesinglelineofcode: Message.Info(File.Load("help.htm")) wecandisplayaHTMLfile. SoletcreatetheHTMLfileinGambas.RightclickintheGambasprojectmanager.Thisbringsup apopupmenu.FromthelistselectNew.Thisshowsasubmenuwiththeitemswecanaddtoour project.WeneedtoaddaTextfilesoselectTextfile...fromthismenu.Givethefilethename help.htmandpresstheOKbuttontosaveit.Thiswilladdthefiletothedatasectionofyour projectandwillopenthenewtextfileintheGambastexteditorwindow.EnterthefollowingHTML
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page73of110
intothetexteditorandsaveit.Notethat,asbefore,the iconinthefollowinglistingmeansthis lineisacontinuationofthepreviousline. help.htm <html> <head> <title>NotationsHelp</title> </head> <body> <h2><fontcolor='Blue'>NotationsHelp</font></h2> <hr> <p>Notationsisasimplenotetakingapplication.The followingbuttonsareinthetoolbar: </p> <p>The<b><fontcolor='Blue'>New</font></b>buttonwillcreate anewnote <br>The<b><fontcolor='Blue'>Delete</font></b>buttonwill deletethecurrentlyselectednote <br>The<b><fontcolor='Blue'>Refresh</font></b>buttonwill showallavailablenoteinthenoteslist <br>The<b><fontcolor='Blue'>Search</font></b>buttonwill findallnoteswiththesearchtextinanoteornotetitle <br>The<b><fontcolor='Blue'>Save</font></b>buttonwill updatethecurrentnote <br>The<b><fontcolor='Blue'>Help</font></b>buttonwillshow thishelp </p> <hr> <p>Notationsv.0.0.1wasdevelopedbyTimothyMarshalNichols inMay2006.Itisissuedunderthe<b>TheGNUGeneralPublic License2</b>. </p> <hr> </body> </html>
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page74of110
ThefollowingscreenshotshowswhatthisHTMLlookslikeinamessageboxwhentheapplication isrunandtheuserpressesthehelpbutton.
Thereisonefinalfileweneed.Whenwecreatethenotesdatabaseweshallalsoaddafirstnote. Thiswillbeawelcomenotegivingtheusersomehelpinformation.Asthetextforthisnoteisgoing tobemorethanafewlinewearegoingtoloadthetextfromafile.Thismethodofloadingthetext fromafilewillbeverysimilartothatusedforthehelp.Thisalsogivesusagreatdealofflexibility ifweneedtochangethisapplicationinthefuture.Wecaneasilyincorporatetextchangestothe welcomehelptext. RightclickintheGambasprojectmanagerandselectthemenutoaddanewtextfile.Thistimegive thefilethenameWelcome.txtandpresstheOKbuttontosaveit.Thiswilladdthefiletothe datasectionofyourprojectandwillopenthenewtextfileintheGambastexteditorwindow.Enter thefollowingtextandsavethefile.Asyouwillnoticeitisverysimilartothehelptext. Welcome.txt
Page75of110
4.3: CheckingouruserinterfaceforCRUD
Manyapplicationdeveloperswouldalreadyhaveleaptintothecodingstagebynow.Butitisworth standingbackandcheckingthedesignofourapplicationforfunctionality.Onecheckingmethod oftenusedwithdatabaseapplicationsisCRUD.CRUDstandsforCREATE,READ,UPDATE, DELETE.Itisachecklisttoapplytorecordsorentitiesindatabasetablesagainstoperations performedbyusers. TheCRUDchecklistisoftensetoutasamatrix.Alongonesidearelistedthetablesorentitiesin thedatabase.Alongtheothersidearelistedtheuserrolesforthedatabase.Insideeachcellyoulist theCRUDactionsthateachuserrolecanperformoneachtableorentity.Thefollowingdiagram demonstratesanimaginaryCRUDmatrix.
GettingStartedwithGambasVersion2:ATutorial [email protected] User User1 User2 Administrator R,U C,R,U,D C,R,U,D Table1 R,U C,R,U C,R,U Table2 R,U C,R,U,D
Page76of110
Table3
FromthismatrixwecanseethatUser1canonlyreadandupdatetables1and2.User2has differentlevelsofaccesstoeachtable.TheAdministratorhasfullaccesstoalltablesapartfrom table2.Alsofortable2wehavenowayofdeletingarecord.Theseobservationsmightbecorrect forourimaginaryapplication.ButwithaCRUDmatrixlikethisweneedtochecktherequirements forourapplicationagaintofindout. CRUDisachecklist.Itisachecklistthathelpsyouspotanymissingoperationsinyour application.Thisdoesnotmeanthateveryusershouldbeabletoperformalltheseoperations.In manycasesthereareoperationsyouwouldnotwantperformedbyallusers.Forexampleina bankingdatabaseyouwouldnotwantalluserstobeabletodeletedetailsoffinicaltransactions. RatherwithCRUDyouarecheckingthefunctionalityofyourdatabaseapplication.Youthenhave tothinkaboutwhysomeusershouldhaveornothavesomeparticularfunctionality.Itisthe thinkingprocessthatisimportant. OftenanadditionaloperationisaddedtotheCRUDchecklist.ThisisLforLIST.Canauserlist databaserecords?IwouldalsoaddSforSEARCH.Canausersearchdatabaserecordsusingsome searchcriteria? TherearelotsofdescriptionsofCRUDontheinternet.SearchforCRUD+databases. Youcouldtry:http://en.wikipedia.org/wiki/CRUD_(acronym) IfindCRUDisausefulchecklistevenwhenyouarenotdealingwithadatabase.Anyplaceina applicationwhereyouareaddingorremovingdatafromcontrolsatruntimeisworthputting throughtheCRUDchecklist.Thiscouldbeagrid,atextarea,acomboboxormanyothercontrols. CRUDismostoftenpresentedasamatrix.InourNotationsapplicationweonlyhaveoneuserand onetable.Sothematrixlooksabitsilly.InsteadletsusetheCRUDLSchecklisttothinkaboutthe actionsperformedbyouruseronthedatabaserecords.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page77of110
thechangesawarningmessageisdisplayed.Youcanthenchoosetocontinueandlosethe changesorcanceltheaction.
4.4: Addingthecode
Thisisthesectionwherewegetourapplicationtodoit'srealwork.Thecodeforthisapplicationsis splitintotwosections.Thefirstistheformwindowthathandlestheuserinterface.Wehavejust createdthecontrolsweneedforthisandtheresizingcode.Laterweshalladdcodetohandle operationscreatedwhentheusereditsnotes.Thesecondcodesectionisgoingtobetheinterfaceto thedatabase.Creatingthismoduleiswhatwearegoingtodonext. OurcodetocommunicatewiththedatabaseisgoingtobeplacedinaGambasmodule.Havingthis databasecodeinonemodulemakesiteasiertoseparatethedatabasespecificcodefromtheuser interfacecode.RightclickintheGambasprojectmanagerandselectNewfromthepopupmenu. ThenselectModule...fromthesubmenu.InthedialogcallthemoduleModuleDatabaseand leavethecheckboxesinthedefaultstateofunchecked.ClickontheOKbuttontocreatethe module. Wefirstneedtwovariablesthatareusedbyanumberofprocedures.Thefirstisadatabase connectionobject.ThisisonlyusedinsidethisproceduresoitismadePRIVATE.Thesecond variableisaResultobject.ThisholdsourNotesdataaswellasbeingusedtoupdateanddelete notes.AsitisalsousedbytheFormNotationsclassitismadePUBLIC. ModuleDatabase.module PRIVATEdatabaseConnectionASNEWConnection PUBLICNotesASResult ContinuedBelow
Page78of110
Firstwesetuptheinformationfortheconnectiontothedatabaseserver.Weusetheinformation passedtotheprocedurefordatabasetype,hostname,usernameandpassword.Noticewesetthe databasenamepropertytoablankstring.Thisisbecausewewanttoopenaconnectiontotheserver firstandcheckthatthedatabaseexists.Havingsetuptheconnectionwetrytoopenit.Thisisone ofthekeypointstheprocedurecouldproduceanderror.Wethentestifthedatabasenamewe requirealreadyexists.Ifitdoesnotexistthenweaddthisdatabasetotheserver. ForaSQLitedatabaseIfoundyouneededtogivethesystemashortdelaytowritethenewly createddatabasetodiskbeforeattemptingtoopenit.Thisisnotrequiredforclient/servertypesof databaseslikeMySQLorPostgreSQL.Asitdoesnotdoanyharmweincludeitforalltypesof databases. Ifwereachthispointthenweknowtheseexistsadatabasewiththerequiredname.Sowesetthe databasenameontheconnection.(Wealsosetthehostnameagain,thisisnotstrictlynecessary,but Ithinkitmakesthecodeabitmorereadable.)Thenweopenthedatabaseconnection.Thisisthe secondkeypointwherewecouldproduceanderror. Wethentestifthenotestableexistsinthedatabase.Ifthetabledoesnotexistthenweneedtoadd it.Wedothisbycreatinganewtableobjectusingourdatabaseconnection.Wethenaddthe requiredfieldstothistableandstatewhichfieldistheprimarykeyforthetable.Inordertowrite thenewtableintothedatabasewecalltheupdatemethodonthetableobject. ThefollowingtableshowssomeinformationaboutthefieldsforourNotestable.Theinformationin thefirstthreecolumnsisrequiredbyGambas.ThefinalcolumnsshowwhattheGambasdatatypes maptoforsomedatabasetypes. FieldName CreateDate LastModified GambasType gb.Date gb.Date Comment PrimaryKey SQLite2Type DATETIME DATETIME MySQLType datetime datetime
GettingStartedwithGambasVersion2:ATutorial [email protected] FieldName Title Note Priority GambasType gb.String gb.String gb.Integer Comment Length0fora unlimitedstring Length0fora unlimitedstring SQLite2Type TEXT TEXT INT4
Page79of110
Wearegoingtowriteaproceduretoaddrecordstoourdatabase.Sowemayaswellusethisto createafirstrecordinourdatabase.Thecontentofthenoteistakenfromthewelcometextfilewe createdabove.Asthisisarelativefilepathitwouldbeincludedintheapplicationwhenitis compiled. Gambasversion1doesnotunderstandtheDconvfunction.Solinesthatincludeit: ...Dconv(Error.Text)... shouldjustomitthefunctioncall: ...Error.Text... ThisalsoappliestomostoftheproceduresinModuleDatabasethatfollow. ModuleDatabase.module PUBLICSUBOpenDatabase(DBTypeASString,DBHostASString,DBName ASString,UserNameASString,UserPasswordASString) DIMnotesTableASTable DIMerrorMessageHeaderASString 'Openaconnection(tothedatabaseserveronly) databaseConnection.Type=Lower(DBType) databaseConnection.Host=DBHost databaseConnection.Name="" databaseConnection.Login=UserName databaseConnection.Password=UserPassword databaseConnection.Port="" 'Opentheconnection TRYdatabaseConnection.Open() IFERRORTHEN errorMessageHeader="Couldnotopendatabaseconnection"& DBHost Error.Raise(Error.Text)
Page80of110
'Checkiftheserverconnectionhasadatabasewiththe 'requireddatabasename. IFNOTdatabaseConnection.Databases.Exist(DBName)THEN PRINT"Databasenotfound.Creatingnewdatabase" 'Createnewdatabase databaseConnection.Databases.Add(DBName) 'IfoundIneededthiswithaSQLitedatabase '(butnotwithaMySQLdatabase) WAIT0.5 ENDIF 'Closetheserverconnection databaseConnection.Close() 'Openaconnectiontothedatabase databaseConnection.Host=DBHost databaseConnection.Name=DBName TRYdatabaseConnection.Open() IFERRORTHEN errorMessageHeader="Couldnotopendatabase"&DBName& "on"&DBHost Error.Raise(Error.Text) ENDIF 'CheckifthedatabasehasaNotestable IFNOTdatabaseConnection.Tables.Exist("Notes")THEN PRINT"Databasetablesnotfound.Creatingnewnotestable" 'AddaNotestabletothedatabase notesTable=databaseConnection.Tables.Add("Notes") notesTable.Fields.Add("CreateDate",gb.Date) notesTable.Fields.Add("LastModified",gb.Date) notesTable.Fields.Add("Title",gb.String,0) notesTable.Fields.Add("Note",gb.String,0) notesTable.Fields.Add("Priority",gb.Integer,,0) notesTable.PrimaryKey=["CreateDate"] notesTable.Update() 'Addadefaultwelcomerecord AddData("Welcome",File.Load("Welcome.txt"),0)
Page81of110
errorMessageHeader="Databaseconnectionerror:"&DBName& "on"&DBHost ENDIF Error.Raise("<b>"&errorMessageHeader&"</b><hr>Error:<br>"& DConv(Error.Text)) END ContinuedBelow Asyoucanseemostoftheaboveproceduredealswithcheckingwehaveavaliddatabaseand tables.Thecodetocreatetheconnectionisrelativelysmall.Ifyouknewyouhadavaliddatabase thenyoucouldcutthisproceduredowntothefollowingcode: databaseConnection.Type=Lower(DBType) databaseConnection.Host=DBHost databaseConnection.Name=DBName databaseConnection.Login=UserName databaseConnection.Password=UserPassword databaseConnection.Port="" databaseConnection.Open() Alsoyouwouldneedsomeerrorcheckingwhenyouopenedthedatabaseconnection. Whencommunicatingwithadatabaseitisimportanttohandleanypossibleerrors.Butwhereisthe bestplaceinyourapplicationforsuchcode?Wewantthismoduletobegeneralandflexible.So herewejustformattheerrormessage.TheGambasmessageboxcanuseHTMLformattingsowe addsomeinformationandHTMLformattingandpassontheerrorusingtheError.Raise method.ThismeansthatinthecodeintheFormclassweneedtocatchtheseerrorsanddisplaythe errormessage.Therearethreepossibleerrorswecouldhaveinthisprocedure:
Thismodulewillgiveaslightlydifferenterrormessageineachcase.Intheproceduresbelowwe adoptasimilarapproachtohandlingerrors.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page82of110
Thefollowingprocedurewillclosetheconnectiontothedatabase.Thisprocedureiscalledwhenwe closeourapplication.WeplaceaTRYbeforetheclosemethodaswedonotwantanyerrors displayedtotheuserifthedatabaseisalreadyclosed.Ifthereisaerrorclosingthedatabasewe PRINTasmessage.Thisissoyoucanseeerrorswhendevelopingtheapplication.Howeverthe usershouldnotseethismessage. ModuleDatabase.moduleContinued PUBLICSUBCloseDatabase() TRYdatabaseConnection.Close() IFERRORTHENPRINT"Errorclosingdatabase" END ContinuedBelow ThisnextfunctionaddsarecordtoourNotesdatabasetable.Thevaluespassedtothefunctionare theNoteTitle,theNoteitselfanditsPriority.Forthecreationandlastmodifiedtimeweusethe currenttime. UsingtheCreatemethodontheconnectionobjectwecreateaResultobjectthatisdesignedto addrecordstoadatabasetable.WepassthenameofthetabletotheCreatemethod.Thisreturns aResultobjectthathasoneemptyrecordinit.ThefieldsinthisResultobjectarethefieldsinour table.Wethenfillthefieldswiththerequiredvaluesforthenewrecord.ThenwecalltheUpdate methodwhichwilladdournewrecordtothedatabasetable. Ifthereareanyerrorsincreatingthedatabaserecordtheweformattheerrormessageandpassitup tothecallingprocedure.Thefunctionreturnsathedateandtimethatthenotewascreated.This dateandtimeisthevalueofthekeyfieldofthenewlycreatednote.Itallowsthecallingprocedure tofindthenewnoteusingthiskey. ModuleDatabase.moduleContinued 'Createarecord PUBLICFUNCTIONAddData(TitleASString,NoteASString,Priority ASInteger)ASString DIMnewNoteASResult DIMcreateTimeASDate createTime=Now
GettingStartedwithGambasVersion2:ATutorial [email protected] newNote=databaseConnection.Create("Notes") newNote["CreateDate"]=createTime newNote["LastModified"]=createTime newNote["Title"]=Conv(Title,Desktop.Charset, databaseConnection.Charset) newNote["Note"]=Conv(Note,Desktop.Charset, databaseConnection.Charset) newNote["Priority"]=Priority newNote.Update() RETURNFormatDate(createTime) CATCH
Page83of110
Error.Raise("<b>Adddatabaserecorderror</b><hr>Error:<br>"& DConv(Error.Text)) END ContinuedBelow AResultobjectisastructurethatcanstoretheresultofadatabasequery.Therearethreekindsof ResultobjectsCreate,ReadandWrite.TherearefourmethodwecanusedtocreateaResult object.ThefunctionalityofthereturnedResultobjectdependsonthemethodusedtocreateit. Thesemethodsaresummarisedinthefollowingtable.WehavealreadyusedtheCreatemethodto addadatabaserecordseeabove.Butwealsopresentitheretobecomplete. Method ResultType Comment CreatesaResultobjectwithonerecordthat canbeusedforaddingrecordstoatable. Thismethodreturnsdatafromasingletable. Tableisthe(caseinsensitive)nameofthe databasetable.RequestisaoptionalSQL typeWHEREclauseusedtofilterthetable rows.Argumentsisaoptionallistof parameterstobesubstitutedintheRequest clause.ThereturnedResultobjectcannotbe updated.
Page84of110
Thismethodreturnsdatafromasingletable. Tableisthe(caseinsensitive)nameofthe databasetable.RequestisaoptionalSQL typeWHEREclauseusedtofilterthetable rows.Argumentsisaoptionallistof parameterstobesubstitutedintheRequest clause.ThereturnedResultobjectis updateable. InthereturnedResultobjectrecordscanbe updatedbymovingtoarowchangingthe fieldvaluesandcallingtheUpdatemethod. Recordscanbedeletedbymovingtoarow andcallingtheDeletemethod.Therecord isthendeletedfromtheunderlyingdatabase table. YoucannotaddrecordtothiskindofResult object.SeetheCreatemethodabove. HereRequestisanySQLquery. Argumentsisaoptionallistofparameters thatareusedinthequery.ThereturnedResult objectcannotbeupdated. ThismethodcanbeussendanySQLqueryto thedatabase.Seeabove
ReadOnly
WewanttobeabletoeditdatabaserecordssoweusetheEditmethodtoreturnaResultobject. Usingthenameofournotestableasaparametertoselectallthedatabasenotesrecords.Ifthereare anyerrorsinselectingthedatabaserecordsthenweformattheerrormessageandpassituptothe callingprocedure. ModuleDatabase.moduleContinued 'Readatable PUBLICSUBSelectData() Notes=databaseConnection.Edit("Notes") CATCH Error.Raise("<b>Selectdatabaserecordserror</b><hr>Error:<br>" &DConv(Error.Text)) END ContinuedBelow
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page85of110
WeopenedtheNotesResultobjectwiththeEditmethodontheConnectionobject.Wepassed theEditmethodthenameourNotesdatabasetable.ThismeanswehaveaResultobjectthatcan beedited.Herewewanttoupdatearecord.Thefirstvaluespassedtothefunctionistheindexinthe Resultobjectoftherecordwewanttoupdate.Thefirstthingthisproceduredoesistomovetothis record. TheothervaluespassedtothefunctionarethenewvaluesfortheNoteTitle,theNoteitselfandits Priority.ThesevaluesarecopiedtotheResultobject.WealsosettheLastModifiedfieldtothe currentdateandtime.WedonotchangetheCreateDateasthisisthekeyfield.Whenwehave settherequiredvaluesforthetablesfieldstheUpdatemethodisthencalledtoupdatethe databasetable.Ifthereareanyerrorsinupdatingthedatabaserecordthenweformattheerror messageandpassituptothecallingprocedure. ModuleDatabase.moduleContinued 'Updatearecord PUBLICSUBUpdateData(RowASInteger,TitleASString,NoteAS String,PriorityASInteger) Notes.MoveTo(Row) Notes["LastModified"]=Now Notes["Title"]=Conv(Title,Desktop.Charset, databaseConnection.Charset) Notes["Note"]=Conv(Note,Desktop.Charset, databaseConnection.Charset) Notes["Priority"]=Priority Notes.Update() CATCH Error.Raise("<b>Updatedatabaserecorderror</b><hr>Error:<br>" &Dconv(Error.Text)) END ContinuedBelow InordertodeleteanotesrecordallweneedistheindextothenotesrecordrowintheResultobject. Thisispassedasaparametertothedeletefunction.Wemakesureweareonthisrowandcallthe ResultobjectsDeletemethod.Thisdeletestherecordfromthedatabasetable.Ifthereareany errorsindeletingthedatabaserecordthenweformattheerrormessageandpassituptothecalling
Page86of110
Error.Raise("<b>Deletedatabaserecorderror</b><hr>Error:<br>" &DConv(Error.Text)) END ContinuedBelow Inthedatabasemoduleweprovideamethodthatconvertsadateobjecttoaformatteddatestring. Wedothissowecanhaveacommonformatforthedate/timeinourapplication.Wealwaysusethis methodcalltoformatthedate.Thenifweeverneedtochangethedateformatweonlyhavetodo thisinoneplace. ModuleDatabase.moduleContinued PUBLICFUNCTIONFormatDate(dASDate)ASString RETURNFormat(d,"ddmmmyyyyhh:nn:ss") END
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page87of110
Wethencallsomefunctionstotodisplayinformationfromthedatabase.Firstwecallthefunction wecreatedabovetocreateadatabaseconnection.Wethencallfunctionstorefreshthenoteslistin theColumnViewandtodisplaythecurrentlyselectednote.Ourdatabaseprocedurescanthrow errorssoweneedtocatchtheseanddisplaytheerrormessage. Whencallingaproceduresorfunctioninamodulewehavetousetheformat: ModuleName.ProcedureName(...) or object=ModuleName.FunctionName(...) withoutprefixingtheproceduresorfunctionwiththemodulenameiswillnotbevisiblewithinthe callingobject.AlsoonlyPUBLICproceduresorfunctioninamodulecanbeaccessed. SomeolderversionsofGambasuseSystem.HometoreturntheusersHome directory.Sothelinethatcallsouropendatabasemethodshouldbechangedtothe following: ModuleDatabase.OpenDatabase("sqlite",System.Home, Application.Name,"","") FormNotations.class PRIVATEchangesMadeASBoolean PUBLICSUBForm_Open() ME.Title=Application.Name&"Version:"& Application.Version 'ColumnViewproperties ColumnViewNotes.Columns.Count=3 ColumnViewNotes.Columns[0].Text="P" ColumnViewNotes.Columns[0].Width=20 ColumnViewNotes.Columns[1].Text="Title" ColumnViewNotes.Columns[1].Width=150 ColumnViewNotes.Columns[2].Text="LastModified" ColumnViewNotes.Columns[2].Width=150 'UsethisconnectionforaSQLitedatabase ModuleDatabase.OpenDatabase("sqlite",User.Home, Application.Name,"","")
GettingStartedwithGambasVersion2:ATutorial [email protected] RefreshNotes() IFColumnViewNotes.Current<>NULLTHEN DisplayNote(ColumnViewNotes.Current.Key) ENDIF CATCH Message.Warning(ERROR.Text) END ContinuedBelow
Page88of110
Whentheformisabouttocloseweneedtocheckiftheuserhasmadeanychangestothecurrent notethathavenotbeensavedyet.Aswearegoingtohavetoperformthistestinanumberofplaces wehavewrittenasmallfunctionforthis.Itwillshowamessageboxwarningofanyunsaved changes.ThisfunctionreturnsTRUEiftheuserwantstocanceltheselectedaction.Tocancelthe closeeventontheformweusetheSTOPEVENTstatement.STOPEVENTonlycancelstheevent andpreventsanyothereventshandlersfortheeventbeingcalled.Itdoesnotexitthecurrentevent handler.SoweneedtheRETURNstatementtodothis. IftherewerenochangestothedatabaseortheuserclickedtheContinuebuttonwhenprompted aboutunsavedchangesthenweclosethedatabaseconnectionandquittheapplication. FormNotations.classContinued PUBLICSUBForm_Close() IFTestChangesMade()THEN STOPEVENT RETURN ENDIF ModuleDatabase.CloseDatabase() END ContinuedBelow Thisisourformresizingcodeagain.Wehaverepeateditheretoshowitspositioninthecode listing.(IfyouareusingGambasversion1yourcodemaylookdifferent.Seeabove.) FormNotations.classContinued
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page89of110
PUBLICSUBForm_Resize() HPanelTools.Width=ME.ClientWidth HSplitWindow.Move(0,HPanelTools.Height,ME.ClientWidth, ME.ClientHeightHPanelTools.Height) END PUBLICSUBHSplitWindow_Resize() TextBoxTitle.Width=PanelNote.ClientWidth TextAreaNote.Resize(PanelNote.ClientWidth, PanelNote.ClientHeightTextAreaNote.Top) END ContinuedBelow Thenextgroupofprocedureshandleeventswhentheuserclicksonabuttoninourtoolbar.This procedurehandlestheclickeventwhentheuserselectsthenewnotebutton. Firstwecheckwhichofthenotepriorityradiobuttonsisselectedandsetaintegerbaseduponthe selection.Thepriorityvalue0isforlowpriority,thevalue1isformediumpriorityandthevalue2 isforhighpriority.Wethensendthisvaluealongwiththetitletextandnotetexttotheaddnote functionwecreatedearlier. Addingthenotetothedatabaseisveryeasy.Themainproblemisfindingitagain!Whentheuser addsanewnotewewantthenewnotetobehighlightedintheColumnViewandtobethecurrently selectednote.OurAddDatafunctionreturnsthekeyofthenewlycreatednote.Wethencallour refreshnotemethodtoupdatetheColumnView.Thisshouldincludethenewnote.Wethensearch thetextintheColumnViewLastModifiedcolumnforthekeyandmakethisthecurrentnote. FormNotations.classContinued PUBLICSUBToolButtonNew_Click() DIMkeyASString DIMpriorityASInteger IFRadioButtonHigh.ValueTHEN priority=2 ELSEIFRadioButtonMedium.ValueTHEN
GettingStartedwithGambasVersion2:ATutorial [email protected] priority=1 ELSE priority=0 ENDIF key=ModuleDatabase.AddData(TextBoxTitle.Text, TextAreaNote.Text,priority) RefreshNotes() 'Findthenotewejustcreated IFColumnViewNotes.MoveFirst()THENRETURN REPEAT IFkey=ColumnViewNotes.Item[2]THEN
Page90of110
ColumnViewNotes[ColumnViewNotes.Item.Key].Selected=TRUE BREAK ENDIF UNTILColumnViewNotes.MoveNext() 'Makethenotewecreatedthecurrentnote IFColumnViewNotes.Current<>NULLTHEN DisplayNote(ColumnViewNotes.Current.Key) ENDIF CATCH Message.Warning(ERROR.Text) END ContinuedBelow ThisprocedureistohandlewhentheuserclicksontheDeleteNotetoolbarbutton.Wefirstcheck thatanotehasbeenselectedintheColumnViewtodelete.Ifanoteisselectedwedisplayawarning messagethatallowstheusertocanceltheaction.IftheyselectYestothispromptwecallthedelete methodwecreatedearlier.WethencallourrefreshnotemethodtoupdatetheColumnViewand thencallourdisplaymethodtoshowthedefaultnote. FormNotations.classContinued PUBLICSUBToolButtonDelete_Click() IFColumnViewNotes.Current<>NULLTHEN IFMessage.Warning("Areyousureyouwanttodeletethe
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page91of110
note?\n\n"&ModuleDatabase.Notes["Title"],"Yes","Cancel")=1 THEN ModuleDatabase.DeleteData(ColumnViewNotes.Current.Key) RefreshNotes() IFColumnViewNotes.Current<>NULLTHEN DisplayNote(ColumnViewNotes.Current.Key) ENDIF ENDIF ELSE Message.Info("Nonotehasbeenselectedtodelete") ENDIF CATCH Message.Warning(ERROR.Text) END ContinuedBelow WenowhandletheeventwhentheRefreshtoolbarbuttonisclicked.Wewantarefreshbutton because,asweshallseeinthenextprocedure,theusercanselectjustthenotesthatcontaina specificsearchtext.ThiswillrefreshtheColumnViewanddisplayallnotes. Beforewerefreshthelistwecheckthattherearenounsavedchangedtothecurrentnoteusingthe functionwearegoingtocreatebelow.Wethenusecodesimilartothatintheformopeneventto displaytheColumnViewlistanddisplaythedefaultnote. FormNotations.classContinued PUBLICSUBToolButtonRefresh_Click() IFTestChangesMade()THENRETURN RefreshNotes() IFColumnViewNotes.Current<>NULLTHEN DisplayNote(ColumnViewNotes.Current.Key) ENDIF CATCH Message.Warning(ERROR.Text) END
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page92of110
ContinuedBelow ThisprocedurehandlestheeventoftheuserclickingontheSearchbutton.Theuserwillhave enteredsometextintheTextBoxSearchnexttothesearchbutton.Theobjectiveofthis procedureisthentosearchthroughallnotetitlesandthenotecontentsforthesearchtext.Andto placeallthenotesthatcontainthesearchtextintheColumnView. Westartthisprocedurebycallingourfunctiontotestifthecurrentnotehaschangesthathavenot beensaved.Wearegoingtocreatethisfunctionbelow.Nextwetestiftheuserhasenteredsome texttosearchforintheTextBoxSearchcontrol.Ifthereisnotexttherewedisplayamessageto theuser. ToperformthesearchwecalltheRefreshNotesproceduresendingitthesearchtextasaparameter. Wethentestifthisprocedurefoundanynoteswiththerequiredsearchtext.Ifsomenoteshavebeen foundthentheColumnView'scurrentvaluewillbeset.Ifitissetthenwecallourprocedureto displaythecurrentnote.Ifnonoteshavebeenfoundthenweclearthecontrolsontherighthalfof theformwindowthatdisplaythecurrentnoteandalsodisplayamessagetotheuserinformingthem thatthesearchtexthasnotbeenfound. FormNotations.classContinued PUBLICSUBToolButtonSearch_Click() IFTestChangesMade()THENRETURN IFTextBoxSearch.TextTHEN RefreshNotes(TextBoxSearch.Text) IFColumnViewNotes.Current<>NULLTHEN DisplayNote(ColumnViewNotes.Current.Key) ELSE TextBoxTitle.Text="" RadioButtonMedium.Value=FALSE RadioButtonHigh.Value=FALSE RadioButtonLow.Value=FALSE TextAreaNote.Text="" changesMade=FALSE Message.Info("Thesearchtext\""&TextBoxSearch.Text& "\"hasnotbeenfoundinanynote") ENDIF
Page93of110
Message.Info("Thereisnosearchtexttofindinnotes") ENDIF CATCH Message.Warning(ERROR.Text) END ContinuedBelow Thisprocedurehandlestheeventwhenthebuttontoupdatethecurrentlyselectednoteisclicked. Wefirsttestifthereisacurrentlyselectednoteanddisplayamessageifnonoteisselected. Nextwefindthevaluetosendtothedatabaseforthepriorityfromthepriorityradiobuttons.We thensavetheindexkeytothecurrentnotesowecanfinditagainafterwerefreshthenoteslist.We thencallourdatabaseproceduretoupdateanote.Thisprocedurerequirestheindexkeyforthenote toupdatealongwiththeinformationforthenote. WecallourproceduretorefreshthenoteslistintheColumnViewwiththenewdata.Thisprocedure willsetthecurrentnotetoadefaultnote.Buthereisyourbemoreusefultotheusertodisplaythe notetheyhavejustupdated.Soweusetheindexkeywehavesavedtosetthecurrentiteminthe ColumnView.Wethencallthedisplaynoteprocedurepassingittheindexkeytodisplaythe updatednotecontent. FormNotations.classContinued PUBLICSUBToolButtonUpdate_Click() DIMpriorityASInteger DIMnoteNumberASInteger IFColumnViewNotes.Current=NULLTHEN Message.Info("Nonotehasbeenselectedtoupdate") RETURN ENDIF 'Getvaluefromradiobuttonsforpriority IFRadioButtonHigh.ValueTHEN priority=2 ELSEIFRadioButtonMedium.ValueTHEN priority=1
Page94of110
ModuleDatabase.UpdateData(noteNumber,TextBoxTitle.Text, TextAreaNote.Text,priority) 'Refreshthenoteslist RefreshNotes() 'Displaythisnote ColumnViewNotes[noteNumber].Selected=TRUE DisplayNote(noteNumber) CATCH Message.Warning(ERROR.Text) END ContinuedBelow Thehelpbuttonisverysimple.WeloadtheHTMLhelpfilewecreatedearlierintoamessagebox todisplaythehelp. FormNotations.classContinued PUBLICSUBToolButtonHelp_Click() Message.Info(File.Load("help.htm")) END ContinuedBelow ThiseventhandlerisforwhentheuserclicksonarowintheColumnView.Wethenwantthenote theuserclickedontobedisplayed.Weknowtheusermusthaveclickedonavalidnoteasclick eventisonlyfirediftheColumnViewhassomeitemstoselect.Wecheckiftherehavebeenchanges madetothepreviousnotethathavenotbeensaved.Wearegoingtocreatethisfunctionbelow.If theuserselecttocanceltheactionwehighlightthepreviousnoteintheColumnView.Ifthereare nounsavedchangesortheuserhasselectedtocontinuethenwecallourdisplaynotesmethodto showtheselectednote.ThekeyoftheColumnViewviewitemwehavedesignedtomatchtheindex forthenote.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page95of110
FormNotations.classContinued PUBLICSUBColumnViewNotes_Click() 'Checkifchangeshavebeenmadetothepreviousnote IFTestChangesMade()THEN 'Userselectedtocancelchangeofnote 'Displaythepreviousnote ColumnViewNotes[ModuleDatabase.Notes.Index].Selected=TRUE ELSE 'Displaythenewnote DisplayNote(ColumnViewNotes.Current.Key) ENDIF END ContinuedBelow Thisgroupofeventhandlersareusedtodetectiftheuserhasmadeanychangestothecurrentnote. IfthetextinaTextBoxorTextAreaismodifiedtheChangeeventiscalled.AlsotheClickeventon theRadioButtonisusedtodetectifaRadioButtonhasbeenselected.Notethattheclickeventon theRadioButtonisalsocallediftheuserchangedthecurrentRadioButtonusingthekeyboard. FormNotations.classContinued PUBLICSUBTextBoxTitle_Change() changesMade=TRUE END PUBLICSUBTextAreaNote_Change() changesMade=TRUE END PUBLICSUBRadioButtonPriority_Click() changesMade=TRUE END
Page96of110
WenowcometotheprocedureswehaveintheFormNotationsclass.Wehavecalledallofthese proceduresinthecodeabove.Thisfirstprocedurewehavecalledmanytimesabove.Itisused refreshtheColumnViewwiththecurrentnotesfromthedatabase. MyfirstintentionwastowriteseparateproceduresforrefreshingtheColumnViewnoteslistandfor searchingnotesforsomesearchtext.Insomewaysthisisthemoreobviousdesignchoice.Butifwe hadusedtwoproceduresmostofthecodeineachprocedurewouldhavebeenthesame.Soitseems bettertouseaOPTIONALparametertotheRefreshNotesprocedureasthesearchtext.Ifthis parameterissetthenfilteroutthenotesthatdonotcontainthistext. Wecallourdatabaseproceduretoselectallthenotesinthedatabase.Wewantthedefaultnotetobe thefirstnotewefindwiththehighestpriority.WeusethefirstItemvariabletokeeptrackofthe priorityofthenotewehaveselected.SoweneedtoinitialisefirstItemtoavaluelowerthenany possiblepriorityvalueinthedatabase.WethenconverttheSearchTextvariabletolowercaseso wecanperformacaseinsensitivesearchforthesearchtext.NextwecleartheColumnViewofany itemsthatitcurrentlymaycontain. Nowwecometothemainloopofthisprocedure.Hereweloopthroughalltherecordthathave beenreturnedfromthedatabase.Wedecideifwewanttotestforthesearchtextbycheckingifthe variableSearchTexthasavalue.IfSearchTexthasavaluethenwecheckifthesearchtext canbefoundinthenotesTitlefieldorinthenotesNotefield.Ifitcannotbefoundweusethe CONTINUEstatementtoskipprocessingthecurrentrecord. WeaddeachitemtotheColumnViewandselecttheimagefortheitembaseduponthepriority field.ThisplacestheimageinthefirstcolumnoftheColumnView.WeusethetextvaluesH, Mand(aslow)forthepriorityvaluessotheitemscanbesortedbypriority.(IfweusedLfor thelowpriorityitemsthelistwouldhavethelowpriorityitemsbetweenthehighandmedium priorityitems.Thiswouldnotlookverygood.) OneimportantpointisusingtheindexfromtheResultobjectasthekeytotheColumnViewitems. ThisenablesustoeasilyfindarecordintheResultobjectwhenweneedtoupdateordeleteanotes recordinthedatabase. WetheaddthetitleofthenotetothesecondcolumnoftheColumnView.Thenweaddthenotes lastmodifieddateandtimetothethirdcolumn.Hereweformatthedataandtimeusingthefunction inourdatabasemodule.Thefinalcheckintheloopistomakethedefaultselecteditemthefirst itemwefindwiththehighestpriority.
GettingStartedwithGambasVersion2:ATutorial [email protected] FormNotations.classContinued PRIVATESUBRefreshNotes(OPTIONALSearchTextASString) DIMfirstItemASInteger ModuleDatabase.SelectData() firstItem=1 SearchText=Lower(SearchText) ColumnViewNotes.Clear FOREACHModuleDatabase.Notes IFSearchTextTHEN
Page97of110
IFNOT((InStr(Lower(ModuleDatabase.Notes["Title"]), SearchText)>0)OR (InStr(Lower(ModuleDatabase.Notes["Note"]),SearchText)> 0))THEN 'Ifthesearchtextisnotfoundthengoontothenext record CONTINUE ENDIF ENDIF IFCInt(ModuleDatabase.Notes["Priority"])=1THEN ColumnViewNotes.Add(ModuleDatabase.Notes.Index,"M", Picture["Images/dialoginformation.png"]) ELSEIFCInt(ModuleDatabase.Notes["Priority"])>1THEN ColumnViewNotes.Add(ModuleDatabase.Notes.Index,"H", Picture["Images/mediarecord.png"]) ELSE ColumnViewNotes.Add(ModuleDatabase.Notes.Index,"") ENDIF ColumnViewNotes[ModuleDatabase.Notes.Index][1]= ModuleDatabase.Notes["Title"] ColumnViewNotes[ModuleDatabase.Notes.Index][2]= ModuleDatabase.FormatDate(ModuleDatabase.Notes["LastModified"]) 'Selectfirstitemwithhighestpriority IFCInt(ModuleDatabase.Notes["Priority"])>firstItemTHEN ColumnViewNotes[ModuleDatabase.Notes.Index].Selected=TRUE firstItem=CInt(ModuleDatabase.Notes["Priority"])
Page98of110
Thisprocedurewilldisplayaselectednoteinthedetailssectionoftheformwindowontheright sideoftheform.TheprocedureexpectstheindextoarowintheNotesResultobjecttoselectwhat's displayed.ThiswhyweusedthisindexasthekeyforitemsintheColumnView.Wesimplyneedto movetothedesiredrowtogettherecordweneed. Wecopythenotetitletothetitletextbox.Thenwesettheselectedradiobuttonforthenotepriority basedupontheintegerinthePriorityfield.Thenotecontentiscopiedtothenotetextarea.We placethecursorinthetextareaattheendofthetextandsetthefocustothetextarea.Thisseemsto bethemostreasonablepositionfortheusertostartfromaftertheyhavejustselectedanote. FinallywesetthechangesMadevariabletoFALSE.Tostatetheobvious:thismustbedoneafter wehavecompletedallthechangesweneedtomaketothenotescontrols.Thisisbecausethese controlsfirechangesmadeeventsthatsetthisvariabletoTRUE. FormNotations.classContinued PRIVATESUBDisplayNote(RowASInteger) ModuleDatabase.Notes.MoveTo(Row) TextBoxTitle.Text=ModuleDatabase.Notes["Title"] IFCInt(ModuleDatabase.Notes["Priority"])=1THEN RadioButtonMedium.Value=TRUE ELSEIFCInt(ModuleDatabase.Notes["Priority"])>1THEN RadioButtonHigh.Value=TRUE ELSE RadioButtonLow.Value=TRUE ENDIF TextAreaNote.Text=ModuleDatabase.Notes["Note"] TextAreaNote.Pos=String.Index(TextAreaNote.Text, Len(TextAreaNote.Text)) TextAreaNote.SetFocus() changesMade=FALSE
Page99of110
Ourfinalfunctiontestsiftheuserhasmadeanychangestothecurrentnote.Whendevelopingthe applicationIfoundIwaswritingthiskindoflogicinanumberofplaces.Soitlookedlikeagood ideatowriteafunctionforthis.Thisalsoensuresourapplicationhasacommonformatforhandling changesthathavenotbeensaved. WecheckforchangestothecurrentnotebylookingatthevalueofthechangesMadevariable.If therearechangesthathavenotbeensavedthenwedisplayamessagebox.Iftheuserhasclickedthe ContinuebuttonthenwereturnFALSEotherwisewereturnTRUE.Wehaveputthefunctionreturn logicthiswayroundsoourmessageboxfunctionbehavesthesamewayasthemethodsinthe Dialogclassforgettingafilenameandpath. FormNotations.classContinued PRIVATEFUNCTIONTestChangesMade()ASBoolean DIMmessASString IFchangesMadeTHEN mess="Changesmadetothenote\n\n\t"&TextBoxTitle.Text& "\n\nhavenotbeensaved.Doyouwanttocontinue?" IFMessage.Warning(mess,"Continue","Cancel")<>1THEN RETURNTRUE ENDIF RETURNFALSE END
4.5: Runningtheproject
Wehavenowcompletedtheprojectsoletsrunit.YouruntheprojectbyclickingonthegreenRun buttonintheprojectmanagerwindoworbypressingtheF5key.ASQLitedatabasewillbecreated inyouruserhomedirectoryandatableaddedtothedatabase.Thenthewelcomenoteisaddedto thetable.Wecannowtestourapplicationworkscorrectly.Therefollowssomeofthetestswemight perform.Thisfirstsetofteststesthowweconnecttothedatabase.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page100of110
DatabaseConnectionTests Test ExpectedResult Pass/Fail Runtheapplicationwithavalid Anewdatabaseandtableshouldbe connectionandwhenthedatabasedoesnot created.Thewelcomenoteshouldbe exist. displayed. Runtheapplicationagainwiththevalid connectionanddatabase. Callthedatabasewithaninvalid connection. Nochangesshouldbemadetothe database.Thefirstnotefoundwiththe highestpriorityshouldbedisplayed. Anerrormessageshouldbedisplayed.
Afteropeningtheapplicationinthe Anerrormessageshouldbedisplayed, previousstepclickonallthebuttonsinthe toolbarinturn. Thereisaforthpossibletestyoucouldadd.Thisiswherewehaveavalidconnectionanddatabase butthedatabasetabledoesnotexist.Foraproductionapplicationyouwouldwanttoperformthis test.AsitisabitofacomplextestnewGambasusersmightwanttoskipit. Thenextsetoftestchecktheadding,reading,updatinganddeletingofnotes.Agoodwayof developingthistestlististouserourCRUDLSchecklistasastartingpoint.Lookateachitemin theCRUDLSlistanddeveloptestsforwhentheactionsucceeds.Wealsoneedtestsfortheallthe possiblewayseachactioncouldfail.Thefollowingtestsassumeweareconnectedtothedatabase. DatabaseCreate,Read,UpdateandDeleteTests.PlusListandSearchTests Test ChangethecurrentnoteclicktheAdd button. ExpectedResult Anewnoteisaddedtothedatabaseand thisbecomesthecurrentnote. Pass/Fail
Changethecurrentnotebutmakesurethe Anewnoteisaddedtothedatabasewith notehasthesametitleasanexistingnote. theduplicatenotetitleandthisbecomes thecurrentnote. ThenclicktheAddbutton. ClickontheRefreshbutton.(Makesure Thenoteslistisrefreshedfromthe anychangestothecurrentnotehavebeen database.Thefirsthighestprioritynote becomesthecurrentnote. savedbeforeyoudothis.) ClickontheRefreshbuttonafterchanges Thenoteslistisrefreshedfromthe havebeenmadetoanotebuthavenotbeen database.Thefirsthighestprioritynote saved.Inthemessageboxthatisdisplayed becomesthecurrentnote.Changestothe previousnotearelost. clickontheContinuebutton.
Page101of110
Pass/Fail
ClickontheRefreshbuttonafterchanges Therefreshactioniscancelled. havebeenmadetoanotebuthavenotbeen saved.Inthemessageboxthatisdisplayed clickontheCancelbutton. Clearthesearchtextboxofanytext.Click Amessageisdisplayedstatingthereisno searchtext. ontheSearchbutton. Entersomesearchtextinthesearchtext Onlythosenotesthatcontainthesearch box.Verifythistextcanbefoundinsome textinthenotetitleorcontentareshown. notes.ClickontheSearchbutton.(Make sureanychangestothecurrentnotehave beensavedbeforeyoudothis.) Entersomesearchtextinthesearchtext Amessageisdisplayedstatingthatthe box.Verifythistextcannotbefoundin searchtextwasnotfound.Nonotesare somenotes.ClickontheSearchbutton. displayed. (Makesureanychangestothecurrentnote havebeensavedbeforeyoudothis.) ClickontheSearchbuttonafterchanges Onlythosenotesthatcontainthesearch havebeenmadetoanotebuthavenotbeen textinthenotetitleorcontentareshown. saved.Inthemessageboxthatisdisplayed Changestothepreviousnotearelost. clickontheContinuebutton. ClickontheSearchbuttonafterchanges Thesearchactioniscancelled. havebeenmadetoanotebuthavenotbeen saved.Inthemessageboxthatisdisplayed clickontheCancelbutton. Makesomechangestoanoteandthen clickontheUpdatebutton.Testinturn changestothetitle,noteandpriority. Thecurrentnoteisupdatedandthenotes listisupdated.Theupdatednoteremains thecurrentnote.
Thecurrentnoteisdeletedandthenotes WithanoteselectedclickontheDelete button.Theninthewarningmessageclick listisrefreshed. ontheContinuebutton. Thedeleteactioniscancelled. WithanoteselectedclickontheDelete button.Theninthewarningmessageclick ontheCancelbutton. ClickontheDeletebuttonwheneitherno Amessageisdisplaysstatingthereisno noteisselectedortherearenonotesinthe currentnotetodelete. databasetable. Ourfinalbatchoftestscovertheuserinterfacetoourapplication.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page102of110
Clickontheheadinginthecolumnviewof Thenotessortorderchangeshouldchange notes. totherelevantcolumn. Testtheresizingofthewindowfromeach Theformscontrolsshouldberesizedtofit sideofthewindow. thewindow. Testtheresizingofthewindowfromeach Theformscontrolsshouldberesizedtofit cornerofthewindow. thewindow. Resizethewindowsoitswidthislessthan Iconsthatdonotfitwithinthewidthofthe widthofalltheiconsinthetoolbar. toolbarmoveontoasecondline.Therest oftheformscontrolsareresized appropriately. Usethebarbetweenthetwohalf'softhe Thecontrolsinthetwohalf'softhe formwindowtoresizeeachsectionofthe windowshouldberesizedcorrectly. window.(Thistestdoesnotapplyto GambasVersion1)
4.6: SwitchingtoaMySQLorPostgreSQLDatabase
WearenotgoingtodealwithinstallingorsettingupaMySQLorPostgreSQLdatabase.For informationonthisyoushouldlookathttp://www.mysql.org/orhttp://www.postgresql.org/. PreformingainternetsearchforInstalling+MySQL+Linuxfindsalargeamoutof help.AlsotryInstalling+MySQL+YourLinuxdirstibutionname.Similarresults canbeobtainedforPostgreSQLwithInstalling+PostgreSQL+Linux. Swappingtoaoneofthesedatabasesisverysimple.FindthelineForm_Openeventinthe FormNotationsclassthatlookslikethis: ModuleDatabase.OpenDatabase("sqlite",User.Home, Application.Name,"","") andchangeittosomethinglikethisforaMySQLdatabase: ModuleDatabase.OpenDatabase("mysql","localhost", Application.Name,"mysql","password") MakesuretheMySQLuseraccountyouselecthaspermissionstocreatethedatabaseandtablesthe firsttimethisprocedureisrun.CheckonyourMySQLinstallationorwithyourdatabase
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page103of110
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page104of110
5:
Appendix1:DatabaseCommandswithExecandSQL
InthisappendixweshalllookatconvertingtheNotationsapplicationtodirectlyusingStructured QueryLanguage(SQL)tocommunicatewithadatabase.Inthemainsectionofthistutorialwe avoidedusingSQLinordertodemonstratemoreoftheGambasdatabaseclasses.Wealsomadethe designdecisiontoplaceallthecodetocommunicatewiththedatabaseinsideonemodulecalled ModuleDatabase.Thisdecisionhaspaidbenefitsnowasallthechangesweneedtomakeare confinedtothisonemodule. IntheexampleNotationsprojectthatshipswiththistutorialtherearetwoextra directoriesintheproject.ThesubdirectorycalledModuleDatabaseSQLcontainsa versionofthefileModuleDatabase.modulethatfollowsthecodeexamplesinthis appendix.Simplycopythisfileintothemainprojectdirectoryandoverwritetheone thatalreadyexiststhere. Inordertotestthisfileyouwillneedtocompiletheprojectagain.Gambasbydefault onlycompilesfilesthathavechangedusingaprojecteditor.SelectProjectmenuinthe Gambasprojectmanager.ThenselectthesubmenuoptionCompileAll.Thiswill ensureallfilesarenewlycompiledandyouarerunningthelatestversionoftheproject. YoucanalsoclickontheCompilealltoolbarbuttonintheprojectmanagertoachieve thesameresult. ThesubdirectorycalledModuleDatabaseGambascontainsabackupcopyofthe originalfileModuleDatabase.module.Youcanusethisfiletorestoretheprojecttoits originalformat. Thestructureofthecommandsweneedisfairlystraightforward.WeonlyneedtwoGambas databaseobjects,aconnectionobjectandaresultobject.TheExecmethodontheconnection objectreturnsareadonlyresultobject.SotogetrecordsfromthedatabaseweconstructourSQL statement,passthistotheExecmethod,andthenwecanreadthereturneddatafromtheresult object: sql=SQLselectstatement result=connection.Exec(sql) YoualsocanusetheExecmethodtosendanyvalidSQLstatementstoyourtargetdatabase.So thismethodcanalsobeusedwhenweadd,updateordeleterecordsfromthedatabase. sql=CreateSQLupdate,insertordeletestatement(s) connection.Exec(sql) Ofcoursewiththesemethodyoustillneedtocatchanyerrorsreturned.Wearenotgoingtodeal withhowtouseSQLinthistutorial.IfyouneedinformationonSQLagoodplacetostartisthe websitesforthedatabasevendorslistedintheGambasResourcessection.
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page105of110
TherearetwoimportantissuestoconsiderwhenconstructingthestringfortheSQLstatement.The firstisweneedtoformatthedate/timeinawaythatisunambiguousandunderstoodbythe database.Thisfragmentshowshowweformatthecurrentdate/time: '&Format(Now,"yyyymmddhh:nn:ss")&' Thiswillproduceastringsomethinglike'2006051319:38:34'atthetimeofwritingthis sentence(on13May2006at19:38:34). InourSQLstatementswehaveusedtextstringsthataresurroundedbysinglequotes.Thismeans thatiftheuserentersasinglequoteintheirtitleornoteentrythentheINSERTorUPDATESQL statementwouldfail.ThiswouldbeconfusingtotheuserastheywouldjustseeanbadSQLquery errormessageandnotknowhowtocorrecttheproblem.Hencewehaveadoptedthe(admittedly crude)approachofreplacinganysinglequoteswithdoublequoteswhenconstructingourSQL query.(Youcanincludesinglequoteswithinatextstringintheversionofthisapplicationusing Gambasobjectstoaddandupdaterecords.) ThisisalistingofthechangesweneedtomaketotheModuleDatabasecodetousetheSQL methodforcommunicationstothedatabase. AfterenteringthislistingyoushouldreruntheallthetestsintheRunningtheproject sectiontoensureyourapplicationstillworkswiththisdifferentmethodof communicatingwiththedatabase. Alsoifyouchangethedatabasetype,asdescribedin,SwitchingtoaMySQLor PostgreSQLDatabaseyoushouldbeverythoroughinrerunninganytesting.Youneed torepeatallyourtestingforeachtypeofdatabaseyouintendtosupport.Youneedtodo moreretestingthanityouusedtheGambasmethodofcommunicatingwiththe database. InthefollowinglistingyouneedtomakeafewsmallchangesforGambasversion1. Thelinesthathavetheformat: sql&=xxx needtobechangedto: sql=sql&xxx asGambasversion1doesnotunderstandthe&=operator.AlsoGambasversion1does notunderstandtheDconvfunction.Solinesthatincludeit: ...Dconv(Error.Text)... shouldjustomitthefunctioncall: ...Error.Text...
Page106of110
PUBLICSUBOpenDatabase(DBTypeASString,DBHostASString,DBName ASString,UserNameASString,UserPasswordASString) DIMsqlASString DIMerrorMessageHeaderASString 'Openaconnection(tothedatabaseserveronly) databaseConnection.Type=Lower(DBType) databaseConnection.Host=DBHost databaseConnection.Name="" databaseConnection.Login=UserName databaseConnection.Password=UserPassword databaseConnection.Port="" 'Opentheconnection TRYdatabaseConnection.Open() IFERRORTHEN errorMessageHeader="Couldnotopendatabaseconnection"& DBHost Error.Raise(Error.Text) ENDIF 'Checkiftheserverconnectionhasadatabasewiththe 'requireddatabasename. IFNOTdatabaseConnection.Databases.Exist(DBName)THEN PRINT"Databasenotfound.Creatingnewdatabase" 'Createanewdatabase databaseConnection.Databases.Add(DBName) 'IfoundIneededthiswithaSQLitedatabase '(butnotwithaMySQLdatabase) WAIT0.5 ENDIF
Page107of110
errorMessageHeader="Couldnotopendatabase"&DBName& "on"&DBHost Error.Raise(Error.Text) ENDIF 'CheckifthedatabasehasaNotestable IFNOTdatabaseConnection.Tables.Exist("Notes")THEN PRINT"Databasetablesnotfound.Creatingnewnotestable" 'AddaNotestabletothedatabase sql="CREATETABLE'Notes'(" sql&="CreateDateDATETIMENOTNULL," sql&="LastModifiedDATETIME,titleTEXT," sql&="NoteTEXT," sql&="PriorityINTEGERNOTNULLDEFAULT0," sql&="PRIMARYKEY(CreateDate));" databaseConnection.Exec(sql) 'Addadefaultwelcomerecord AddData("Welcome",File.Load("Welcome.txt"),0) ENDIF CATCH IFerrorMessageHeader=""THEN errorMessageHeader="Databaseconnectionerror:"&DBName& "on"&DBHost ENDIF Error.Raise("<b>"&errorMessageHeader&"</b><hr>Error:<br>"& DConv(Error.Text)) END PUBLICSUBCloseDatabase() TRYdatabaseConnection.Close()
Page108of110
PUBLICFUNCTIONAddData(TitleASString,NoteASString,Priority ASInteger)ASString DIMsqlASString DIMcreateTimeASDate createTime=Now Title=Replace(Title,"'","\"") Note=Replace(Note,"'","\"") sql="INSERTINTONotes" sql&="(CreateDate,LastModified,Title,Note,Priority)" sql&="VALUES(" sql&="'"&Format(createTime,"yyyymmddhh:nn:ss")&"'," 'CreateDate sql&="'"&Format(createTime,"yyyymmddhh:nn:ss")&"'," 'LastModified sql&="'"&Conv(Title,Desktop.Charset, databaseConnection.Charset)&"'," sql&="'"&Conv(Note,Desktop.Charset, databaseConnection.Charset)&"'," sql&=Priority&");" databaseConnection.Exec(sql) RETURNFormatDate(createTime) CATCH Error.Raise("<b>Adddatabaserecorderror</b><hr>Error:<br>"& DConv(Error.Text)) END 'Readatable PUBLICSUBSelectData() DIMsqlASString sql="SELECT*FROMNotes;" Notes=databaseConnection.Exec(sql) CATCH
GettingStartedwithGambasVersion2:ATutorial [email protected]
Page109of110
Error.Raise("<b>Selectdatabaserecordserror</b><hr>Error:<br>" &DConv(Error.Text)) END 'Updatearecord PUBLICSUBUpdateData(RowASInteger,TitleASString,NoteAS String,PriorityASInteger) DIMsqlASString DIMcreateDateASDate Title=Replace(Title,"'","\"") Note=Replace(Note,"'","\"") Notes.MoveTo(Row) sql="UPDATENotes" sql&="SETLastModified='"&Format(Now, "yyyymmddhh:nn:ss")&"'," sql&="Title='"&Conv(Title,Desktop.Charset, databaseConnection.Charset)&"'," sql&="Note='"&Conv(Note,Desktop.Charset, databaseConnection.Charset)&"'," sql&="Priority="&Priority&"" createDate=Notes["CreateDate"] sql&="WHERECreateDate='"&Format(createDate, "yyyymmddhh:nn:ss")&"';" databaseConnection.Exec(sql) CATCH Error.Raise("<b>Updatedatabaserecorderror</b><hr>Error:<br>" &DConv(Error.Text)) END 'Deletearecord PUBLICSUBDeleteData(RowASInteger) DIMsqlASString DIMcreateDateASDate Notes.MoveTo(Row) createDate=Notes["CreateDate"] sql="DELETEFROMNotes"
Page110of110