D E L P H I, L A Z A R U S, O X Y G E N E, S M A R T M O B I L E, A N D P A S C AL R E L A T E D L A N G U A G E S A N D R O I D, I O S, M A C , W I N D O W S & L I N U X
BLAISE PASCAL MAGAZINE 52
GENERICS EXPLAINED / PART 1 BY DETLEF OVERBEEK TURBO COCOA FOR DELPHI AND ANDROID BY VSEVOLOD LEONOV TMS FNC USER INTERFACE CONTROLS, A SET OF FRAMEWORK NEUTRAL CONTROLS, INTRODUCTION BY BRUNO FIERENS HUMOR BY KIM MADSEN SOFTDRAW BY DAVID DIRKSE HOW TO BUILD AN APP IN XML WITH FIREMONKEY INCLUDED STYLE SHEETOVERVIEW BY DETLEF OVERBEEK HOW TO DEAL WITH BIG NUMBERS BY MAX KLEINER
PRINTED ISSUE PRICE € 15,00 DOWN LOAD ISSUE PRI CE € 5,0 0
BLAISE BLAI SE PASCAL PASCAL MAGAZINE 52 D E L P H I, L A Z A R U S, S M A R T M A N D P A S C A L R E L A T E D F O R A N D R O I D, I O S, M A C, W I N
O B I L L A N D O W S
E S T U D G U A G & L I N U X
I E
O, S
CONTENTS ARTICLES FROM THE EDITOR PAGE 4 GENERICS EXPLAINED / PART 1 PAGE 5 BY DETLEF OVERBEEK TURBO COCOA FOR DELPHI AND ANDROID PAGE 9 BY VSEVOLOD LEONOV TMS FNC USER INTERFACE CONTROLS, A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 15 INTRODUCTION WHO!? ME!? BY BRUNO FIERENSW HUMOR BY KIM MADSEN PAGE 23 SOFTDRAW PAGE 24 BY DAVID DIRKSE HOW TO BUILD AN APP IN XML WITH FIREMONKEY PAGE 27 INCLUDED STYLE SHEETOVERVIEW BY DETLEF OVERBEEK HOW TO DEAL WITH BIG NUMBERS PAGE 36 maXbox BY MAX KLEINER
FNC FRAMEWORK NEUTRAL COMPONENTS
Advertisers BARNSTEN 14 COMPONENTS 4 DEVELOPERS 40 COMPUTER MATH AND GAMES 26 TURBO COCOA 13
2
Publisher: Foundation for Supporting the Pascal Programming Language in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep) © Stichting Ondersteuning Programmeertaal Pascal
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
BLAISE BLAI SE PASCAL PASCAL MAGAZINE 52 D E L P H I, L A Z A R U S, S M A R T M A N D P A S C A L R E L A T E D F O R A N D R O I D, I O S, M A C, W I N
O B I L L A N D O W S
E S T U D G U A G & L I N U X
I E
O, S
CONTENTS ARTICLES FROM THE EDITOR PAGE 4 GENERICS EXPLAINED / PART 1 PAGE 5 BY DETLEF OVERBEEK TURBO COCOA FOR DELPHI AND ANDROID PAGE 9 BY VSEVOLOD LEONOV TMS FNC USER INTERFACE CONTROLS, A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 15 INTRODUCTION WHO!? ME!? BY BRUNO FIERENSW HUMOR BY KIM MADSEN PAGE 23 SOFTDRAW PAGE 24 BY DAVID DIRKSE HOW TO BUILD AN APP IN XML WITH FIREMONKEY PAGE 27 INCLUDED STYLE SHEETOVERVIEW BY DETLEF OVERBEEK HOW TO DEAL WITH BIG NUMBERS PAGE 36 maXbox BY MAX KLEINER
FNC FRAMEWORK NEUTRAL COMPONENTS
Advertisers BARNSTEN 14 COMPONENTS 4 DEVELOPERS 40 COMPUTER MATH AND GAMES 26 TURBO COCOA 13
2
Publisher: Foundation for Supporting the Pascal Programming Language in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep) © Stichting Ondersteuning Programmeertaal Pascal
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
Stephen Ball http://delphiaball.co.uk @DelphiABall
Peter Bijlsma -Editor peter @ blaisepasca blaisepascal.eu l.eu
Dmitry Boyarintsev
Michaël Van Canneyt, michael @ freepascal freepascal.org .org
Marco Cantù www.marcocantu.com marco.cantu marco.cant u @ gmail.com gmail.com
David Dirkse www.davdata.nl E-mail: David @ davdata.nl
Benno Evers b.evers @ everscustomtechnology.nl
Bruno Fierens Primož Gabrijelčič www.tmssoftware.com www.primoz @ gabrijelcic.org m bruno.fierens bruno.fier ens @ tmssoftware.c tmssoftware.co o m
Fikret Hasovic fhasovic @ yahoo.com
dmitry.living @ gmail.com
Cary Jensen www.jensendatasystems.com http://caryjensen.blogspot.nl
Peter Johnson http://delphidabbler.com
[email protected]
Wagner R. Landgraf wagner @ tmssoftware.com
KimMadsen Madsen Kim www.component4developers kbm @ components4developers.com
Max Kleiner www.softwareschule.ch max @ kleiner.com kleiner.com John Kuiper john_kuiper @ kpnmail.nl Andrea Magni www.andreamagni.eu andrea.magni @ gmail.com www.andreamagni.eu/wp
Boian Mitov mi tov mito v @ mit ov.c ov .com om
Jeremy North
jeremy.north @ gmail.com
Detlef Overbeek - Editor in Chief www.blaisepascal.eu editor @ blaisepascal.eu
Howard Page Clark hdpc @ talktalk.net
Heiko Rompel
[email protected]
Wim Van Ingen Schenau -Editor wisone @ xs4all.nl
Peter van der Sman sman @ prisman.nl
Rik Smit rik @ blaisepascal.eu www.romplesoft.de
Bob Swart www.eBob42.com Bob @ eBob42.com
B.J. Rao
[email protected]
Daniele Teti www.danieleteti.it d.teti @ bittime.it
Anton Vogelaar ajv @ vogelaar-electronics.com
Siegfried Zuhr siegfried @ zuhr.nl
Editor - in - chief Detlef D. Overbeek, Netherlands Tel.: Tel.: +31 (0)30 890.66.44 / Mobile: +31 (0)6 21.23.62.68 News and Press Releases email only to
[email protected] Editors Peter Bijlsma, W. (Wim) van Ingen Schenau, Rik Smit, Correctors Howard Page-Clark, James D. Duff Trademarks All trademarks used are acknowledged as the property of their respective owners. Caveat Whilst we endeavour to ensure that what is published in the magazine is correct, we cannot accept responsibility for any errors or omissions. If you notice something which may be incorrect, please contact the Editor and we will publish a correction where relevant. relevant. Subscriptions ( 2013 prices ) 1: Printed version: subscription € 80.-- Incl. VAT VAT 6 % (includin g code, programs and printed magazine, 10 issues per year excluding postage). 2: Electronic - non printed subscription € 50.-- Incl. VAT 21% (including code, programs and download magazine) Subscriptions can be taken out online at www.blaisepascal.eu or by written order, or by sending an email to
[email protected] u Subscriptions Subscriptions Subscriptio ns can start at any date. All issues published in the calendar year of the subscription will be sent as well. Subscriptions run 365 days. Subscriptio ns will not be prolonged without notice. Receipt of payment will be sent by email. Subscriptions Subscriptio ns can be paid by sending the payment to: ABN AMRO Bank Account no. 44 19 60 863 or by credit card: Paypal Name: Pro Pascal Foundation-Foundation for Supporting the Pascal Programming Language (Stichting Ondersteuning Programeertaal Pascal) IBAN: NL82 ABNA 0441960863 BIC ABNANL2A VAT no.: 81 42 54 147 (Stichting Programmeertaal Pascal) Edelstenenbaan baan 21 / 3402 XA IJsselstein, The Netherlands Netherlands / Tel.: + 31 (0) 30 890.66.44 / Mobile: + 31 (0) 6 21.23.62.68 Subscription department Edelstenen
[email protected]
Copyright notice All material published in Blaise Pascal is copyright © SOPP Stichting Ondersteuning Programeertaal Pascal unless otherwise noted and may not be copied, distributed or republished without written permission. Authors agree that code associated with their articles will be made available to subscribers after publication by placing it on the website of the PGG for download, and that articles and code will be placed on distributable data storage media. Use of program listings by subscribers for research and study purposes is allowed, but not for commercial purposes. Commercial use of program listings and code is prohibited without the written permission of the author author..
Issue Nr 4 2016 BLAISE BLAISE PASCAL MAGAZINE
3
From the editor
T
he summer just started, and finally it's getting warmer. You now see butterflies are all around us, so I found it striking that some of their patterns and textures sometimes look like small pictures, and that is how I thought of smart mobiles: they're everywhere and appear to be some sort of insects. It's inevitable to be in contact with them. So I thought better to be in control of them and create my own apps for SM ( Strange abbreviation). The first problem one finds is how to use text exchange on mobile data. But the problem is, at least in principle, easy to solve: Try XML (eXtensible wha t we did. Markup Mark up Langua Lan guagge). So that is what You can find that in the article on page 27: How to build an app with XML. During my research I found that styles from which you can choose when you use FMX are available, but you can't preview to make an easy choice. So we helped that out in the same article. For our subscribers there will be a special PDF file on a larger format to have a better view and use it separately in your toolbox. This article is only the beginning of what I hope will be a long list of how to create apps for FMX. I will try to find out how to make your own styles and write something about that. Origina lly, I had planned for an article about Originally, “from Delphi code to Raspberry”. But it wasn't as easy as I hoped for: the only way to get that done is in a number of steps and it will not be easy: first create your app in (VCL) Delphi. Then set that code to Lazarus. Go to a Raspberry Pi version of your choice and make sure Lazarus is running on your Raspberry Pi. The higher the version the better the compile time will be. I have asked Michael van Canneyt to write down these steps and create an app on it. But be cautious: making the Delphi project for Lazarus available won't be easy. It will have to be done with trial and error. It always is about learning… Spoken of learning learning:: we have just now established the DELPHI-PASCAL-ACADEMY. The institute will be officially registered at the CRKBO (Central Register Kort Beroepsonderwijs , a Dutch register for professional educations ). Since we have started to do lessons and seminars, this is a logical next step: we are very often asked if there is a possibility for creating and teaching. The educational languages will be English and Dutch.
4
This is an institute you can become a member of as a person or Company. As a person you can then follow lessons. As a member you will be able to get study material etc. depending on the subject, and we will write that material if it is not available. All other information will soon become available on the internet and in our Magazine as well on twitter etc. n our Magazine as well on twitter etc. Something Somethin g to learn about: we have started a series of articles to explain in depth what Generics is and how to use it and see the advantages – they are huge! We also will talk about Anonymous methods - what they are and how to use them. We want to do as much as possible for our community and therefore please tell us what you want to know about, or what subjects we should use for your interest. We have lots of plans: there is a project that is still on the shelf, such as the “Leap”. It is a tremendous challenge because Windows is changing all the way, and the hardware might do so as well as the software of the “Leap” itself. What we want with it is still not being picked up by the Leap itself. I'll write an article how far we have come until now and show some examples of what we have done. It is a while ago that we started that project and want you to know what the position now is…. We still plan to finish it but it is a tremendous challenge… Speaking about plans: we will publish a new book (with examples code etc.) to start learning Delphi from start up to FMX and Android. Bruno Fierens has started a very special thing about FNC ( framework fram ework neut n eutral ral compon co mponents ents ) he is blogging about this subject and he also will explain how you as a reader could try to create your own FNC components. I think that's great news. The best news about Delphi Berlin is that the designer form is back! It gives you the old fashioned feeling of Delphi 7 and that in a very modern version. I am glad Idera did this! In September 2016 we plan to do the next Big Delphi Conference and are trying again to have some guest speakers that will surprise you…. I have always wanted to have a humoris humoristic tic page about IT. I found a guy called Kim Bo Madsen. I hope you like these first two installments. Please let us know.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
type
GENERICS EXPLAINED / PART 1 PAGE 1 / 4
List
- = class ... end ;
BY DETLEF OVERBEEK starter
to distinguish procedures from lambda expressions and symbols, to use a single lexical INTRODUCTION environment for all variables, and to evaluate the In this series of article s we want to explain what operator position of a procedure call in the same way as an operand position. Generics is and what you can do wi th it. By relying entirely on procedure calls to express We will give you diagrams, overviews, simpl e iteration, Scheme emphasized the fact that tailexamples and more complex exam ples. This all recursive procedure calls are essentially goto's that because Generics is a very important technique pass arguments. Scheme was the first widely used and can make designs easier b etter and: faster. programming language to embrace first class escape procedures, from which all previously known HISTORY OF GENERICS sequential control structures can be synthesized. More The phrase “Generic programming” recently, building upon the design of generic was originated by David Musser and arithmet ic in Common Lisp , Scheme introduced the Alexander Stepanov. concept of exact and inexact numbers. Scheme is also Generics are derivatives of Generic Programming for the first programming language to support hygienic Java. This concept specifies the type of the objects macros, which permit the syntax of a block-structured stored in a Java Collection. In 1998 Philip Wadler created language to be extended reliably.) expert Delphi 2009 and up
Generic Java, an extension on the Java language to support generic types.
In 2004 Generics was added to the Java-language, as a part of J2SE 5.0. Before Generics each variable declaration needed a specific type. To container Classes this is a problem: there is no easy way to create a container which allows only specific types (Strings or integers etc.) and accepts them from objects. ( Either the container influences all subtypes of a class). Usually an object had to be created, or another container class to be created for each inherited subclass. Generics will allow type – control during compile time, without creating a lot of container-classes. Each container contained almost identical code. Generics make the writing of a program more efficient because only one container needs to be created. Besides offering more efficient coding, some exceptions are changed to Compile-TimeErrors, which is known as Type-Safety. The desire for a language to better support Generic Programming led Alexander Stepanov and David Musser through “Scheme” *, “Ada” ** and finally to “C++”***, where Generic Programming has been most successful. SCHEME*
is a statically scoped and properly tail-recursive dialect of the Lisp programming language invented by Guy Lewis Steele Jr. and Gerald Jay Sussman. It was designed to have an exceptionally clear and simple semantics and few different ways to form expressions. A wide variety of programming paradigms, including imperative, functional, and message passing styles, find convenient expression in Scheme. Scheme was one of the first programming languages to incorporate first class procedures as in the lambda calculus , thereby proving the usefulness of static scope rules and block structure in a dynamically typed language. Scheme was the first major dialect of Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
Lisp
ADA**
is a structured, statically typed, imperative, wide-spectrum, and object-oriented high-level computer programming language, EXTENDED FROM PASCAL AND OTHER LANGUAGES. It has built-in language support for design-by-contract, extremely strong typing, explicit concurrency, offering tasks, synchronous message passing, protected objects, and nondeterminism. Ada improves code safety and maintainability by using the compiler to find errors in favor of runtime errors. Ada is an international standard; the current version is known as Ada 2012. Ada was originally designed by a team led by Jean Ichbiah of CII Honeywell Bull under contract to the United States Department of Defense (DoD) from 1977 to 1983 to supersede the hundreds of programming languages then used by the DoD. Ada was named after Ada Lovelace (1815–1852), who is credited with being the first computer programmer. ) C++
is a general-purpose programming language. It has imperative, object-oriented and generic programming features, while also providing facilities for low-level memory manipulati on. It was designed with a bias toward system programming and embedded, resourceconstrained and large systems, with performance, efficiency and flexibility of use as its design highlights. C++ is a compiled language, with implementations of it available on many platforms and provided by various organizations, including the FSF, LLVM, Microsoft, Intel and IBM and Embarcadero’s Delphi . The current C++14 standard supersedes these and C++11 , with new features and an enlarged standard library. C++ was developed by Bjarne Stroustrup at Bell Labs since 1979, as an extension of the C language as he wanted an efficient and flexible language similar to C, which also provided high-level features for program organization.)
5
type
GENERICS EXPLAINED / PART 1 PAGE 2/4 WHAT IS SO SPECIAL ABOUT GENERICS? As soon as you have written a class that uses generic type parameters (GENERICS) you can use that class with whatever type or a type you have chosen yourself. And that for each sort of use of a class to create that class. The chosen type will now become available as method-parameters, returns types and property types. You do not have to typecast* the types or to convert them. *typecasting changes the data type into another. Delphi is a strict-type-casting-language, which means that if you want to use an integer as a string, just create a string. But typecasting gives you the possibility of converting one type into another, like: (integer) 123456 = (string) ' 123456' . So you do not have to convert. i := integer(f) ; // Treats f as an integer i := f as integer ; // Fails with non-object types
As an example: most developers have in the past used a TObjectList. You can use it as is, and insert Objects and remove them out again. But that requires that you collect the Objects from TObjects each time you use them and turn them into WhatEverObject_ClassName. You could also write a descendant class of TObjectList TObject-members with and override () the your (custom) types. But that also concerns the Class that only will work with your own type. An example: You use a Generic TObjectList . TobjectList and the corresponding methods ( procedures or functions )
will accept parameters of the type TmyCustomType and add the collection TmyCustomType-objects in stead of Tobject. So you don't have to wite special code to make it available for TMyCustomType. That is one of the advantages that GENERICS offers. This happens by creating the class with a pl ac eh ol de r for a ru nt im e- ty pe . Just watch the < T… > . The brackets before and after are called “Angled Brackets” (<>). During runtime, you give the type of the class, as soon as you declare it. Then this type replaces your “placeholder” by the class if you create it as Object. The declaration of a Generic Class equals the declaration of a normal class, record or interface type.
6
List- = class ... end ;
The difference is that a list - of one or more type parameters - will be placed between “Ang led Brackets” (< ... >) type-identifier in the declaration of a Generic. A type parameter can be used as a type-identifier within a container type declaration and a method-body. Type // TKey en TValue zijn type parameters TPair = class FKey: TKey; FValue: Tvalue; function GetValue: TValue ; ; end function TPair.GetValue: TValue ; begin Result:= FValue; ; end
TYPE ARGUMENT
Generic types are created by declaring of typearguments. In Delphi, you can use whatever type as a type argument except the following: • a static array, they are called static because their size is static, and because they use static memory. • a short string , is a counted-array of (ANSII) characters, up to 255 characters in the string. The first byte of this array stands for the length of the string. Since this was the most important string type in Delphi 1 (16 bit Delphi), it now is only used as the ShortString because of backwardcompatibility. • a record type which contains a field of a derived (recursive) type like one or more of these types.
type TWatDanOok = class FData: T;
; end var F: TWatDanOok ; // 'Integer' is het type argument van TwatDanOok begin ... . end
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
type List- = class ... end ;
GENERICS EXPLAINED / PART 1 PAGE 3/4 EXPLANATION OF THE DIAGRAM On the next page you will find a diagram which describes what the differences are, if you would use a program that is compiled with generic types or if you would do that with one of the very often used types: va ri an ts . It shows how much faster the use of generics is in that case. VARIANTS (Partly from the Delphi Helpfiles) Sometimes we want to juggle with data whose type varies or can’t be found at compile time because there is no other option. Then an option would be using variables and parameters of type Va ri an t, that represent values which can change type at run time . Variants are more flexible but need more memory than regular variables, and working with them needs more time: they are slower than statically bound types. Moreover, not permitted (illegal) operations on variants mostly result in run-time errors, where similar mistakes with regular variables would have created exceptions at compile time.
As default, Variants can hold values of any type except records, sets, static arrays, files, classes, class references, and pointers. Variants can hold anything but structured types and pointers. They can hold dynamic arrays , and they can hold a special kind of static array called a variant array . Variants can mix with other variants and with integer, real, string, and Boolean values in expressions and assignments; the compiler automatically performs the necessary type conversions. That why it is more slow and time consuming. NOTE: Variant records are considered inherently "unsafe." A variant record is very similar to using the "absolute" directive because the variant field parts of the record are literally overlaid in memory atop each other. You can assign a value as one type and then read it out as a different type. If you are using variants, you might see compiler warnings about unsafe code, such as W1 04 7 Unsa fe cod e '%s' (Delphi).
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
On 32-bit platforms, a variant is stored as a 16-byte record. On 64-bit platforms, a variant is stored as a 24-byte record. A variant record consists of a type code and a value, or a pointer to a value, of the type specified by the type code. All variants are initialized on creation to the special value Unassigned. The special value Null indicates unknown or missing data. The standard function VarType returns a variant's type code. The varTypeMask constant is a bit mask used to extract the code from VarType's return value, so that, for example, VarType(V) and varTypeMask = varDouble
returns True if V contains a D ou bl e or an a rr ay o f D ou bl e . ( The mask simply hides the first bit, which indicates whether the variant holds an array .) The TVarData record type defined in the System unit can be used to typecast variants and gain access to their internal representation. In the coming issues we will go on to explore the Generic Class , the use of it by creating a number of programs that show in detail how to handle it and show the advantages of a not so new trend of using Generics - but slowly its becoming clear how great this “NEW” class is....
type List- = class ... end ;
7
GENERICS EXPLAINED / PART 1 PAGE 4/4 ADVANTAGES OF GENERICS IN COMPARISON WITH VARIANTS USING VARIANT
USING GENERICS
CPU
MEMORY
COMPILER
USING VARIANT
USING GENERICS
SLOWER DURING RUNTIME
MUCH FASTER DURING RUNTIME
M S U L C O H W F E A R S D T U E R R I D N U G R C I O N G M P R I U L N E T T I I M M E E O P F E R T I H O E D P R O G R A M
C O M P I L E S F A S T
Compiles
Compiles
PROGRAM
PROGRAM
Creates Generics
Program Starts
All kind of types a e r g g e r a y t t n r i t e r r L i s t c e E S t I n A Creates as little as possible units
SLOWER DURING COMPILETIME
Uses Variant type
Create String Create Int Create Array Create String Create Int Create Array Run Create String Create Int Run Array Run Create Run Run Run Run Run Run Free Run Run Run Free Free Free Free Free Free Free Free Free Free Free
Program starts Uses Strings is already created
Uses Integer is already created
Uses Array is already created Program stops
Compiler clears Generics
SLOWER DURING RUNTIME, MUST BE CREATED OVER AND OVER AGAIN
Uses Variant Integer Uses Variant String Uses Variant Array EARLIER
LATER
Program stops
MUCH FASTER DURING RUNTIME OF THE PROGRAM SLOWER DURING COMPILE TIME PERIOD
8
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
S L O W D U R I N G R U N T I M E O F T H E P R O G R A M
TURBO COCOA FOR DELPHI AND ANDROID PAGE 1/4 BY VSEVOLOD LEONOV starter
expert
Delphi
INTRODUCTION Previously, we've considered how TurboCocoa - as an additional tool for Delphi 10.1 Berlin - can be used for creating tr ue-native app’s for iOS. In addition, we've discussed why native controls and native app architecture are important. Now we'll show, how to make platform oriented applications for Android with Delphi. Delphi developers since XE2 have many options in project types when developing applications fr om the viewpoint of platforms. In the world of mobile app development the choice is between multi-device projects on the base of the same codebase, including UI forms, and platform-specific projects with the help of TurboCocoa and Delphi. The mechanism of the last approach is simple: one uses Android Studio as a native development tool for designing UI, and then use the design only in Delphi project with full power of modern Object Pascal and non-visual components, including data access ones, and any of business logic and algorithmic code (See Figure 1).
Fig. 1. Schematics of TurboCocoa project.
The reasons of using TurboCocoa with Delphi are mutiple • App size • Performance • Native look & feel for particular device /Android version • Same developer capabilities as in case of use Android Studio • Natural behavior of UI and same UX in comparison with native app. The reasons are not of equal importance for Delphi developers. Some may want the same power, as Android Studio users. Some may want to avoid criticism for size and speed, some may want not to imitate, but secure native UX for demanding customers. But we must warn you, to get all these you'll need to switch from classic way of designing forms with VC L/ FM to And roi d St ud io . Nevertheless, the form designer is only you need to know in Android Studio, while principles of User Interface visual modeling are the same, and you'll see this further. First, you need Delphi 10.1 Berlin installed on your PC. Second, visit www.turbococoa.com and download free beta. Third, install TurboCocoa on your machine as Delphi add-on, and start a new project from menu “Ot her ” . Then select “Turbo .An dro id” and “Si ngl e Act ivit y App lica tio n” (See Figuur 2).
Fig. 2. Starting a new project for TurboCocoa Android application
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
9
TURBO COCOA FOR DELPHI AND ANDROID PAGE 2/4 Once you selected the project type and pressed “OK ” button, TurboC ocoa generates for you a specific project, which can build a true native Android application from Object Pascal source code and UI design. For the first time, you may be asked for paths, which is rather typical. If you ever tried Android development in Delphi, you know how to set paths for Android SDK in Delphi IDE SDK Manager. The dialog is a little bit different, while the paths are the same, you can just manually copy them from SDK Manager (See figure 3).
The project doesn't include kind of “dfm/fmx” files, which can be used to make a UI design in Delphi IDE. Instead ( according to described mechanics how TurboCocoa works) you right click on “And roid _te st_ 1” node in Proj ect Man age r and select “ Launch Android Studio”. Don't be disappointed at first glance, the IDE is different, the principles are the same. Just start designing the interface: • In the “Palette” window find section “Text Fields ”
•
Drag and drop “Pla in Text” onto entire area of the mobile form • Find section “Wid get s” , then drag and drop “Bu tto n” control onto the form • Find section “Text Fi eld s” and put “Pla in Text” on the form
Figuur 3: Paths settings
After finding right paths and setting folder and project name, it is generated by TurboCocoa, and we can start looking at its structure (See figure 4 below).
Please, note, visual controls are located not “De lph i VCL s tyle ” , they are not “an cho red ” in the traditional way, but are somehow “al ign ed” , and this is more logical, at least, for mobile applications, when screen size can be considerably different and orientation can be changed during runtime. You can then find the “Pr ope rti es” window and use it in the ObjectInspector style to change necessary properties. In order to set an onClick event for the button, find the corresponding property in “Pr ope rtie s” list and type “Bu tto nCl ick ” or something else you like (See figure 5, next page). The response will be then programmed in Delphi with Object Pascal. Save the project in Android Studio. Actually, we need only the form design, which you can see in text form by switching to the “Text ” tab in the bottom. Then, go back to Delphi for the programming.
Figure 4
10
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
TURBO COCOA FOR DELPHI AND ANDROID PAGE 3/4
Figuur 5: Designing UI in Android Studio for TurboCocoa project
In Delphi we work with the source file TurboCocoa is in turn responsible for taking the UI MainActivity.pas. The project contains the design file to the Delphi project and use it in other two pas files, but they are mainly g enerated building the final Android app. automatically and should not be modified. In MainActivity.pas you see the class TMainActivity: Open MainActivity.pas and have a look into it. “Act ivi ty” can be roughly considered TMainActivity = class(TJavaGeneric) as a form for the first approxima tion. private We've made its design in Android Studio, so protected for the further modification you need to right public click again on the project name in the Project procedure onCreate(const savedInstanceState: JBundle); Manager and select “La un ch A ndr oid S tud io/ To procedure onDestroy; Android Studio”. procedure onPause; Then you add more controls, save, and go procedure onResume; back to Delphi. Let's think of Android Studio [IBAction] as a platform specific form designer, procedure ButtonClick(id: Pointer); ; end nothing more.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
11
TURBO COCOA FOR DELPHI AND ANDROID PAGE 4/4 The difference in the code above and your code is the attribute [IBAction ] and the procedure ButtonClick , which you definitely can type without problem. The procedure name should correspond to what you typed in Android Studio for Button component, property “on Cli ck” . Then the main work is to enter the code for procedure:
Finally, you compile the project, build and procedure TMainActivity.ButtonClick(id : Pointer ); deploy for the only platform Android (See var figure. 6). You can watch the time of MyLabel: JTextView; MyEdit : JEditText; tmp : string ; deployment and time of launch, as begin well as the size of the MyLabel := TJTextView.Wrap(Super.findViewById (R .id .textView )); mobile app, made in Delphi MyEdit := TJEditText.Wrap(Super.findViewById (R.id .editText )); with TurboCocoa. tmp := 'Hello, ' + JStringToString(MyEdit .getText .toString ) + '!' ; MyLabel .setText(StrToJCharSequence (tmp )); ; end
Some explanation needed, and here they are. In contrast to methods for working with iOS controls in TurboCocoa (see previous article ), we don't need outlets. We have recognizable control id-s in Android Studio, and we can manipulate with them. You can switch to Android Studio, open “Text” tab, and look at:
These are properties of TextView, which is our “La bel ”. Its id is tex tVi ew, but we don't have to remember this, only to understand, from where the corresponding identifier appears in Delphi code. In the procedure ButtonClick we define local variables as reference to native controls in the form. For the reference type we use a type of controls in Android Studio with prefix “J”. Then we bind the reference variable with the native control in runtime: MyLabel := TJTextView.Wrap(Super.findViewById (R.id .textView ));
Once we get the proper reference, we can manipulate with control in object oriented manner. As in case of iOS development with TurboCocoa, the string types are different, than we use in Object Pascal . That's the reason why we introduce local variable “tm p”, just to simplif y the code. Converters “JS tri ngToSt rin g” and “St rToJCh arS equ enc e” are easy to understand from their names and easy to use. It makes the code a little bit longer, but this is the only, but not critical drawback, originated from string representation difference. 12
Fig. 6. Resulting Android app
SUMMARY: TurboCocoa helps Delphi developers make true native UX apps for different platforms Mac OS/iOS/Android. Development for Android in Delphi with TurboCocoa calls for only design skills in Android Studio, while Object Pascal remains an effective programming language together with non-visual components and any legacy code. The resulting apps are fast, compact, and fully meet expectations by customers, who value the native UX.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
http://turbococoa.com/
20% discount on TURBO COCOA.
PRICING - $149 for perpetual license - $39 for annual renewal - $99 yearly subscription
DISCOUNT COUPON # BPM 48665
Issue Nr 4 2016
BLAISE PASCAL MAGAZINE
13
Registered users of any earlier version qualify for the upgrade price! If you are currently using any earlier version of RAD Studio, Delphi, C++Builder or Borland Developer Studio and are looking for the lowest cost to move for ward, now is the time to upgrade. • Save up to 45% off the new user price • Update Subscription is now included with all licenses, so you’ll never miss an update again • Plus, you get access to the free bonus pack ebook and software downloads How to qualify for the upgrade price of 10.1 Berlin and save up to 45%: Purchase 10.1 Berlin at the Upgrade price through June 20, 2016. Even if the description says Upgrade from XE6 or later, all earlier version users can upgrade during this special offer period. Buy Delphi or C++Builder 10.1 Berlin Professional edition and receive a Mobile Add-on Pack with Update Subscription FREE! Go mobile for less! How to qualify for a free Mobile Add-on pack when you buy 10.1 Berlin: Purchase the specially marked Delphi or C++Builder 10.1 Berlin Professional Named User license with Mobile Add-on through June 20, 2016. Special price includes the full Delphi or C++Builder Professional license, Mobile Add-on Pack and one year of Update Subscription.
FREE BONUS PACK Get these Free Bonuses with your purchase of RAD Studio, Delphi or C++Builder 10.1 Berlin
If you are currently using any earlier version of RAD Studio, Delphi, C++Builder or Borland Developer Studio, and are looking for the lowest cost to move for ward, now is the time to upgrade. New Object Pascal Handbook by Marco Cantu Do more with Delphi
This 300-page ebook is a complete guide to the current, modern Object Pascal programming language by best-selling Delphi books author and Delphi Senior Product Manager, Marco Cantu. This new language manual for new & existing Object Pascal developers covers core language features, object-oriented programming with Object Pascal, and the latest language features like generics, anonymous methods, and reflection in todays' Delphi compilers.
VCL and FireMonkey Premium Styles Modernize your apps with premium VCL & FMX styles Customize the look of your VCL Windows applications with seven premium styles including the Coral, Diamond, Emerald, Sterling, Jet, Vapor, Radiant and Copper style. Customize your multi-device applications w ith nine premium FireMonkey styles including Jet, Sterling, Diamond, Emerald Crystal, Emerald Dark, Coral Crystal, Coral Dark, Vapor, Radiant and Copper styles.
or call: +31 (0)235422227 http://www.barnsten.com/default/development-tools/amnesty 14
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 1 / 8 BY BRUNO FIERENS
FNC FRAMEWORK NEUTRAL COMPONENTS
From the editor: you won’t believe this! I think this is the best so far that ever coul d have happened to PASCAL: developing code on multiple platforms made easy. I would call I the new F(ea)uture INTRODUCTION As your customers use an ever increasing number of devices & operating systems, it is a daily challenge for us, software developers to make our software available for the myriad of target platfor ms in use. Fortunately, as Pascal developers, we already have a huge benefit that Delphi meanwhile targets 4 platforms: Windows, Mac OSX, iOS and Android. Add Lazarus to that, and Pascal developers can also target Linux and its derivatives such as Raspbian and many more. The 3 main frameworks we have available to create our software for these pla tforms are: VCL, FMX and LCL. The framework to use will be determined by the target and the IDE used. That implies that the controls that can be used are also typically determined by this choice and might limit your abilities when some controls or control features are not available for one of these frameworks. Addressing that limitation is exactly one of the primary goals of the TMS FNC UI Controls. It offers you a set of powerful & feature-rich UI controls that you can use in Delphi's VCL framework, FMX framework and Lazarus LCL framework. It allows to create Win32, Win64, Mac OS-X, iOS, Android, Linux, Raspbian, ... applications with a single codebase and a single lea rning curve.
First limitation is the design-time form fileformat that is different between VCL, FMX and LCL. VCL uses the .dfm f ile, F MX uses the .fmx file and LCL uses the .lfm file. For applications for different devices with different form factors, it typically already requires to design the form separately for separate frameworks, so this isn't too much of a limitation. For other applications, a solution is to create the controls at runtime. A second limitation is the namespaces (unit names).
CONCEPT
FNC controls enable you to write and use 100% identical Pascal code, be it in a VCL app, FMX app or LCL APP. The FNC components methods, properties and events are therefore 100% identical regardless of the framework being used. As an example, the following code creates a new event in our FNC Planner control: var plIt: TTMSFNCPlannerItem ;
begin plIt := TMSFNCPlanner1.Items.Add; (14 ,0 ,0 ,0); plIt.StartTime := Date + EncodeTime (16 ,0 ,0 ,0); plIt.EndTime := Date + EncodeTime := 'New event'; plIt.Title plIt.Text := 'Content';
; end
and from this code, it is impossible to tell whether it will be from a VCL, FMX or LCL app. In the application UI, it will also look exactly the same regardless of framework or operating system: → see image 1 right top... This means that if you properly separate your logic or adopt an MVC approach, you can easily share .PA S files between VCL and FMX projects, between VCL and LCL projects etc... There are in this respect actually only two limitations.
To be able to register identical classnames for different framework controls in Delphi, it is required that these live in different namespaces. As such, the FNC VCL controls unit names have the prefix VCL. , the FNC FMX controls unit names have the prefix FMX. and the FNC LCL controls use prefix LCL (without dot, to be able to support FPC versions older than v3.0). In practice, this means that for the example above with the TMSFNCPlanner, the unit clauses for the different frameworks would be as below. To keep using a single source file, a solution is to set a define at project level depending on the framework and write: uses {$IFDEF VCL} VCL.TMSFNCPlannerBase, VCL .TMSFNCPlannerData, VCL.TMSFNCPlanner, VCL.TMSFNCCustomControl ; {$ENDIF} {$IFDEF FMX} FMX.TMSFNCPlannerBase, FMX .TMSFNCPlannerData, FMX.TMSFNCPlanner, FMX.TMSFNCCustomControl ; {$ENDIF} {$IFDEF LCL} LCLTMSFNCPlannerBase, LCLTMSFNCPlannerData , LCLTMSFNCPlanner, LCLTMSFNCCustomControl ; {$ENDIF }
15
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 2 / 8 In the same way, when used, we could include the resource of our form file that is different in each framework via a conditional define: {$IFDEF VCL} {$R *.dfm} {$ENDIF} {$IFDEF FMX} {$R *.fmx} {$ENDIF} {$IFDEF LCL} {$R *.lfm} {$ENDIF}
FNC FRAMEWORK NEUTRAL COMPONENTS
CONTROLS In TMS FNC UI Pack v1.0, there are already 29 controls included. On the tool palette this looks like: VCL, FMX
These are of course the things you need to take in to account when you want to create a single codebase to build projects with multiple frameworks. In other cases, you do not need to take care of this and you can enjoy the exact same feature set of this UI component library irrespective of the IDE and platform you target. Another important core concept is the introduction of the TMS FNC Graphics library that is included. This enables you to write graphics code that is framework independent . This includes framework neutral colors, fill, stroke, alignment, font, path types and the TTMSFNCGraphics class using this to draw everything you need. This is a sample code snippet of framework neutral drawing: var gr: TTMSFNCGraphics ; begin gr := TTMSFNCGraphics.Create(PaintBox1.Canvas); := gcYellow; gr.Fill.Color gr.Stroke.Color := gcGray; gr.DrawRectangle (0 ,0 ,100,20); gr.Font.Color := gcRed ; gr .DrawText(2,0,100,20,'Hello world' ,false) gr.Free; ; end
The result is:
and is exactly the same on every framework, target, device, ...
16
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
FNC
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 3/8
FRAMEWORK NEUTRAL COMPONENTS
LCL
This includes a grid, planner, richeditor, treeview, various color, font, fontsize, bitmap ... picker , toolbar, ... and more. INTRODUCING THE TMS FNC GRID
The TMS FNC Grid is a high-performance, not data-bound grid capable of dealing with hundreds of thousands of rows, has a wide range of cell types and inplace editors, offers built-in sorting, filtering and grouping and can import and export data in several file formats. To illustrate some of the capabilities of the TMS FNC Grid , begin
As another quick introduction to the
:= 2; TMSFNCGrid1.FixedRows grid, this 2 line snippet demonstrates TMSFNCGrid1.ColumnCount := 7; how data from a CSV file can be loaded (1 ,0 ,2 ,1); TMSFNCGrid1.MergeCells and automatic filtering via a drop down (3 ,0 ,2 ,1); TMSFNCGrid1.MergeCells in the column header is enabled: (5 ,0 ,2 ,1); TMSFNCGrid1.MergeCells := 'Monday' ; TMSFNCGrid1.Cells [1,0] TMSFNCGrid1.LoadFromCSV ('e:\tms\cars.csv' ); TMSFNCGrid1.HorzAlignments[1,0] := gtaCenter ; TMSFNCGrid1.Options.Filtering.DropDown := true; := 'AM' ; TMSFNCGrid1.Cells [1,1] := 'PM' ; TMSFNCGrid1.Cells [2,1] := 'Tuesday' ; TMSFNCGrid1.Cells [3,0] TMSFNCGrid1.HorzAlignments[3,0] := gtaCenter ; := 'AM' ; TMSFNCGrid1.Cells [3,1] := 'PM' ; TMSFNCGrid1.Cells [4,1] := 'Wednesday' ; TMSFNCGrid1.Cells [5,0] TMSFNCGrid1.HorzAlignments[5,0] := gtaCenter ; := 'AM' ; TMSFNCGrid1.Cells [5,1] := 'PM' ; TMSFNCGrid1.Cells [6,1] TMSFNCGrid1.AutoNumberCol (0); TMSFNCGrid1.AddCheckBox(1,2,false); TMSFNCGrid1.AddRadioButton (1,3,1); (3 ,2 ,50); TMSFNCGrid1 .AddProgressBar TMSFNCGrid1.Cells [3,3] := 'Hello world' ; TMSFNCGrid1.AddBitmapFile (5,2,'e:\tms\calendar.png' ); TMSFNCGrid1.AddBitmapFile (5,3,'e:\tms\mail.png'); := 'Red' ; TMSFNCGrid1.Cells [1,4] TMSFNCGrid1.Colors[1,4] := gcRed; := 'Yellow' ; TMSFNCGrid1.Cells [3,4] TMSFNCGrid1.Colors[3,4] := gcYellow ; := 'Lime' ; TMSFNCGrid1.Cells [5,4] TMSFNCGrid1.Colors[5,4] := gcLime ; TMSFNCGrid1.FontNames [1,4] := 'Courier New' ; TMSFNCGrid1.FontStyles[3,4] := [fsBold]; TMSFNCGrid1.FontSizes [5,4] := 12; TMSFNCGrid1.AddNode (2,2);
; end
17
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
FNC
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 4/8
Of course, this is just a very brief introduction to the TMS FNC Grid. Just the FNC grid alone could deserve multiple articles to cover it in detail. You can familiarize yourself with the TMS FNC Grid by reading the full PDF developers guide you can find at http://www.tmssoftware.biz/download/ manuals/TMSFNCGridDevGuide.pdf or use the
trial or full version of the component that comes with several samples.
Some weeks ago, we released the TMS FNC UI Pack, a set of Framework Neutral Components (FNC), i.e. UI controls that can be used from VCL Windows applications, FireMonkey (FMX) Windows, Mac OS-X, iOS, Android applications and LCL framework based Lazarus applications for Windows, Linux, Mac OSX,.. The TMS FNC UI Pack contains highly complex & feature-rich components such as grid, planner, rich editor, treeview, toolbars. To create such complex components that work under 3 frameworks and a myriad of operating systems is not a trivial excercise and requires intricate knowledge about the VCL, FMX and LCL frameworks as well as the operating systems the controls need to work under. To help ourselves and the users of the TMS FNC UI Pack, we have introduced several abstractions that facilitate creating framework neutral components and this is what we want to cover in this brief introduction to developing FNC custom controls.
18
FRAMEWORK NEUTRAL COMPONENTS
INTRODUCIN G THE TMS FNC PLANNER Our TMS FNC Planner is a scheduling component with various built-in time-axis options, i.e. a day, week, month, period, half-day period, timeline as well as custom time-axis mode where you can fully control the duration of each timeslot in the Planner. The Planner supports single and multiresource views and can have the time-axis horizontal or vertical. When targeting the Planner to a mobile device, it will automatically use a touch-friendly approach to select, insert, delete, pan in the Planner. As a brief introduction to the TMS FNC Planner, we'll demonstrate a monthly car rental Planner with horizontal time axis and several resources in the left axis. In this code, we set the time axis programmatically horizontal and add 9 resources with 3 groups of 3 resources, representing small, medium and large cars. Via TMSFNCPlanner.Mode, we set the time line to a day period timeline and via TMSFNCPlanner.ModeSettings the period is set to the month May. After some further customization of timeline size and font, some random car rentals are added on the Planner:
FNC FRAMEWORK NEUTRAL COMPONENTS
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
FNC
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 5/8
FRAMEWORK NEUTRAL COMPONENTS
var
grp: TTMSFNCPlannerGroup ; plIt: TTMSFNCPlannerItem ; i, d: integer ;
begin
TMSFNCPlanner1.OrientationMode := pomHorizontal ; TMSFNCPlanner1.Mode := pmDayPeriod; TMSFNCPlanner1.Positions.Count := 9; TMSFNCPlanner1.Groups.Clear ; grp := TMSFNCPlanner1.Groups.Add; grp.StartPosition := 0; := 2; grp.EndPosition := 'Small'; grp.Text grp := TMSFNCPlanner1.Groups.Add; grp.StartPosition := 3; := 5; grp.EndPosition grp.Text := 'Medium' ; grp := TMSFNCPlanner1.Groups.Add; grp.StartPosition := 6; := 8; grp.EndPosition := 'Large'; grp.Text TMSFNCPlanner1.Resources.Clear ; := 0 to 8 do for i
begin
TMSFNCPlanner1.Resources.Add ; TMSFNCPlanner1.Resources.Items [i ].Text := 'Car ' +inttostr(i + 1 );
; end
:= 35; TMSFNCPlanner1.TimeLineAppearance .LeftSize TMSFNCPlanner1.TimeLineAppearance.LeftFont .Size := 10; TMSFNCPlanner1.TimeLineAppearance.LeftFont.Style := [fsBold]; (2016 ,5 ,1 ); TMSFNCPlanner1.ModeSettings.StartTime := EncodeDate := EncodeDate (2016 ,6 ,1 ); TMSFNCPlanner1.ModeSettings.EndTime := 35; TMSFNCPlanner1.TimeLine .DisplayUnitSize TMSFNCPlanner1.TimeLine .DisplayUnitFormat := 'd/m'; for i := 0 to 10 do
begin d := random(20); plIt := TMSFNCPlanner1.Items.Add; plIt.StartTime := EncodeDate (2016,5,1) + d ; := EncodeDate (2016,5,1) + d + 1 + random (5); plIt.EndTime plIt.Resource := Random(9); := 'Rental' ; plIt.Text := gcYellowgreen; plIt.Color ; end ; end
19
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 6/8
FNC FRAMEWORK NEUTRAL COMPONENTS
INTRODUCING THE TMS FNC RICHEDITOR
begin TMSFNCRichEditor1.AddText ('Dear Mr. NAME' ); With the TMS FNC Rich Editor you can TMSFNCRichEditor1.AddLineBreak ; assemble a WordPad-style editor or Outlook TMSFNCRichEditor1.AddText ('CC: EMAIL'); style mail application in a matter of minutes. TMSFNCRichEditor1.SelStart := 9; TMS FNC Rich Editor comes with TMSFNCRichEditor1.SelLength := 4; capabilities to do WYSIWYG editing of rich TMSFNCRichEditor1.SetSelectionMergeField ('NAME'); text with images, URLs, bullet lists, custom TMSFNCRichEditor1.SelStart := 21; graphics, mail merging etc... To make TMSFNCRichEditor1.SelLength := 5; development even faster, there is a pre-built TMSFNCRichEditor1.SetSelectionMergeField ('EMAIL'); toolbar for rich editor editing and formatting end ;
and non-visual components to facilitate the import and export from HTML & RTF files and that of course in all frameworks, operating systems and target devices supported. In this introduction sample, drop the TTMSFNCRichEditor on the form as well as the TTMSFNCRichEditorFormatToolbar and assign the TTMSFNCRichEditor to
When the app is started, the text can be further decorated by editing & formatting via the toolbar. When it is ready, following code performs the merge with the NAME and EMAIL field and is exported to RTF via TTMSFNCRichEditorRTFIO and after this, the merge is undone:
TTMSFNCRichEditorFormatToolbar. RichEditor. Also add a TTMSFNCRichEditorHTMLIO and TTMSFNCRichEditorRTFIO non-visual
component on the form and also assign the TTMSFNCRichEditor to TTMSFNCRichEditorHTMLIO.RichEditor
and TTMSFNCRichEditorRTFIO.RichEditor.
The rich editor content can be initialized with following code to perform a mail-merge that uses here two merge fields: NAME and EMAIL.
20
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
FNC
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 7/8
FRAMEWORK NEUTRAL COMPONENTS
var
sl: TStringList ; begin sl := TStringList.Create; try sl.Add('NAME=Elon Musk'); sl.Add('[email protected]' ); TMSFNCRichEditor1.Merge(sl ); finally sl.Free; ; end TMSFNCRichEditorRTFIO1.Save ('e:\tms\merge.rtf' ); TMSFNCRichEditor1.UnMerge ; ; end
var
INTRODUCING THE TMS FNC TREEVIEW
Finally, another large feature-packed control from the TMS FNC UI Controls set we want to introduce is the TMS FNC TreeView , TTMSFNCTreeView. This is a multi-column treeview control with regular mode and virtual mode and designed for and capable of using millions of nodes. In addition, the nodes support rich information, text atttributes can be customized per node cell, HTML formatted text in node cells is possible, images, checkboxes can be added and optional inplace editing is available. In this introduction we'd like to demonstrate the difference in regular (node collection) based mode and virtual mode when using the TTMSFNCTreeView. The first code snippet demonstrates an initialization of a 2 column treeview:
tn,cn: TTMSFNCTreeViewNode ; begin TMSFNCTreeView1.BeginUpdate ; TMSFNCTreeView1.Columns .Clear ; TMSFNCTreeView1.Nodes .Clear ; TMSFNCTreeView1.Columns .Add .Text := 'Country' ; TMSFNCTreeView1.Columns .Add .Text := 'Capital' ; tn := TMSFNCTreeView1.AddNode(nil); := 'Europe' ; tn.Text[0] cn := TMSFNCTreeView1.AddNode(tn); := 'Germany' ; cn.Text[0] := 'Berlin' ; cn.Text[1] cn := TMSFNCTreeView1.AddNode (tn); := 'France' ; cn.Text[0] := 'Paris' ; cn.Text[1] cn := TMSFNCTreeView1.AddNode (tn); cn.Text[0] := 'United Kingdom'; := 'London' ; cn.Text[1] tn := TMSFNCTreeView1.AddNode (nil); := 'Asia'; tn.Text[0] cn := TMSFNCTreeView1.AddNode (tn); := 'Japan' ; cn.Text[0] := 'Tokyo' ; cn.Text[1] cn := TMSFNCTreeView1.AddNode (tn); := 'China' ; cn.Text[0] := 'Peking' ; cn.Text[1] TMSFNCTreeView1.EndUpdate ; ; end
21
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
TMS FNC USER INTERFACE CONTROLS,
A SET OF FRAMEWORK NEUTRAL CONTROLS, PAGE 8 / 8
FNC FRAMEWORK NEUTRAL COMPONENTS
procedure TForm1.TMSFNCTreeView1GetNodeText ( Sender: Tobject ; Anode: TTMSFNCTreeViewVirtualNode ; AColumn: Integer ; string property. AMode: TTMSFNCTreeViewNodeTextMode ; In a next step, we'll use the TTMSFNCTreeView in var AText: string); virtual mode and insert 1 million nodes! Columns begin are not virtual, so this must be initialized and to if ANode.Level = 0 then AText := keep it simple, this will be initialized to one .Index) 'Root node '+inttostr(ANode column: else begin if ANode.Level = 1 then AText := TMSFNCTreeView1.Columns .Clear ; 'Child node '+inttostr(ANode .Index) TMSFNCTreeView1.Columns .Add ; TMSFNCTreeView1.Columns[0].Text := 'Large treeview' ; else if ANode.Level = 2 then AText := ; end .Index); 'Subchild node '+inttostr(ANode ; end To use the TTMSFNCTreeView in virtual
Important to note here is that the text in the multiple columns of the treeview can be simply accessed with an array indexed Node.Text[]:
mode, two events are crucial: the OnGetNumberOfNodes() event and the OnGetNodeText() event. The first is triggered to know how many nodes at root level or child level should be added. The latter is used to retrieve the column text of the node. Let's start with the OnGetNumberOfNodes event. This event has parameters ANode and a var parameter ANumberOfNodes. ANode is either a node with ANode.Level set to -1 indicating the number of root level nodes is requested or it contains the node for which the number of child nodes is requested. With the ANode.Level property, you can know how many hierarchical levels deep the node is. In this example, we'll insert 1 million (100x100x100) nodes by inserting 100 root level nodes that have each 100 children and each child has again 100 subchildren. procedure TForm1.TMSFNCTreeView1GetNumberOfNodes ( Sender: Tobject ; Anode : TMSFNCTreeViewVirtualNode ; var ANumberOfNodes: Integer ); begin if ANode.Level = -1 then ANumberOfNodes := 100 else if ANode.Level = 0 then ANumberOfNodes := 100 else if ANode.Level = 1 then ANumberOfNodes := 100; ; end end ;
Then, the other event for virtual node handling, OnGetNodeText is used to return the text for node columns. Note that this event will be triggered for each node and for each column for this node. The column for which the event is triggered is indicated with the AColumn parameter. As we have only 1 column in this example, this is ignored and the node text is directly returned:
22
CONCLUSION We hope this brief introduction of the major controls in the TMS FNC UI Pack whetted your appetite to start exploring the components, discovering the benefits and efficiency of having one UI component set to cover all the target operating systems you want to target and perhaps cook up your first Linux GUI apps with LCL. You can get the trial version for Delphi from
http://www.tmssoftware.com/site/ tmsfncuipack.asp and there is also a sample TV Guide project that can be used from VCL, FMX and LCL that you can obtain from
http://www.tmssoftware.com/site/ bl og .a sp ?p os t= 33 5 We're eager to learn how your experience is going and to hear your feedback, comments and furth er wishes and needs in this direction. About the author Bruno Fierens Studied civil electronic engineering at university of Ghent, Belgium (1987-1992) and started a career as R&D digital hardware enginee r. Besides the fascination for electronics, Bruno Fierens set the first steps in programming with Turbo Pascal v3.0 and used all Borland Pascal & Delphi versions since that time. In 1996, he founded TMS software for the activity of application and component development with Delphi. TMS software became Borland Technology Partner in 1998, developed Delphi Informant award-winning grid & scheduling components and now has an intern ational team of software developers working on a large portfolio of components. Bruno Fierens is from 2012 Embarcadero MVP and frequent speaker at Delphi conferen ces world-wide. He does and oversees VCL, IntraWeb, .NET and FireMonkey component development
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE productivity software buiding blocks
Kim Madsen
We would like you to build us this No no... you want to have this Thats the future! Think about the competition!
Would be nice if it also solved this problem
Ok. I think I Know what you want
But we can only afford this
Kim Madsen
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
23
SOFTDRAW PAGE 1/2 BY DAVID DIRKSE starter
expert
Delphi
INTRODUCTION This article describes the drawing of soft lines and ellipses. “Sof t” means th at the pen does not f ollow pixels but smoothes over pixels. As a result, the lines do not have steps.
A horizontal oriented line is drawn by a pen having a height of 1 pixel and a width of .25 pixel.
Below the comparison: the smooth line on top, below without smoothing.
For a vertical oriented line the pen is 1 pixel in width and 0.25 pixel in height. Figure 1: Part of the above picture enlarged 10 times:
These pictures are drawn by a modified pen: not 1*1 size but 1 * 0.25 pixel. Differentiation must be made between horizontaland vertical oriented lines:
We notice that a pixel is divided into 16 (4*4) subpixels. We have to record the subpixels that have been colored by the pen. Var Blender : array[...., …] of word ;// 1 word per pixel, array same size as canvas Correspondence of Blender bits and subpixels
24
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
SOFTDRAW PAGE 2/2 So, drawing takes 3 steps: 1. blender word bits are set if covered by the pen 2. Drawing is done in a bitmap. blender array is scanned , bitmap pixel color is calculated as average of original and covered subpixels. 3. bitmap is copied to a paintbox to become visible.
For people interested in math, see below the origin of the formula, using implicit differentiation For easy calculation, the center of the ellipse is assumed (0,0). In reality, x and y bias values have to be added.
Example: if
5 subpixels were covered then 5/16 of the pen color and 11/16 of the original pixel color make the new color. Two procedures make the core of soft drawing: procedure Qpixel(x,y : single) ; // draws a soft pixel using the selected pen procedure Softline( x1,y1,x2,y2 : smallInt ); //draws a softline from (x1,y1) to (x2,y2)
If x1 > x2 then the coordinates are traded. Drawing is always from left to right. Please refer to the source code for details. ELLIPSES pr oc ed ur e So ft El li ps e( x1 ,y 1, x2 ,y 2 : SmallInt);
The ellipse is drawn by subsequently calling Qpixel(.. , ..);
X runs in quarter pixel steps from -sx to + sx. Then y runs in quarterpixel steps from -sy to + sy. Please refer to the source code for details.
// draws a soft ellipse
Left top is (x1,y1), right bottom of the enclosing rectangle is (x2,y2). Additional problem is the pen selection because an ellipse has horizontal- and vertical oriented arcs. In the picture below (sx,sy) is the center point between the horizontal and vertical orientation. At this point the pen has to be changed. Also consider the reflections of (sx,sy) on the axis.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
25
SPECIAL OFFER: L A C S A P K R N I A L S C E E G M A A P G D R & A H T W O A H M R E T U P M O C E S K R I D D I V A D
E S K R I D D I DAV
ml es.ht _ Gam h t a terM ompu kse/C ir D id v u/Da les at cal.e presa laisepas .b www
FOR THE SUMMER BUY THE BOOK FOR 30 EUROS
INCLUDING: • 53 projects and code fully explained.
; ure ed proc r a v o d n to 9 begi := 1 for i n begi
The Delphi 3 – Delphi Berlin source code is available together with full explanation. Most of the projects can be done with FPC and or Lazarus as well. • For a preview go to: http://www.blaisepascal.eu/ david_dirkse/ UK_Book_Department_DavData.html • PDF file - excellent readable on your tablet. Printable.
; end ; end
TH & A M TER ASCAL U P COM S IN P E GAM
POCKET EDITION Also printed in full color. A fully indexed PDF file is included.
€ 30,00
On tablet
The book contains 87 chapters, 53 projects with source code and compiled programs (exe). The book is highly educational and suitable for beginners as well as for professionals.
Resize, rotate, compress digital images. Design your own font, generate and reduce Truth Tables from Boolean algebra. And more important: understand how it all works!
Play board games, solve puzzles, operate a vintage mechanical calculator, Produce 3dimensional computer art, generate lists of prime numbers, explore and draw any mathematical function.
For the games, winning strategies are explained. For puzzles the search algorithm. For all projects: the math behind is thoroughly discussed.
Solve systems of equations, calculate the area of complex polygons. Draw lines, circles and ellipses.
http://www.blaisepascal.eu/david_dirkse/UK_Book_Department_DavData.html 26
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
HOW TO BUILD AN APP IN XML WITH FIREMONKEY INCLUDED STYLE SHEETOVERVIEW starter
PAGE 1/9 BY DETLEF OVERBEEK
expert
Delphi FireMonkey In this article some of the possibilities that are available with xml are explained. The article will start by giving a short introduction into what XML is and how it can be used in Delphi. In this article we want to show how XML works, by creating a very simple application made in FMX (Embarcadero) showing some specialties about FMX and explaining some of it, so you will be able to build an extension of this program yourself and later on port it to your own Smart Mobile.
First some Wiki knowledge: (Extensible Markup Language (XML) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. It is defined by the W3C's XML 1.0 Specification and by several other related specifications all of which are free open standards. The design goals of XML emphasize simplicity, generality and usability across the Internet. It is a textual data format with strong support via Unicode for different human languages. Although the design of XML focuses on documents, it is widely used for
the representation of arbitrary data structures such as those used in web services. Several schema systems exist to aid in the definition WIKIPEDIA of XML-based languages, while many application programming interfaces (APIs) have been developed to aid the processing of XML data.) If you want to take a deeper dive: https://en.wikipedia.org/wiki/XML
We will look into how to create a structure we can use for this XML and then apply node values and child nodes. (See the figure below)
HOW TO CREATE A FIRST XML STRUCTURE.
You can either take Notepad or something like that and make your own structure and let the extension be .xml.
Figure 1: the lay out of the application in Delphi Seattle / Win7
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
27
HOW TO BUILD AN APP IN XML PAGE 2/9 WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
In a following article we will explain how you can create your xml through coding. For now it would be best to take the xml we already have created: Friends.xml . The application makes use of this at the start of the program: procedure TXmlApp.FormCreate; It should be available in your main dir. This first .xml is only used by the program to alter the text and show what it does. We have kept it simple so you can of course play around with this. Next time we will also add branches and make it therefore more complex. In the interface section there is the uses and type section. Under the uses a number of FireMonkey units are added because this is a “FireMonkey Multidevice” application. Go to files: new → multidevice form.
In the example project there are 2 type declarations. The first one is 'TPerson = class'. This class is used as a container for storing information. It has been added below. It consist of 3 string variables and an IXMLDocument . This class allows us to call the information in procedures similarly to using global variables. type TPerson = class
public UserID: string; firstName: string; lastName: string; XML: IXMLDocument ;
; end NR.: 1
The second type is the form on which we added a number of components. These will be explained later and have therefore not been listed here. Under strict private we added FPerson: Tperson;. This is an instantiation of the TPerson = Class and will be used for the storage of the information. It suffices to say that these units are required similarly to the standard units that are added to a VCL forms application and FireMonkey of course will allow you to drop only those components on the form that are allowed by FMX. Besides those units in the uses section the following units have been added XmlIntf and XmlDoc. XmlIntf and XmlDoc are required for the handling of the XML. It contains the component IXMLDocument which we will be used in the example project. For extra help refer to: http://docwiki.embarcadero.com/RADStudio/S eattle/en/Working_with_XML_Documents
28
strict private FPerson: TPerson ;
NR.: 2
EXPLANATION OF Strict Private .
In Delphi there's a "bug" that makes the visibility of all members public within the same unit. The strict keyword corrects this behaviour, so that private is actually private, even within a single unit. For good encapsulation I would recommend always using the strict keyword.
The function GetNodeText will be used to extract the nodevalue from the node with a specific tag. It uses the parameter 'pvTagName' to find the right node in the 'pvItemNodes' and then extract the value.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
HOW TO BUILD AN APP IN XML PAGE 3/9 WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW class function TFormMyFirstApp.GetNodeText(pvItemNodes: IXMLNodeList; const pvTagName: string): string; var lvNodeName, lvNodeValue: string; lvItemIndex : Integer ; begin for lvItemIndex := 0 to pvItemNodes.Count - 1 do begin := pvItemNodes[lvItemIndex].NodeName; lvNodeName lvNodeValue := pvItemNodes[lvItemIndex].Text ; if (lvNodeName = pvTagName) The procedure FormDestroy frees the FPerson := lvNodeValue; then Result object. This is required because it has no owner. ; end NR.: 3 The other functions and procedures are al linked to ; end
the form and will be freed on its destruction. The procedure AddNodeTex t is used for procedure TFormMyFirstApp.FormDestroy (Sender : TObject ); creating nodes with a nodevalue. The parameter 'pvPersonNode' is the node that begin gets added and 'pvKey' is the nodename and FPerson.Free NR.: 4 ; end the 'pvValue' is the nodevalue. (In this program however it’s changed and no added - we wil safe that for a future article). class procedure TFormMyFirstApp.AddNodeText (pvPersonNode : IXMLNode ; pvKey , pvValue : string); var lvPersonInformation: IXMLNode ; begin lvPersonInformation := pvPersonNode .addchild(pvKey); lvPersonInformation.NodeValue := pvValue ; NR.: 5 ; end
The procedure Fill is used to get the information The button btnLoadEditsClick is used for to load the from 'pvPersonNode' and saved in the FPerson information from FPerson string variables UserID, string variables userID Firstname and Lastname. firstName and lastName to the edits. procedure TFormMyFirstApp.Fill( pvPersonNode : IXMLNode ); NR.: 6 var lvItemNodes: IXMLNodeList ; begin := pvPersonNode.ChildNodes ; lvItemNodes := TFormMyFirstApp.GetNodeText(lvItemNodes 'userID' , ); FPerson.userID , ); FPerson.Firstname := TFormMyFirstApp.GetNodeText(lvItemNodes 'firstName' , ); FPerson.Lastname := TFormMyFirstApp.GetNodeText(lvItemNodes 'lastName' ; end procedure In the FormCreate procedure we create an TFormMyFirstApp.btnLoadEditsClick( Sender : TObject ); FPerson object using the variable declared in begin the strict private section . Next we create edtUserID.text := Fperson.UserID; the IXMLDocument named XML which is located in edtfirstName.text := Fperson .firstName; the FPerson object. With the LoadFromFile edtlastName.text := Fperson .lastName; procedure we fill the IXMLDocument. Next we NR.: 7 ; end set the node to lvPersonNodes. You can set a node at different levels. You can set the node to the root by referring to the DocumentElement. The button ReloadXml calls the procedure In this case we go 1 node deeper and go straight ReloadXml. ReloadXml is a separate procedure for the childnodes - because the information we which is also called in the FormCreate. want to retrieve is stored at that level. procedure TFormMyFirstApp.FormCreate( Sender: TObject ); NR.: 8 var lvPersonIndex: Integer ; lvPersonNodes : IXMLNodeList ; begin FPerson := TPerson.Create; FPerson.XML := TXMLDocument .Create(nil); FPerson.XML .LoadFromFile ('c:\DelphiProjects\XML Article\friends.xml' ); lvPersonNodes := FPerson.XML.DocumentElement.ChildNodes; for lvPersonIndex := 0 to lvPersonNodes.Count - 1 do begin Fill(lvPersonNodes[lvPersonIndex ]); ; end Issue Nr ;4 2016 BLAISE PASCAL MAGAZINE ReloadXml ; end
29
HOW TO BUILD AN APP IN XML PAGE 4/9 WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW procedure TFormMyFirstApp.ReloadXml ; NR.: 9 begin Memo1.Text := ShowText(FPerson .XML.DocumentElement); // a simple solution to show the content again ; end ReloadXml
The Procedure ReloadXml uses the function Showtext (page 31 Nr.:15) to return a string containing the XML information. The string is not actual XML but the function mimics the XML functionality to make the string appear as if it was XML in Memo1 at the top of the form. It is important to know that the memo is loaded the first time with content during the FormCreate procedure. Actually the work is done by DoButtonLoadXml
MEMO FIELD
btnLoadEditsClick
procedure TXmlApp.DoButtonLoadXml ; NR.:10 begin Memo1.Text := ShowText(FPerson .XML.DocumentElement); ; end Procedure TFormMyFirstApp.ClearEdits ; begin edtUserID.text := ''; edtfirstName.text := ''; edtlastName.text := ''; NR.:11 ; end
Clear edits procedure procedure TFormMyFirstApp.btnReloadXmlClick(Sender : TObject ); begin ReloadXml; NR.:12 ; end Figure 3: The running application
The procedure btnLoadEdits (page 29 Nr.: 7) Several Edit Fields
The procedure SavePersonClick saves the text from the edits and adds it to the FPerson string variables. Then the IXMLDocument is cleared and the IXMLDocument is loaded with the data. But to fianalze it you will have to write all of that to the XML file. (see page 31 Nr.:14
procedure TFormMyFirstApp.SavePersonClick(Sender : TObject ); NR.:13 var lvFriendsNode, lvPersonNode: IXMLNode ; lvPersonNodes : IXMLNodeList; lvIndex : Integer ; begin FPerson.UserID := edtUserID.Text; FPerson.firstName := edtfirstName .Text; FPerson.lastName := edtlastName.Text; FPerson.XML.ChildNodes .Clear ; ('friends'); lvFriendsNode := FPerson.XML.addchild begin ('person' ); lvPersonNode := lvFriendsNode.addchild begin TFormMyFirstApp.AddNodeText(lvPersonNode, 'userID', FPerson .UserID); TFormMyFirstApp.AddNodeText(lvPersonNode, 'firstName', FPerson .FirstName ); TFormMyFirstApp.AddNodeText(lvPersonNode, 'lastName' , FPerson .Lastname); ; end ; end ; end
30
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
HOW TO BUILD AN APP IN XML PAGE 5/9 WITH FIREMONKEY - INCLUDED STYLE SHEETOVERVIEW
The procedure btnWriteToXMLClick NR.:14 procedure TFormMyFirstApp.btnWriteToXMLClick(Sender : TObject ); var XML: IXMLDocument ; lvFriendsNode , lvPersonNode : IXMLNode ; lvPersonNodes: IXMLNodeList ; lvIndex : Integer ; begin XML := TXMLDocument.Create(nil); := True; XML.Active ('friends' ); lvFriendsNode := XML.addchild begin ('person' ); lvPersonNode := lvFriendsNode.addchild begin TFormMyFirstApp .AddNodeText(lvPersonNode, 'userID' , FPerson .UserID); TFormMyFirstApp .AddNodeText(lvPersonNode, 'firstName', FPerson .FirstName); TFormMyFirstApp .AddNodeText(lvPersonNode, 'lastName' , FPerson.Lastname); ; end ; end XML.SaveToFile('c:\DelphiProjects\XML Article\friends.xml' ); ; end Function TFormMyFirstApp.ShowText(Node : IXMLNode ; ident : string = ''): string; var i, j: Integer ; attributes: string; begin ( .NodeType = ntText) if Node then Result := Node.NodeValue else if (Node.NodeType = ntElement) then begin for j := 0 to (Node.AttributeNodes .Count -1) do begin attributes := attributes + Format(' %s"=%s"', [Node .AttributeNodes [j ].NodeName , Node.AttributeNodes[j ].NodeValue ]); ; end Result := #10 + ident + '<'+ node.NodeName + attributes + '>';
for i:= 0 to Node.ChildNodes.Count - 1 do Result := Result + ShowText(Node .ChildNodes [i ], ident + '
');
Result := Result + '' + Node.NodeName + '>' + #13;
; end ; end
NR.:15
Now for the use of FMX it’s necessary to show how you can make use of the Styles of FMX. Drop a component called Style book on your form. A style book is something that in HTML is CSS Styles. It contains some ready made styles you can choose from. For your convenience we have made images of them used by our application. (See page32 up to 35). Now if you doubleclick on the coponent a new sort of view appears. ( See page 35 )
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
31
BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 6/9
Air_Style
Amakrits_Style
AquaGraphite_style
Blend_Style
32
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 7/9
GoldenGraphite_Style
Light_Style
MetropolisUIBlue_Style/ MetropolisUIBlack_Style/ MetropolisUIBlue_touch.Style MetropolisUIBlack_touch_Style Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
33
BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 8/9
MetropolisUIDark.Style/ MetropolisUIDark_touch_Style
MetropolisUIGreen_Style/ MetropolisUIGreen_touch_Style
RubyGraphite_style
Transparent_Style.png
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
34
BUILD AN APP IN XML WITH FIREMONKEY - INCLUDED STYLE SHEET OVERVIEW PAGE 9/9
Win10ModernBlue_Style
Win10ModernDark_Style
Opens the dialog to find your style Necessary to go back and see the result
Figure 4: The running application
If you click on the left most button a window wil open up to allow you choose the Style that you like or want: Here is the address where it is located:
C:\Program Files (x86)\Embarcadero\Studio\17.0\Redist\styles\Fmx So if you take the correct name of the style as you can find in the article, it will load it. But it’s not yet done. To see how it really affects your application, it is necessary to make use of the Apply and Close Button at the right shown on the figure number 4. You will be back in the normal design view.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
Have fun creating your first XML based App! The code for this app has been written by Vincent Overbeek
35
HOW TO DEAL WITH BIG NUMBERS PAGE 1/4 BY MAX KLEINER
maXbox Starter 41 A BIG DECIMAL OR BIG INT INTERFACE Today we step through numbers and infinity. As you may know there's no simple solution to print, calculate or store big numbers or decimals.
For example you want to compute 400000078669 / 2000123 your calculator shows (so does my Casio FX-880P):199987.7401 So this is not the end of the line, a second test is maxcalcF('400000078669 / 2000123') and we get: 199987.740088485 And there are even more numbers that need to compute so we switch to to get the http://www.wolframalpha.com real precision thing or at least an approximation: 199987.7400884845581996707202507045816682274 04014653098834421683066491410778237138415987 416773868407092963782727362267220... http://www.wolframalpha.com/input/?i=4 00000078669%2F2000123 again as you suppose the numbers go on. Use "Power Towers" to write them down. The decimal point is the most important part of a decimal number like above. Without it, we would be lost ... and not know what each position meant.
36
maXbox
Dividing decimals is almost the same as dividing whole numbers, except you use the position of the decimal point in the dividend to determine the decimal places in the result. Our division is always an approximation. Approximate means you're going to round the number. Because you're not actually giving the exact number, all those numbers after the decimal, the rounded number is called an approximation: 199987.7401 is roundToPrec4 of: 199987.740088485 Although, you probably wondered how they get those nice and fancy graphical user interfaces (GUI) for large numbers, here in maXbox we do also have one: ma Xb ox 3 56 8_ U_ Bi gF lo at Te st sc ri pt 2. pa s
Compiled done: 6/18/2015 The idea that you are approximating is that, as you are only taking the first 50 decimal places as you can see at the screen-shot. The same like wolfram goes like this: 199987.740088484558199670720250704581668227 4040146530988344168306649141077823713841598 74167738684070929637827273622672205. When we try to write this decimal number (or the well known PI or SQR(2)) in decimal notation, we get an endless stream of digits. 3.141592653589723.....and so on forever. But suppose instead, we use fractional notation.
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
HOW TO DEAL WITH BIG NUMBERS PAGE 2/4 maXbox Then we can write each part as a precise (irreducible) 400000078669 2000123 A fraction is an exact ratio of 2 numbers, and if those 2 numbers are integers, or at least rational numbers, then the fraction can more appropriately be called a rational number. An irrational number can be represented as an approximation to a rational number to an extremely high degree of accuracy. It's quite clear that there are fractions which can't be expressed in finite decimal form!
With a BigInt Library you'll see the full range of Fact(70):11978571669969891796072783721 987892755536628009582789845319 680000000000000000
All examples can be found online: maxbox3\examples\161_bigint_class_maxp rove2.txt http://www.softwareschule.ch/examples/ 161_bigint_class_maxprove2.txt
Now, here's the big problem. Not every number is rational! For example there is no fraction for sqrt(2). That is, no matter what whole numbers m and n you pick, m/n is not the square root of 2. Euclid wrote down a real AND beautiful proof of this fact around 2300 years ago. Interesting point about those real numbers is also the possibility to divide the number to his prime factorization: 29×37×127^(-1)×179×15749^(-1)×2082607 ma xc al cF (' 29 *3 7* (1 27 ^- 1) *1 79 *( 15 74 9^ 1)*2082607'); >> 199987.740088485
REAL BIG INTEGER
So what about big integers? For example you want to compute fact(70), your calculator shows: fact(70) = 1.19785716699699e+100
or ma xc al cF (' 70 !' ) 1.19785716699699E100
or even more
The call respectively the calculation goes like this: function GetBigIntFact(aval: byte): string; //call of unit mybigint var mbRes: TMyBigInt ; i: integer; begin mbRes:= TMyBigInt.Create(1); try //multiplication of factor for i:= 1 to aval do mbRes.Multiply1(mbres , i ); Result:= mbRes.ToString; finally //FreeAndNil(mbResult); mbRes.Free; ; end ; end
Or you want the power of 100 like 2^100 = 12676506002282299670376 function BigPow(aone, atwo : integer ): string; var tbig1, tbig2: TInteger ; begin tbig1:= TInteger.create(aone); //tbig2:= TInteger.create(10); try tbig1.pow(atwo); finally result:= tbig1.toString(false); tbig1.Free; ; end ; end
1.197857166996989179607278372168909873 6458938142546425857...× 10^100
but the maximum range on Pascal, C or Delphi depends on your operating system types, means nowadays an int64 range is big. Now that the "signed" words are finally up-topar with the unsigned integer types, languages introduce a new 64-bits integer type, called Int64, with a whopping range of -2^63..2^63 - 1
Another way is to use a type extended, but the limitation is precision like Wr it el n( Fl oa tT oS tr (F ac t( 70 )) ) it only shows 1.2E+0100 or 1.19785716699698966E100
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
37
HOW TO DEAL WITH BIG NUMBERS PAGE 3/4 maXbox At least one really big, it's 333^409 6 (10332 decimal digits)!:
I'm trying to move a part of SysTools to Win64. There is a class TStDecimal which is a fixed-point value with a total of 38 significant digits. The class itself uses a lot of ASM code.
8542410589577088732296696591791458471 0138161386222147182917677810495360579 0662731836109375886562057769732224078 7369539815043322468151403276684789485 function BigDecimal(aone: float; atwo : integer ): string ; 2704687578755031097050417025182159123 begin 1581498325263250655809688846574990085 with TStDecimal.create do begin 9669714028055717222616721730816157657 try 7272999991338993244872051682800307067 //assignfromint(aone) 0499485838754788611631774723703891999 assignfromfloat(aone) //2 6958139536234769725670960895462872160 RaiseToPower(atwo) //23 2617326909732389848441307614286016432 result := asstring 3281696899530174488741933479651249141 finally 5546213966841046206162049080873850267 free 4650541288448161671070156327238251274 ; end 3281792004009389099676108083535339433 ; end 5725524764503872061091991652109449193 9222603486211588501821307572510489932 end ; 0094825429972785833085677027994289424 1606617524881072717128594007583728367 4910402380201480381659625620772921132 SysTools is hosted under Sourceforge: 4307343621431621697813033533870396651 http://www.sourceforge.net/ 2798938013065335070551824759826900420 projects/tpsystools 1863795492471837910714543445430478178 The class TStDecimal is defined in the unit 7239952937171734656039024994397675239 StDecMth. It has the following 0512439014099231872228674262774255372 description: StDecMth declares and implements 4933304310551768256663623236667348978 4851223121246465215815916502622714756 TStDecimal. This is a fixed- point value with a 5034147013414617346249445763685652587 total of 38 significant digits of which 16 are to the 2971987877831270158832603817205011322 right of the decimal point. 6371434556915439803996403854732786566 1366556882568704.2292943165706246 2026993558297850455952524136828406393 1428407486751810074659865765594581378 0192514534642025708505465055466519186 0004262625760818849535769666297091453 It is important to note that Infinity is not a real 7002071987397488841496932636449655414 number, it is an idea . 2960625942272943281855130658659637414 An idea of something without an end. 1177639546182930097371192049744072353 1587803915956018581696810199146742826 Infinity is not "getting larger", it is already fully 1271606169667518376174065032487760281 formed. Sometimes students or people 8378317677730431971470829242037195598 (including me) say it "goes on and on" which 4142794539461134475921078967271031215 sounds like it is growing somehow. But infinity 1288626779198995387011439234510647066 1101764762310248123763791491889455422 does not do anything, it just is. 4081908148706733079384730490856632162 Wr it el n( '' ) 5640799436867768527108759041690965302 Wr it el n( 'B ig L ot to C om bi na ti on 1 60 0 2692727792891817098986146184008177018 of 5000!') 1767033389755570766416722785651840954 Wr it el n( '' ) 3885689046572793127635154465381472711 Wr it el n( Bi no mi na lC oe ff ic ie nt (5 00 0, 7240451212404891260149108022108352756 1600)); 8260609161657527584296850614033467693 Wr it el n( '' ) 4667568824407601228835743948301133856 Wr it el n( 'S am e Lo tt o Co mb 6 o f 45 !' ) 6729184892015764928314102429169028065 Wr it el n( Bi no mi na lC oe ff ic ie nt (4 5, 6 )) ; 2494545083790886477617437201261672363 -->8145060 7912448112789399431625831010771676068 Wr it el n( 'S am e Lo tt o Co mb 3 9 of 4 5! ') 2781353130522059276715028909294777177 Wr it el n( Bi no mi na lC oe ff ic ie nt (4 5, 8545830155927642694762695926174086054 39)); -->8145060 2034506012289981568628167702061562869 9561954771340366063324712132695944068 OK, 1/3 is a finite number ( it is not infinite). 4119059465666117348540308246233404699 But written as a decimal number the digit 3 2360387210154102113393219475674943157 repeats forever (we say "0.3 repeating"): 388839887567715636613 0.333333333333333333333... (etc.)
Etc etc etc...( Takes 3 pages)
38
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
HOW TO DEAL WITH BIG NUMBERS PAGE 4/4 maXbox APPENDIX STUDY WITH BIGINT DIRECT There's no reason why the 3s should ever stop: // TODO: Copy a f ile in a conne cted s hare path they repeat infinitely. // this is 333^4096: Okay, I hope you're not one of those people who denies 0.999. .. = 1, because it sounds like function GetBigIntDirect: string; you're saying 0.333... doesn't exactly equal //Unit mybigint 1/3. var mbResult: TMyBigInt ; i : integer ; If there are only a finite amount of 3s, I wouldn't begin argue a bit that they're not equal, but with an mbResult:= TMyBigInt.Create(333); try infinite amount, they are.
Test the script with F9 / F2 or press Compile. CONCLUSION
And we can easily create much larger numbers than those! But none of these numbers are even close to infinity. Because they are finite, and infinity is ... not finite! “WISE MEN SPEAK, BECAUSE THEY HAVE SOMETHING TO SAY; FOOLS, BECAUSE THEY HAVE TO SAY SOMETHING” . -
// Faktoren im Zaehler aufmultiplizieren ---> 2^12=4096 for i:= 1 to 12 do begin mbResult.Multiply(mbresult , mbresult ); //writeln(inttostr(i)+': '+mbresult.tostring); ; end Result:= mbResult.ToString; finally //FreeAndNil(mbResult); mbResult.Free; ; end ; end TMyBigInt = class
private Len: Integer; Value: AnsiString; Plato procedure Trim; procedure Shift(k: Integer); procedure MultiplyAtom(Multiplier1 : TMyBigInt; Multiplier2: Integer ); Feedback @ [email protected] public Literature: constructor Create(iValue: Integer = 0); Kleiner et al., Patterns konkret, 2003, procedure Add(Addend1, Addend2 : TMyBigInt ); Software & Support procedure Multiply(Multiplier1, Multiplier2 : http://www.softwareschule.ch/download/ ; TMyBigInt); overload codesign_2015.pdf procedure Multiply(Multiplier1: TMyBigInt ; http://www.softwareschule.ch/ ; Multiplier2: Integer); overload download/XXL_BigInt_Tutorial.pdf unction ToString: string; http://www.mathsisfun.com/numbers/ procedure CopyFrom(mbCopy: TMyBigInt ); infinity.html ; https://github.com/maxkleiner/maXbox3/ end
maXbox
releases
Issue Nr 4 2016 BLAISE PASCAL MAGAZINE
39