Sunday, March 22, 2020

Delphi Tip of the Day - Object Inspector Search

I was watching an excellent video on how to use the batch move capabilities within Delphi to import text data into a database and had one of those "What the heck just happened" moments. The object inspector was only displaying the "Name" property.

What the heck just happened...


I rewound the video by about 20 seconds and paid careful attention to what was going on. The presenter used the "search" box associated with the Object Inspector. What? I had no idea you could do that. Wow! Game Changer!

I've been staring at the object inspector for years and never even saw the search box even though it's right there, plain as day, in my face. Sure beats scrolling up and down through all the properties anytime I wanted to make a change.

Game Changer!




Alternate Game Changer!


I'd like to thank Bruce McGee for the following "Quick Edit" tip:

Right-click on a control at design time and select Quick Edit from the drop-down menu. It works for VCL and FMX controls. The VCL image on DocWiki is not correct. It actually reads "Caption" instead of "Text" in my version of Delphi.

http://docwiki.embarcadero.com/RADStudio/Rio/en/Quick_Edit_(VCL)
http://docwiki.embarcadero.com/RADStudio/Rio/en/Quick_Edit_(FireMonkey)


Enjoy!
Semper Fi,
Gunny Mike

Saturday, March 21, 2020

Delphi - SQLite Sample Projects

I've been exploring SQLite within Delphi. There are several sample SQLite applications that come with Delphi if you selected to install the samples during setup. I've put together the list of SQLite samples that are available.

The common samples file path is located here:
..\Studio\20.0\Samples\Object Pascal\Database\FireDAC\Samples\

FireDAC.SQLiteIniFile Demo Sample 

This sample uses FireDAC to connect to an SQLite database that emulates the structure and the operations of an INI File.

AddOn\SQLiteIniFile\Demo\SQLiteIniDemo.dproj

FireDAC.TFDLocalSQL MegaFMX Sample 

The sample shows different TFDLocalSQL applications.

Comp Layer\TFDLocalSQL\MegaFMX\LSQLMega.dproj

FireDAC.SQLite Encryption Sample 

This sample demonstrates how to encrypt/decrypt an SQLite database.

DBMS Specific\SQLite\Encryption\SQLite_Encrypt.dproj

Controlling Database Access Rights 

The SQLite is an embedded DBMS. This implies that it is a single user DBMS and does not need such concepts as a user, access rights, and so on. Still, some application can benefit from an access right control, for example:

  •  An application can restrict rights depending on an end-user license. A demo license means less possibilities, a full license provides all possibilities. 
  • Multi-tier data access frameworks can use their own user concept and control data access rights using some generic approach. 

 Again, SQLite provides a unique feature allowing you to authorize or not SQL commands. To work with this API, a Delphi application should set the OnAutorize event handler of the TSQLiteDatabase object, which is a database connection wrapping object. Hook this event after a database connection is opened.

DBMS Specific\SQLite\OnAuthorize\SQLite_OnAuthorize.dproj

Hooking Database Updates 

SQLite provides an unique API allowing you to monitor all updates to a database. This feature can be used, for example, to log all updates to a DB. To work with this API, a Delphi application should set the OnUpdate event handler of the TSQLiteDatabase object, which is a database connection wrapping object. Hook this event after a database connection is opened.

DBMS Specific\SQLite\OnUpdate\SQLite_OnUpdate.dproj

Custom Collations 

SQLite stores and handles all character data either in UTF8 or UTF16, depending on the OpenMode connection parameter. When SQLite needs to compare or sort a character data, it has to know what rules to use for this. The rules are known as a collation.

DBMS Specific\SQLite\UserCollation\SQLite_UserColl.dproj

Custom Functions 

SQLite does not support the stored procedure or function concept, as it allows you to use the host language environment to extend the engine functionality. SQLite allows you to register host language functions in the SQLite engine and use them in the SQL commands. FireDAC simplifies this by introducing the TFDSQLiteFunction component.

DBMS Specific\SQLite\UserFunc\SQLite_UserFunc.dproj

