How to Gambas 3 Building GUI Applications version 0.0.1 Pre-release 1 Main Author: Willy Raets (The Netherlands) <willy@development.earthshipbelgium.be> Version: 0.0.1 Pre-release 1 (2013-09-29) Contributing author: Illustrations: Sholzy (United Stated), Illustrations 173 Willy Raets (The Netherlands), Illustrations 1-172, 174-178 Proofreaders: Alain J. Baudrez (Belgium) Ammar Ali Kurd (Yemen) Jim Cook (United States) Netizen1993 (United States) Instruction and example testing Alain J. Baudrez (Belgium) Ammar Ali Kurd (Yemen) Jim Cook (United States) Netizen1993 (United States) Advisors: Alain J. Baudrez (Belgium) Ian Roper (Australia) How to Gambas 3 – Building GUI Applications (this work) is licensed by Willy J.L. Raets under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License In short meaning that everyone can share and read this work for free, as is. Commercial use is not allowed, neither is changing the work. You need to attribute in the manner required by the licensor (see below). Check the full license text for a detailed explanation. For conditions of use prohibited by this license, contact the licensor. THIS WORK IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THIS WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THIS WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. UNLESS OTHERWISE MUTUALLY AGREED BY THE PARTIES IN WRITING, LICENSOR OFFERS THIS WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THIS WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. For full license text visit: http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode Attribution is required as follows: 'How to Gambas 3 – Building GUI Applications' by Willy Raets (http://howtogambas.org) Table of Contents 1 HOW THIS GOT STARTED.........................................................................................1 2 FOREWORD................................................................................................................2 3 BEFORE YOU GET STARTED....................................................................................3 3.1 BACKGROUND INFORMATION......................................................................................................3 3.2 EXAMPLE CODE.....................................................................................................................3 3.3 GOOD PRACTICE...................................................................................................................3 3.4 TERMINAL.............................................................................................................................3 3.5 WARNING.............................................................................................................................4 3.6 CONTROLS AND MENUS...........................................................................................................4 4 INTRODUCTION..........................................................................................................5 4.1 WHAT IS GAMBAS?................................................................................................................5 5 SOME GOOD PRACTICES.........................................................................................6 5.1 FOLDER ORGANISATION............................................................................................................6 5.1.1 Development folder........................................................................................................ 6 5.1.2 Distributions folder......................................................................................................... 7 5.2 PROJECT ORGANISATION..........................................................................................................9 5.3 ORGANISING YOUR CODE.........................................................................................................9 5.3.1 Commenting your code................................................................................................ 10 5.3.2 Clear choices for names.............................................................................................. 11 5.3.3 Indenting code............................................................................................................. 12 5.3.4 Eliminate repeating code.............................................................................................. 13 6 A FIRST GUI APPLICATION: TEXTPLAY.................................................................14 6.1 WHAT WILL BE DONE IN THIS CHAPTER......................................................................................14 6.2 STARTING A NEW PROJECT.....................................................................................................14 6.3 CREATING A FORM AND CONTROLS...........................................................................................18 6.3.1 Placing controls on a form............................................................................................ 19 6.3.2 A closer look at the controls......................................................................................... 22 6.4 CODING, TESTING, CODING, TESTING.........................................................................................24 6.4.1 Objects, properties, events and methods.....................................................................24 6.4.2 Write some code and test (round 1).............................................................................24 6.4.3 Code some improvements and test (round 2)..............................................................27 7 EXTENDING APPLICATION TEXTPLAY..................................................................30 7.1 WHAT WILL BE DONE IN THIS CHAPTER......................................................................................30 7.2 OPEN AN EXISTING PROJECT...................................................................................................30 7.3 MODIFY MAIN FORM AND ADD CONTROLS....................................................................................31 7.3.1 Copy controls on the form............................................................................................ 33 7.3.2 A closer look at the controls......................................................................................... 34 7.4 CODING, TESTING AND ADAPTING.............................................................................................37 7.4.1 Coding and testing (round 1)........................................................................................ 37 7.4.2 Adapting, coding and testing (round 2).........................................................................38 7.4.3 Adding new controls, code and test (round 3)..............................................................41 7.4.4 Add some last controls, code and test (round 4)..........................................................46 7.5 A LAST REVIEW OF THE APPLICATION.........................................................................................53 7.5.1 Do you need a button Show?.......................................................................................53 7.5.2 Could iSwitch format be more clear?...........................................................................53 7.5.3 Should the button Add be enabled if no Add is checked?............................................54 7.5.4 Should the button Clear be enabled if there is nothing to clear?..................................54 7.6 ANSWERS TO THE LAST REVIEW ...............................................................................................54 7.6.1 Do you need a button Show?.......................................................................................54 7.6.2 Could iSwitch format be more clear?...........................................................................56 7.6.3 Should the button Add be enabled if no Add is checked?............................................56 7.6.4 Should the button Clear be enabled if there is nothing to clear?..................................57 8 YOUR SECOND APPLICATION: TEXTPLAYT(W)O.................................................59 8.1 WHAT WILL BE DONE IN THIS CHAPTER......................................................................................59 8.2 START A NEW PROJECT AND DESIGN THE FIRST FORM...................................................................59 8.3 PLAYING WITH TEXT THE OTHER WAY AROUND.............................................................................60 8.3.1 Some first coding to split the text.................................................................................60 8.3.2 Determine the number of splits....................................................................................64 8.4 SEARCH FOR TEXT...............................................................................................................68 8.4.1 Make a new form......................................................................................................... 68 8.4.2 Make FrmSearchReplace open from btnSearch on FrmMain......................................70 8.4.3 Project intermezzo: Form class interaction explained..................................................71 8.4.4 Back on track to code a Public method on FrmMain....................................................73 8.4.5 Lets search some string............................................................................................... 74 8.5 SEARCH AND REPLACE TEXT...................................................................................................76 8.5.1 Prepare the forms for Search and Replace..................................................................76 8.5.2 Making FrmSearchReplace appear depending on selection in FrmMain.....................77 8.5.3 Replace searched strings............................................................................................ 80 9 YOUR THIRD APPLICATION: NUMPLAY.................................................................82 9.1 WHAT WILL BE DONE IN THIS CHAPTER......................................................................................82 9.2 START A NEW PROJECT AND DESIGN A FORM...............................................................................82 9.3 DOING THE MATHS................................................................................................................83 9.3.1 Analyse the needs and determine a strategy...............................................................84 9.3.2 Implement error handling............................................................................................. 88 9.4 WORKING WITH NUMBERS IN TEXT VARIABLES AND TEXT CONTROLS..................................................90 9.4.1 Simple beginnings........................................................................................................ 91 9.4.2 Next challenge............................................................................................................. 92 9.5 HOW ABOUT DATE AND TIME...................................................................................................95 9.5.1 Adding some code....................................................................................................... 96 9.5.2 More date and time...................................................................................................... 97 9.6 ANOTHER APPROACH, ENUMERATE............................................................................................99 9.6.1 iSwitch enumerated..................................................................................................... 99 10 YOUR FOURTH APPLICATION: IMAGEPLAY....................................................102 10.1 WHAT WILL BE DONE IN THIS CHAPTER..................................................................................102 10.2 START A NEW PROJECT AND DESIGN A FORM..........................................................................102 10.3 LET ME SEE SOME IMAGES.................................................................................................103 10.3.1 Making some images............................................................................................... 103 10.3.2 Make the images appear.......................................................................................... 104 10.3.3 Code the labels........................................................................................................ 107 10.4 LOADING IMAGES USING CODE.............................................................................................111 10.4.1 The mission............................................................................................................. 112 10.4.2 Make the labels work again......................................................................................113 11 YOUR FIFTH APPLICATION: SIMPLETEXTEDITOR..........................................115 11.1 WHAT WILL BE DONE IN THIS CHAPTER..................................................................................115 11.2 START A NEW PROJECT AND DESIGN A FORM..........................................................................115 11.3 MAKING A MENU..............................................................................................................116 11.3.1 Coding the menu entry New.....................................................................................118 11.3.2 Adding Icon and keyboard shortcut to menu entry New...........................................119 11.4 SAVING YOUR FIRST TEXT FILE.............................................................................................120 11.4.1 On a mission............................................................................................................ 120 11.4.2 Lets save some text................................................................................................. 121 11.4.3 Get name and path to save to..................................................................................123 11.5 OPENING YOUR FIRST TEXT FILE..........................................................................................126 11.5.1 Code for opening..................................................................................................... 126 11.5.2 Make sure an opened file can be saved...................................................................127 11.6 LITTLE INTERMEZZO..........................................................................................................128 11.7 BACK ON TRACK FOR SAVE AS...........................................................................................132 11.7.1 Code Save As menu item......................................................................................... 132 11.7.2 Simplifying the code for saving................................................................................133 11.8 PUTTING THE DOTS ON THE I...............................................................................................134 11.8.1 Offer to save when closed after editing text file........................................................135 11.8.2 Bug!! What bug?!..................................................................................................... 138 11.8.3 Resizing the application window..............................................................................141 11.8.4 Adding a ToolBar...................................................................................................... 143 11.8.5 Reordering menu items............................................................................................ 147 11.8.6 Adding new menus................................................................................................... 148 11.8.7 Application caption................................................................................................... 150 11.9 A LAST NOTE ON CODE ORGANISATION...................................................................................153 12 END NOTE FOR PRE-RELEASE 1......................................................................155 13 APPENDICES............................................................................................................ I 14 BIBLIOGRAPHY....................................................................................................XII List of Illustrations Illustration 1: Organisation of 'Development' folder...........................................................6 Illustration 2: Organisation of 'Distributions' folder.............................................................8 Illustration 3: Application folder with version folders containing the packages...................9 Illustration 4: Organisation of a project folder in the Gambas IDE.....................................9 Illustration 5: Gambas 3.4.1 opening screen...................................................................14 Illustration 6: 'New project' screen step 1. Select the type of application........................15 Illustration 7: 'New project' screen step 2. Select the folder for the new project..............15 Illustration 8: Create a new folder for Learning projects..................................................16 Illustration 9: Select the folder 'Gambas3-Learning'........................................................16 Illustration 10: 'New project' screen step 3. Name the project folder and project ...........17 Illustration 11: Message when project has been created successfully............................17 Illustration 12: New project 'TextPlay' opened in Gambas 3 IDE.....................................18 Illustration 13: FMain in Sources folder of the project.....................................................18 Illustration 14: Empty form in IDE....................................................................................19 Illustration 15: Label icon in ToolBox...............................................................................20 Illustration 16: Label control drawn on the form..............................................................20 Illustration 17: TextBox icon in ToolBox...........................................................................20 Illustration 18: TextBox control drawn on the form...........................................................21 Illustration 19: Button icon in ToolBox..............................................................................21 Illustration 20: Two button controls drawn on the form....................................................21 Illustration 21: Select Alignment of the Label control.......................................................22 Illustration 22: Label1 aligned right..................................................................................23 Illustration 23: Label1 Text property changed..................................................................23 Illustration 24: Controls after changing the properties.....................................................23 Illustration 25: Select Event Click for button control........................................................25 Illustration 26: FMain.class..............................................................................................25 Illustration 27: Menu Debug -> Run to test the application..............................................26 Illustration 28: Application running with message shown.................................................27 Illustration 29: Message when no name entered.............................................................29 Illustration 30: Message when name entered..................................................................29 Illustration 31: Gambas welcome screen 'Recent projects'.............................................30 Illustration 32: Mouse appearance will change where the pointer is................................31 Illustration 33: Form dragged wider and Label and TextArea selected............................31 Illustration 34: Drag the buttons to the bottom of the form..............................................32 Illustration 35: Result after adapting the form..................................................................32 Illustration 36: Pasted controls on the form.....................................................................33 Illustration 37: Controls dragged to the spot you need them...........................................33 Illustration 38: Result after copy/pasting all needed controls...........................................33 Illustration 39: Label1 after changing the Text property...................................................34 Illustration 40: Name properties of both TextBoxes changed..........................................34 Illustration 41: Main form after the changes in the exercise............................................35 Illustration 42: Names of buttons changed in Fmain.class as well..................................36 Illustration 43: Main form after adding two more controls................................................36 Illustration 44: Result after clicking button Add................................................................37 Illustration 45: Hierarchy of the controls on main form....................................................38 Illustration 46: Hierarchy after adaptation........................................................................38 Illustration 47: Set selected controls NoTabFocus property to True................................39 Illustration 48: Clicking Add without filling in a name.......................................................40 Illustration 49: Three CheckBoxes and three RadioButtons............................................41 Illustration 50: All CheckBoxes selected, only one RadioButton......................................41 Illustration 51: Result of 2 lines selected.........................................................................43 Illustration 52: Clicked button Add with only Name selected...........................................45 Illustration 53: New controls added and adapted............................................................46 Illustration 54: Testing the new code...............................................................................49 Illustration 55: Selecting RadioButton 'Show' deselects RadioButton '1 line'...................50 Illustration 56: ToolBox tab Container showing Frame....................................................50 Illustration 57: Frame Show placed on form....................................................................51 Illustration 58: RadioButtons pasted into Frame Show....................................................51 Illustration 59: All RadioButtons placed in their Frames..................................................52 Illustration 60: RadioButtons show working as supposed................................................52 Illustration 61: No button Show but still doing the same job............................................55 Illustration 62: Main form in IDE design mode.................................................................60 Illustration 63: Main form when run from IDE..................................................................60 Illustration 64: Text splitted on the dot (.).........................................................................62 Illustration 65: Result of splitting on \n.............................................................................63 Illustration 66: Renewed result of splitting on "\n"...........................................................64 Illustration 67: Result of splitting on "\n" showing 2 lines.................................................65 Illustration 68: Split for 4 lines.........................................................................................67 Illustration 69: Next a split for 1 line (other lines are now cleared)..................................68 Illustration 70: Ad a new form to the project....................................................................68 Illustration 71: Dialog to name the form...........................................................................69 Illustration 72: FrmSearchReplace with controls placed..................................................69 Illustration 73: FrmSearchReplace opened from btnSearch............................................71 Illustration 74: Running btnSplit code from btnSearch on another form..........................72 Illustration 75: Interaction between methods in different form classes............................73 Illustration 76: Search string passed as argument of a Public method............................74 Illustration 77: Seems like search performs as expected................................................76 Illustration 78: Replace TextBox and Button added to FrmSearchReplace.....................76 Illustration 79: FrmSearch property Enabled set to true on FrmMain..............................77 Illustration 80: Search shown when search selected.......................................................79 Illustration 81: Search and Replace shown when search/replace selected.....................79 Illustration 82: Search still works well..............................................................................81 Illustration 83: Replace does a good job as well.............................................................81 Illustration 84: FrmMain after placing all controls............................................................83 Illustration 85: FrmMain when run...................................................................................83 Illustration 86: lblOperator shows selected Operator.......................................................84 Illustration 87: Console output in IDE..............................................................................86 Illustration 88: Calculating values 10 and 2.....................................................................87 Illustration 89: Division by zero error...............................................................................87 Illustration 90: Error 26 returned.....................................................................................89 Illustration 91: Division by zero now handled properly.....................................................90 Illustration 92: FrmMain after adding some controls........................................................90 Illustration 93: Calculating the text seems to work..........................................................91 Illustration 94: Division by zero taken care off.................................................................94 Illustration 95: Unknown operator taken care off.............................................................94 Illustration 96: Some extra controls added to play with date and time.............................96 Illustration 97: After Date is selected the other controls are updated accordingly...........97 Illustration 98: Timer object can be found in the toolbox on tab 'Special'.........................98 Illustration 99: Timer object can be anywhere on the form..............................................98 Illustration 100: Every second the tbxDate1 and 2 change their content.........................99 Illustration 101: Controls placed on FrmMain................................................................102 Illustration 102: Create a new folder 'Images' in the project Data folder........................103 Illustration 103: Made some modern art image.............................................................103 Illustration 104: Image copied, edited and saved. That makes two works of art............104 Illustration 105: Make panel appear..............................................................................104 Illustration 106: Opening the 'Select a picture' form......................................................105 Illustration 107: Image 'MyImage.png' in PictureBox picOne.........................................105 Illustration 108: Both images in their PictureBox...........................................................105 Illustration 109: Running ImagePlay for the first time....................................................106 Illustration 110: Clicking the button switches the images between the PictureBoxes....107 Illustration 111: Labels now showing the image dimensions.........................................108 Illustration 112: Two more png images made in the editor............................................108 Illustration 113: Running the application with the new images......................................109 Illustration 114: Images switch but labels show wrong dimensions...............................109 Illustration 115: All works as expected..........................................................................110 Illustration 116: All new controls placed on FrmMain.....................................................111 Illustration 117: Project folder structure.........................................................................112 Illustration 118: Auto-complete function of IDE will recognise the path.........................112 Illustration 119: The pictures seem to load but the labels aren't adapted......................113 Illustration 120: Loading images now adapts the Labels accordingly............................114 Illustration 121: FrmMain after placing the control.........................................................115 Illustration 122: Select Menu editor...............................................................................116 Illustration 123: Adding 9 menu entries in the Menu editor............................................116 Illustration 124: Indent the menu entry..........................................................................117 Illustration 125: The end result of editing the menu entries...........................................117 Illustration 126: There is a menu File on FrmMain in IDE..............................................118 Illustration 127: Before and after clicking menu File -> New.........................................118 Illustration 128: Set the keyboard shortcut for menu New.............................................119 Illustration 129: Selecting the new icon.........................................................................119 Illustration 130: File menu with the newly added icon for New......................................120 Illustration 131: Make sure your menu entry for Save has an icon and keyboard entry 121 Illustration 132: Ready to save my first file....................................................................124 Illustration 133: Dialog Save text file.............................................................................125 Illustration 134: Notification that the file has been saved...............................................125 Illustration 135: Dialog Open text file.............................................................................127 Illustration 136: Saved the changes to the text file........................................................128 Illustration 137: Part of the File menu disabled as should be........................................129 Illustration 138: Oops.., no way to save a new text file..................................................130 Illustration 139: The end result of some polishing of the File menu...............................131 Illustration 140: Save As dialog.....................................................................................132 Illustration 141: Notification that the file was saved using a new name.........................133 Illustration 142: The auto-help will know your new routine............................................134 Illustration 143: Closing after editing gives a warning and option to save.....................138 Illustration 144: Changed shown in Console means Change event is triggered............139 Illustration 145: Dragging the window bigger doesn't change the TextArea...................141 Illustration 146: Set the Arrangement property of FrmMain...........................................141 Illustration 147: The TextArea now does resize with the window...................................142 Illustration 148: Arrangement set to Fill does the job.....................................................142 Illustration 149: HBox is found on the Tab Container.....................................................143 Illustration 150: All new controls in place.......................................................................143 Illustration 151: A strange looking form, but New button works.....................................144 Illustration 152: Set txaMain property Expand to True...................................................144 Illustration 153: Make sure all ToolButtons are inside the HBox....................................145 Illustration 154: A running resizeable SimpeTextEditor with Toolbar..............................146 Illustration 155: Toolbar with property Spacing set to False..........................................147 Illustration 156: Toolbar with property Spacing set to True............................................147 Illustration 157: A click on Move Up button brings the item higher................................147 Illustration 158: Added menus with ToolBar menu item set checked.............................148 Illustration 159: A new menu View Toolbar....................................................................148 Illustration 160: With ToolBar checked..........................................................................149 Illustration 161: With Toolbar unchecked.......................................................................150 Illustration 162: Menu Help -> About shows some info on the application.....................150 Illustration 163: 'New text document' added to application caption...............................151 Illustration 164: Caption showing the name of the opened text file...............................152 Illustration 165: Save the new text document................................................................153 Illustration 166: After saving the caption changed.........................................................153 Illustration 167: FrmMain.class code organised in certain order...................................154 Illustration 168: Gambas website - Menu Mailing lists/Forums..........................................II Illustration 169: Gambas website - Overview Mailing Lists & Forums...............................II Illustration 170: Subscribe to the Gambas-user mailinglist...............................................III Illustration 171: Gambas mailing list Forum.....................................................................IV Illustration 172: Gambas IDE - System information form..................................................V Illustration 173: White Island and GambasForum (circled the login and join)..................VI Illustration 174: Search, Post since last visit and Topics with unread posts....................VII Illustration 175: Gambas based projects with sub forum 'How to Gambas 3'................VIII Illustration 176: Sub forums and topics of 'How to Gambas 3' forum...............................IX Illustration 177: Topics in sub forum 'Building GUI Applications'......................................IX Illustration 178: Gambas Learning - a learning aid for Gambas........................................X Appendices Appendix I: Linux command reference...............................................................................I Appendix II: Subscribe to the official Gambas mailing lists/Forum....................................II Appendix III: Reporting problems on the official Gambas mailing list................................V Appendix IV: White Island Software and GambasForum quick tour.................................VI Appendix V: Getting help with the 'How to Gambas 3' guides.......................................VIII Appendix VI: Application Gambas Learning – a learning aid for Gambas.........................X Appendix VII: Overview of the 'How To Gambas 3' guides..............................................XI 1. How this got started 1 How this got started Somewhere in 2009 I finally decided to install Linux on one of my systems. After my first initial exploring of the operating systems, the provided applications and more a new world opened up to me. I soon discovered the stability and power of Linux and moreover the power of an open source community. So after exploring Linux a while I felt like programming. Since most of my last and current work involved programming client interfaces for databases in VB, I went looking for a good alternative on the Linux platform. And then I found Gambas (at that time in version 2) and loved it right from the start. It's ease of use and logic in syntax surprised me, captured me and never let me go. Since that day all my coding that is not job related is done in Gambas1. For me, as a professional application developer , finding my way in Gambas wasn't always that easy. Documentation is very basic and explains the syntax of the language with little or no examples. There are some guides out there, but they are scares. Nevertheless I manage because of my years of experience with programming. I can see how a new programmer might find it hard to understand how Gambas and Linux work, then leave in disappointment and frustration. Back in the old days, about every computer had a programming language and manual delivered along with it. A lot of young people in those days learned programming this way and Gambas is an excellent tool to do just that on a Linux platform. As it is based on BASIC (Beginners All purpose Symbolic Instruction Code), a language many in the eighties learned themselves, it is perfect for a beginner to learn programming. Although a lot has changed since Basic saw birth, it still is the same language, but much more powerful because of Gambas providing an environment to make event driven GUI (Graphical User Interface) applications. It's possible to build easy GUI applications doing simple things in no time. And that is what this series aims at. People new to programming and wanting to learn the skills. So that is what will be covered in a simple manner, so any newbie can learn. Every part of the series will cover a specific topic. And in time you will have all the basic skills to build your own applications in Gambas 3. Enjoy... Willy Raets, Main author, May 2012 A special thanks to all the contributors on the White Island Software and GambasForum, for their help in improving this guide and of course all developers of Gambas for their effort spent on creating the powerful Basic language, named Gambas. This guide is dedicated to an old friend, Jos (a.k.a. Yellowmoor), to help him get started with Gambas programming. I would like to dedicated the 'How To Gambas 3'-series to my three sons Nicky, Luca and Nino. 1 Meanwhile Gambas has been introduced at my job and is being used there as well. The environment has gone from Windows only to a mixed Windows/Linux one.(added September 23th, 2013) 1 2. Foreword 2 Foreword This guide is the second in the series 'How To Gambas 3'. The guide is aimed at people new to Gambas and programming and discusses the building of simple standalone GUI applications. This pre-release 1 is a first public release of a still unfinished guide. Fact that it isn't finished yet, doesn't mean it can't prove useful to people new to programming in Gambas. The guide will learn you the basics of making new GUI projects in the Gambas IDE. Drawing controls on forms, learn to code their events and run the program. It will explain terminology common to programming and Gambas in specific. You will learn about user interaction, input and output of data, handling text-based and numeric data, localisation, the basics of loading and saving data to files and of handling images in your application. Besides that Gambas syntax and useful string, arithmetical and other functions are explained and demonstrated. All is learned in a step by step approach explaining each and every new detail, accompanied by code, screenshots2 and hands on practice in using the Gambas IDE, typing code, compiling and running code and see things work (or fail). Often examples are approached in a manner that let's you stumble upon problems that gradually get solved. This will slowly get you acquainted with detecting problems , different manners of solving the same problem and a broader insight in the Gambas language in general. At the end of pre-release 1 you should be capable of building very basic GUI applications, handling text and numbers, save and load files and images, working with menus and toolbars and have a basic understanding of concepts like Public, Private, methods, functions, objects, controls and such. In the chapters still in development, things like printing data, drawing on a DrawArea, more complex saving and loading of data, form classes, modules, the Gambas IDE and it's possibilities, folder structures of projects, Gambas components and their function and maybe even more will be explained. For now enjoy pre-release 1, Willy Raets, September 28th, 2013 Practical note: When you copy/paste code from the code boxes into the Gambas IDE you might get errors running the code. To prevent this from happening simply copy/paste the code into a plain text editor first and next copy/paste from the text editor into the Gambas IDE and you won't have this trouble. Better practice is to simply type the code directly into the Gambas IDE as this will get you familiar with typing code in the editor and working with the auto-help feature, during typing. 2 All screenshots are made on Linux Mint 13 – Mate 1.4 with English language installed using Gambas 3.4.2, except otherwise mentioned. Screenshots might look different on your distribution and with your localisation settings. 2 3. Before you get started 3 Before you get started You will need to have at least Gambas 3.3.x or higher, installed on your system 3. Installing Gambas will not be covered in this book. 'How to Gambas 3 – Installing Gambas' covers the installation of Gambas in detail and for different distributions. You will also need to know some conventions used in this book for clear understanding of the materials presented herein. 3.1 Background information When explaining how to built and code in Gambas 3, I will sometimes provide extra background. This extra background is meant to give some deeper insight into the world of both Linux and Gambas. This background is not necessary for completing the examples, but will give you a better comprehension of Gambas in general. This is how background information is presented in this book. It will give you some more insight on the item being explained. Background information will be placed in a yellow box. 3.2 Example code Example code is used to explain Gambas using sample applications that get built up and explained in detail from the scratch. 'Sample code ' Public Sub Form_Open() Me.Center Me.Caption = “Sample application” End The Gambas code that you need to write in the examples will be placed in a white box. 3.3 Good Practice If something is considered as a good practice it will be placed in a green box. This is how good practice information is presented in this book. It is advised to start using this good practice in applications you built. Good practice will make for more effective maintenance of your system or applications. 3.4 Terminal If you would ever need to run a command in a terminal window it will be placed in a black box. This means you will need to open a terminal interface like Gnome terminal, LX terminal or whatever application lets you go to the command line interface on your distribution. 3 Code will most likely work as well in Gambas 3.1.x or higher, although this was not tested. Just give it a try if that is your situation, since nothing I know of has changed in the syntax and use of the core Gambas components discussed and used in this guide. 3 3. Before you get started uname -a 3.5 Warning If it would ever be needed to get your attention to matters that are of great importance they will be placed in a red box. This is an important procedure. Pay attention as things can go seriously wrong :-) 3.6 Controls and menus When testing the applications built in Gambas you will need to do things like click on a button to see if the code does what it is supposed to do. When, for example, referring to the button with Cancel on it I will refer to it as: Click on the button Cancel When for example referring to a menu About... in the menu Help I will refer to it as: Click on menu Help → About... 4 4. Introduction 4 Introduction 4.1 What is Gambas? As the Gambas website states: 'Gambas almost means Basic'. With the 'G' for Gambas, the 'a' for almost, the 'm' for means and the 'bas' for Basic. A nice little playing on words. According to the official website 'Gambas is a free development environment based on a Basic interpreter with object extensions'. It is comparable to a popular counterpart on an mainstream platform. The person behind the project and main developer is Benoît Minisini from France with the help of others. Gambas provides you with an IDE for easy development of GUI applications. Gambas components provide you with extra syntax and functionality to code for things like database access, networking access, CGI web applications, internationalisation and more. Visit the Gambas Introduction at the official Gambas website for more details.4 IDE or Integrated Development Environment is a software application that provides comprehensive facilities to computer programmers for software development.1 In Gambas this means you have an environment where you can easily design your forms, put controls on them (like buttons, text fields, check boxes and so on) and code them in a source code window. You get a tree view on the project so you can easily browse from one form design to another and see other files like icons contained in the project. The Gambas IDE also has a debugger so you can run applications in development time without having to make executables or distribution packages, a thing the IDE does as well. You can add or remove components to the project in the IDE and in this way add or remove functionality to your applications. 1. Source: http://en.wikipedia.org/wiki/Integrated_development_environment Gambas provides you with the tools for RAD (Rapid Application Development) through use of the IDE. This makes GUI application design, debugging and packaging for distribution easy and by Gambas supporting OOP (see below in yellow), a concept that makes reuse of parts already built possible, saving time, energy, and reducing errors. No need to do things over and over again. Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs. Programming techniques may include features such as data abstraction, encapsulation, messaging, modularity, polymorphism, and inheritance. Many modern programming languages now support OOP, at least as an option1 1. Source: http://en.wikipedia.org/wiki/Object-oriented_programming 4 http://gambas.sourceforge.net 5 5. Some good practices 5 Some good practices If you develop applications there are some good practices that can make your life easier. I'll try to give an overview on how I organise my projects, code and more for Gambas. This is the way I have done it for my own needs and it is a sort of evolution that took place over the years of programming in different languages. This doesn't have to be how you want to organise your projects, code and more, it is just a suggestion that could prove useful. 5.1 Folder organisation This is probably not the first thing most of you would think about but to me it is an important one, especially when having several projects running. Here is how I organise my folders for Gambas development. I develop in both Gambas 2 and 3. You can do it differently when only developing in Gambas 3. First I create 2 folders in my home folder or in a folder made for it. One is called 'Development', the other 'Distributions'. This you can simply do from within your File Manager application beloning to your Linux distribution. 5.1.1 Development folder In my case in the 'Development' folder I create a 'Gambas2' and a 'Gambas3' folder. Within the 'Gambas3' folder I create following folders: ➢ Application documentation ➢ Gambas3-ArchivedApps ➢ Gambas3-GameZone ➢ Gambas3-Projects ➢ Gambas3-SourceOthers ➢ Gambas3-TestZone ➢ Gambas3-Tools Illustration 1: Organisation of 'Development' folder 6 5. Some good practices 1. Application documentation This folder is used to place documentation files made to accompany applications I distribute. 2. Gambas3-ArchivedApps Archived applications can be any application I haven't looked at for a long time. I never trow them away, but relocate them to this folder. They can sometimes still be useful just to remember how you done something in those days, or as a base for an entire new application. 3. Gambas3-GameZone The folder I store my Gambas game projects 4. Gambas3-Projects The folder I use for all my distributed application projects. Each project will get his own folder named after the project. This will be done when creating a new project in the Gambas IDE. 5. Gambas3-SourceOthers In this folder I unpack project source code from other developers they shared. I can then open them as normal projects in the Gambas IDE. It could be for purpose of checking out code, testing the application or help solving an error. When not useful they get deleted instead of archived. 6. Gambas3-TestZone This folder is for making a quick project for testing something, or for trying out things or for replicating a question asked on a forum to see if I can come up with a solution. They are no serious projects, but exactly what the folder says, test zone applications. They often get deleted instead or archived. 7. Gambas3-Tools The folder I use for applications (libraries) I develop for use in my distributed projects, or for tools I use myself. You can make more or less folders to categorise and organise your projects on your system. You can add new folders later and replace projects. For the projects you will be making in this guide you could make a 'Gambas3-LearningZone' folder to put them in. All that is up to you. 5.1.2 Distributions folder This folder contains the distribution packages for all my applications. In my case in the 'Distributions' folder I create a 'Gambas2' and a 'Gambas3' folder. Within the 'Gambas3' folder I create following folders: ➢ Archived ➢ Website ➢ Zone-Games ➢ Zone-HowToExamples ➢ Zone-Ideas ➢ Zone-Libraries ➢ Zone-MyTools ➢ Zone-PackageInstallers ➢ Zone-Projects ➢ Zone-Testing 1. Archived folder The 'Archived' folder contains distribution packages of applications no longer maintained. 2. Website folder 7 5. Some good practices Illustration 2: Organisation of 'Distributions' folder The 'Website' folder contains information for website of the distributed applications and things like online version files, data files beloning to certain applications and so on 3. Zone folders Within the different 'Zone' folders there are folders named after the application they contain distribution packages for. Within the application folder there is a folder named after each version release number containing: ➢ A source package of that version of the application ➢ A folder for each distribution an installation package is made for ➢ (If needed) a gambas executable of that version of the application 1. Source package of that version of the application The source packages will enable you to revert back to a previous version of the application. 2. A folder for each distribution an installation package is made for The distribution specific folders will be made by the Gambas IDE upon making the packages if you select so. They will contain both installation and source packages specific to that distribution. 3. A gambas executable of that version of the application Executables make for easy quick testing by other developers or in a virtual machine. They are not always required but come in handy in some situations. 8 5. Some good practices Illustration 3: Application folder with version folders containing the packages Note that in Gambas 3 you can make packages for more than just the distributions shown above. 5.2 Project organisation Within the Gambas IDE you can also work on organising for your own benefit. It is good practice to make folders in there that contain specific data, like a folder for images or icons. This can all be done from within the Gambas IDE. Illustration 4: Organisation of a project folder in the Gambas IDE How this all is done will be discussed later in this guide. 5.3 Organising your code One very important aspect of building applications is to make sure you still understand what you where doing a year later, when you want to change parts of it or (re)use them somewhere else. 9 5. Some good practices The other thing is that, if you built your applications open source, it makes the code more readable to those looking at it. 5.3.1 Commenting your code A first good start is by putting comments into your code. Commenting in Gambas is easy. Just start the line with ' What could you comment about. Well this is what I tend to do: ➢ Identify each class and its function ➢ Describe the functionality of each block of code in one line of comment ➢ Write comments at parts that need improvement (including ideas on improvement) 1. Identify each class and its function This is an example of the identification comment in a class in one of my projects. ' Gambas class file ' ' --------------------------------------------------' Application: SysInfo ' Class: SysInfo ' Function: Library for system information retrieval ' Author: W.J.L. Raets ' GNU General Public Licence - Version 3 ' --------------------------------------------------You could include more in there like maintenance or revisions you do in the code and the date you did them. This is especially useful in projects where more that one persons works on the same project. This way all developers involved will have an idea on what has changed. But even in your own personal projects you might be happy someday when looking back at ½ year old code for having done this. 2. Describe the functionality of each block of code in one line of comment This again is an example of describing blocks of code by functionality in one of my projects (see next page). The (rest of code) blocks are quite long pieces of code, so I left them out. Without these simple comments dividing the code into parts that are coded in that specific area I would get lost in my own code. In the example on the next page I have made the comments bold. So don't be sparse with commenting your application. 10 5. Some good practices Static Public Sub ReadDesktopInfo() Dim sWinMan, sWinManAid, sDeskAid As String Dim iPosition, iPosB, iPosE, iSwitch As Integer '======== Find x window manager ============== Try Exec ["kwin", "--version"] To sWinMan ...(rest of code) Else CompWindowManager = Trim(sWinMan) Endif ' === Determine desktop based on window manager === Select sWinManAid Case "met" '---- metacity & Gnome 2 … (rest of code) Case "mut" '---- mutter & Gnome 3 … (rest of code) End 3. Write comments at parts that need improvement Again, this will only help you. I have had to deal with code that worked on certain distributions and gave errors on others. Being clear with comments on what distros gave trouble and needed further investigation enabled me to gradually get it working on all distros. Again an example of how that could look with the comments made bold. Static Public Sub ReadDbInfo() Dim sMySql, sSqlite, sPostGreSql As String Dim iPosB, iPosE As Integer 'Stable on most returned distros - LXDE a bit troublesome 'TODO: sqlite3 needs testing results returned for analysing 'TODO: figure out sqlite retrieval on an LXDE based desktop Try Exec ["mysql", "-V"] To sMySql '==check for Mysql == … (rest of code) End And believe me, one day when you look back at an application you built and forgot about you will be very happy with all your comments in your code. Some special keywords like 'TODO: in your comments will generate an inline task. This makes it easy tracking code, where things need to be done and also works very well as a reminder of things that still need to be done in your code. Later in this guide I will go into this a bit further in an example application. 5.3.2 Clear choices for names Picking the right names for variables you use in your code can make for more readable code. Two things I tend to do are: ➢ Pick a name that describes the content ➢ Begin the name with a lower case letter identifying the type of content it represents 1. Pick a name that describes the content 11 5. Some good practices Names of variables that suggest what their content will be, are easier to comprehend and remember when reading or writing many lines of code. In one of my applications I try to extract the window manger used on the system. An easy name for that could be WinMan. The name tells us that the information on window manger retrieved on the system will be stored in the variable named WinMan. 2. Begin the name with a lower case letter identifying the type of content it represents Going back to the previous example of the window manager being stored in a variable named WinMan it is best make some minor adjustment to the name to identify the type of content. The content that will be extracted from the system will contain text, so in Gambas it's type is String. Now to indicate that the variable WinMan will contain data of the type String I named it sWinMan. By putting a lower case 's' in front of 'WinMan' I identify the variable as being a string containing window manager information. In the course of this guide and all the examples you will get more examples on how you could use this to your benefit. 5.3.3 Indenting code Another good practice for clear and readable code is indenting code. For example say you want to check if some condition is met and do one thing or another depending on the result of the condition. In Gambas you would code this with an If ...Then .. .Else. Lets say you want to test if our sWinMan is empty or not. I will first give an example of less readable code without any indenting. Static Public Sub Test() Dim sWinMan As String sWinMan = TextBox1.Text If Len(sWinMan) = 0 Then sWinMan = “Unable to trace” Else sWinMan = Trim(sWinMan) Endif End Next the same code but with indenting applied for more readable and structured code. Static Public Sub Test() Dim sWinMan As String sWinMan = TextBox1.Text If Len(sWinMan) = 0 Then sWinMan = “Unable to trace” Else sWinMan = Trim(sWinMan) Endif End The indenting makes clear what part is executed if the condition is met and what part is executed if the condition isn't met. 12 5. Some good practices In the examples provided in this guide you will get to see more examples of indenting as I use it in all my coding. 5.3.4 Eliminate repeating code 1. Subroutines and functions When you find that you have code in a form class that repeats itself it would make for better and more readable code to abstract it into a subroutine or function that can be called. This also makes for easier maintenance for the code as you only need to change it at one place in your form class, instead of several. You will see examples of this in this guide. 2. Modules When you find that you have code in several form classes repeating itself or performing likewise tasks, try to abstract it and place it in a module. This way it can be used within the entire project. This also makes for easier maintenance of the code as you only need to change it at one place in the project instead on several forms classes. Modules are actually exported classes, that is why they work for the entire project. You will get to see some examples on using modules in this guide. 3. Classes Classes can be considered as the templates for objects. When having likewise code in modules in different applications you should consider making a new project and copying the module code into classes, abstract some code and finally Export these classes and make a library out of this application for installation on your or other people's system. Use this library in all the projects you have a need for its provided functionality. This also makes for easier maintenance of the code as you only need to change it in one project (the library) instead of in each project over and over again. The scope of this book does not cover libraries and classes, other than the Form classes. 13 6. A first GUI application: TextPlay 6 A first GUI application: TextPlay Lets get started with using Gambas 3 and build a first simple GUI application. 6.1 What will be done in this chapter Main focus will be creating a form with some controls, write some simple code for the controls and run the application. This will involve ➢ Opening Gambas IDE and make a new project ➢ Make a main form ➢ Place four controls on the form (Two buttons, a TextBox and a Label) ➢ Write some simple code ➢ Run the application from Gambas IDE You can learn about: ➢ How to make a new project in Gambas3 ➢ Working with the Gambas IDE ➢ Button, TextBox and Label controls ➢ Event driven programming, objects, methods and properties ➢ User interaction (input from user, output from application) 6.2 Starting a new project First you start Gambas from terminal or menu depending on how you installed it5. On first opening Gambas it should show the examples. Illustration 5: Gambas 3.4.1 opening screen 5 See 'How To Gambas 3 – Installing Gambas' 14 6. A first GUI application: TextPlay Now click on New Project... to make a new project. In the 'New project' screen you select the type of application you wish to build. Illustration 6: 'New project' screen step 1. Select the type of application Select Graphical application as that is what you are going to build, a GUI application. No further options need to be selected. Illustration 7: 'New project' screen step 2. Select the folder for the new project 15 6. A first GUI application: TextPlay Browse to the folder /Development/Gambas36 and select it. Now right click and select Create directory in the menu. Illustration 8: Create a new folder for Learning projects Name the folder Gambas3-Learning and select it. Illustration 9: Select the folder 'Gambas3-Learning' Next click button Next. 6 See 5.1. Folder organisation 16 6. A first GUI application: TextPlay In the 'New project' screen step 3 you can name both the folder where the project will be located and the name the actual application will have. They can be different if you like. Illustration 10: 'New project' screen step 3. Name the project folder and project For both 'Project name'7 and 'Project title'8 type TextPlay. Next click the button OK and you get a message a new project has been created. Illustration 11: Message when project has been created successfully 7 8 Name of the folder the project will be located in and the name of installed executable. Name of the actual application as used in a distro menu once installed. 17 6. A first GUI application: TextPlay After clicking OK the Gambas 3 IDE opens with a new empty project named TextPlay. Illustration 12: New project 'TextPlay' opened in Gambas 3 IDE You have just created a new project in Gambas for building a first GUI application. Each project opened in IDE has 4 major zones: ➢ Zone 1: Menu and toolbar zone ➢ Zone 2: Project browser ➢ Zone 3: Working area ➢ Zone 4: Debug area They will gradually make more sense when working with the examples that will be built in this guide. 6.3 Creating a form and controls Next step is to create a form with some controls on it. Since you chose to create a new 'Graphical application' a form is already in place named FMain9. You will find this form in the Project browser (zone 2) in the folder 'Sources'. Illustration 13: FMain in Sources folder of the project 9 Note the small black arrow in the project browser in front of the FMain icon. That arrow indicates that this form is the first one to run, after starting the application 18 6. A first GUI application: TextPlay Just double click Fmain and the empty form will be in the Working area (zone 3) Illustration 14: Empty form in IDE In the 'Working area' (zone 3) you see an empty form and at the right of it a box with 'Properties/Hierarchy'. Underneath the 'Properties/Hierarchy' you will find a ToolBox to build the controls. The ' Properties/Hierarchy' is only visible when forms are in the 'Working Area'. If code is viewed in the 'Working Area' there will be no ' Properties/Hierarchy' box nor Toolbox. 6.3.1 Placing controls on a form First you will place a Label on the form. For that you go to the ToolBox and hover your mouse over each of the icons until you find the 'Label' icon (a big A). 19 6. A first GUI application: TextPlay Illustration 15: Label icon in ToolBox Click on the Label icon and next drag a rectangle on the form. Illustration 16: Label control drawn on the form This should give you a Label control. Next search the ToolBox for a TextBox icon. Illustration 17: TextBox icon in ToolBox 20 6. A first GUI application: TextPlay Click on the TextBox icon and next drag a rectangle on the form. Illustration 18: TextBox control drawn on the form This should give you a TextBox control. Next search the Button icon in the ToolBox. Illustration 19: Button icon in ToolBox Click on the Button icon and drag two rectangles on the form. Illustration 20: Two button controls drawn on the form This should give you two buttons. 21 6. A first GUI application: TextPlay 6.3.2 A closer look at the controls First select the Label by clicking on it. The 'Properties/Hierarchy' Box will show properties of the selected control, Label1. You are about to change some of them and see what they do. Note that when you selected Label1 in the 'Properties/Hierarchy' Box it says 'Label1 Label' (Label1 is the name of the control and Label is the type of control). In the box below you can find Help on Label (gb.gui). First click on the 'Alignment' property on Normal and a selection box will appear. Select Right. Illustration 21: Select Alignment of the Label control 22 6. A first GUI application: TextPlay This will align the text of the label to the right. Illustration 22: Label1 aligned right Next go to the 'Text' property and click on Label1 and type Enter your name: Illustration 23: Label1 Text property changed You will see the typed text appear in your label on your form. Your label is now ready for use in the application. Label controls are usually used in combination with an input control. The Label is used to make clear what the input control is for and should contain. For example a Label could show 'Name', followed by an input control like a TextBox where the user can type his/her name. This doesn't mean you can use Labels otherwise. Next lets focus on the other controls by means of exercise. Here is what needs to be done: ➢ Select TextBox1 and empty the Text property. ➢ Select Button1 and change the Text property to 'Show'. ➢ Select Button2 and change the Text property to 'Clear'. Illustration 24: Controls after changing the properties Your end result should look like the illustration above. 23 6. A first GUI application: TextPlay 6.4 Coding, testing, coding, testing... Now that you have finished the making and customising of the form and controls focus will go to make it do something. 6.4.1 Objects, properties, events and methods You will first need to understand some basics before continuing. The form and all the controls you made are all objects. There are different kinds of objects. Like the form is an object, each control is an object, classes are objects. Some objects are creatable10, others are not. As you have seen objects have properties, but objects can also have events and methods. Properties are about the object. For example a Button control can have a property Text that contains the text shown on the Button. Events can happen to an object. For example a Button control can have the event click. This means that when this event happens to the object you can make something happen (in other word you need to code what needs to happen). Methods can be done by an object. For example a Button control has the method Show. You can use this method to show the Button or hide it. This is a very basic explanation, but enough to comprehend what you will be doing next. 6.4.2 Write some code and test (round 1) Now lets start with the fun part, the actual coding or writing Gambas code. This is what you want to happen when running your code: 1. You want to type your name in the TextBox. 2. When clicking on Button 'Show' you want a message box with the name typed in the TextBox. 3. When clicking on the Button 'Clear' you want to empty the contents of the TextBox. Let's analyse this and divide it into two pieces: 1. User input: - Type name - Click on Button Show - Click on Button Clear 2. Application output: - Message with name - Clear a TextBox In the user input you can see some events (or things that can happen to an object). Text being entered by the user in a TextBox and clicking on buttons. So these are events where you need to write your code. In the application output you see what needs to happen, so what you need to code. Now for the text being entered nothing realy needs to be coded as things happen when clicking the buttons. Clicking the Show button needs to show you a message box with the entered text. Clicking the Clear button needs to clear the entered text. 10 A "creatable" object is an object that can be instantiated by itself. 24 6. A first GUI application: TextPlay Right click on button Show, select Event → Click. Illustration 25: Select Event Click for button control This will open the FMain.Class in a new tab in the 'Working Area'. Illustration 26: FMain.class 25 6. A first GUI application: TextPlay As you see the cursor is positioned in Public Sub Button1_Click(). In short this means that this Subroutine (Sub) belonging to object Button1 and taking place on the Event Click is Public for Fmain.class. Write this code for Public Sub Button1_Click(): Public Sub Button1_Click() Message(TextBox1.Text) End The object named TextBox1 holds the text entered by the user in the property Text. To get there you write TextBox1.Text11. The method Message() displays a String value in a message box. Next double click FMain in the project browser (or click tab FMain.form) to go back to the form. Right click button Clear and select Event → Click. Write this code for Public Sub Button2_Click(): Public Sub Button2_Click() TextBox1.Text = “” End The = “” (2 times double quote) sets an empty string value (or Null value) to the TextBox1.Text property. Strings are anything in between double quotes. Note that copying the code with quotes into IDE will generate errors. You need to type the quotes in IDE. Next step is to test this little application. For this you go to menu Debug → Run (or hit F5 on your keyboard). Illustration 27: Menu Debug -> Run to test the application 11 You will notice when tying code in Gambas IDE you will get some help along the way. Like when typing the name of a control followed with a dot you will see all methods, functions, constants and properties of that control. 26 6. A first GUI application: TextPlay Now lets see if the application does what you want it to do. Enter your name in the TextBox and click Show. A message with the entered name will appear. Click OK to close the message. Illustration 28: Application running with message shown Next click Clear and the TextBox will be empty. So all seems to work as expected, but that doesn't mean you are ready yet as there certainly is some room for improvement. 6.4.3 Code some improvements and test (round 2) As you have seen the message box centres on the screen, the application is on the top-left of the screen. It would look nicer if the application was centred on the screen as well. Another thing that would be nice is that, in case no text is entered and the show button would be clicked the message would ask you to enter some text first. So these added requirements will mean you need to code some event belonging to Fmain to make it appear centred on the screen. To figure out what event to code for Fmain simply select Fmain (in case a control is selected simply click on an empty space on the form to select it), right click and select menu Event → Open. You will need the event Open because you want the form to centre when it opens12. Write this code for Public Sub Form_Open(): Public Sub Form_Open() Me.Center End Me refers to Fmain. Center is the method that will center FMain. 12 Another option is to simply double click the form to go to Form_Open() 27 6. A first GUI application: TextPlay You will also need to add a test to the Click event for button Show to act one way or the other depending on the result of the test. What needs testing is if text has been entered into TextBox1. So you need to check the property Text if it is empty or not. Change the code for Public Sub Button1_Click() to: Public Sub Button1_Click() If IsNull(TextBox1.Text) Then 'Test if name entered Message(“First fill in a name”) Else Message(“The name entered is “ & TextBox1.Text) Endif End IsNull(TextBox1.Text) will test if TextBox1.Text is empty13 and return True if it is. If true a message will tell you to first fill in a name. If false the name will be shown, but a bit more nicer this time. Note: If IsNull(TextBox1) Then is the same as: If IsNull(TextBox1.Text) = True Then. IsNull() is a datatype function of type Boolean, meaning it will be true or false. Depending on the expression tested. IsNull(expression) Returns True if expression is NULL. NULL means: - The NULL constant - A null object reference - A zero length string - A null date - An uninitialized variant More on IsNull() see http://gambasdoc.org/help/lang/isnull?ja&v3 If expression Then..Else..Endif Behind If you need a test (expression) that returns a Boolean (True/False) The code for Then is run when test returns true. The code for Else is run when test returns false. Endif ends the code block. You can use logic operators (like And and Or) in the expression to test for more than one condition. More on If see http://gambasdoc.org/help/lang/if?v3 Message() needs to contain string values. Text between quotes is considered string as is the content of a Text property. To connect them together to one string you use &. Next it is time to test. Press F5 and next click the button Show. 13 A TextBox with a space entered by the user might look empty but actually isn't as it is not equal to Null (it contains a space and thus as string looks like “ “ and has a length of 1 instead of looking like this “” with a length of 0). 28 6. A first GUI application: TextPlay Illustration 29: Message when no name entered As you can see the application is now centred on the screen. Clicking Show results in a message to first fill in a name. Now click OK enter a name and click Show again. Illustration 30: Message when name entered You see this results in a nicer result than in the first round of testing. Congratulations, you have just build a first GUI application in Gambas 3. Now close the project in menu File → Quit. This will also close Gambas and set you at the point to start for the next chapter. 29 7. Extending application TextPlay 7 Extending application TextPlay 7.1 What will be done in this chapter Main focus will be on adding some more controls and code to further explore Gambas and run the application. This will involve: ➢ Open an existing project for changes ➢ Add new controls (Radio Button, CheckBox, TextArea, Frame) ➢ Add/change code to events of some of the controls ➢ Run the application from IDE You can learn about: ➢ Working with the Gambas IDE ➢ More controls ➢ More properties, events and methods ➢ User interaction 7.2 Open an existing project First you start Gambas and it should open on the Recent Projects tab. If not click on it. Illustration 31: Gambas welcome screen 'Recent projects' The project TextPlay should be in the list somewhere on top if recently opened14. Click on TextPlay to open in IDE. 14 Or it could be the only application in there if TextPlay is your first Gambas 3 application. 30 7. Extending application TextPlay 7.3 Modify main form and add controls Next step will bring us back to Fmain to redesign the form for some additional controls to be added later. To get get there just double click Fmain in the project browser. Once you have the FMain in the 'Working Area' move your mouse to middle of the right border of the form. Illustration 32: Mouse appearance will change where the pointer is Your pointer will change appearance and you will be able to drag the form wider. So drag the form a bit wider. Illustration 33: Form dragged wider and Label and TextArea selected Next click the Label, hold down ctrl key and click the TextBox. 31 7. Extending application TextPlay This will select both of them and you will be able to drag them a bit to the left, as there is still some room left over. Illustration 34: Drag the buttons to the bottom of the form Next select button Show, hold ctrl key and select button Clear. Drag them to the bottom of the form. Illustration 35: Result after adapting the form Your form should look like in the illustration above. 32 7. Extending application TextPlay 7.3.1 Copy controls on the form In the next step you are going to add a Label, TextBox and a Button to the form. Instead of using the ToolBox and draw them you will simply copy and paste existing controls on the form. For this first select the Label and TextBox and next press ctrl+c (to copy the controls). Next press ctrl+v (to paste the controls on the form). Illustration 36: Pasted controls on the form Now drag the newly pasted controls below the ones already there. Illustration 37: Controls dragged to the spot you need them Next select one of the buttons, copy/paste it and drag it to the bottom-left of the form. Illustration 38: Result after copy/pasting all needed controls 33 7. Extending application TextPlay 7.3.2 A closer look at the controls Now that all the new controls are in place lets have a closer look at some of their properties. First select the most top Label and check its Name property, Alignment property and Text property in the 'Properties/Hierarchy' Box. Now select the other Label and do the same check. You will find one Label named Label1, the other named Label2. All other properties (except for X and Y location on the form) are copied from Label1 to Label2 during the Copy/Paste of Label1. When copy/pasting controls their name will always be a copy of the name of the original control with an added number. The number will be one higher than the previous one. Example: If you copy/paste Label1, the copy will be named Label2. If you next copy/paste either Label1 or Label2 the next copy will be named Label3 Select the Text property for Label1 and type Enter your first name: Illustration 39: Label1 after changing the Text property Next select TextBox1. Change the Name property to tbxFirstName. Next select TextBox2 and change the name property to tbxName. Illustration 40: Name properties of both TextBoxes changed Some more adaptations as a little exercise: - Change the Name properties of the left button to btnShow - Change the Name properties of the middle button to btnClear - Change the Name properties of the right button to btnAdd - Change the Text properties of the right button to Add 34 7. Extending application TextPlay Illustration 41: Main form after the changes in the exercise In case I do not use the name of a control on a form in code I will keep the original name given to the control when first drawn on the form (or copied onto the form). In case I am going to use the name of the control in code, I like to have a name that makes some sense. Two things are important to me: 1. I would like to know the type of control 2. I would like to get an idea what the control is for For this I have developed my own system, based on the naming of variables according to type (see 5.3.2 Clear choices for names). I use three lower case letter to identify the type of control, next a Capital letter followed by lower case identifying the purpose of the control. Some examples: TextBox1 → tbxFirstName Button1 → btnShow Label3 → lblResult TextArea1 → txaResult CheckBox1 → cbxShow1 RadioButton1 → rbnYes You will get to see more of this as the guide continues. If all changes are met have a look at the FMain.class. Click the tab Fmain or in the project browser right click FMain and select Edit code 35 7. Extending application TextPlay Illustration 42: Names of buttons changed in Fmain.class as well You will notice that changing the name properties for Button1 and Button2 also changed their names in the FMain.class. Be aware that, when changing a Name property of a control on a form, only the form class the control belongs to, will change the name in code as well. Now two more things are left to do and they make for a great exercise as well: - Add a Label (below tbxName) to the form, name it lblResult - Add a TextBox (below lblResult) to the form, name it tbxResult and set ReadOnly to True - Add a TextArea (below tbxResult) to the form, name it txaResult and set ReadOnly to True - Empty the Text property of lblResult and txaResult Illustration 43: Main form after adding two more controls The result should look like the illustration above. 36 7. Extending application TextPlay 7.4 Coding, testing and adapting In this part you are first going to add new code, test it, improve it, test it again as so on. You will not always start with the best solution but gradually work towards one and this is done on purpose (you will be seeing more of that). This way you will learn what can and can't be done in Gambas. You will learn what can go wrong and how to fix it. It is like learning to ride a bicycle, it is falling down that makes for a greatest learning curve. 7.4.1 Coding and testing (round 1) First focus will be to make the Add button do something. Since there are two input fields now (tbxFirstName and tbxName) it would be nice to let the Add button 'add' both names together and show them in lblResult, tbxResult and tarResult. Let's code for this. Select button Add, right click and go to Event → Click Type following code for Public Sub btnAdd_Click() Public Sub bntAdd_Click() Dim sResult As String sResult = tbxFirstName.Text & “ “ & tbxName.Text lblResult.Text = sResult tbxResult.Text = sResult txaResult.Text = sResult End Dim (short for Dimension) is to declare local variables and their types. In Gambas you always need to declare your variables before you can use them in your code. The & is used to add different strings together to one string. In this case the string in tbxFirstName.Text followed by a space (“ “) and the string in tbxName.Text. The space is to separate the first name from the name. Now run the project type in your first name and name and click Add to see what happens. Illustration 44: Result after clicking button Add Now click Clear and see what happens. As it seems only the first name gets cleared. It would be nice if not only first name gets cleared but name and the results as well. 37 7. Extending application TextPlay Next click in the first name box and press Tab key a few times. The order of how Tab jumps from one control to the other can be determined by you. So here is two points for change. Note the difference in how the result is shown in lblResult, txbResult and txaResult. Also note that the lblResult, tbxResult and txaResult are not editable, meaning you can't change the content. For tbxResult and txaResult you needed to set property ReadOnly to True. Labels don't have a ReadOnly property as they are default read only. 7.4.2 Adapting, coding and testing (round 2) First have a look at the order controls will be selected when using the Tab key. For this go to the 'Properties/Hierarchy' Box of Fmain and click on the Tab Hierarchy. Illustration 45: Hierarchy of the controls on main form You can select a control in the Hierarchy Box and move it up or down, changing the order it will be selected. The only fields that need to be 'Tabbed' are FirstName, Name and the three buttons. So move them up in the hierarchy. Label1 and Label2 are of no importance so move them down. Illustration 46: Hierarchy after adaptation 38 7. Extending application TextPlay Next click on the Properties Tab and select Label1, Label2, lblResult, tbxResult and txaResult. In the properties scroll to the property NoTabFocus and set this to True Illustration 47: Set selected controls NoTabFocus property to True This should take care of the Tab key order. Now lets have a look at the code of btnClear and adapt it to meet your requirements. Change code for Public Sub btnClear_Click() to: Public Sub btnClear_Click() 'tbxFirstName.Text = “” tbxFirstName.Text = Null tbxName.Text = Null lblResult.Text = Null tbxResult.Text = Null txaResult.Clear End The ' before tbxFirstName.Text = “” makes the line a comment. So it will not be executed. Here you just try another manner of clearing the content using Null. When replacing a piece of code with new code a good practice is to comment the old code rather than deleting it. Next write the new code below the commented code. If the new code turns out to be problematic or buggy, you can delete the new code and remove the comments from the old one, rather than having to code it all over again. If the new code turns out a success you could consider removing the old (commented) code. The txaResult could be cleared using txaResult.Text = Null but I wanted to show you another way of clearing content. Just play around with the different options and see what works and what doesn't if you want to learn some more. One more feature would be nice to add. When clicking Add if one of the name boxes is empty you should be told that it is empty and set the focus on that box. For this you will need to adapt the code for the btnAdd. Change the code for Public Sub btnAdd_Click() to: 39 7. Extending application TextPlay Public Sub bntAdd_Click() Dim sResult As String If IsNull(tbxFirstName.Text) Then Message(“Fill in first name”) tbxFirstName.SetFocus Else If IsNull(tbxName.Text) Then Message(“Fill in name”) tbxName.SetFocus Else sResult = tbxFirstName.Text & “ “ & tbxName.Text lblResult.Text = sResult tbxResult.Text = sResult txaResult.Text = sResult Endif Endif End First you test if tbxFirstName is empty. If so a message will be displayed and focus will be set to First Name box (tbxFirstName.SetFocus → SetFocus is a method that gives focus to the control). If tbxFirstname is not empty you test if tbxName is empty. If so a message is displayed and focus is set to the Name box. If tbxName is not empty the result will be shown. As you can see you can use an If..Then..Else in another If..Then..Else.. Indenting will make clear where each block of the If..Then..Else.. is resided. Now it is time to run the application. First click on Add without entering names. See what happens. Next enter a name for First Name and click Add and see what happens. Illustration 48: Clicking Add without filling in a name 40 7. Extending application TextPlay Next enter a name for Name and click Add and see what happens. Next click the Clear button and see what happens. If all is well the code should be working as supposed to. 7.4.3 Adding new controls, code and test (round 3) For the next part you need to go back to the form design. Place three CheckBoxes and three RadioButtons on the form. Illustration 49: Three CheckBoxes and three RadioButtons Next run the application and click on the three CheckBoxes, then click on the three RadioButtons and note the difference. Illustration 50: All CheckBoxes selected, only one RadioButton Where all three CheckBoxes can be selected only one RadioButton can at any given time. Keep that in mind. Now back to form design. 41 7. Extending application TextPlay Here is what you need to do (yes, exercise time): - Change RadioButton1 name properties to rbtLine1, Text properties to 1 Line - Change RadioButton2 name properties to rbtLine2, Text properties to 2 Lines - Delete RadioButton3 - Change CheckBox1 name properties to cbxFirstName, Text properties to Add - Change CheckBox2 name properties to cbxName, Text properties to Add - Change CheckBox3 Visible property to False What you require is when 1 Line is selected clicking the button Add shows the information in 1 Line. When 2 Lines is selected clicking the button Add shows the information in two lines. But that is not all. First name will only be added if cbxFirstName is selected, Name will only be added if cbxName is selected. Next you need to code Add button to incooperate the new requirements. When a CheckBox is selected its value is set to -1, if it is deselected its value is set to 0. When a RadioButton is selected its value is set to True, if not selected it is set to False. So this is what you need to to be able to test what needs to be done. Lets take it step by step. First you code for the RadioButtons to work. Change the code for Public Sub btnAdd_Click() to: Public Sub bntAdd_Click() Dim sResult As String If IsNull(tbxFirstName.Text) Then Message(“Fill in first name”) tbxFirstName.SetFocus Else If IsNull(tbxName.Text) Then Message(“Fill in name”) tbxName.SetFocus Else If rbtLine1.Value Then sResult = tbxFirstName.Text & “ “ & tbxName.Text Else sResult = tbxFirstName.Text & “\n“ & tbxName.Text Endif lblResult.Text = sResult tbxResult.Text = sResult txaResult.Text = sResult Endif Endif '1 line selected '2 lines selected '\n generates a new line End As you can see only rbtLine1 gets tested. As there are only two RadioButtons one of them will always be selected. So if rbtLine1 is not selected rbtLine2 is. Run and see if this first part of code does the job. Just see what happens and pay special attention to the different result outputs when 2 Lines is selected. 42 7. Extending application TextPlay Illustration 51: Result of 2 lines selected As you can see in the illustration above a TextBox can not hold two lines off text. Both Label and TextArea can. The strange character in the TextBox is the line feed shown (“\n”). Next lets add the code for the CheckBoxes and remove the TextBox as it is of no use any longer. Back to Form design: - Remove tbxResult - Check Fmain.class code if tbxResult is used and remove if needed. Again a nice exercise. And if you might forget to remove tbxResult from code some where, don't worry, IDE will tell you once you try running the application. Just so you know. Next change the code for Public Sub btnAdd_Click() to: Public Sub bntAdd_Click() Dim sResult As String Dim iSwitch As Integer 'iSwitch will be used to determine what needs to be shown iSwitch = 0 ' 'Test if first name needs to be added before checking if field is empty If cbxFirstName.Value = -1 Then If IsNull(tbxFirstName.Text) Then Message(“Fill in first name”) tbxFirstName.SetFocus iSwitch = -1 Else iSwitch = 1 Endif Endif 43 7. Extending application TextPlay 'Test if Name needs to be added before checking if field is empty If iSwitch <> - 1 Then If cbxName.Value = -1 Then If IsNull(tbxName.Text) Then Message(“Fill in name”) tbxName.SetFocus iSwitch = -1 Else If iSwitch = 1 Then iSwitch = 12 Else iSwitch = 2 Endif Endif Endif Endif ' 'Check iSwitch what needs to be done If iSwitch <> -1 Then Select iSwitch Case 1 'Show first name sResult = tbxFirstName.Text Case 2 'Show name sResult = tbxName.Text Case 12 'Show first name and name If rbtLine1.Value Then 'Check for 1 line sResult = tbxFirstName.Text & “ “ & tbxName.Text Else sResult = tbxFirstName.Text & “\n“ & tbxName.Text '\n generates a new line Endif End Select lblResult.Text = sResult txaResult.Text = sResult Endif End iSwitch is set to -1 every time one of the name boxes needs to be filled in and gets the focus. In such a case nothing further needs to be tested or shown. Select expression Case expression End Select Select enables you to test for different results of one and the same expression. Behind Case you need an expression Each Case can be tested against the expression behind Select (as long as types match). You can use Case Else for all other outcome if needed End Select ends the code block. Expression in example code above is iSwitch of type Integer. So behind the Case you need an Integer value or expression to test possible outcome of iSwitch. More on select see http://gambasdoc.org/help/lang/select?v3 44 7. Extending application TextPlay In an expression you can use operators to make comparisons. a < b → a smaller than b a = b → a equals b a <= b → a smaller than or equal to b a > b → a bigger than b a >= → a equal to or bigger than b a <> b → a different from b You can compare both number values and strings. For strings alphabetic order is used to determine outcome. 10 = 11 → returns false 10 < 11 → returns true “Word” = “None” → returns false “Word” = “Word” → returns true “Word” < “None” → returns false “Word” >= “None” → returns true More on operators evaluation order see http://gambasdoc.org/help/lang/evalorder?v3 More on string operators see http://gambasdoc.org/help/cat/stringop?v3 More on arithmetic operators see http://gambasdoc.org/help/cat/arithop?v3 Now back to running the project. If you get errors you probably forgot to remove tbxResult somewhere in the code. Fix it. Type a first name and a name and select only first name to add. Next click Add and see what happens. Now select name to add and deselect first name. Click Add and see what happens. Now select both and click Add to see what happens. Illustration 52: Clicked button Add with only Name selected It should all work as expected. 45 7. Extending application TextPlay 7.4.4 Add some last controls, code and test (round 4) Lets complicate things a bit more by adding some more requirements. First you would like to enter Country as well, and have a CheckBox to Add. Further more you would like the option to present the information in 3 lines as well. And last, but not least, you want to be able to determine what to Show when clicking button Show. Outcome could be either first name, name or country. So lets start with yet another exercise: - Place a new Label and TextBox below Label2 and tbxName to hold the country information - Name the new TextBox tbxCountry - Adapt the properties of both controls to confirm to those of Label2 and tbxName - Add a new RadioButton and name it rbtLine3 - Change rbtLine3 properties to confirm to the other two RadioButtons - Make CheckBox3 visible again and name it cbxCountry - Adapt properties to confirm to the other CheckBoxes As you might notice the instructions get less detailed, so more will be up to you. This is done intentionally. Just follow the logic of name and text properties already on the form and see if you manage. Don't forget to check the hierarchy of the controls on the form! Illustration 53: New controls added and adapted First let's focus on code to make tarResult show proper text when clicking btnAdd. For this you will need to add some code to the btnAdd_Click routine. Public Sub bntAdd_Click() Dim sResult As String Dim iSwitch As Integer 'iSwitch will be used to determine what needs to be shown iSwitch = 0 46 7. Extending application TextPlay ' 'Test if first name needs to be added before checking if field is empty If cbxFirstName.Value = -1 Then If IsNull(tbxFirstName.Text) Then Message(“Fill in first name”) tbxFirstName.SetFocus iSwitch = -1 Else iSwitch = 1 Endif Endif ' 'Test if Name needs to be added before checking if field is empty If iSwitch <> - 1 Then If cbxName.Value = -1 Then If IsNull(tbxName.Text) Then Message(“Fill in name”) tbxName.SetFocus iSwitch = -1 Else If iSwitch = 1 Then iSwitch = 12 Else iSwitch = 2 Endif Endif Endif Endif '--------- ADDED CODE -----'Test if Country needs to be added before checking if field is empty If iSwitch <> - 1 Then If cbxCountry.Value = -1 Then If IsNull(tbxCountry.Text) Then Message(“Fill in a country”) tbxCountry.SetFocus iSwitch = -1 Else If iSwitch = 1 Then iSwitch = 13 Else If iSwitch = 2 Then iSwitch = 23 Else If iSwitch = 12 Then iSwitch = 123 Else iSwitch = 3 Endif Endif Endif Endif Endif Endif '---------- END ADDED CODE ------ 47 7. Extending application TextPlay ' 'Check iSwitch what needs to be done If iSwitch <> -1 Then Select iSwitch Case 1 'Show first name sResult = tbxFirstName.Text Case 2 'Show name sResult = tbxName.Text Case 12 'Show first name and name rbtLine1.Value Then 'Check for 1 line sResult = tbxFirstName.Text & “ “ & tbxName.Text Else sResult = tbxFirstName.Text & “\n“ & tbxName.Text '\n generates a new line Endif '----------- ADDED CODE -----------------Case 3 'Show country sResult = tbxCountry.Text Case 13 'Show first name and country If rbtLine1.Value Then 'Check for 1 line sResult = tbxFirstName.Text & “ “ & tbxCountry.Text Else sResult = tbxFirstName.Text & “\n“ & tbxCountry.Text Endif Case 23 'Show name and country If rbtLine1.Value Then 'Check for 1 line sResult = tbxName.Text & “ “ & tbxCountry.Text Else sResult = tbxName.Text & “\n“ & tbxCountry.Text Endif Case 123 'Show first name, name and country If rbtLine1.Value Then 'Check for 1 line sResult = tbxFirstName.Text & “ “ & tbxName.Text & “ “ & tbxCountry.Text Else If rbtLine2.Value Then 'Check for 2 lines sResult = tbxFirstName.Text & “ “ & tbxName.Text & “\n “ & tbxCountry.Text Else sResult = txbFirstName.Text & “\n“ & txbName.Text & “\n “ & txbCountry.Text Endif Endif '----------- END ADDED CODE -----------------End Select lblResult.Text = sResult txaResult.Text = sResult Endif End Next add one line of code to the btnClear_Click routine 48 7. Extending application TextPlay Public Sub btnClear_Click() 'tbxFirstName.Text = “” tbxFirstName.Text = Null tbxName.Text = Null '– ADDED CODE -tbxCountry.Text = Null '-- To clear the checkboxes cbxFirstName.Value = 0 cbxName.Value = 0 cbxCountry.Value = 0 '– END ADDED CODE -lblResult.Text = Null tbxResult.Text = Null txaResult.Clear End Time to test the application. Hit F5 to run the application. Fill in some values and check if everything works as expected. Illustration 54: Testing the new code Also try using the button Clear to see if everything clears up well. Everything should work just fine, if not check your code to see if you haven't made a mistake somewhere. Now let's focus on the last requirement: you want to be able to determine what to Show when clicking button Show. Outcome could be either first name, name or country. With current controls on the form there is no way to determine what to show when clicking button Show. You will need some extra RadioButtons to get that job done. Add three RadioButtons behind the three CheckBoxes. Next run the application and select one of them. What happens and why? Try answering this for yourself before reading further. 49 7. Extending application TextPlay You will probably have noticed that when clicking on one of the newly added RadioButtons the RadioButton selected at lines group gets deselected. Illustration 55: Selecting RadioButton 'Show' deselects RadioButton '1 line' Remember page 41: “Where all three CheckBoxes can be selected only one RadioButton can at any given time. Keep that in mind.” All RadioButtons act like this when being in the same container. And for a RadioButton that makes sense as you only want one to be selected. In this case your form is the container of the placed RadioButtons and since all the RadioButtons are in the same container only one can be selected. So what you need is a separate container to hold your newly added RadioButtons. First rename the RadioButtons to rbtShow1, rbtShow2 and rbtShow3. Next select them and do ctrl+x (or right click and select cut in menu). Illustration 56: ToolBox tab Container showing Frame Next select the Tab container in the ToolBox and click on Frame. Drag a frame on the form where the cut RadioButtons used to be and name it frmShow. Set the Text to “Show”. 50 7. Extending application TextPlay Illustration 57: Frame Show placed on form Now with the frame selected do ctrl+v (or right click and select paste in menu) Illustration 58: RadioButtons pasted into Frame Show Now run the application again and see what happens. You should be able to click the Show RadioButtons independently from the one for lines. Containers Containers make it easy to manage controls that belong together. If you drag the frame over the form all controls within the frame will be dragged along as they are in the container. When for example you need certain controls visible under certain conditions, place them in one container. Next you can make them visible or invisible just by setting the Visible property of the container, instead of setting the Visible property of each individual control. A Frame is a container with edges borders and a label. More on Frame see http://gambasdoc.org/help/comp/gb.qt4/frame?v3 Back to design place the Line RadioButtons in their own frame as well. Name the Frame fraLines with Text Lines 51 7. Extending application TextPlay Consider it good practice to always place RadioButtons in their own container. In time you will find out this has his advantages When completed your result should look something like the illustration below. Illustration 59: All RadioButtons placed in their Frames Now let's recode the btnShow event click to meet our requirements (code see next page). Illustration 60: RadioButtons show working as supposed Now run and test the result. If all is well it should work. 52 7. Extending application TextPlay Public Sub btnShow_Click() If rbtShow1.Value Then If IsNull(tbxFirstName.Text) Then Message(“First fill in a first name”) Else Message(“The name entered is “ & tbxFirstName.Text) Endif Else If rbtShow2.Value Then If IsNull( tbxName.Text) Then Message(“First fill in a name”) Else Message(“The name entered is “ & tbxName.Text) Endif Else If IsNull( tbxCountry.Text) Then Message(“First fill in a country”) Else Message(“The name entered is “ & tbxCountry.Text) Endif Endif Endif End 7.5 A last review of the application In this last part of this chapter you are going to review your application and see if it can be simplified and made more friendly in use. 7.5.1 Do you need a button Show? That is a very good question. You have made an application where you first need to select what to show and then click the button Show to make it show. So, could you not simply select what to show and it shows? That is for you to figure out. Start with deleting the button Show. Now think about the next three questions and see if you can answer them: - When do you want this to happen? - Where do you want this to happen? - Do I have usable code in my project I can simply copy/paste? The answer to the first question will give you the event to code, the second one the object(s) to code (read: controls). Take a moment to think about this and try to solve it yourself, before continuing to the answer. A positive answer to the third question will make for a quick redo to meet the new demands. Think about this as well and solve it yourself, before going to the answer. 7.5.2 Could iSwitch format be more clear? As you gave seen you have used the variable iSwitch to be set accordingly to selections made in the add CheckBoxes to determine what needs to be show in the Label and TextArea. These are the values of iSwitch and what they represent: Value Represents 1 first name → 1 line 53 7. Extending application TextPlay 12 first name and name → 1 or 2 lines 2 name → 1 line 23 name and country → 1 or 2 lines 123 first name, name and country → 1, 2 or 3 lines If you would add a next field the Value of iSwitch would get more complicated. So thinking about these values and their format is something that can make life easier in a later stage of development when things need to be added or changed. So here are some more questions to think about: - What format could do better? - Can the current variables type (Integer) hold the improved format? The answer to the first question will determine the outcome of the second. Again, think about this as well and solve it yourself, before going to the answer. 7.5.3 Should the button Add be enabled if no Add is checked? Again, good question. Should it be enabled or would it be better to enable it when a Add gets checked and disabled when no Add is checked? Again think about the next two questions and see if you can answer them: - When do you want this to happen? - Where do you want this to happen? The answer to the first question will give you the event to code, the second one the object to code. Take a moment to think about this and try to solve it yourself, before continuing to the answer. 7.5.4 Should the button Clear be enabled if there is nothing to clear? The questions keep coming. Wouldn't it be better to have button Clear enabled when TextArea and Label have content and have it disabled when no content present? And again think about the next two questions and see if you can answer them: - When do you want this to happen? - Where do you want this to happen? The answer to the first question will give you the event to code, the second one the object to code. Take a moment to think about this and try to solve it yourself, before continuing to the answer. 7.6 Answers to the last review Here you will find all answers to the questions posed in 7.5. Make sure that you have first tried to solve the answers yourself and don't be afraid of failure. There is no such thing as failure, only lessons to be learned. And discovering how to do these thing yourself by failing and trying all over again is the method with the biggest learning curve that sticks the longest. This is one of the main reasons I choose to start examples with code that can be improved and show you the improvements step by step. In this way they will make more sense. So after you tried and succeeded or not have a look at how I did it and keep in mind that there are other possibilities as well. You might have solved it differently and have it working just as well. 7.6.1 Do you need a button Show? Judging the illustration on the next page I would say you don't. 54 7. Extending application TextPlay Illustration 61: No button Show but still doing the same job The questions and their answers: - When do you want this to happen? → As soon as one of the RadioBoxes in Frame show is clicked → RadioBoxes Click event - Where do you want this to happen? → On rbtShow1, rbtShow2 and rbtShow3 - Do I have usable code in my project I can simply copy/paste? → parts of the btnShow code are usable Code example: Public Sub rbtShow1_Click() If IsNull(tbxFirstName.Text) Then Message(“First fill in a first name”) Else Message(“The first name entered is “ & tbxFirstName.Text) Endif End Public Sub rbtShow2_Click() If IsNull(tbxName .Text) Then Message(“First fill in a name”) Else Message(“The name entered is “ & tbxName.Text) Endif End 55 7. Extending application TextPlay Public Sub rbtShow3_Click() If IsNull( tbxCountry .Text) Then Message(“First fill in a country”) Else Message(“The country entered is “ & tbxCountry.Text) Endif End Code, run and test is all that is left. 7.6.2 Could iSwitch format be more clear? It sure can be more clear. Let's look at the questions and their answers: - What format could do better? → Example: 100 → first item needs to be shown 110 → first and second item need to be shown 111 → all items need to be shown 001 → third item needs to be shown 101 → first and third item needs to be shown …. - Can the current variables type (Integer) hold the improved format? → No it can't, you would need a String, because in Integer 001 would become 1. You want it to remain 001, hence a String and in code quote “001”!! Feel free to adapt your code to meet the new requirements. Make sure to change iSwitch into String and adapt all 1, 12, 2, 23, 13 and 123 values accordingly. Change the iSwitch -1 value to “000”, indicating nothing to be shown. 7.6.3 Should the button Add be enabled if no Add is checked? No it should not be enabled. Again let's have a look at the questions and answers: - When do you want this to happen? → When form opens, no Add is checked so button should be disabled → Form open event → When one of the Add gets checked button should be enabled → CheckBox Click event → When all Adds get deselected the button should disable → CheckBox Click event - Where do you want this to happen? → On Fmain and cbxFirstName, cbxName and cbxCountry Code to disable the button Add on opening the form: Public Sub Form_Open() Me.Center btnAdd.Enabled = False End Code to enable disable button Add when clicking cbxFirstName, cbxName or cbxCountry: As you will notice in code below, you can run code from one routine (being cbxFirstName_Click) from another routine (being cbxName_Click and cbxCountry_Click). 56 7. Extending application TextPlay Public Sub cbxFirstName_Click() If (cbxFirstName.Value = 0) And (cbxName.Value = 0) And (cbxCountry.Value = 0) Then btnAdd.Enabled = False Else btnAdd.Enabled = True Endif End '– Since code for other checkboxes is same use cbxFirstName_Click routine to do the job -Public Sub cbxName_Click() cbxFirstName_Click End Public Sub cbxCountry_Click() cbxFirstName_Click End You will get to see more of this further in the guide. For now just knowing that it is possible will do. 7.6.4 Should the button Clear be enabled if there is nothing to clear? No it should not be enabled. And again let's have a look at the questions and answers: - When do you want this to happen? → When form opens, no content so button should be disabled → Form open event → When Text is Added button should be enabled → btnAdd Click event → When Text is Cleared button should be disabled → btnClear Click event - Where do you want this to happen? → On Fmain and btnAdd and btnClear Code to disable the button Clear on opening the form: Public Sub Form_Open() Me.Center btnAdd.Enabled = False btnClear.Enabled = False End Add this code to the btnAdd_Click event: 57 7. Extending application TextPlay Public Sub btnAdd_Click() …. ….. Endif '– Add this line at the end of the routine btnClear.Enabled = True End Add this code to the btnClear_Click event: Public Sub btnClear_Click() …. ….. tarResult.Clear '– Add this at the end of the routine '– You need to set the focus to another control before disabling btnClear as it has the focus btnAdd.SetFocus btnClear.Enabled = False End Since btnClear has the focus when being clicked and you can't disable a control that has the focus you need to set the focus to another control before disabling btnClear. You will notice that upon clicking clear, the Adds are deselected by code resulting in the Add button being disabled as well. In this example that is just perfect. You probably didn't expect that to happen, but you did code for it. But it is a good demonstration of event driven programming. One event can trigger a next event, that can trigger a next event. So keep your mind to it not to end up with unwanted side effects coming from parts of could you would never look for. Now close the project in menu File → Quit. This will also close Gambas and set you at the point to start for the next chapter. 58 8. Your second application: TextPlayT(w)o 8 Your second application: TextPlayT(w)o 8.1 What will be done in this chapter Main focus will be string functions, for that you will built a new application. This will involve ➢ Opening Gambas IDE and make a new project ➢ Make a main form ➢ Place fourteen controls on the form (1 TextArea, 5 TextBoxes, 2 buttons, 1 frame, 2 RadioButtons, 1 ValueBox, 2 labels) ➢ Make a search and replace form ➢ Place four controls on the form (2 TextBoxes, 2 buttons) ➢ Write some code ➢ Run the application from Gambas IDE You can learn about: ➢ Working with the Gambas IDE ➢ Working with more than one form ➢ How to interact between forms ➢ Meaning of Subroutines, Public and Private ➢ Working with numbers ➢ Working with String functions to search and replace text ➢ Working with String functions to split text and more ➢ User interaction (input from user, output from application) 8.2 Start a new project and design the first form Open Gambas3 IDE and start a new graphical application project named TextPlayT(w)o. Right click Fmain and select Rename.. in the menu and name it FrmMain. Place following controls on FrmMain with some properties pre-set: 1 TextArea: Name → txaContent; Text → empty 1 Label: Text → Split character; Alignment → Right 1 TextBox: Name → tbxSplit ; Text → empty 1 Label: Text → Number of splits; Alignment → Right 1 ValueBox: Name → vbxSplit 1 Button: Name → btnSplit; Text → Split 4 TextBoxes: Name → tbxLine1...tbxLine4; Text → empty; ReadOnly → True 1 Frame: Name → fraSearch; Text → Search or Search/Replace; Enabled → False 1 RadioButton (in fraSearch): Name → rbtSearch; Text → Search 1 RadioButton (in fraSearch): Name → rbtReplace; Text → Search/Replace 1 Button: Name → btnSearch; Text → Search; Enabled → False When finished with placing all controls and setting all properties accordingly you should have something like in the illustrations on the next page. First illustration (62) shows the form in the IDE designer. Second illustration (63) shows the form when run. 59 8. Your second application: TextPlayT(w)o Illustration 62: Main form in IDE design mode Illustration 63: Main form when run from IDE 8.3 Playing with text the other way around In TextPlay(w)o you are going to start with doing the opposite of TextPlay. In TextPlay you had input in TextBoxes and it was put together in a TextArea. In this example you will get your input in the TextArea (one big string) and need to split it to fit in the TextBoxes (several strings). 8.3.1 Some first coding to split the text You start with some code to make FrmMain centre upon opening. 60 8. Your second application: TextPlayT(w)o Public Sub Form_Open() Me.Center End Step 1: Focus on splitting the text What you need to accomplish is split entered text in the TextArea (txaContent) into the TextBoxes (tbxLine1 to tbxLine4). For that you need to know on what character to split. Example: txaContent.Text → “split this text on space” tbxSplit.Text → “ “ (a space) Pressing Split should result in: tbxLine1.Text → “split” tbxLine2.Text → “this” tbxLine3.Text → “text” tbxLine4.Text → “on” So input is the text entered in txaContent and the character entered in tbxSplit. The splitting needs to take place when btnSplit is clicked. For splitting strings you can use the function Split(). StringArray = Split(String As String [, Separators As String, Escape As String, ...]) Split enables you to split a string using the Separator to determine where to Split the string. String is the string to split Separators are the characters used to split the text. By default the seperators are not returned. StringArray is an array of strings into where the results of Split are returned. So it contains all the splitted string results as separate strings in one array of strings. Split has more options than mentioned above. Split is a String Function. String functions are functions that can be used to do work with Strings. More on Split see http://gambasdoc.org/help/lang/split?v3 Overview of String Functions see: http://gambasdoc.org/help/cat/string?v3 As the splitting needs to take place when btnSplit is clicked you will start with coding this event: Public Sub btnSplit_Click() Dim sSplit As String[] 'String followed by [ and ] declares a string array Dim sText As String Dim iX As Integer iX = 1 ' Used to determine what txbLine to output to sSplit = Split(txaContent.Text, tbxSplit.Text) For Each sText In sSplit Select iX Case 1 tbxLine1.Text = sText Case 2 tbxLine2.text = sText 61 8. Your second application: TextPlayT(w)o Case 3 tbxLine3.Text = sText Case 4 tbxLine4.Text = sText End Select iX = iX + 1 Next End For Each Variable In Expression Next Repeats a loop while enumerating the object in expression Expression must be a reference to a enumerable object like a collection or an array Variable is the reference to the item in the enumerable object in Expression In above code sText (variable) stands for each string item in the string array sSplit (expression) More on For Each see http://gambasdoc.org/help/lang/foreach?v3 Now run the application and: 1. in txaContent type: Split.On.Dot.Please 1. in tbxSplit type: . 3. click btnSplit Illustration 64: Text splitted on the dot (.) It runs as expected, but try again with some other text in txaContent en Split on “\n” (line feed). Run the application and: 1. in txaContent type: This is Line 1 Next line aka as line 2 62 8. Your second application: TextPlayT(w)o Line 3 above is empty and this is line 4 1. in tbxSplit type: \n 3. click btnSplit Illustration 65: Result of splitting on \n Now this makes sense as “ Separators are the characters used to split the text” So Split will check for both “\” and “n” to split and that is exactly what happened. Step 2: Improve splitting the text What you want is it to split on a line feed (“\n”) instead. So you need to code the btnSplit event to recognize the “\n” and act accordingly. For this you need to add an extra “\”15. So back to IDE for some recoding: Public Sub btnSplit_Click() Dim sSplit As String[] 'String followed by [ and ] declares a string array Dim sText As String Dim iX As Integer iX = 1 ' Used to determine what txbLine to output to Select tbxSplit.Text Case “\\n” ' To check for a line feed tbxSplit.Text = Chr(10) ' To split on a line feed (=Chr(10)) End Select sSplit = Split(txaContent.Text, tbxSplit.Text) For Each sText In sSplit Select iX Case 1 tbxLine1.Text = sText Case 2 tbxLine2.text = sText Case 3 tbxLine3.Text = sText 15 The extra “\” makes sure the following “\” is preserved. 63 8. Your second application: TextPlayT(w)o Case 4 tbxLine4.Text = sText End Select iX = iX + 1 Next End Chr(Code As Integer) As String Returns the character for the Code (with Code being the ASCII code) Code needs to be a Integer value from 0 to 255 In above code Chr(10) stands for a line feed. More on Chr() see http://gambasdoc.org/help/lang/chr?v3 Overview of String Functions see: http://gambasdoc.org/help/cat/string?v3 Now run the application again and do the same test as done before. Illustration 66: Renewed result of splitting on "\n" Seems you have a perfect split on “\n” or a line feed. Note that once clicking btnSplit the content of tbxSplit contains Chr(10). Because TextBoxes are single line they represent it with this symbol instead of going to a new line. 8.3.2 Determine the number of splits Now that the split works as needed focus is on the numbers of splits you want. Step 1: Implement to take number of splits into account As you have 4 lines to show the splitted strings it would be great if you entered 2 in number of splits and only 2 where shown, or enter 1 and only one is shown. So you will again need to recode btnSplit event to make that happen: 64 8. Your second application: TextPlayT(w)o Public Sub btnSplit_Click() Dim sSplit As String[] 'String followed by [ and ] declares a string array Dim sText As String Dim iX, iNumSplits As Integer iX = 1 ' Used to determine what txbLine to output to iNumSplits = vbxSplit.Value ' Used to determine number of splits Select tbxSplit.Text Case “\\n” ' To check for a line feed tbxSplit.Text = Chr(10) ' To split on a line feed (=Chr(10)) End Select sSplit = Split(txaContent.Text, tbxSplit.Text) For Each sText In sSplit If iX <= iNumSplits Then Select iX Case 1 tbxLine1.Text = sText Case 2 tbxLine2.text = sText Case 3 tbxLine3.Text = sText Case 4 tbxLine4.Text = sText End Select iX = iX + 1 Endif Next End Now check if it works by running the application Illustration 67: Result of splitting on "\n" showing 2 lines 65 8. Your second application: TextPlayT(w)o You will notice that when showing 4 lines and next trying 2 lines that lines 3 and 4 are still filled. The reason behind this is that the tbxLine variables aren't cleared before a new split. Step 2: Recode to make tbxLine variables clear To do this you need to code the btnSplit event again: Public Sub btnSplit_Click() Dim sSplit As String[] 'String followed by [ and ] declares a string array Dim sText As String Dim iX, iNumSplits As Integer iX = 1 ' Used to determine what txbLine to output to iNumSplits = vbxSplit.Value ' Used to determine number of splits ClearLines 'This starts a subroutine Select tbxSplit.Text Case “\\n” ' To check for a line feed tbxSplit.Text = Chr(10) ' To split on a line feed (=Chr(10)) End Select sSplit = Split(txaContent.Text, tbxSplit.Text) For Each sText In sSplit If iX <= iNumSplits Then Select iX Case 1 tbxLine1.Text = sText Case 2 tbxLine2.text = sText Case 3 tbxLine3.Text = sText Case 4 tbxLine4.Text = sText End Select iX = iX + 1 Endif Next End Private Sub ClearLines() tbxLine1.Clear tbxLine2.Clear tbxLine3.Clear tbxLine4.Cear End As you can see in the code above the code for clearing the lines is taken into a separate routine (Public Sub ClearLines()). This separate routine is a subroutine (indicated by the Sub). It is a Private routine (indicated by Private). The fact that the routine is a subroutine and Private means that it can be called anywhere within the same class it resides to be executed. The class subroutine ClearLines() resides in the form class of FrmMain (the tab in IDE named FrmMain.Class). So anywhere in the code of FrmMain you can use subrourine ClearLines(). 66 8. Your second application: TextPlayT(w)o You call the routine simply by its name to be executed (in our code you simply write ClearLines). Upon execution the interpreter after executing the line 'iNumSplits = vbxSplit.Value' will run the subroutine ClearLines and execute it line by line before continuing with the execution of 'Select tbxSplit.Text' [Static] {Public | Private} {Procedure | Sub} Identifier(Parameter As Datatype.....) Identifier is the name of the subroutine or procedure Parameter is/are values that can be passed to the subroutine/procedure when calling it. You have to declare a data type for each parameter used. A subroutine or procedure does not return any values. Use a function for that. More on Sub see http://gambasdoc.org/help/lang/sub?v3 Private Keyword that declares accessibility of a method (sub/procedure or function), variable or property A Private declared method, variable or property can NOT be used outside its own class. More on Private see http://gambasdoc.org/help/lang/private?v3 Public Keyword that declares accessibility of a method (sub/procedure or function), variable or property A Public declared method, variable or property can be used outside its own class. More on Private see http://gambasdoc.org/help/lang/public?v3 Now run the application again and first let it split showing 4 lines Illustration 68: Split for 4 lines Next split again for 1 line and see if lines 2 to 4 are cleared (see illustration on next page). 67 8. Your second application: TextPlayT(w)o Illustration 69: Next a split for 1 line (other lines are now cleared) Seems that all is working as expected. 8.4 Search for text For this part you first need to make a new form. The new form is going to serve as a window to enter the search string. 8.4.1 Make a new form To make a new form in the Project Browser right click Sources. In the menu select New → Form. Illustration 70: Ad a new form to the project 68 8. Your second application: TextPlayT(w)o Name the form FrmSearchReplace. Illustration 71: Dialog to name the form Place following controls on FrmSearchReplace with some properties pre-set: 1 TextBox: Name → tbxSearch ; Text → Enter a string to search... 1 Button: Name → btnSearch; Text → Search Illustration 72: FrmSearchReplace with controls placed 69 8. Your second application: TextPlayT(w)o Now add some initial code to the form open event (right click the form and select menu Event → Open) Public Sub Form_Open() Me.Caption = “Search” End This will give the FrmSearchReplace the caption “Search”. As you notice FrmSearchReplace is not centered, FrmMain is. Idea is that FrmSearchReplace gets opened when clicking the btnSearch in FrmMain. To make sure that FrmSearchReplace is not in front of txaContent, you leave all default, meaning in top left of your screen 8.4.2 Make FrmSearchReplace open from btnSearch on FrmMain Double click FrmMain in the Project Browser and next select btnSearch. As you might remember btnSearch was disabled. So in btnSearch properties set enabled to True. Next right click the selected btnSearch and in the menu select Event → Click. This will open the Tab FrmMain.class ready to code the click event of btnSearch. Public Sub btnSearch_Click() FrmSearchReplace.Show End What you do here is call the method Show of FrmSearchReplace. So you tell the FrmSearchReplace to show itself. Forms inherit the Window class which means properties, methods and events are inherited from the window class every time a form is made. Forms The Form class inherits the Window class. This means that properties, methods (routines) and events of the Windows class (parent class to the form class) are inherited from the window class every time a form is made. This also means that you can use these in your forms. Sub Show() Shows the window More on Forms see http://gambasdoc.org/help/comp/gb.qt4/form?v3 More on Show see http://gambasdoc.org/help/comp/gb.qt4/window/show?v3 Now run the application and click the btnSearch. You should see something like the illustration on the next page. Notice the window caption of FrmSearchReplace stating Search. 70 8. Your second application: TextPlayT(w)o Illustration 73: FrmSearchReplace opened from btnSearch Seems you now have an application consisting of two forms. And from within one form you can open the other. Now the real challenge is to enter a search string in the FrmSearchReplace and search for the string in txaContent on FrmMain. This will require some interaction between the two forms and brings us to a next level. 8.4.3 Project intermezzo: Form class interaction explained You already had a first glimpse at Private and Public declarations. With two forms at hand this is going to start making sense. The requirement of having to search a string entered in a TextBox on one form to be searched in a TextArea on another form and then have the result selected in that TextArea requires you to understand the difference in Private and Public. They are the basis of what will and will not be available to other Form classes to use in their code. By default coded events (named subs, procedures or methods) of controls you draw on a form are Public. So in our project what can one form use from the other? Let's make an overview and see what is available and what is not. Public in FrmSearchReplace are: Methods Form_Open Private in FrmSearchReplace are: Methods Public in FrmMain are: Methods Form_Open 71 8. Your second application: TextPlayT(w)o btnSplit_Click() btnSearch_Click Private in FrmMain are: Methods ClearLines() So Public means available to other forms, Private means NOT available to other forms. Let's give this a go in the IDE. Double click FrmSearchReplace in the Project Browser. Now double click btnSearch. This will open a btnSearch_Click() method in the FrmSeachReplace.class (= all the code for the form). Write the following code to the btnSeach click event: Public Sub btnSearch_Click() FrmMain.btnSplit_Click End Next run the application. In txaContent type: To be or not In tbxSplit type: “ “ (a space) In vbxSplit type: 4 Next click btnSearch to open FrmSearchReplace. In FrmSearchReplace click btnSearch and see what happens in FrmMain. Illustration 74: Running btnSplit code from btnSearch on another form What actually happened upon clicking btnSearch on the Search form is that code from another form class got called by the current form Class and executed before returning. So you can directly call Public methods from another class to be executed. Indirectly the Private method ClearLines got called as well. With this difference that it was called from a method (btnSplit_Click()) within its own class. 72 8. Your second application: TextPlayT(w)o Illustration 75: Interaction between methods in different form classes You can now remove the code from btnSearch in FrmSearchReplace class as it was just an example. Back to our problem to solve in this project. There are two possible approaches: 1. Code the searching on form FrmSearchReplace 2. Code the searching on form FrmMain In both approaches it comes down to get the string that needs to be searched and perform a search. The code for searching will not be that different. What it comes down to is what is the best approach in getting the string and next selecting it when found. Let's have a look at both approaches and see what fits best. 1. Code the searching on form FrmSearchReplace So what you need to get is the content from txaContent.Text. This means declaring a Public variable as String and make sure every time txaContent.Text is changed the string is passed to the variable. Next search can be performed and then somehow the result has to be selected in txaContent while it isn't even Public!! All in all a tough road to walk that requires a lot of extra coding. 2. Code the searching on form FrmMain What you need here is pass the string to be searched from FrmSearchReplace to FrmMain, perform the search and select the result in txaContent. As all takes place on FrmMain this is a much easier approach. All that needs to be done is pass a string from one form to another, nothing more. What you need is a method (sub or procedure) on FrmMain that can pass an argument, perform the search and select the result. 8.4.4 Back on track to code a Public method on FrmMain First check out how passing arguments in a methods works. 73 8. Your second application: TextPlayT(w)o In FrmMain class write following code: Public Sub SearchString(StringToSearch As String) Message(StringToSearch) End StringToSearch is a string value that gets passed to the method upon calling it. In FrmSearchReplace class write following code: Public Sub btnSearch_Click() FrmMain.SearchString(tbxSearch.Text) End Now run the application, click btnSearch on FrmMain, write your name in the search field and click btnSearch. You should see your name appear in a message box. So the Text property of tbxSearch (although not being Public) is passed to another class as an argument (StringToSearch) to be used in a Public method in that other class. So passing arguments is one way of passing Private data to another Class. Keep that in mind! Illustration 76: Search string passed as argument of a Public method I hope this makes clear how passing arguments works. Now that you have seen it working you know the search string can reach method SearchString in FrmMain all you need to do is code for it to be found. 8.4.5 Lets search some string Search a string and select it in tarContent when found is the mission to complete. For that you need to code the method SearchString in FrmMain class: 74 8. Your second application: TextPlayT(w)o Public Sub SearchString(StringToSearch As String) Dim iB, iL As Integer iB = 1 iB = InStr(tarContent.Text, StringToSearch, iB) 'Determines the start position of string found iL = Len(StringToSearch) 'Determines length of the string If iL > 0 Then tarContent.Select(iB - 1, iL) 'Select the found string only when length > 0 Endif End Position = Instr(String As String , Substring As String [, Start As Integer, ...]) Instr enables you to search a string to determine its start position. Position is the start position of the string found (0 when nothing found) String is the string value that will be searched SubString is the string value that you are searching for Start is the position you want the search to begin Instr has more options than mentioned above. Instr is a String Function. String functions are functions that can be used to do work with Strings. More on Instr see http://gambasdoc.org/help/lang/instr?v3 Overview of String Functions see: http://gambasdoc.org/help/cat/string?v3 Length = Len(Args As String) Len enables you to determine the length of a string Length is the length of the string in arguments Args (0 when empty) Args is the string value you want to determine the length of Lenght is determined by byte count of the string. ASCII characters take up one byte. Characters like ü or é (UTF-8) take up two bytes and thus will count for two!! Len is a String Function. String functions are functions that can be used to do work with Strings. More on Len see http://gambasdoc.org/help/lang/len?v3 Overview of String Functions see: http://gambasdoc.org/help/cat/string?v3 Now run the application and do some testing. In txaContent write: I am looking for my name Have you seen my name It is Willy they tell me Please search for my name Next click btnSearch on the main form to open the Search form. In the Search form type “Willy” (without the quotes) and click Search. Willy should be selected in txaContent on the main form. 75 8. Your second application: TextPlayT(w)o Illustration 77: Seems like search performs as expected All should work as expected and select the searched string when found, select nothing when nothing is found. 8.5 Search and replace text Before you can start searching and replacing string you will need to add some controls to you current FrmSearchReplace. 8.5.1 Prepare the forms for Search and Replace In the IDE click FrmSearchReplace in the Project Browser. Place following controls on FrmSearchReplace with some properties pre-set: 1 TextBox: Name → tbxReplace ; Text → Enter the replace string... 1 Button: Name → btnReplace; Text → Replace Fastest method is to select tbxSearch and btnSeach, copy and paste them onto the form, drag them to the proper location and adapt the properties Name and Text. Illustration 78: Replace TextBox and Button added to FrmSearchReplace Next click FrmMain in the Project Browser Select fraSearch and set the property Enabled to True 76 8. Your second application: TextPlayT(w)o Illustration 79: FrmSearch property Enabled set to true on FrmMain With the frame for choosing between Search and Search/Replace enabled and FrmSearchReplace prepared for Replacing you are set for the next step. 8.5.2 Making FrmSearchReplace appear depending on selection in FrmMain When clicking button Search on FrmMain you want FrmSearchReplace to appear different depending on what was selected in the fraSearch (a Frame). When Search is selected FrmSearchReplace has to: - have caption Search - show search field - show search button When Search/Replace is selected FrmSearchReplace has to: - have caption Search and Replace - show search and replace fields - show search button - show replace button You will start with FrmMain to get the fraSearch and RadioButtons to work: ' -- Used to determine how FrmSearchReplace is shown 1=search, 2=replace -Public SearchReplace As Byte Public Sub Form_Open() Me.Center rbtSearch.Value = True rbtSearch_Click End You use Public to declare a variable SearchReplace to pass a value to FrmSearchReplace to determine whether to search or to search and replace. rbtSearch is set to True so it is the default selection upon opening FrmMain. Next you execute the rbtSearch click event. This is the next step you need to code. Clicking on one of the RadioButtons has to set SearchReplace to value 1 or 2, that is all. 77 8. Your second application: TextPlayT(w)o Datatypes Datatypes determine the type of data a variable can contain when declared. The datatype also determines the length of the space used by the data. Gambas native datatypes are: Type Boolean Byte Short Integer Long Single Float Date String Variant Object Pointer Description True or False 0 to 255 -32.768 to 32.767 -2.147.483.648 to 2.147.438.647 -9.223.372.036.854.775.808 to 9.223.372.036.854.775.807 single precision floating-point type double precision floating-point type Date and time each stored in an Integer A variable length string of characters Any datatype Anonymous reference to any object A memory address Default value False 0 0 0 0 0.0 0.0 Null Null Null Null 0 More on datatypes see http://gambasdoc.org/help/cat/datatypes?v3 More on Floating Point Numbers: http://gambasdoc.org/help/cat/float?v3 More on single precision floating-point format: https://en.wikipedia.org/wiki/Single_precision_floating-point_format More on double precision floating point format: https://en.wikipedia.org/wiki/Double_precision_floating-point_format Code for event click of rbtSearch: Public Sub rbtSearch_Click() SearchReplace = 1 'search End Code for event click of rbtReplace: Public Sub rbtReplace_Click() SearchReplace = 2 'replace End With this code in place you have your means to know what FrmSearchReplace has to show upon opening. If FrmMain Public variable SearchReplace is 1 it's a search, when 2 it's a replace. Now let's make that happen. For this you need to code the Open event of FrmSearchReplace: Public Sub Form_Open() Select FrmMain.SearchReplace Case 1 78 8. Your second application: TextPlayT(w)o Me.Caption = "Search" btnReplace.Visible = False tbxReplace.Visible = False Case 2 Me.Caption = "Search and Replace" btnReplace.Visible = True tbxReplace.Visible = True End Select End Now run the application and see if all reacts as wanted Illustration 80: Search shown when search selected Illustration 81: Search and Replace shown when search/replace selected 79 8. Your second application: TextPlayT(w)o 8.5.3 Replace searched strings To replace a string you again will write a Public method for FrmMain that does all the replacing. In FrmMain write following code: Public Sub ReplaceString(StringToReplace As String, StringToReplaceWith As String) txaContent.Text = Replace(txaContent.Text, StringToReplace, StringToReplaceWith) End Now all that you need to do is run above code when button Replace is clicked. In FrmSearchReplace write following code: Public Sub btnReplace_Click FrmMain.ReplaceString(tbxSearch.Text, tbxReplace.Text) End Again all you do is pass some arguments (being the search and replace strings) to the method ReplaceString to be dealt with accordingly. Result = Replace(String As String, Pattern As String, ReplaceString As String[, ...]) Replace enables you to search a string and replace it with another string. Result is the outcome of String with Pattern replaced by ReplaceString String is the string value that will be searched Pattern is the string value that you are searching for ReplaceString is the string value that Pattern will be replaced by Replace has more options than mentioned above. Replace is a String Function. String functions are functions that can be used to do work with Strings. More on Replace see http://gambasdoc.org/help/lang/replace?v3 Overview of String Functions see: http://gambasdoc.org/help/cat/string?v3 Now run the application for some testing In txaContent write: Try to replace Willy with silly if you can First search for it, next click Replace So go ahead type above lines, next type Willy in Search field and click button Search. If that works type silly in the Replace field and click button Replace. If all is well Willy should now be silly (see illustrations on the next page). Play with it for a while and see what can and can't be done. The RadioButtons in this example are placed on FrmMain to explain interaction between forms and Public variables and how to deal with these situations. It would be better practice to place them on FrmSearchReplace. 80 8. Your second application: TextPlayT(w)o Illustration 82: Search still works well Illustration 83: Replace does a good job as well In this chapter you have worked with several String functions. You have noticed by now that a lot is possible using String functions. You will come to learn that they can be useful in a lot of situations, like importing a comma delimited file, extracting returned information from a linux command run or building a text editor just to mention a few examples. They are very powerful tools to use and some of them you will be using a lot when working with text based information, so get familiar with them. Now in Gambas IDE click menu File → Quit. This gets you ready for the next chapter. 81 9. Your third application: NumPlay 9 Your third application: NumPlay 9.1 What will be done in this chapter Main focus will be numerical data, for that you will built a new application. This will involve ➢ Opening Gambas IDE and make a new project ➢ Make a main form ➢ Place a number of controls on the form ➢ Write some code ➢ Run the application from Gambas IDE You can learn about: ➢ Working with the Gambas IDE ➢ Working with numeric data, date and time ➢ Error handling ➢ Working with Arithmetical functions and Date & Time functions ➢ Working with Localization and Translation functions ➢ Transfer numeric data in strings to numerical data types ➢ User interaction (input from user, output from application) ➢ Enumeration 9.2 Start a new project and design a form Open Gambas3 IDE and start a new graphical application project named NumPlay. Rename form FMain to FrmMain. Do this by right clicking FMain in the Project Browser and next click Rename. Place following controls on FrmMain with some properties pre-set: 1 ValueBox: Name → vbxNum1 1 ValueBox: Name → vbxNum2 1 Label: Name → lblOperator ; Text → empty; Alignment → Right 1 Separator 1 ValueBox: Name → vbxResult 1 Label: Name → lblResult ; Text → empty; Alignment → Right 1 Button: Name → btnCalc; Text → Calculate 1 Frame: Name → fraOperator; Text → Operator 1 RadioButton (in fraOperator): Name → rbtAdd; Text → + 1 RadioButton (in fraOperator): Name → rbtSubtract; Text → 1 RadioButton (in fraOperator): Name → rbtMultiply; Text → * 1 RadioButton (in fraOperator): Name → rbtDivide Text → / 1 RadioButton (in fraOperator): Name → rbtPower Text → ^ When finished with placing all controls and setting all properties accordingly you should have something like in the illustrations on the next page. First illustration (84) shows the form in the IDE designer. Second illustration (85) shows the form when run. 82 9. Your third application: NumPlay Illustration 84: FrmMain after placing all controls Illustration 85: FrmMain when run 9.3 Doing the maths In NumPlay you are going to work with numbers and calculations. Along the road you'll also have a look at numerical data shown in text based controls and in using input from text based controls for calculations. 83 9. Your third application: NumPlay 9.3.1 Analyse the needs and determine a strategy Based on the operator clicked you need to do some things. To begin with lblOperator needs to show the calculation operation to be done when clicking btnCalc. Lets start by doing this first. You know that each RadioButtons text property holds the operation. This only needs to put placed in the lblOperator text property. For this you need to code the Click event of each RadioButton: Public Sub Form_Open() Me.Center rbtAdd_Click 'To ensure lblOperator shows + End Public Sub rbtAdd_Click() lblOperator.Text = rbtAdd.Text End Public Sub rbtSubtract_Click() lblOperator.Text = rbtSubtract.Text End Public Sub rbtMultiply_Click() lblOperator.Text = rbtMultiply.Text End Public Sub rbtDivide_Click() lblOperator.Text = rbtDivide.Text End Public Sub rbtPower_Click() lblOperator.Text = rbtPower.Text End Now run the application and see what happens when clicking the RadioButtons. Illustration 86: lblOperator shows selected Operator 84 9. Your third application: NumPlay Next challenge is to make the calculations based on the selected operator. So when clicking btnCalc you need to perform the selected operation on the values entered in vbxNum1 and vbxNum2 and return the result in vbxResult. Clearly the Operation selection is centrally crucial in all that needs to happen. Somehow when clicking btnCalc you need to determine what RadioButton is selected and act accordingly. There are several possible approaches, one of them is using a switch that is set when a RadioButton is clicked. This is how the switch value could represent the Operator Operator: + * / ^ Switch value: 0 1 2 3 4 To implement this some code needs to be added: Private iSwitch As Integer Public Sub Form_Open() Me.Center rbtAdd_Click 'To ensure lblOperator shows + End Public Sub rbtAdd_Click() lblOperator.Text = rbtAdd.Text iSwitch = 0 End Public Sub rbtSubtract_Click() lblOperator.Text = rbtSubtract.Text iSwitch = 1 End Public Sub rbtMultiply_Click() lblOperator.Text = rbtMultiply.Text iSwitch = 2 End Public Sub rbtDivide_Click() lblOperator.Text = rbtDivide.Text iSwitch = 3 End Public Sub rbtPower_Click() lblOperator.Text = rbtPower.Text iSwitch = 4 End Public Sub btnCalc_Click() 85 9. Your third application: NumPlay Print iSwitch End Print iSwitch will be executed when clicking on btnCalc giving us the current value of iSwitch during run time. This will help you check if all works as expected. Run the application, select subtract and next click btnCalc. If you pay attention in the console output of the IDE you will see 1 appear when clicking btnCalc Illustration 87: Console output in IDE Using the Print instruction will output to the IDE console during runtime. It is a way of checking what is happening during runtime and comes in handy when something is not working as expected to help you investigate what is actually happening. Print instruction is typically used to output to the user in a command line Gambas application. A simple Print followed by a string will output to the standard output (in IDE being the console, in a command line application being the terminal it runs in). Print can also used to output to Streams. Streams are internal objects that Gambas creates for manipulating files, processes, sockets, and many other objects that can be used as files. More on Print see http://gambasdoc.org/help/lang/print?v3 Click another operator and next on btnCalc to see if all the Switch values meet your requirements. Now that you have ensured yourself that iSwitch holds the proper value next step is to code for the calculations based on iSwitch. For this you need to code the Click event of btnCalc: 86 9. Your third application: NumPlay Public Sub btnCalc_Click() Select iSwitch Case 0 vbxResult.Value = vbxNum1.Value + vbxNum2.Value Case 1 vbxResult.Value = vbxNum1.Value – vbxNum2.Value Case 2 vbxResult.Value = vbxNum1.Value * vbxNum2.Value Case 3 vbxResult.Value = vbxNum1.Value / vbxNum2.Value Case 4 vbxResult.Value = vbxNum1.Value ^ vbxNum2.Value End Select End Now run the application, enter 10 and 2 for values and try all calculations. Illustration 88: Calculating values 10 and 2 As you will notice the calculations run well, but now try with values 10 and 0. As soon as you try dividing you will get an error as you are not allowed to divide by zero. Illustration 89: Division by zero error 87 9. Your third application: NumPlay As you will also notice you application is not reacting. To stop it click the Stop button in the IDE toolbar (located below the menu bar). 9.3.2 Implement error handling This is a good time to introduce some error handling. What you would like to know is the error code. This is a number that can be used to indicate what went wrong. Add some code to the btnCalc click event: Public Sub btnCalc_Click() Select iSwitch Case 0 vbxResult.Value = vbxNum1.Value + vbxNum2.Value Case 1 vbxResult.Value = vbxNum1.Value – vbxNum2.Value Case 2 vbxResult.Value = vbxNum1.Value * vbxNum2.Value Case 3 vbxResult.Value = vbxNum1.Value / vbxNum2.Value Case 4 vbxResult.Value = vbxNum1.Value ^ vbxNum2.Value End Select Catch Print Error.Code Error.Clear End The keyword Catch will execute whenever an error in btnCalc_Click occurs. Error.Code will return the error number. Error.Clear will clear the error so the application doesn't hang. Catch This instruction indicates the beginning of the error management part of a function or a procedure. The catch part is executed when an error is raised between the beginning of the function execution and its end. This error can be raised by the function itself, or by any other function called during its execution, provided that this deeper function has no catch part itself: the deeper the catch part is, the more priority it has. More on Catch see http://gambasdoc.org/help/lang/catch?v3 More on Error management see http://gambasdoc.org/help/cat/error?v3 Error Use this class for managing errors raised while the interpreter is running. Do not mix up with ERROR (with Capital letters)!! More on Error see http://gambasdoc.org/help/comp/gb/error?v3 More on Error management see http://gambasdoc.org/help/cat/error?v3 Run the application and enter 10 and 0 and do a division. The console will output 26 88 9. Your third application: NumPlay Illustration 90: Error 26 returned Now that you know that error 26 occurs when trying to divide by zero you can Catch the error and code it to do what you would like to happen. In this case you would like to notify the user that it is not allowed to divide by zero and maybe even set the focus to the second value. Adapt the code for Catch accordingly Public Sub btnCalc_Click() Select iSwitch Case 0 vbxResult.Value = vbxNum1.Value + vbxNum2.Value Case 1 vbxResult.Value = vbxNum1.Value – vbxNum2.Value Case 2 …. End Select Catch Select Error.Code Case 26 Message.Warning(“You are not allowed to divide by zero!!”) vbxNum2.SetFocus Case Else Print Error.Code End Select Error.Clear End Error.Code holds Integer values. And since this might be the first in more possible errors a Select Case is used instead of an If Then for possible further errors to occur. For now if an other error than 26 occurs you will see its number in the Console of the IDE. Now run the application again and see what happens when you try to divide by zero. 89 9. Your third application: NumPlay Illustration 91: Division by zero now handled properly As you can see the application no longer allows division by zero and informs the user. All happens without hanging the application. 9.4 Working with numbers in text variables and text controls Next you will have a look if numbers entered in a text control or held by a text variable (String) can be used for calculations. Place following controls on FrmMain with some properties pre-set: 1 TextBox Name → tbxNum1 1 TextBox: Name → tbxNum2 1 TextBox: Name → tbxResult 1 Button: Name → btnCalcText; Text → Calc text 1 TextBox: Name → tbxOneLine When finished with placing all controls and setting all properties accordingly you should have something like in the following illustrations. Illustration 92: FrmMain after adding some controls 90 9. Your third application: NumPlay 9.4.1 Simple beginnings As the title says, you are going to begin simple. Simple in this case means you right clicl on button 'Call Text' and in pop p menu select Event → Click. This will bring you to the code editor ready to code the click event of btnCalcText. Now copy all the code in between Public Sub btnCalc_Click() and End () (so the code of the entire routine except Public Sub … and End()) and paste it into the Public Sub btnCalcText_Click() event. Next change all vbx... control names to tbx.. control names and the .Value to .Text. The result should look like below Public Sub btnCalcText_Click() Select iSwitch Case 0 tbxResult.Text = tbxNum1.Text + tbxNum2.Text Case 1 tbxResult.Text = tbxNum1.Text – tbxNum2.Text Case 2 tbxResult.Text = tbxNum1.Text * tbxNum2.Text Case 3 tbxResult.Text = tbxNum1.Text / tbxNum2.Text Case 4 tbxResult.Text = tbxNum1.Text ^ tbxNum2.Text End Select Catch Select Error.Code Case 26 Message.Warning(“You are not allowed to divide by zero!!”) tbxNum2.SetFocus Case Else Print Error.Code End Select Error.Clear End Now hit <F5> to run the application and see what will happen if you simply start calculating with text. When started enter 1 in the two ValueBoxes and 1 in the two TextBoxes. Next click both buttons to see what happens. Illustration 93: Calculating the text seems to work 91 9. Your third application: NumPlay You will notice that calculating the text values seem to work out of the box. 9.4.2 Next challenge Let's try something more challenging. Let's say you want to type '2 + 3' into txbOneLine, next click btnCalcText and see the result in tbxResult. Something quite different. For this you will need to get the two numbers and the operator out of a string. You can use string functions to get this done. Next you will need to transform the string numbers to numbers and determine what operator to use on the two numbers. Last step is to return the result to tbxResult. So back to the code editor in IDE to change the code to: Public Sub btnCalcText_Click() Dim sOperator, sHelp As String Dim iB As Integer Dim iNum1, iNum2 As Float '-- find the first number – iB = 1 iB = InStr(tbxOneLine.Text, " ", iB) sHelp = Mid(tbxOneLine.Text, 1, iB – 1) iNum1 = Val(sHelp) '-- find the operator – INC iB sOperator = Mid(tbxOneLine.Text, iB, 1) '-- find the next number – iB = InStr(tbxOneLine.Text, " ", iB) sHelp = Mid(tbxOneLine.Text, iB + 1, Len(tbxOneLine.Text) – iB) iNum2 = Val(sHelp) Select sOperator Case "+" tbxResult.Text = iNum1 + iNum2 Case "-" tbxResult.Text = iNum1 – iNum2 Case "*" tbxResult.Text = iNum1 * iNum2 Case "/" tbxResult.Text = iNum1 / iNum2 Case "^" tbxResult.Text = iNum1 ^ iNum2 Case Else '– show a warning if an illegal operator is provided -Message.Warning("Unknown operator: " & sOperator) End Select Catch Select Error.Code Case 26 Message.Warning(“You are not allowed to divide by zero!!”) tbxNum2.SetFocus Case Else Print Error.Code 92 9. Your third application: NumPlay End Select Error.Clear End As you can see three new functions are introduced. Mid(), a string function, INC is an arithmetical function and Val() a Localization and Translation function. As you have already worked with several string functions, and have been shown where to find them, it is part of your learning process to get acquainted with the online Gambas documentation and learn to comprehend the function Mid(). Val() and INC are explained below. Expression = Val(String) Val converts a string into a boolean, a number or a date, according to the string contents. Expression is the variable that will hold the converted value String is the string to convert. The order Val checks to determine where to convert to is: - Date/Time → returns Date & Time - Floating point number → returns a floating point number - 64 bit Long Number → returns a long number - Integer → returns an integer - Boolean → returns matching boolean value (0 or -1) - Otherwise → returns Null Val is a Localization and Translation Function. These functions are useful when dealing with translations (language) and localisation (currency settings and such). More on Val see: http://gambasdoc.org/help/lang/val?v3 Overview of Localization and Translation Functions see: http://gambasdoc.org/help/cat/localize?v3 INC Increments a variable. Variable can be any target or assignment, but MUST be numeric Same as: Variable = Variable + 1 or Variable += 1 INC is a Arithmetical Function. These functions are useful when dealing with numeric data. Note: The opposite of INC is DEC (decrements a variable). More on INC see: http://gambasdoc.org/help/lang/inc?v3 Overview of Arithmetical Functions see: http://gambasdoc.org/help/cat/arith?v3 Time to run your application once more and see some results. Type these strings into tbxOneLine and click CalcText after each entry: 2+4 45 / 0 3 ) 56 a–3 93 9. Your third application: NumPlay You will notice that most of above either returns a result or gives you a message what is wrong, except for the last one. It does nothing. Illustration 94: Division by zero taken care off Illustration 95: Unknown operator taken care off Of course it is possible to take care of this as well. Have a go at it yourself and see what you can come up with. The solution is provided on the next page, but really try figure out something yourself first before moving to the next page. Remember, most learning takes place when things go wrong, not when everything works from the beginning. It's the trying to make it work process that will stick much longer and build comprehension on the matter, not the copy/paste and run process. Also know that of you come up with another solution to make it work doesn't make it wrong as it works and you will have learned about Gambas doing so. A little hint for on the road: Check out IsNumber() in the Gambas documentation. 94 9. Your third application: NumPlay Public Sub btnCalcText_Click() ... sHelp = Mid(tbxOneLine.Text, 1, iB – 1) If IsNumber(sHelp) Then iNum1 = Val(sHelp) Else Message.Error(sHelp & " is no number") Stop Event Endif '-- find the operator – iB += 1 ... sHelp = Mid(tbxOneLine.Text, iB + 1, Len(tbxOneLine.Text) – iB) If IsNumber(sHelp) Then iNum2 = Val(sHelp) Else Message.Error(sHelp & " is no number") Stop Event Endif Select sOperator ... End As you might noticed, instead of using a Switch to escape the event from running excessive code I chose to use the Stop Event. It does exactly what is says, it stops the event from running any further. STOP EVENT This statement must be used in an event handler. It tells the interpreter that the event that called the event handler must be cancelled. More on STOP EVENT see: http://gambasdoc.org/help/lang/stopevent?v3 Overview of Event management: http://gambasdoc.org/help/cat/event?v3 9.5 How about date and time Next to numbers you will probably need to handle date and time information in some of the applications you plan to built. Let's have a look at that. Place following controls on FrmMain with some properties pre-set: 1 DateBox Name → dbxDate 1 TextBox: Name → tbxDate1 1 TextBox: Name → tbxDate2 1 ValueBox: Name → vbxDate When finished with placing all controls and setting all properties accordingly you should have something like in the following illustrations. 95 9. Your third application: NumPlay Illustration 96: Some extra controls added to play with date and time 9.5.1 Adding some code First thing you are going to do is make sure that when selecting a date, the value representing the date is shown in vbxDate, the date part is shown in tbxDate1 and the time part is shown in tbxDate2. Select the DateBox and right click. In menu select Event → Change. Next type following code: Public Sub dbxDate_Change() Dim iDays As Days If Not IsNull(dbxDate.Value) Then iDays = dbxDate.Value vbxDate.Value = iDays tbxDate1.Text = Format(dbxDate.Value, "dd-mm-yyyy") tbxDate2.Text = Format(dbxDate.Value, "hh:nn:ss") Endif End First thing you might notice is that dbxDate.Value returns a number of days if put into an Integer. Second thing you might notice is the Format() function. With format you can convert values to strings in a certain output format. So the “dd-mm-yyyy” makes sure the value is only the date part and in this order '19-092013'. If you would change it to “yyyy-mm-dd” it would look like '2013-09-19'. Same goes for “hh:nn:ss” representing two digits for hours, minutes and seconds separated by ':' Make sure to have a look at the user defined formats in the Gambas documentation. There are a lot of examples to be found. Link is in the box on the next page. 96 9. Your third application: NumPlay String = Format(Expression, [, Format ]) Converts the expression into a string by using the format that depends on the type of expression Expression is the variable that will hold the value that will be converted Format is the format description (how it needs to be returned) The function can format date, times, numbers and currency. Format is a Localization and Translation Function. These functions are useful when dealing with translations (language) and localisation (currency settings and such). More on Format see: http://gambasdoc.org/help/lang/format?v3 More on user defined formats see: http://gambasdoc.org/help/cat/userformat?v3 Overview of Localization and Translation Functions see: http://gambasdoc.org/help/cat/localize?v3 Run the application and see what it returns when selecting a date. Next try the selecting the next day and see the value below the DateBox go up with 1. Illustration 97: After Date is selected the other controls are updated accordingly 9.5.2 More date and time To learn some more about date and time you will need to add one more control to your form. This control is a special control named Timer. You place it on your form but it will not be seen during runtime. Check the illustration on the next page to see where it is located. Place following control on FrmMain with some properties pre-set: 1 Timer Name → tmrInterval; Enabled → True The Timer is a virtual object that gets triggered in a certain interval and runs the code you would like. The interval is determined by setting the Timer property Delay (in milliseconds). The timer can be placed anywhere on the form itself. 97 9. Your third application: NumPlay Illustration 98: Timer object can be found in the toolbox on tab 'Special' Illustration 99: Timer object can be anywhere on the form Now this is what you are about to do. Every 1000 milliseconds (1 second), tbxDate1 will show current date/time in format “ddd mmm yyyy hh:nn:ss”, tbxDate2 will show current date/time in format “hh:nn:ss:uu”. To get current date/time you will use the function Now. Timer This class implements a timer object A timer object raises events regularly, each time it is triggered. The amount of time between each event is specified by the Delay property. More on Timer see: http://gambasdoc.org/help/comp/gb/timer?v3 Right click the Timer object and click on its Timer event and add following code: 98 9. Your third application: NumPlay Public Sub tmrInterval_Timer() tbxDate1.Text = Format(Now, "ddd mmm yyyy hh:nn:ss") tbxDate2.Text = Format(Now, "hh:nn:ss:uu") End Now Returns current date and time. Now is a Date and Time Function. More on Now see: http://gambasdoc.org/help/lang/now?v3 Overview of Date and Time Functions see: http://gambasdoc.org/help/cat/time?v3 Time to run your application and see what happens. Just sit back and watch the tbxDate1 and 2 change. If nothing happens you forgot to set the Timer property Enabled to true. Illustration 100: Every second the tbxDate1 and 2 change their content 9.6 Another approach, enumerate It was brought to my attention by Alain, one or our contributors, that NumPlay provided an excelent occasion to explain enumerating. So, thanks to Alain, here is a little extra added to the chapter. 9.6.1 iSwitch enumerated Earlier on (in 9.3.1) you used the Integer variable iSwitch and based on its value determined what operator to use. This is how the switch value represented the Operator in 9.3.1: Operator: + * / ^ Switch value: 0 1 2 3 4 99 9. Your third application: NumPlay In the demonstrated code in 9.3.1, you as a developer need to know what value represents what operator. To make life easier you could implement enumeration. Enumeration can be used to declare a list of integer constants. This will help you give a meaningful name to the different operator values that need testing, as they are integers. Using ENUM your code will look like this: Private iSwitch As Integer '– line below is added -Private ENUM PlusSign=0, MinusSign=1, MultiplySign=2, DivideSign=3, PowerSign=4 Public Sub Form_Open() Me.Center rbtAdd_Click 'To ensure lblOperator shows + End Public Sub rbtAdd_Click() lblOperator.Text = rbtAdd.Text iSwitch = PlusSign '← changed End Public Sub rbtSubtract_Click() lblOperator.Text = rbtSubtract.Text iSwitch = MinusSign '← changed End Public Sub rbtMultiply_Click() lblOperator.Text = rbtMultiply.Text iSwitch = MultiplySign '← changed End Public Sub rbtDivide_Click() lblOperator.Text = rbtDivide.Text iSwitch = DivideSign '← changed End Public Sub rbtPower_Click() lblOperator.Text = rbtPower.Text iSwitch = PowerSign '← changed End By using ENUM you can now test iSwicht in your code against something more meaningful like PlusSign instead of 0 or DivideSign instead of 5. It makes for more readable and easier maintained code in a later stage of development. 100 9. Your third application: NumPlay Enumeration declaration {Public | Private } ENUM Identifier [ = Value ] [, Identifier [ = Value ] ...] This keyword declares an enumeration or a list of integer constants. If the Value of a constant is not specidied, then it is the value of the previous constant plus one, or zero for the first constant. More on Enumeration declaration see: http://gambasdoc.org/help/lang/enumdecl?v3 More on ENUM see: http://gambasdoc.org/help/lang/enum?v3 In this chapter you have worked with Arithmetical, Date and time and localization and translation functions. You will have noticed in this and previous chapters that a lot is possible using functions. You will come to learn that they can be useful in a lot of situations. They are very powerful tools to use and some of them you will be using a lot, so get familiar with them. Now in Gambas IDE click menu File → Quit. This gets you ready for the next chapter. 101 10. Your fourth application: ImagePlay 10 Your fourth application: ImagePlay 10.1 What will be done in this chapter Main focus will be images. for that you will built a new application. This will involve ➢ Opening Gambas IDE and make a new project ➢ Make a main form ➢ Place a number of controls on the form ➢ Write some code ➢ Run the application from Gambas IDE You can learn about: ➢ Working with the Gambas IDE ➢ Working with images ➢ Working with project file paths ➢ User interaction (input from user, output from application) 10.2 Start a new project and design a form Open Gambas3 IDE and start a new graphical application project named ImagePlay. Rename form FMain to FrmMain. Do this by right clicking FMain in the Project Browser and next click Rename. Place following controls on FrmMain with some properties pre-set: 1 PictureBox: Name → pbxOne; Width → 128; Height → 128 1 PictureBox: Name → pbxTwo; Width → 128; Height → 128 1 Label: Name → lblDimOne ; Text → empty; Alignment → Center 1 Label: Name → lblDimTwo ; Text → empty; Alignment → Center 1 Button: Name → btnSwitch; Text → Switch Image When finished with placing all controls and setting all properties accordingly you should have something like in the next illustration. Illustration 101: Controls placed on FrmMain 102 10. Your fourth application: ImagePlay 10.3 Let me see some images 10.3.1 Making some images Before getting started with coding, you will need some images. You will create some new ones right in the Gambas IDE. First, in the Project Browser, right click the folder Data and in the menu click New → Folder. Name the folder Images Illustration 102: Create a new folder 'Images' in the project Data folder Next, right click the folder Images and in menu select New → Image... Name the Image MyImage, extension PNG, width and height 128 pixels. Click the newly made image and make something, like colour the background, draw a circle. Just play a bit with the Image editor to make some image. Illustration 103: Made some modern art image 103 10. Your fourth application: ImagePlay Now first save the image. Use the Save Project button in the button bar below the menu. You will know if a image is saved when the image is visible in the Project Browser before its name. To understand compare Illustration on previous page (unsaved MyImage.png) and the illustration below (saved MyImage.png and NextImage.png). Next, in the Project Browser, right click MyImage.png ans select Copy. Now right click folder Images and in menu select Paste. Rename the image file by right clicking it and selecting Rename.. Name the image NextImage.png and Illustration 104: Image copied, edited and saved. That makes two works of art. The only goal of this little exercise is to end up with two different images sized 128 x128 pixels. If you are missing the panel with image preview, left of the image editor, look for > and click on it to make the panel appear. The > will change to < (see illustration below). Illustration 105: Make panel appear You will find more of these panels that can be visible or not. So now you know what to look for. 10.3.2 Make the images appear Mission is to make the images you have just created visible. For this you will go the the properties of both images and set the Picture property. For this first select pbxOne and in the Properties/Hierarchy panel look for Picture. Click the … to open the 'Select a Picture' form. In the left pane click open the folder Image and select MyImage.png in the right panel. 104 10. Your fourth application: ImagePlay Illustration 106: Opening the 'Select a picture' form Next click OK and see the image in the Form Designer. Illustration 107: Image 'MyImage.png' in PictureBox picOne Now do the same for pbxTwo, but use NextImage.png Illustration 108: Both images in their PictureBox 105 10. Your fourth application: ImagePlay Now right click the form and select Event → Open and add next code: Public Sub Form_Open() Me.Center End Time to run the application and have a look at what you just created. Illustration 109: Running ImagePlay for the first time Well the images should be there. But the button 'Switch Image' still needs some work. Goal is to switch the images in the PictureBoxes when clicking button 'Switch Image'. In the editor you used the PictureBox property Picture to add the image to the PictureBox. So simply exchanging their properties should do the job. But for that you will need a temporary storage for one of the two properties. So you need to do something like: 1. Store picOne Picture property in the temporary storage 2. Store picTwo Picture property in picOne Picture property 3. Store the temporary storage in picTwo Picture property For the temporary storage you need a variable of type Picture. This because the Picture property of a PictureBox holds content of type Picture. Picture This class represents a picture. The picture contents are stored in the display server, not in the process memory like an Image. More on Picture see: http://gambasdoc.org/help/comp/gb.qt4/picture?v3 Back to coding the click event of btnSwitch: 106 10. Your fourth application: ImagePlay Public Sub btnSwitch_Click() Dim picTemp As Picture picTemp = pbxOne.Picture pbxOne.Picture = pbxTwo.Picture pbxTwo.Picture = picTemp End Run the application and click 'Switch picture' to see if it works. Illustration 110: Clicking the button switches the images between the PictureBoxes 10.3.3 Code the labels There are still two labels on the form that need some coding. The labels will be used to show the dimensions of the loaded image in the PictureBoxes above. For this you will need to read the Picture properties Width and Height. Back to coding: Public Sub Form_Open() Me.Center lblDimOne.Text = pbxOne.Picture.Width & " x " & pbxOne.Picture.Height & " pixels" lblDimTwo.Text = pbxTwo.Picture.Width & " x " & pbxTwo.Picture.Height & " pixels" End Run the application to see the result. 107 10. Your fourth application: ImagePlay Illustration 111: Labels now showing the image dimensions When switching the images nothing happens to the Labels, so time to make a new image. In 'Project Browser' right click Image folder to create SmallImage.png (64 x 64) and BigImage.png (256 x 256). Illustration 112: Two more png images made in the editor Now go to the FrmMain in IDE and change the properties of pbxOne and pbxTwo. Make sure pbxOne has LittleImage.png in its Picture property and pbxTwo has BigImage.png in its Picture property. Once done run the application again and see what it looks like. 108 10. Your fourth application: ImagePlay Illustration 113: Running the application with the new images When running the application you will see that the labels give the proper dimensions, but the images aren't shown properly. LittleImage.png is TopLeft in pbxOne, BigImage.png can only be seen partial, because of its size being 256 x 256, where pbxTwo is 128 x 128. So that are some things that need attention. Try clicking button 'Switch Image' and see what happens. Illustration 114: Images switch but labels show wrong dimensions As you can see, the images switch, but the labels don't. This makes sense as you coded the Form_Open event, meaning that only on opening the form the Labels get their content. There is no code on the btnSwitch_Click event doing the same. So more work is needed. First you need to make sure that an image is shown in its total in the PictureBoxes, no matter what its size is. 109 10. Your fourth application: ImagePlay Second you need to make the Labels show the proper dimensions. Let's get to work: First set the properties of the both PictureBoxes to meet this: Alignment → Center Stretch → True The property Stretch will make sure the image is adapted to meet the dimensions of the PictureBoxes, the Alignment will center the image in the PictureBoxes. Next more code is needed to make the Labels show the proper dimensions. Public Sub btnSwitch_Click() Dim picTemp As Picture picTemp = pbxOne.Picture pbxOne.Picture = pbxTwo.Picture pbxTwo.Picture = picTemp lblDimOne.Text = pbxOne.Picture.Width & " x " & pbxOne.Picture.Height & " pixels" lblDimTwo.Text = pbxTwo.Picture.Width & " x " & pbxTwo.Picture.Height & " pixels" End Now run the application again. Illustration 115: All works as expected You will find all working as expected, even when switching the images the labels show th proper dimensions. One thing you might have notices is that the code used for showing the label dimensions in both Form_Open and btnSwitch_Click event are exactly the same. This means you can write a routine with that code and call the routine from both events, rather than having same code at two places. Advantage is that if you need to change something to the code, it only needs to be changed at one place. As you only need this routine on FrmMain you will code for a Private routine. Here is the full code for FrmMain: 110 10. Your fourth application: ImagePlay Public Sub Form_Open() Me.Center ShowDimensions End Public Sub btnSwitch_Click() Dim picTemp As Picture picTemp = pbxOne.Picture pbxOne.Picture = pbxTwo.Picture pbxTwo.Picture = picTemp ShowDimensions End Private Sub ShowDimensions() lblDimOne.Text = pbxOne.Picture.Width & " x " & pbxOne.Picture.Height & " pixels" lblDimTwo.Text = pbxTwo.Picture.Width & " x " & pbxTwo.Picture.Height & " pixels" End 10.4 Loading images using code Last part of image handling you will have a look at is loading the images using code. For this you will need to add some more controls to the form. Place following controls on FrmMain with some properties pre-set: 1 Button: Name → btnOneMy; Text → Load My 1 Button: Name → btnOneSmall; Text → Load Small 1 Button: Name → btnTwoNext Text → Load Next 1 Button: Name → btnTwoBig; Text → Load Big When finished with placing all controls and setting all properties accordingly you should have something like in the next illustration. Illustration 116: All new controls placed on FrmMain 111 10. Your fourth application: ImagePlay 10.4.1 The mission Now that controls are in place this is what needs to be done: 1. btnOneMy needs to load MyImage.png into pbxOne upon clicking 2. btnOneSmall needs to load SmallImage.png into pbxOne upon clicking 3. btnTwoNext needs to load NextImage.png into pbxTwo 4. btnTwoBig needs to load BigImage.png into pbxTwo To load an image into a PictureBox property Picture you will use Picture.Load. Picture.Load Static Function Load (Path As String) As Picture Loads a picture from the disk. More on Picture see: http://gambasdoc.org/help/comp/gb.qt4/picture/load?v3 To be able to load the picture you will need a path. Since the images are within the project folder some more explanation is needed. Illustration 117: Project folder structure For Gambas the Data folder presents the root folder. So addressing the Images folder will give path: “Images”. If you need BigImage.png the path looks like: “Images/BigImage.png”16 When typing the code in IDE you will see that the auto-complete function will recognise the path and files in there. Just hit Enter when proper file is selected instead of typing al. Illustration 118: Auto-complete function of IDE will recognise the path 16 More on paths and Gambas: http://gambasdoc.org/help/cat/path 112 10. Your fourth application: ImagePlay The code looks like this: Public Sub btnOneMy_Click() pbxOne.Picture = Picture.Load("Images/MyImage.png") End Public Sub btnOneSmall_Click() pbxOne.Picture = Picture.Load("Images/SmallImage.png") End Public Sub btnTwoNext_Click() pbxTwo.Picture = Picture.Load("Images/NextImage.png") End Public Sub btnTwoBig_Click() pbxTwo.Picture = Picture.Load("Images/BigImage.png") End After this all it takes is run and test. Illustration 119: The pictures seem to load but the labels aren't adapted 10.4.2 Make the labels work again Because you made a routine for updating the labels content, it shouldn't be to hard to get the labels to work as needed. Simply call the routine from each button click event should do the trick. This is what is looks like: 113 10. Your fourth application: ImagePlay Public Sub btnOneMy_Click() pbxOne.Picture = Picture.Load("Images/MyImage.png") ShowDimensions End Public Sub btnOneSmall_Click() pbxOne.Picture = Picture.Load("Images/SmallImage.png") ShowDimensions End Public Sub btnTwoNext_Click() pbxTwo.Picture = Picture.Load("Images/NextImage.png") ShowDimensions End Public Sub btnTwoBig_Click() pbxTwo.Picture = Picture.Load("Images/BigImage.png") ShowDimensions End Again, run the application to see if the adaptation to the code works. Illustration 120: Loading images now adapts the Labels accordingly This concludes this chapter. In Gambas IDE click menu File → Quit. This gets you ready for the next chapter. 114 11. Your fifth application: SimpleTextEditor 11 Your fifth application: SimpleTextEditor 11.1 What will be done in this chapter Main focus will be loading and saving data and menus. for that you will built a new application. This will involve ➢ Opening Gambas IDE and make a new project ➢ Make a main form ➢ Place a number of controls on the form ➢ Make a menu and a toolbar ➢ Write some code ➢ Run the application from Gambas IDE You can learn about: ➢ Working with the Gambas IDE ➢ Saving data to file ➢ Opening a saved file ➢ Making menus and coding them ➢ Making Toolbars and coding them ➢ Working with local file paths ➢ User interaction (input from user, output from application) 11.2 Start a new project and design a form Open Gambas3 IDE and start a new graphical application project named SimpleTextEditor. Rename form FMain to FrmMain. Do this by right clicking FMain in the Project Browser and next click Rename. Place following control on FrmMain with some properties pre-set: 1 TextArea: Name → txaMain; Text → empty When finished with placing the control and setting all properties accordingly you should have something like in the next illustration. Illustration 121: FrmMain after placing the control 115 11. Your fifth application: SimpleTextEditor 11.3 Making a menu Believe it or not, in this chapter you are going to build a full functional text editor. With the form made you already can enter text in the TextArea. Only thing missing is saving it to a text file. For that you could add a save button, but that is not what you will be doing here. To make a menu right click FrmMain in the IDE and select Menu editor... or press Ctrl + E. Illustration 122: Select Menu editor... Once the menu editor is opened add 9 menu entries by clicking button Insert 9 times. Illustration 123: Adding 9 menu entries in the Menu editor 116 11. Your fifth application: SimpleTextEditor Assuming Menu9 is the first and Menu1 the last in the list, this is what you need to do for each of the menu entries17: Menu9: Name → mnuFile; Caption → File Menu8: Name → mnuFileNew; Caption → New; Click button Indent in Toolbar (see below) Menu7: Name → mnuFileOpen; Caption → Open..; Click button Indent in Toolbar Menu6: Name → Seperator1; Caption → empty; Click button Indent in Toolbar Menu5: Name → mnuFileSave; Caption → Save; Click button Indent in Toolbar Menu4: Name → mnuFileSaveAs; Caption → Save As...; Click button Indent in Toolbar Menu3: Name → mnuFileClose; Caption → Close; Click button Indent in Toolbar Menu2: Name → Seperator2; Caption → empty; Click button Indent in Toolbar Menu1: Name → mnuFileQuit; Caption → Quit; Click button Indent in Toolbar Illustration 124: Indent the menu entry Illustration below is how the end result should look like in the Menu Editor. Illustration 125: The end result of editing the menu entries Next close the Menu Editor and in IDE have a look at your form. Click on File to see what happens. 17 You do this by clicking the menu entry in the menu editor list and next changing the properties in the fields below the menu list. The selected menu entry will be the one you are editing. 117 11. Your fifth application: SimpleTextEditor Illustration 126: There is a menu File on FrmMain in IDE 11.3.1 Coding the menu entry New Now click on New in the newly made File menu and you will be taken to the code editor to the click event of this menu entry. Lets add some code to FrmMain: Public Sub Form_Open() Me.Center txaMain.Visible = False End Public Sub mnuFileNew_Click() txaMain.Clear txaMain.Visible = True 'Needed if another text document is already loaded End Now run the application and click menu File → New to see what will happen. Illustration 127: Before and after clicking menu File -> New 118 11. Your fifth application: SimpleTextEditor 11.3.2 Adding Icon and keyboard shortcut to menu entry New Back to the Menu Editor to add an icon and a keyboard shortcut. Once in Menu Editor click on the menu entry for New and set shortcut to CTRL and N Illustration 128: Set the keyboard shortcut for menu New Next at the property Picture click on the first button behind the textbox of Picture to open the Picture dialog. Select Tab Stock and select the New icon18. Illustration 129: Selecting the new icon 18 Icons might differ from desktop to desktop, depending on type of desktop and themes selected. 119 11. Your fifth application: SimpleTextEditor Click OK to close the Picture dialog after you selected the icon New. Next click OK again to close the Menu Editor. Now run the application again and once running on your keyboard press Ctrl + N and see what happens. This should give you an new empty text area, same as when clicking the File → New entry. So no extra coding to get the job done. Now click on menu File to see your menu icon. Illustration 130: File menu with the newly added icon for New Now that you can create a new text file and are able to enter text into the TextArea, next step will be to save the content of the TextArea to a file. 11.4 Saving your first text file When you want to save a newly made text file you will want to browse for a location, but when the file has been opened for editing you will already know where to save. So, what we actually have when saving a file is two situations: 1. New text file → no known location19 2. Existing text file → known location (as it has been opened from somewhere) If you compare this to Save As you will have only one situation: 1. Existing text file → unknown location (although it has been opened from somewhere) Seems that one thing you need to know is whether a text file is new or has been opened. And it also seems that the actions required for saving a new text file are the same as doing a save as for an existing text file. Another thing of importance is, that when saving an existing file you will need to know its location (being path and full name). These are the factors that will determine our approach in saving text files. 11.4.1 On a mission Yes, I'm going to send you on a mission. A mission to: 19 Location in the meaning of path and file name. 120 11. Your fifth application: SimpleTextEditor 1. Add a save icon to menu save 2. Add the keyboard entry Ctrl + S to the save menu 3. Have the code editor ready for coding the click event for the Save menu Your menu should look like the illustration on the next page. If you don't know how, read the back the part on how you did this for the menu entry New. Illustration 131: Make sure your menu entry for Save has an icon and keyboard entry Menus and keyboard shortcuts If you take a closer look at menus in common applications like web browsers, document managers, mail clients or whatever, you will notice that menus have a certain order and that this is actually of importance. Why could this be important? Imagine one developer of applications placing a File menu on a different location, another one placing Save in menu entry Edit, another one thing that Quit is better of in menu Misc. That would create a lot of confusion amongst people using the different applications as they would have to search for a function in different places depending on the application they are using. So having some sort agreement on menus makes life easier for those using your applications. No user will expect the File menu to be at another location than right at the beginning of the menu. No user will look for Save in any other menu that File. So in all it makes sense. Same for keyboard shortcuts. If you would use Ctrl + S to open a file, a lot of users would get confused as they are used to Ctrl + S for saving. There are some directives for both Gnome and KDE development. These directives are known as Human interface guidelines or hig. Have a look at them if you plan on designing applications with menus, so you can make menus that appeal to the already present 'menu 'intuition of the people using them. More on Human interface guidelines: https://en.wikipedia.org/wiki/Human_interface_guidelines Gnome hig on menus: https://developer.gnome.org/hig-book/stable/menus.html.en KDE hig on menus: http://techbase.kde.org/Projects/Usability/HIG/Menu_Bar 11.4.2 Lets save some text Now that all is a place you can start working for a solution based on the earlier analysis made. 121 11. Your fifth application: SimpleTextEditor If a file is opened you know two things: 1. its location 2. that it is NO new file So you could work with a variable that is set to true when a file is loaded. When false this means you have a new file and no location. When true you have an existing file and a location. Expect that this variable will be needed all over the FrmMain, so best make it a Private variable. You have learned about the difference between Private and Public. Private meaning that it can only be used within the class (in our case FrmMain.Class), Public meaning you can use it in other classes as well (remember the search and replace example in TextPlay(T)wo). Variables versus Private variables versus Public variables For 'regular' variables you use Dim to declare them. Their reach is the Function or Method they are declared in. You can't use them outside the function or method where they where declared. As shortly discussed in chapter 5. Some good practices, and seen in the examples so far, I precede my variable names with a letter like s or I. This is to identify the type of variable. For Private variables you use Private to declare them. Their reach is the entire class they are declared in. You can use them in any function or method within the class they where declared. You can't use them in other classes. When using Private variables I use the same convention as for 'regular' variables but add a $ sign in front of the letter to make them stick out and know as Private variables. For Public variables you use Public to declare them. Their reach is the entire class they are declared in and all other classes in the project. You can use them in any function or method within the project they where declared. You can use them in other classes. For Public variables I don't use the same convention as for 'regular' variables. I give them a meaningful name beginning with a capital letter and no indication of type. Some examples: Type String Integer, Long, Short, Byte Float Boolean Object (handle) Collection Arrays 'Regular' Private Public sMyName $sMyName MyName iMyNum $iMyNum MyNum fMyNum $ fMyNum MyNum bIsLoaded $bIsLoaded IsLoaded hFileToLoad $hFileToLoad FileToLoad cMyColl $cMyColl MyColl determined by type (e.g Array of strings → sNames) This approach is one that has grown throughout years of application development in other languages. It is almost the same as the naming convention used in the in Gambas written components source code and in the official examples. I have nick named my naming approach the 'gbwilly convention' :) Up to some coding. Add the following to FrmMain.class: Private $bLoaded As Boolean = False Public Sub Form_Open() ... 122 11. Your fifth application: SimpleTextEditor … End Public Sub mnuFileSave_Click() If $bLoaded Then 'Just save the file Else 'This means you have a new file Print "New file" 'Now you will need a path and a file name to save to Endif End Now run and make a new text file and watch the IDE console output. It should print 'New file' when you click menu File → Save. Next challenge you face is that you need some form of interaction with the user to provide the application with a save path and a name of the file, for you to use when saving the file. 11.4.3 Get name and path to save to To interface with the user for getting a save path and file name you will be using Dialog. Dialog.SaveFile (gb.form.dialog) Static Function SaveFile() As Boolean Calls the file standard dialog to get the name of a file to save. Returns TRUE if the user clicked on the Cancel button, and FALSE if the user clicked on the OK button. More on Dialog.SaveFile see: http://gambasdoc.org/help/comp/gb.form.dialog/dialog/savefile? v3 More on Dialog see: http://gambasdoc.org/help/comp/gb.form.dialog/dialog?v3 So Dialog is what you will use, back to the code editor in IDE. Public Sub mnuFileSave_Click() If $bLoaded Then 'Just save the file Else 'This means you have a new file Print "New file" 'Now you will need a path and a file name to save to '--- START OF ADDED CODE ---Dialog.Title = Application.Title & (" - Save text file") Dialog.Path = User.Home If Dialog.SaveFile() Then Return File.Save(Dialog.Path, txaMain.Text) Message.Info("File " & File.Name(Dialog.Path) & " saved.") '--- END OF ADDED CODE ---- 123 11. Your fifth application: SimpleTextEditor Endif End File.Save (gb) Static Sub Save(FileName As String, Data As String) Save the contents of a string into a file. File.Name (gb) Static Function Name (Path As String) Returns the name component of a file path (name component is filename and file extension). More on File.Save see: http://gambasdoc.org/help/comp/gb/file/save?v3 More on File.Name see: http://gambasdoc.org/help/comp/gb/file/name?v3 More on File see: http://gambasdoc.org/help/comp/gb/file?v3 User.Home (gb) Static Property Read Home As String Returns the home directory of the current user. More on User.Home see: http://gambasdoc.org/help/comp/gb/user/home More on User see: http://gambasdoc.org/help/comp/gb/user Run the application, start a new text file, type some text. Illustration 132: Ready to save my first file Next click File → Save. In the dialog form browse to a location you want to save the file, in the Name filed type 'test.txt' and click button Save. 124 11. Your fifth application: SimpleTextEditor Illustration 133: Dialog Save text file You will receive notification when saved. Illustration 134: Notification that the file has been saved 125 11. Your fifth application: SimpleTextEditor Run the application again open a new file, type some text, click File → Save and in the dialog click Cancel. Now that the file is saved you have a excuse to code opening a file, to see if the file was really saved. 11.5 Opening your first text file Opening the text file is kind of reverse to saving a text file. For opening the text file you will need the user to browse to the file and select it. Next load the content of the text file into txaMain. Make sure to keep track of the fact that the file was loaded ($bLoaded) and to keep track of its location (path and file name). So you need another variable to store the location. Best go Private again as you might need it in more than one method. 11.5.1 Code for opening To interface with the user for getting a file you will be using Dialog again. Dialog.OpenFile (gb.form.dialog) Static Function OpenFile([Multi As Boolean]) As Boolean Calls the file standard dialog to get the name of a file to open. Returns TRUE if the user clicked on the Cancel button, and FALSE if the user clicked on the OK button. More on Dialog.OpenFile see: http://gambasdoc.org/help/comp/gb.form.dialog/dialog/openfile? v3 More on Dialog see: http://gambasdoc.org/help/comp/gb.form.dialog/dialog?v3 So Dialog,OpenFile is what you will use, back to the Gambas IDE. Private $bLoaded As Boolean = False Private $sPathFileLoaded As String … Public Sub mnuFileOpen_Click() Dialog.Title = Application.Title & (" - Open text file") Dialog.Path = User.Home If Dialog.OpenFile() Then Return txaMain.Text = File.Load(Dialog.Path) txaMain.Visible = True 'Make the TextArea visible once file loaded $sPathFileLoaded = Dialog.Path 'Store the full path of the loaded file $bLoaded = True 'Set to True indicating NO new file End File.Load (gb) Static Function Load(FileName As String) As String Loads a file and returns its contents as a string. More on File.Load see: http://gambasdoc.org/help/comp/gb/file/load?v3 More on File see: http://gambasdoc.org/help/comp/gb/file?v3 Run the application and try to open the file 'test.txt', you made and see if it works. 126 11. Your fifth application: SimpleTextEditor Illustration 135: Dialog Open text file You should see that it works just fine. But there is one thing you forgot. The saving part is coded for a new text file, but not for an opened text file. So first back to the mnuSave click event. 11.5.2 Make sure an opened file can be saved You can go straight to the IDE as you have managed to gather all intelligence (like a detective) on the opened file, the job should be easy. Public Sub mnuFileSave_Click() If $bLoaded Then 'Just save the file '--- START OF ADDED CODE ---File.Save($sPathFileLoaded, txaMain.Text) Message.Info("File " & File.Name($sPathFileLoaded) & " saved.") '--- END OF ADDED CODE ---Else 'This means you have a new file 127 11. Your fifth application: SimpleTextEditor Once added, run the application, open test.txt, add a line of text and save. Illustration 136: Saved the changes to the text file Close the application and start it again. Open test.txt and you should see a changed file. 11.6 Little intermezzo Time to have a look at the menu and how it looks. The fact that you can save, even when no text file opened is at least disturbing. Just try it, run the application, do NOT open a file or create a new one and click menu File → Save. The application will not crash, but save an empty file. But it does look odd. So the file menu should behave according to the file being opened or not. When no file there are some menu items you would like to see disabled. These are: 1. Save 2. Save as... 3. Close You know that $bLoaded will tell you if an application is loaded, so every time this Boolean is changed, these menus need to change. For this you will create a Private method that sets the above mentioned menu items to enabled or disabled according to the value in $bLoaded20. Back to editing the code in the IDE. Private Sub Form_Open() ... SetFileMenu 'Add to the end of the Form_Open event End 20 You see that $bLoaded is being used all over the project. Now you know why it has been declared Private. 128 11. Your fifth application: SimpleTextEditor Public Sub mnuFileOpen_Click() … SetFileMenu 'Add to the end of the mnuFileOpen_Click event End Public Sub mnuFileQuit_Click() Me.Close 'About time you can close the application End Private Sub SetFileMenu() If $bLoaded Then mnuFileSave.Enabled = True mnuFileSaveAs.Enabled = True mnuFileClose.Enabled = True Else mnuFileSave.Enabled = False mnuFileSaveAs.Enabled = False mnuFileClose.Enabled = False Endif End Now run the application and see the menu without and with opened text file. Illustration 137: Part of the File menu disabled as should be This will work just test, but there is one exception when is will not work as expected. See if you can discover it. 129 11. Your fifth application: SimpleTextEditor Well, did you discover it? If not run the application again from scratch. Click on File → New (or use Ctrl + N), type some text and try to save it. Illustration 138: Oops.., no way to save a new text file.. Did you find it hard to save the text file? Well, I didn't manage. Guess all you need is some more code to solve this problem. So, when a new file is created you would like to be able to: 1. Save the file 2. Close the file (even without saving) When closing a file make sure that $bLoaded is set to False, $sPathFileLoaded and txaMain are empty. Another thing to take care of is that when a new file is saved make sure that $bLoaded is set to True and $sPathFileLoaded holds the path of the newly saved file. Back to the editor: Public Sub mnuFileNew_Click() … SetFileMenuNew 'Add to the end of the mnuFileNew_Click event End Public Sub mnuFileSave_Click() … Else … $sPathFileLoaded = Dialog.Path 130 11. Your fifth application: SimpleTextEditor $bLoaded = True Message.Info("File " & File.Name(Dialog.Path) & " saved.") Endif End Public Sub mnuFileClose_Click() txaMain.Clear txaMain.Visible = False $sPathFileLoaded = Null $bLoaded = False SetFileMenu End ... Private Sub SetFileMenuNew() mnuFileSave.Enabled = True mnuFileClose.Enabled = True End Run the application and all should be working correctly. Start a new text file and see f you can save it. Save it and the Save as should appear as well. Next close it and the File menu should adapt to the new situation and the TextArea should be gone. Next start another new text file, now close it and again see the menu change accordingly. One more thing, make sure that menu File → Open, File → Close and File → Quit all get an icon and File → Quit gets a keyboard shortcut (Ctrl + Q). Illustration 139: The end result of some polishing of the File menu 131 11. Your fifth application: SimpleTextEditor 11.7 Back on track for Save As Now all that is left for coding in the File menu is Save As... You have arranged that the Save As menu item will only be seen when an existing project is opened or a new one has been saved. 11.7.1 Code Save As menu item What needs to happen when Save As is launched is actually about the same as when a new document gets saved. The user will get a dialog to determine path and new file name. You need to save to this user determines path and file name. The code is as follows: Public Sub mnuFileSaveAs_Click() Dialog.Title = Application.Title & (" - Save As text file") Dialog.Path = User.Home If Dialog.SaveFile() Then Return File.Save(Dialog.Path, txaMain.Text) $sPathFileLoaded = Dialog.Path $bLoaded = True Message.Info("File " & File.Name(Dialog.Path) & " saved.") End Now run the application, open a text file and save it with another name. Illustration 140: Save As dialog 132 11. Your fifth application: SimpleTextEditor You will see that this works as expected. Illustration 141: Notification that the file was saved using a new name You might also have noticed that the code for Save As is, except for the dialog form caption, exactly the same. So there is some more work to be done 11.7.2 Simplifying the code for saving This common code makes for a perfect example for a routine that can be called for both situation, simplifying your code, lessening the mount of code and making for better maintainable code as you only need to modify code at one place instead of two. Here is what you the changed Save and Save As event will look like: Public Sub mnuFileSave_Click() If $bLoaded Then 'Just save the file File.Save($sPathFileLoaded, txaMain.Text) Message.Info("File " & File.Name($sPathFileLoaded) & " saved.") Else SaveDialog(“Save”) Endif End Public Sub mnuFileSaveAs_Click() SaveDialog(“Save As”) End You'll notice they are a lot shorter and pass an argument for the Dialog form caption. (being 'Save' and 'Save As'). This how the SaveDialog() routine looks lik (it is private because you only use it in the current FrmMain.class): 133 11. Your fifth application: SimpleTextEditor Private Sub SaveDialog(DialogCaption As String) Dialog.Title = Application.Title & (" - " & DialogCaption) Dialog.Path = User.Home If Dialog.SaveFile() Then Return File.Save(Dialog.Path, txaMain.Text) $sPathFileLoaded = Dialog.Path $bLoaded = True Message.Info("File " & File.Name(Dialog.Path) & " saved.") End DialogCaption is the variable used to pass the argument. So calling SaveDialog(“Save”) will pass the string “Save” to variable DialogCaption and use its value wherever DialogCaption is used in the routine. Illustration 142: The auto-help will know your new routine As you see, for a variable used as an argument in a method (or function) I use no prefix to the variable name, but a name that describes what argument will be for. It's type I will know when using the routine in code as the auto-help will tell me (see illustration above). Run the application to see it all at work as it should. You should have one working very simple TextEditor that you can actually use in real life situation. But there is still room for improvement. 11.8 Putting the dots on the i There is of course always room for improvement. Improving an application can take place on many front like its functionality, its user friendliness, its looks, its bugs fixed just to name a few. You are going to focus on one improvement in functionality. It is more a lack of functionality that needs to be implemented and that is rather disturbing. You might have noticed that, when editing a file and next closing it the application will NOT warn you about the file being changed and offering you an option to save it. Another thing that will come around the corner when implementing this functionality is the x on the main form. Users can use this to close the window (and thus the application) circumventing all your code to catch the 'file is edited and thus question for saving' code upon closing. 134 11. Your fifth application: SimpleTextEditor Another thing is that our form is rather small and when opening a large text file and next dragging the form bigger the TextArea will remain small. Some work there as well. And last but not least, wouldn't it be nice to have a toolbar with open, save and other buttons? So a few more thing to do before the application suits the needs. 11.8.1 Offer to save when closed after editing text file The first thing you need to do is determine whether a file is changed or not. For this another private variable is introduced $bChanged (a Boolean). The control you need to check for changes is txaMain, so that is where $bChanged needs to be set to true. TxaMain has a Change event and that is the one you need to code. Not very much code needed to do the job: Private $bChanged As Boolean = False Public Sub txaMain_Change() $bChanged = True End Next thing to do is to take care that when closing the application our change condition is checked and when changed a possibility to save is offered.. This needs to be done at both menu item Close and Quit. Public Sub mnuFileClose_Click() If $bChanged Then 'offer option to save Else txaMain.Clear '← will trigger a change event and set $bChanged to true txaMain.Visible = False $bLoaded = False $bChanged = False '← set to false (see comment above) $sPathFileLoaded = Null SetFileMenu Endif End Public Sub mnuFileQuit_Click() If $bChanged Then 'offer option to save Else Me.Close Endif End Code for offering to save is not yet there but you might notice that it will probably be exactly the same for both Close and Quit event. Now when offering the user to save the file you need to give some options like 'Yes', 'No' and 'Cancel' and act accordingly. 135 11. Your fifth application: SimpleTextEditor Now on several occasions Message has been used in the example applications and one of its variants Message.Info (in this example application). Well, there is more you can do with Message so time to have a closer look. You will be using Message.Warning as that makes sense, you want to war users of unsaved work. Message This class is used for displaying message boxes All Message functions can have up to three buttons: - The first button is always the default button - The last button is always the cancel button Message boxes are modal, meaning the program is paused until one button is clicked. When a message box is closed the index of the clicked button is returned. Message.Warning Static Function Warning(Message As String [, Button1 As String, Button2 As String, Button 3 As String) As Integer Displays a warning message with up to three buttons. The index of the button clicked by the user is returned More on Message.Warning see: http://gambasdoc.org/help/comp/gb.qt4/message/warning?v3 More on Message see: http://gambasdoc.org/help/comp/gb.qt4/message?v3 As indicated above when showing the Message.Warning (with three buttons) the application will pause until user has made his choise. When clicking 'yes' you need to save before Close or Quit When clicking 'No' you Close or Quit without saving When clicking 'Cancel' the Close or Quit has to be aborted. Lets try to code this in a new private function for this: Private Function WarningIsCancelled() As Boolean Dim iAnswer As Integer iAnswer = Message.Question("File has been changed!\nDo you want to save the project?", "Yes", "No", "Cancel") Select iAnswer Case 1 mnuFileSave_Click '<-- Yes: Let the code at the FileSave menu handle the saving Return False Case 2 Return False '<-- No: So no saving Case Else Return True '<-- Cancel: So cancelled End Select End Why a function? Well a function can do all a method can do, but it can also return something. In this case it returns True if button Cancel was clicked in Message.Warning. That is why the function is de- 136 11. Your fifth application: SimpleTextEditor clared As Boolean. The value after the word 'Return' has to be a Boolean as this is the value returned when the function is called. Since you will call this function from Close and Quit event it would be nice to know if 'Cancel' was clicked. So when calling WarningIsCancelled() it will return either True or False. When True, the warning was cancelled so the Closing or Quitting needs to be cancelled as well. Hence the name of the function WarningIsCancelled, a name that gives meaning to what the function actually does. Now lets have a look at the changed code for Close and Quit event: Public Sub mnuFileClose_Click() If $bChanged Then If Not WarningIsCancelled() Then txaMain.Clear '← Message.Warning received a yes or no txaMain.Visible = False $bLoaded = False $bChanged = False $sPathFileLoaded = Null SetFileMenu Endif Else txaMain.Clear txaMain.Visible = False $bLoaded = False $bChanged = False $sPathFileLoaded = Null SetFileMenu Endif End Public Sub mnuFileQuit_Click() If $bChanged Then If Not WarningIsCancelled() Then Me.Close Endif Else Me.Close Endif End Time to run the application to see the effect of all the code. First open a file, edit it and click File → Close You should get a warning telling you that your file has changed and offering you the option to save it. 137 11. Your fifth application: SimpleTextEditor Illustration 143: Closing after editing gives a warning and option to save Now click Cancel to see what happens. You should go back to the file without closing. Now click File → Close again and next click No. The application will close the file. Now open the same file and see if the changes where saved. They shouldn't be as you clicked 'No'. Now make some changes and click File → Close again and select Yes. The file should close and upon opening the changes should be in the newly opened file. Try the same for File → Quit. If all that is done, one question: Did you discover the bug in your application?... 11.8.2 Bug!! What bug?! When you intend something to work a certain manner to provide certain functionality and it doesn't do that job under all circumstances, then you can call that a bug. Try opening a text file, do NOT change the file and click File → Close. What happens? Do you get a warning that your file has been changed when it isn't? Something does seem to trigger the Change event of txaMain. First lets add a Print statement to the Change event so you can check in console when it is triggered. Public Sub txaMain_Change() $bChanged = True Print “Changed” End Now run the application keep your eye on the console. When launching the application nothing happens in the console. When clicking File → Open nothing happens in the console. When selecting a file and clicking OK → console shows 'Changed' 138 11. Your fifth application: SimpleTextEditor Illustration 144: Changed shown in Console means Change event is triggered This actually makes sense as when loading a file to txaMain means a change form the point of view of txaMain. Here is the piece of code run before Change event is triggered. Public Sub mnuFileOpen_Click() Dialog.Title = Application.Title & (" - Open text file") Dialog.Path = User.Home If Dialog.OpenFile() Then Return txaMain.Text = File.Load(Dialog.Path) '← triggers the change event After txaMain.Text = File.Load(Dialog.Path), instead of running the next line of code, the change event for txaMain is triggered. So the Gambas Interpreter will first execute the txaMain_Change() event before returning to the line of code after loading the file. That is where you need to take care of business as change is triggered upon opening and $bChanged is set to true. Adding following line should solve the problem. Public Sub mnuFileOpen_Click() Dialog.Title = Application.Title & (" - Open text file") Dialog.Path = User.Home If Dialog.OpenFile() Then Return txaMain.Text = File.Load(Dialog.Path) $bChanged = False '← Add this line Now try running the application again. Do NOT change anything to the file and click menu File → Close. It should work properly now. So one bug down, up to the next one. Open a file, change a few things and next click on the x to close the window (and thus the application). Next open the application again and open the file. Did the changes save? I bet you they didn't, so there you have a second bug. To catch the closing of a form by the user using x is done in the Form_Close() event. For this you will code the Form_Close event and next cut and past the code of the mnuFileQuit_Click event to the Form_Close event. Next call the Form_Close event from mnuFileQuit_Click event. 139 11. Your fifth application: SimpleTextEditor Public Sub Form_Close() f $bChanged Then If Not WarningIsCancelled() Then Me.Close Endif Else Me.Close Endif End Public Sub mnuFileQuit_Click() Form_Close End Now run the application, open a file, change something and click x. You will get the warning. Click Yes and file will save and application closes. Open the same file and see if the changes saved. Now change again and click x. Select Cancel and you will see that the application, instead of cancelling will close. To solve that problem you will need one more line of code: Public Sub Form_Close() f $bChanged Then If Not WarningIsCancelled() Then Me.Close Else '← add this Stop Event '← and this Endif Else Me.Close Endif End STOP EVENT STOP EVENT This statement must be in an event handler. It tells the interpreter that the event that called the event handler must be cancelled. More on STOP EVENT see: http://gambasdoc.org/help/lang/stopevent?v3 More on Event Management see: http://gambasdoc.org/help/cat/event?v3 Now run the application again, open and change a file, click x and next Cancel and the application should stay opened. In short, second bug down. 140 11. Your fifth application: SimpleTextEditor 11.8.3 Resizing the application window Check if you have got a ReadMe file or some other text file with a good quantity of text and open it using SimpleTextEditor. You will notice that with a lot of text a bigger size window would be better. So go to the border of the SimpleTextEditor window and drag it bigger. Illustration 145: Dragging the window bigger doesn't change the TextArea You will notice the window will resize, but the TextArea will not. To solve this problem go to the FrmMain properties in the Gambas IDE. Set the FrmMain property Arragement to Horizontal Illustration 146: Set the Arrangement property of FrmMain Now run the application, open you big text file and drag the main window bigger. 141 11. Your fifth application: SimpleTextEditor Illustration 147: The TextArea now does resize with the window... TextArea does resize when dragging the window bigger, but not how you would like it. You should try setting property Arrangement to Vertical as well and give it a go. The one you need to make it work properly is Fill. So make sure to end there. Illustration 148: Arrangement set to Fill does the job 142 11. Your fifth application: SimpleTextEditor 11.8.4 Adding a ToolBar To add a ToolBar you will need to go back to the design of your form and make some room below your menu and above your TextArea. Next add a Hbox above the TextArea. HBox: Name → hbxToolBar Illustration 149: HBox is found on the Tab Container Now select the Hbox and add a ToolButton: ToolButton: Name → tbnNew; Width → 22; Height → 22; Picture→ select the New icon from stock 22. You result should look like the illustration below. Check the hierarchy to see if tbnNew is actually placed inside the hbxToolBar (very important). Illustration 150: All new controls in place Next double click tbnNew and code its Click event: Public Sub tbnNew_Click() mnuFileNew_Click End Run the application and see what happens when clicking New in the Toolbar. Drag the window bigger and see what happens there. Although the New button does produce a new empty text file, the forms looks a bit weird. 143 11. Your fifth application: SimpleTextEditor Illustration 151: A strange looking form, but New button works.. Seems you need to fix the Arrangement of the FrmMain. Give it a go and try the different options. Now that you probably figured out that none will work, set the FrmMain property Arrangement to Vertical. Next set the txaMain property Expand to True. Illustration 152: Set txaMain property Expand to True Now give it another run. You should be able to make a new text file, drag the window bigger and all should look just fine. Now add a few more ToolButtons to hbxToolBar. ToolButton: Name → tbnOpen; Width → 22; Height → 22; Picture→ select the Open icon from stock 22. ToolButton: Name → tbnSave; Width → 22; Height → 22; Picture→ select the Save icon 144 11. Your fifth application: SimpleTextEditor from stock 22. ToolButton: Name → tbnSaveAs; Width → 22; Height → 22; Picture→ select the SaveAs icon from stock 22. ToolButton: Name → tbnClose; Width → 22; Height → 22; Picture→ select the Close icon from stock 22. The result should look like illustration below. Make sure the buttons are inside the Hbox. Illustration 153: Make sure all ToolButtons are inside the HBox Next code all the new ToolButtons. Just let them run the click event of the according menu item. Public Sub tbnOpen_Click() mnuFileOpen_Click End Public Sub tbnSave_Click() mnuFileSave_Click End Public Sub tbnSaveAs_Click() mnuFileSaveAs_Click End Public Sub tbnClose_Click() mnuFileClose_Click End Next take care that only those ToolButtons are enabled that need to be enabled, just like you did with the menus. For that you will need to go to the two private routines SetFileMenu and SetFileMenuNew. They will need to look like this: 145 11. Your fifth application: SimpleTextEditor Private Sub SetFileMenu() If $bLoaded Then mnuFileSave.Enabled = True mnuFileSaveAs.Enabled = True mnuFileClose.Enabled = True tbnSave.Enabled = True tbnSaveAs.Enabled = True tbnClose.Enabled = True Else mnuFileSave.Enabled = False mnuFileSaveAs.Enabled = False mnuFileClose.Enabled = False tbnSave.Enabled = False tbnSaveAs.Enabled = False tbnClose.Enabled = False Endif '← added '← added '← added '← added '← added '← added End Private Sub SetFileMenuNew() mnuFileSave.Enabled = True mnuFileClose.Enabled = True tbnSave.Enabled = True tbnClose.Enabled = True '← added '← added End You will notice how easy it is to make all this work because of a well set up code. Only a few things need to be done to make all work. Time for testing the application. Run and try your new buttons, see if they are enabled at the proper times, if they work. Make a new file with the New button, type some text and save it with the Save button. Close it with the Close button and reopen with the Open button. Does all work as expected? Open a file and change it, try to close it with the button. Do you get a warning that file has been changed? All should work as expected and like the menus worked. Illustration 154: A running resizeable SimpeTextEditor with Toolbar 146 11. Your fifth application: SimpleTextEditor All that is left doing is make the ToolBar look a bit better. Simply set the property Spacing of the hbxToolBar to True Illustration 155: Toolbar with property Spacing set to False Illustration 156: Toolbar with property Spacing set to True That wasn't to hard. 11.8.5 Reordering menu items One more thing before this chapter comes to an end. In most applications you will find the menu item Close just above Save. You have it below SaveAs. Lets make a change. Open the Menu Editor. Select the menu item Close and click the Move Up button twice. Illustration 157: A click on Move Up button brings the item higher 147 11. Your fifth application: SimpleTextEditor 11.8.6 Adding new menus You can also easily add a new menu. And that is your next mission. Add these menu items to the bottom of the current ones Menu4: Name → mnuView; Caption → View Menu3: Name → mnuViewToolBar; Caption → Toolbar; Checked → True;Click button Indent in Toolbar Menu2: Name → mnuHelp; Caption → Help Menu1: Name → mnuHelpAbout; Caption → About... Click button Indent in Toolbar Illustration 158: Added menus with ToolBar menu item set checked Run the application to see your new menus. Have a special look at menu View → Toolbar as this one has a checkbox. Illustration 159: A new menu View Toolbar 148 11. Your fifth application: SimpleTextEditor Now when the menu item Toolbar is checked you want the ToolBar to be visible. When unchecked it needs to be invisible. For the About menu item in menu Help you will code a simple Message. Public Sub mnuViewToolBar_Click() If mnuViewToolBar.Checked Then mnuViewToolBar.Checked = False hbxToolBar.Visible = False Else mnuViewToolBar.Checked = True hbxToolBar.Visible = True Endif End Public Sub mnuHelpAbout_Click() Message.Info(Application.Name & " " & Application.Version & "\nAn example application by W. Raets\n\nGNU General Public License version 3") End For the mnuViewToolBar you check its checked status and change it. Clicked when the Toolbar item was checked will uncheck it and vice versa. Besides that it will make the ToolBar hbxToolBar visible or invisible accordingly. The mnuHelpAbout code is just a simple Message.Info. Have a look at your result. Illustration 160: With ToolBar checked Open a text file and click menu View and see the Toolbar item checked. Now click the menuitem Toolbar and see the Toolbar disappear (see illustration on next page). 149 11. Your fifth application: SimpleTextEditor Illustration 161: With Toolbar unchecked Click menu Help → About... to see your About screen. Illustration 162: Menu Help -> About shows some info on the application 11.8.7 Application caption The last 'dot to put on the I' is the application caption. Default it shows the applications name, but it could be used differenty. When a text file is open it could show the application name and the name of the text file. When a new text document is made it could show application name and 'new text document'. As the caption has to be set according to the current state of the text loaded into txaMain, it is going to be needed at more than one place in our FrmMain.class. A private routine would be the proper road to take. Basically there are two situation: 150 11. Your fifth application: SimpleTextEditor 1. No document loaded → no file name 2. Document loaded → file name known or file name is 'new text document' If you write a private method that sets the caption these file names need to get passed to the private method. For that you use an argument, but since there is not always a file name to pass you need to make the argument Optional, meaning you can provide the argument when calling the method but you don't need to. Back to the code editor in IDE to write the routine: Private Sub SetAppCaption(Optional AppCaption As String) If IsNull(AppCaption) Then Me.Caption = Application.Name Else Me.Caption = Application.Name & “ - “ & AppCaption Endif End Because AppCaption is an optional argument, meaning it can be empty, you need to check what cause of action to take when empty (IsNull). Next step is to check at what places the method SetAppCaption needs to be called. First place is when a new document is made. The caption will need to show 'New text document' alongside the application name. Public Sub mnuFileNew_Click() txaMain.Clear txaMain.Visible = True SetAppCaption(“New text document”) End Now run the application and click button New in the Toolbar. Illustration 163: 'New text document' added to application caption 151 11. Your fifth application: SimpleTextEditor Second place to check is when opening a text file. Public Sub mnuFileOpenClick() ... txaMain.Text = File.Load(Dialog.Path) '← this is where the file gets loaded SetAppCaption(File.Name(Dialog.Path)) '← this is where you set the caption ... End Again run and open a text file and see the file name appear in the caption. Illustration 164: Caption showing the name of the opened text file Third place to check is when a new document is saved (so it has a name) and when an existing document is saved as (so it will get another name). This all happens in method SaveDialog. So that is where you need to add the code: Public Sub SaveDialog() ... File.Save(Dialog.Path, txaMain.Text) '← this is where the file gets saved SetAppCaption(File.Name(Dialog.Path)) '← this is where you set the caption ... End And last but not least, the caption should be set when opening the form: Public Sub Form_Open() Me.Center SetAppCaption() ... '← this is where you set the caption (no name known) 152 11. Your fifth application: SimpleTextEditor Run your application once more and try some different things, like starting a new text document and saving it, next save as. If you see the caption changing the application is finished for now. Illustration 165: Save the new text document Illustration 166: After saving the caption changed 11.9 A last note on code organisation Since no application is really free of maintenance, you should organise your code in such manners that, in a later stage (this can be months and other applications later), you understand what you have been doing in the past. Comment can contribute, as can ordering your code. On the next illustration a screenshot of the code of this project in my IDE. You will see that I placed all menu code together, all toolbar code together, all private routines together. All these groups have a comment indicating where they start. 153 11. Your fifth application: SimpleTextEditor Illustration 167: FrmMain.class code organised in certain order Not visible on the screenshot is that at certain point in the code I add comment to explain to myself (in a later stage) what I did there. Might sound strange, but believe me, I am very happy that I give myself these presents. This concludes this chapter. In the next chapter you're going to continue to work with SimpleTextEditor. 154 12. End note for pre-release 1 12 End note for pre-release 1 This work is not finished yet. More chapters will be added as soon as possible and current ones might be further revised. Planned for the next chapter (actually this chapter 12) is printing. After that you will be diving into some more complex situations when it comes to handling data and saving it, you will learn some new more complex controls and have a closer look at what is possible with form classes. This journey will take several chapters. And what will be next I'm not sure about, a closer look at the IDE will be part of it fir sure. Expect at least 6 or 7 more chapters added to the final release. Maybe in between another prerelase will become available, a bit depending on how long things take to write. Meanwhile I hope you enjoyed the first 11 chapters and working with Gambas. Make sure to install the application GambasLearning (see Appendix VI) , for updated information on this and other 'How To Gambas'-guides and more to help the beginning Gambas developer. To be continued... P.S. If you encounter any irregularities in this release please report them back (see Appendix V) and help improve the guide. 155 13 Appendices Appendix I: Linux command reference If you are new to Linux, here are some commands that could be useful when installing Gambas from the official website or from SVN. File commands ls ls -al cd dir cd cd / mkdir dir rm file rm -r dir rm -f file rm -fr dir lists the current directory lists the current directory (hidden files included) change the directory dir (example: cd /usr/bin) change to home directory change directory to root directory make directory dir (example mkdir Gambas3) removes file file (example rm myinfo.txt) removes directory dir (example rm Gambas3) forced remove file file (example rm -f myinfo.txt) forced remove directory dir (example rm -rf Gambas3) System information df du uptime uname -a free show disk usage show directory usage show system uptime show kernel information show memory and swap information Installation from source ./configure make make install Configure the package Compile the package Install the package I Appendix II: Subscribe to the official Gambas mailing lists/Forum When you are experiencing problems installing Gambas and you don't manage to solve them you can always report them on the Gambas mailing list. For this you will first need to subscribe to the mailing list. Open a browser and go to the Gambas website and click on the menu 'Mailing lists/Forums' Illustration 168: Gambas website - Menu Mailing lists/Forums This will open an overview of the available mailing lists and a forum. Illustration 169: Gambas website - Overview Mailing Lists & Forums For reporting your problems use the 'Gambas Users' list. The 'Gambas Developers” and 'Gambas Subversion Commits” lists are meant for those working on the development of Gambas3 (or those just curious) II Then there is a Spanish and French user list and next the forum for those who dislike mailing lists. Option 1: Subscribe to Gambas Users mailing list When clicking 'Gambas Users' you get to the page to register to the mailing list. Illustration 170: Subscribe to the Gambas-user mailinglist Once registered you will receive all posts on the mailing list in the inbox of the mail account you signed up with. You will also be able to send mails to the list. Option 2: Use the forum instead of the mailing list If you dislike mailing list there is a second option. Click 'http://www.nabble.com/Gambasf3425.html' to go to the forum. III Illustration 171: Gambas mailing list Forum On the forum you will find all the topics and posts from the mailing list. To post you will need to register an account. IV Appendix III: Reporting problems on the official Gambas mailing list When reporting your problems on the mailing list first consider a few good practices. 1. Search the official Gambas mailing list forum for an answer before asking questions 2. Provide details on your system when reporting your problem 3. Provide details on your problem when reporting your problem 4. Be clear on what goes wrong and where it goes wrong and the steps that took you there 5. Provide a source archive with a project that shows the problem When having problems provide these details on your system: 1. Kernel information (use uname -a in a terminal) 2. Distribution name and version (Example: Linux Mint 13 Maya) 3. Desktop used (Examples are: Gnome, KDE, LXDE, xfce, Mate, Cinnamon,...) 4. Gambas version All this can be found in the Gambas IDE menu ? → System informations... Illustration 172: Gambas IDE - System information form Just copy/paste into your mail or attach a text file you pasted the information into. V Appendix IV: White Island Software and GambasForum quick tour On White Island Software and GambasForum a Project Collaboration Forum 'How to Gambas 3' has been created open to the public21. Here is a quick tour to get you started on the forum. To go to White Islands Software and GambasForum open a web browser and type http://whiteislandsoftware.com/index.php?page=start as destination. Illustration 173: White Island and GambasForum (circled the login and join) Once there log in or join (see illustration above). When logged in you will be brought to the same page again but now with more details where the login used to be. Click on Forum in the top menu (just behind Home). You will get an overview of all forums present when scrolling down. Forums are categorized into these categories with following forums per category 22: ➢ Website Community ➢ Website Community ➢ Gambas News ➢ General ➢ Introduce yourself ➢ General chat ➢ Graphic and Images ➢ Website comment topics ➢ The GambasForum Coder ➢ Gambas IDE ➢ Ask Quin ➢ Gambas version 3 ➢ Gambas versions 1 and 2 ➢ Raspberry Pi ➢ Gambas based projects ➢ Member's Lounges ➢ gbWilly 21 22 You can visit it as guest and read all information. To post questions on the forum you need to make a free account. Categories and forums as present on October 14th 2012. VI sholzy konaexpress ➢ NatashaDaystar ➢ Piga Software ➢ Gambas Project hosting ➢ Important notices (Read-only) ➢ The Admin's lounge ➢ How To.../Howdo I... ➢ Domains ➢ ➢ If you want to look for something or post something make sure to go to the proper category and forum. When you visit the GambasForum to check what you missed since your last visit there is an easy option at the top left of your user name 'Post since last visit'. Click it and you will see what you missed out on. Illustration 174: Search, Post since last visit and Topics with unread posts Another handy option is the 'search' button for searching the forum if you have some problem with Gambas. If no answer to your problem can be found just start a new topic in the proper category and forum. 'Topics with unread posts' can come in practical at times as well. With this information you have the basics to get started on the forum. There is a lot more out there like a software repository, guides and so on, but that is not what this guide is about. VII Appendix V: Getting help with the 'How to Gambas 3' guides On White Island Software and GambasForum a Gambas based project 'How to Gambas 3' has been created open to the public23. It is set up so that people having trouble with the guide can go there and ask their questions (or check if someone else asked the same) or do suggestions on the manual. These questions and suggestions will be taken into account on improving the guides. So feel free do make good use of this possibility. First browse to the White Island Software and Gambas Forum24 and login (if you want to post your problem). Click on 'Forum' in the topmenu and scroll down to the category 'Gambas based projects' where you will find the forum 'How to Gambas 3' under gbWilly. Illustration 175: Gambas based projects with sub forum 'How to Gambas 3' If you click the forum you will find several sub forums and some general topics. Current sub forums are: ➢ Installing Gambas This contains topics concerning the guide 'Installing Gambas'. Post your questions and/or suggestions on the guide 'Installing Gambas' here. ➢ Building GUI Applications This contains topics concerning the guide 'Building GUI Applications'. Post your questions and/or suggestions on the guide 'Building GUI Applications' here ➢ Project member Section This section is for project contributors only. If you want to contribute send a PM on the forum to gbWilly. The number of sub forums will grow with the number of guides is the series. 23 24 You can visit it as guest and read all information. To post questions on the forum you need to make a free account. Link to website: http://whiteislandsoftware.com/index.php?page=start VIII Illustration 176: Sub forums and topics of 'How to Gambas 3' forum Each sub forum will have its own topics. Make sure to post in the proper sub forum. So for questions on this manual 'Building GUI Applications' you click Building GUI Applications to see the topics present. Illustration 177: Topics in sub forum 'Building GUI Applications' Three topics are of importance: ➢ Suggestions for improvements ➢ Problems with instructions in the manual ➢ Other questions The topics are kind of self explaining, just post in the proper one and it will be picked up. IX Appendix VI: Application Gambas Learning – a learning aid for Gambas Gambas Learning is an application to provide some aid to those learning Gambas. Illustration 178: Gambas Learning - a learning aid for Gambas The application provides you with: ➢ an overview and download of the 'How To Gambas 3' guides (most recent version) ➢ Gambas 3 code snippets for common tasks ➢ a direct access to the Gambas 3 language index ➢ a direct access to the Gambas 3 component index ➢ a direct access to the Gambas 3 error messages index ➢ a direct access to the How To Gambas forum The application receives remote metadata updates25 on the number, version and state of guides available. New code snippets that are available are also part of the metadata updates of Gambas Learning and will update the code snippets seen in Gambas Learning. For more screenshots and download visit: http://howtogambas.org/ 25 This requires a working internet connection X Appendix VII: Overview of the 'How To Gambas 3' guides Here is the list of guides published and planned: ➢ 1. Installing Gambas First version published: November 10th, 2012 ➢ 2. Building GUI Applications First 11 chapters pre-published: September 29th, 2013 XI 14 Bibliography Primary sources Gambas website: Gambas 3 Documentation, URL: http://gambasdoc.org/help/?v3 [Last accessed 28/09/2013]. Gambas website: Reporting a problem, bug or crash, URL: http://gambasdoc.org/help/doc/report?view [Last accessed 14/10/2012] Secondary sources Wikipedia: Gambas, URL: http://en.wikipedia.org/wiki/Gambas [Accessed 09/11/2012] Wikipedia: C Datatypes, URL: https://en.wikipedia.org/wiki/C_data_types [Accessed 02/03/2013] Wikipedia: Object-oriented programming URL: http://en.wikipedia.org/wiki/Object-oriented_programming [Accessed 23/09/2013] XII
© Copyright 2024