The SQLite R*Tree Module 

An R-Tree is a special index that is designed for doing range queries. R-Trees are most commonly used in geospatial systems where each entry is a rectangle with minimum and maximum X and Y coordinates. Given a query rectangle, an R-Tree is able to quickly find all entries that are contained within the query rectangle or which overlap the query rectangle.

This idea is easily extended to three dimensions for use in CAD systems. R-Trees also find use in time-domain range look-ups. For example, suppose a database records the starting and ending times for a large number of events. A R-Tree is able to quickly find all events that were active at any time during a given time interval, or all events that started during a particular time interval, or all events that both started and ended within a given time interval. And so forth. 

DBMS Specific\SQLite\UserRTree\SQLite_UserRTree.dproj

Title: SQLite 

Brief Description: This snippet shows you how to populate a listbox from a SQLite database using FireDAC and LiveBindings. See the section called "Accessing a Database" in the Mobile Tuturials topic in the documentation for more information and licensing requirements.

Platforms supported: iOS, Android

..\Mobile Snippets\FireDACSQLite\FireDAC_SQLite.dproj

Enjoy
Semper Fi,
Gunny Mike

Delphi Tip of the Day - OnShow SetFocus or Form1.ActiveControl

I'm creating a simple database program to explore how SQLite works within Delphi. I want to be able to switch between three databases: Album, Test, and World. So I added a TComboBox and populated the Items property with three values; Album, Test, World. I also set TextHint := 'Choose Database...';

object ComboBox1: TComboBox
    Left = 8
    Top = 8
    Width = 121
    Height = 21
    ParentShowHint = False
    ShowHint = False
    TabOrder = 0
    TextHint = 'Choose database...'
    Items.Strings = (
      'Album'
      'Test'
      'World')

When I ran the program the TextHint for the ComboBox did not display:



That is not what I was expecting. The Combox was the active control which negates being able to see the TextHint "Choose database..."

So I added a little piece of code to the form's onShow event.

procedure TForm1.FormShow(Sender: TObject);
begin
  StatusBar1.SetFocus;
end;

Now when I run the program right from the get-go the StatusBar componet has the focus and the ComboBox displays as intended.


Sometimes it's the small things that make all the difference!

An alternative  to using the OnShow event was suggested in the comments.

Form1.ActiveControl := StatusBar1


I love Delphi! 

Enjoy!
Semper Fi
Gunny Mike

Sunday, February 23, 2020

Delphi Tip of the Day - Autosave Project Desktop

I am not a full-time Delphi guy. So, when I'm learning Delphi by reading OPC (other people's code) I want to make the best of my time. I was studying some code from Cary Jensen that goes with Chapter 6 of his Delphi in Depth: FireDAC book.

When I was done understanding a section of his code, I simply folded it. I figured I beat that code up enough in my mind. I understood it. And I don't need to look at it again, at least not right now. I also didn't want to be distracted by having those code blocks expanded. 

I started a brand new project in Delphi to write some of my own code that was similar but different, just to reinforce what I learned. When I was finished, I reopened Jensen's code and the pieces of code I had folded were no longer folded. 

It turns out this is an easy fix. Simply enable "Save project desktop when closing".
Tools > Options > IDE > Saving and Desktop


Not only did this keep sections of the code I had folded, folded, it remembered whether my last view was Code view or Design view. It also kept track of where in the code view I left off. I was looking at line 522 in the source code when I close the project, Delphi put me right back at line 522 the next time I reopened the project. How cool is that.

Enjoy!
Semper Fi
Gunny Mike


Sunday, February 16, 2020

Delphi Revisited: Database Application Design

I have been creating database applications for over 30 years. Unfortunately, I have never been able to create a single database application in Delphi. That's a very sad fact. One that I'm not very proud of. Because I've been unable to create a database application with Delphi, I considered myself mediocre. And then something happened... Delphi turned 25.

"And then something happened... Delphi turned 25"


I, like so many of you, spent time this past week looking at all the commotion on the internet over Delphi turning 25. Then I looked at the picture of me, and my two boys hanging in my home office. I've been using Delphi since it was Turbo Pascal 3. 


That picture was taken in 1994 for an article that ran in the December issue of Military Lifestyle magazine.


"You don't need to be a programming guru to be successful"


Wow, my Zilch software is 29 years old. It's older than Delphi. I'm not mediocre. I'm living proof you don't need to be a programming guru to be successful. You just need determination.

And then, I had an epiphany regarding my lack of database design skills with Delphi. I realized I have been concentrating on the wrong stuff. I got so bogged down with the "How to do Data Entry" aspects that I totally missed out on everything else I can do with Delphi.

I actually do have one commercial product, Credit Card Math, that uses an ElevateDB database. But you know what, even though this program uses a database, it does not have any "Data Entry" functions.

"Data entry does not a database application make!"


That's it! Data entry does not a database application make! I concentrated on the wrong thing, data entry. I need to focus on the presentation and the analysis, and the reporting of the data and not the data entry. 

All I need is data in the database. I can build the whole presentation layer and reports without having any data entry functions. (light bulb moment)

I have such a renewed spirit. I'm done fiddling around making fancy grids that do all sorts or nifty data entry tricks. I'm going to focus on the meat and potatoes of my application. When the time comes I'll deal with the data entry stuff.

It's time to get ready for Zilch turning 30 in 2021. 

Happy Birthday Delphi!

Semper Fi,
Gunny Mike

Sunday, December 29, 2019

When You Don't Know, What You Don't Know

I've been in a rut for about the past six months. Not just a Delphi programming rut but a "life rut". What's worse, I knew I was in a rut and thought I was trying to get out of it only to realize I wasn't. Then this morning came and... I now know what I didn't know.

"I knew I was in a rut and thought
I was trying to get out of it..."


I was fascinated by a post in the Delphi Developer group on FaceBook written by a long-time VCL developer who is frustrated with making something work on an Android device. Admittedly, this person is not a GUI guy nor an OOP fundamentalist. I can totally relate to this. I have been using Delphi since it was Turbo Pascal 3. I am a traditional "top-down procedural" programmer who has been struggling to wrap my head around OOP fundamentals.

One of the comments on this post stopped me dead in my tracks. It simply stated... "Put your login form in a TFrame" and gave a link to a GitHub repository of FMX Cross-Platform-Samples.

https://github.com/FMXExpress/Cross-Platform-Samples

I've seen some of this FMXExpress stuff before but never knew about this GitHub repository. At the time of this writing there are 99 well organized Cross Platform Samples available. I've been looking for an excuse to rededicate myself to learning FMX cross application development in Delphi and this GitHub repository looks like the perfect spot for me to learn.

"I really don't know what GitHub is or how to use it."


Now, I've heard of GitHub before and I've been to a few different GitHub repositories, but I really don't know what GitHub is or how to use it. This was the my first acknowledgement of YDKWYDK. So I jumped on lynda.com and looked for a course about GitHub and found this one called "Learning GitHub".

About ten minutes into the course the instructor says "Projects allow you to visualize your work with Kanban-style boards." I've never heard of Kanban. What is Kanban? (More YDKWYDK).

"What is Kanban?"


I do another search within lynda.com and discoverd a course called "Stay Lean with Kanban".

Wow, this Kanban stuff is really cool. In it's simplest form Kanban is a way to visualize and prioritize the workload. You visually see what you are doing and what needs to get done. You also eliminate waste by focusing on what's most important. This is done by limiting the work in progress.

I'm about a third of the way through this tutorial and paused it to write this blog because of another YDKWYDK episode.

As I was getting to understand this Kanban stuff it hit me. Why can't I use Kanban for my personal life?

"Why can't I use Kanban for my personal life?"


I can and I intend to do just that. There's a website for "Personal Kanban". There's also a book called "Personal Kanban: Mapping Work | Navigating Life".

It's safe to say I have climbed out of my rut and I'm getting back at it. What a journey today has been...

FB Delphi Developer > FMXExpress > GitHub > Kanban

Semper Fi,
Gunny Mike





Saturday, September 7, 2019

Delphi Tip of the Day - Who's up First?

I'm working on updating my old flagship product and I ran into an issue where a file kept getting deleted on startup. I could not for the life of me figure out where this was happening. I wound up adding vcl.Dialogs to all of the units and then adding code to the Initialization section of each unit hoping I could find out where the damned delete code was.
initialization
begin
  ShowMessage('Inside [Unit Name Here]');
end;
Adding this code to each and every unit was a pain in the butt. And it still didn't help me track down where the file was getting deleted. There had to be an easier way to figure out the order in which each unit was being created.

I turned to the SO community asking for an easy way to generate a list of forms/units in the order they are created. I received the simplest and most elegant solution from Uwe Rabbe. He recommended looking at the C=ICODE segments of the map file.

My first two questions were, "What's a map file? And how do you create one?"

Information on what a *.map file is can be found here.
http://docwiki.embarcadero.com/RADStudio/Rio/en/API_%28%2A.map%29

To create a .map file from inside the IDE click Project > Options > Delphi Compiler > Linking

Set Map file := Detailed


Click Save

Then build your project and you will have a *.map file.

The reason I was having such a hard time tracking down where the file deletion was happening was because it took place within a "dll" file.



Line 47 of the map file shows the first unit of my project is Zglobals (yes the dreaded global unit). Lines 58-60 show the next three units from my project.

Line 59 StdDlls is a precompiled dll unit that I am unable to modify the source code for because it uses "Quick Reports". I do not have Quick Reports installed on my new dev computer. Therefore I cannot actually modify the source code for this unit.

It turns out that the file delete was happening inside the dll.

I just thought that Uwe Rabbe's solution to creating an ordered list of form/units was so simple and elegant I needed to share it with you in case you ever need a quick and easy way to see the order in which each Delphi unit gets created inside one of your projects.

Cheers!
Semper Fi,
Gunny Mike

Sunday, August 11, 2019

Delphi Tip of the Day - Rounding (Again!)

It's been over 7 years since I dove into the mystical world of rounding numbers within Delphi. It's amazing how much code actually gets written in support of the main stuff an application does. I am so glad I wrote my blog... it's the one place I can go back to when I find gaps from my hard drive crash of 2018.

I ran into the old familiar rounding issue - again. And of course, I didn't have the code I used to get it squared away.

My original blog post from 7 years ago, "Rounding the Currency type like they taught us in school", explains the issue in full detail and nothing has changed with regard to how Delphi handles rounding.

And as usual David Heffernan gave...


So I wen back to the Stack Overflow post  to revisit the answers given to my original question. And as usual David Heffernan gave a very straightforward and succinct answer.

{---------------------------------------------------------------}
{ Added 2019-08-07                                              }
{                                                               }
{ Used to solve the Delphi's rounding function.                 }
{                                                               }
{ https://stackoverflow.com/q/10965759/195983                   }
{ https://stackoverflow.com/a/10970283/195983                   }
{---------------------------------------------------------------}
Function RoundTo2dp (Value: Currency): Currency;
begin
  Result := Trunc(Value*100+IfThen(Value>0, 0.5, -0.5))/100;
end;

I added the code to my StrStuff unit. (Does everyone have a StrStuff unit or is it just me?) And it did not compile. So, when I got done cussing out Heffernan for putting bum code out there, I did some digging.

It turns out there are two IfThen functions. One in the SystemStrUtils unit and the other one in the System.Math unit. And of course, I chose the wrong unit.

This specific IfThen function is from System.Math


This specific IfThen function is from the System.Math unit:
unit Strstuff;

interface

uses System.Sysutils, System.Math;

Function RoundTo2dp (Value: Currency): Currency;
And of course after I put the correct unit in the uses clause it worked like a champ. I must admit, it felt good cussing out Heffernan. But as usual... he's right. Again!

Thank you David.

Enjoy!
Semper Fi
Gunny Mike
https://zilchworks.com