Showing posts with label tip-of-the-day. Show all posts
Showing posts with label tip-of-the-day. Show all posts

Sunday, June 7, 2026

Delphi Tip of the Day: Use Beyond Compare Lite Before Accepting AI Code Changes

ChatGPT can be a huge time saver when working with Delphi code.

But that does not mean you should blindly paste AI-generated code into your project and hope for the best.

Here is a simple habit that helps: compare the before and after files first.

Delphi includes a copy of Beyond Compare Lite, and it is easy to overlook. On my machine it is located here:

C:\Program Files (x86)\Embarcadero\Studio\XX.X\bin\

Replace XX.X with your installed RAD Studio version folder.

Recently, I asked ChatGPT for a complete drop-in replacement for a Delphi form that contained a TStringGrid. The goal was simple:

Save and load the grid column widths from the existing config.ini file when the form loads and closes.

ChatGPT gave me the full updated unit. Before replacing my working source file, I opened the original file and the new file in Beyond Compare Lite.

Beyond Compare Lite showing the original Delphi source file on the left and the ChatGPT-modified version on the right.

That made the review much easier.

Instead of hunting through the entire unit by hand, Beyond Compare Lite showed me exactly what changed. In this case, I could quickly see the new private fields, the new load/save methods, and the places where the form startup and shutdown logic had been modified.

That matters.

AI-generated code can be useful, but you still need to own the change. A file comparison tool helps you answer the important questions:

What did it add?
What did it remove?
What did it touch?
Did it change anything I did not ask for?
Does the change make sense before I compile it?

Beyond Compare Lite does a fantastic job of making those differences visible.

It is one of those tools that ships with Delphi but can be easy to forget about. If you are using ChatGPT, Copilot, or any other AI coding assistant, this little utility becomes even more valuable.

My rule of thumb is simple:

Never accept a full-file AI replacement without comparing it first.

Compare it. Review it. Then compile and test it.

AI can help write the code.

Beyond Compare Lite helps you keep your hands on the steering wheel.

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

Monday, May 25, 2026

Delphi Tip of the Day: Folding Code

 Every once in a while, I run into one of those small Delphi features that makes me wonder, “Why haven't I been using this more?”

Code folding is one of those features.

I was reminded of this during
a recent ChatGPT coding session

It does not make your code run faster. It does not fix bad logic. It does not magically turn a messy unit into clean architecture. But it does make the Delphi editor easier to work in, and when you spend a lot of time moving around in the source code, that matters.

I was reminded of this during a recent ChatGPT coding session while working in Delphi 13.1.

We were not doing anything glamorous. We were not building some grand framework or rewriting the whole application. We were doing the kind of careful work real programmers do all the time: find this section of code, replace it with that section of code, compile, test, and move on to the next small change.

In other words, it was surgical coding.

ChatGPT would tell me something like, “Find this method,” or “Replace this block,” or “Add this procedure right below that one.” That works fine when the unit is small. But once the source file starts growing, finding the right place in the code can turn into a scroll hunt. You move up, move down, pass the section you were looking for, scroll back, and hope you do not paste the new code in the wrong place.

That is when folding code started looking a lot less like an editor gimmick and a lot more like a practical navigation tool.

I created a simple test form with one button so I could slow down and look at how Delphi handles folded regions and folded methods. Nothing fancy. Just a small, controlled example where I could see what happens when the editor shows the code as an outline instead of one long strip of source code.

The lesson was simple: when you are making careful, targeted edits, folded code helps you find the right operating table before you pick up the scalpel.

unit Unit1;

interface

{$REGION 'Interface Comments'}
// ============================================================================
// Interface comments go here
// ============================================================================
//
//
// ============================================================================
{$ENDREGION}

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$REGION 'Implementation Comments'}
// ============================================================================
// Implementation comments go here
// ============================================================================
//
//
// ============================================================================
{$ENDREGION}

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  //
  // Button1 Click Code Goes Here
  //
end;


end.

What Is a Delphi Region?

A Delphi region starts with {$REGION ...} and ends with {$ENDREGION}.

For example:

{$REGION 'Interface Comments'}

// code or comments go here

{$ENDREGION}

The text inside the quotes becomes the folded label in the editor. In this example, Delphi shows the folded section as Interface Comments.

That may not seem like much in a small unit, but once a source file grows, these regions can act like road signs. Instead of scrolling through everything line by line, you can collapse the sections you do not need and keep the overall structure visible.

The Before Picture

Nothing Folded

This first screenshot shows the unit with nothing folded.

In a tiny example like this, it is not a big deal. Everything fits on the screen, and there is not much to hunt for. But that is not how real Delphi projects usually stay. A form starts simple, then a few more event handlers get added. Then a few helper methods show up. Then some temporary test code appears. Before long, you are scrolling through the file trying to find the one method you need.

That is where folding starts to earn its keep.

Folding the Regions

Regions Folded

In the second screenshot, the two comment regions are folded.

The code is still there. Nothing has been removed. Delphi simply collapses those sections so they take up less room in the editor.

This is one of the things I like about folding code. It lets me get things out of the way without deleting anything. Sometimes I want those big comment blocks. Sometimes they are helpful. But when I am working on a method, I do not always need to see them.

Folding lets me say, “Not now. Stay there, but get out of my way.”

That is useful.

Folding Regions and Methods

Regions & Methods Folded

The third screenshot shows both the regions and the method body folded.

At this point, the source file starts to look more like an outline. You can see the major parts of the unit without seeing every line inside each part.

That is probably my favorite use of folding. It helps me move around in the source file without getting pulled into the details too soon. When everything is expanded, every line competes for attention. When sections are folded, I can scan the shape of the unit first, then open only the part I need.

For someone like me, that matters. I do not “picture” the code in my mind. I work better when the structure is visible on the screen. Folding code gives me a simple way to make the editor show the structure instead of forcing me to mentally hold it all together.

Customizing the Folded Code Color

Delphi also lets you customize the way folded code looks in the editor.

You can find this under:

Tools > Options > Editor > Color

Then scroll down to the Folded code element.

Delphi 13.1 Editor Color settings

I usually work in the Light theme, so I changed my folded code colors to something I could spot quickly without making the editor look like a warning sign.

My settings are:

Foreground color: Palevioletred
Background color: Mistyrose

That is just my personal preference. You may like something different. The important thing is that folded code should be easy to recognize. I want it to stand out, but I do not want it shouting at me all day.

Palevioletred on Mistyrose works for me. It is visible, but not obnoxious.

At least in my humble opinion.

Why This Helps

The real benefit of folding code is navigation.

When I am working in a source file, I do not always need to see everything. Sometimes I only need the interface section. Sometimes I only need the implementation section. Sometimes I want to hide temporary test methods so I can focus on the production code. Sometimes I want to collapse a group of helper methods because they are not the thing I am working on right now.

That is where regions can be helpful.

For example, you might use:

{$REGION 'Helper Methods'}

or

{$REGION 'Temporary Sample/Test Methods'}

or

{$REGION 'Initialization Code'}

The region names become little signposts inside the editor. When they are folded, they help you move around the unit faster.

Used carefully, code folding reduces visual clutter. Used carelessly, it can become clutter of its own. I would not wrap every tiny thing in a region just because Delphi lets me do it. But for logical sections of code, longer comment blocks, temporary test code, or helper methods, regions can make a unit easier to live in.

Final Thought

Code folding is a small feature, but it solves a real problem.

It helps you move around inside your code without scrolling through every line. It lets you collapse the parts you do not need right now. It turns a long source file into something closer to an outline.

And when you can see the outline, it is easier to find your way.

Sometimes the best productivity improvement is not a new tool. Sometimes it is just making the tool you already use a little easier to work with.

Share Your Colors With a Comment

Please share the foreground and background colors you are using for your Folded Code in the comments.

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

GOTCHAS!

As pointed out by SilverWarrior in the comments. Code errors lead to unfolded code from the error point on. There are two very quick ways to re-fold all the methods instead of toggling the ( - ) or ( + ) in the left margin.

Method Folding quick Steps

Mouse:         Right Click > Fold > Methods
Keyboard:    [ Ctrl ] + [ Shift ] (keep held down) press K then press M





Wednesday, November 26, 2025

Delphi Tip of the Day: Restore Tools > Manage Features... After an ISO Install

 



I recently installed Delphi 13. I went back today to install the Help and Samples and could not.

Tools > Manage Features,,, gave me the following error:



WTF! 

I remember this happening to me about 3 years ago. I was as lost today as I was back then. 

How do you recover from this?
It's 2025, how can Embarcadero still let this crap happen?


A simple dialog that says "Would you like to switch to online mode instead?" which then gracefully handles the fact that the temporary ISO directory used during the initial install is no longer available.

Aren't we paying enough money for Embarcadero to put this type of fix in place?

Anyway, I dug up the old instructions Glenn Dufke posted three years ago when this happened. And his instructions worked today, just like they did back then.


If this happens to you, here is the fix:

  1. Open an elevated Command Prompt
    Right-click Command Prompt ? Run as Administrator

  2. Navigate to your RAD Studio 13 bin folder
    cd "C:\Program Files (x86)\Embarcadero\Studio\37.0\bin"

  3. Run the command Dufke mentioned
    getitcmd.exe -c=useoffline typo
    getitcmd.exe -c=useonline


Semper Fi
Gunny Mike
https://zilchworks.com

Sunday, May 11, 2025

Delphi Tip of the Day: A Better Way to Center Modal Forms


Yesterday, I was going through some final aesthetic checks on my FMX desktop software application. I have two modal forms that popup up during click events. One is help about which I set to screen center. And the other contains code that centers the form on it's parent window.

I was testing the behavior of this form toggling between light and dark themes. I noticed that with light theme the window just appears but with the dark theme I could see the window move it's way from the top of the screen to it's centered position and then switch to dark.

In the OnShow event handler I was calculating Left and Top like I have always done to center the window. This was the first time I'd ever seen the window reposition itself. This is the first time I'd ever used a dark theme. And, this is the first major application I'd written with FMX.

Left := ParentForm.Left + (ParentForm.Width - Self.Width) div 2;
Top := ParentForm.Top + (ParentForm.Height - Self.Height) div 2;
To say the least, I was annoyed by this split second flash centering itself on the parent window. I tried all kinds of stuff to minimize this flash. Nothing work.

There's got to be a better way!

I didn't realize I had left the Position property of the form set to Default. In essence that is screen position (0,0), or the top-left corner. 

The first line of my code was moving the form horizontally from the left edge to the center of its parent. (I never saw that move happening). The second line of code was moving the form vertically from the top edge to the center of its parent (I saw this move happening).

I thought there's got to be a better way? I don't want customers seeing this screen moving like this. I tried setting the form's Visible property to False before the centering code and setting the Visible to True after. Nope, that is unauthorized. 

I tried in the OnCreate instead. Nope. I had created public properties for the forms Left and Top along with getters and setters. I created a whole elaborate scheme to support positioning this form where I wanted it.

Then it dawned on me. "Isn't there a screen position property?"

Yes, there is.
MainFormCenter! It's a thing!

FMX Form Position Property

Are you kidding me. MainFormCenter! It's a thing! When did this show up?

I immediately set the form Position property to MainFormCenter and added an Exit statement to the top of the OnShow event handler. 

And voila! 

It works like a champ. No more flashy form realignment stuff happening.

I then removed all the getters, setters, and properties I added for manually doing the form centering activity. Simple, cleaner code. 😎

BTW, the same thing exists for VCL.

VCL Form Position Property

DocWiki Links:

Enjoy
Semper Fi
Gunny Mike

https://zilchworks.com

Sunday, February 16, 2025

Delphi Tip of the Day: FMX FastReport Text Object (TfrxMemoView)

I've been playing around with FastReport in FMX. To be honest, I've been struggling a bit. So, today I decided to go back to square one and work through the FMX documentation on the FastReport website. https://www.fast-report.com/public_download/docs/FRVCL/online/en/index.html

"The "Text" object... No Problem.
HTML-tags in the "Text" object... Doesn't work as advertised.

The "Text" object (TfrxViewMemo) is extremely powerful. It accepts simple HTML tags that lets you modify a single text field in some really cool ways. It's kind of like a mini "Rich Text" object. 

Here is a what a working example is supposed to look like:



That is one text field with multiple effects applied to separate sections:
  • Bold
  • Italic
  • Bold and Italic
  • Superscript
  • Subscript
  • Color
I ran into an issue when I followed the example to create the "Orange" text. It didn't work. The Original example from the FastReports did not turn the text orange.


Using <font color="#FF8030"> did not display the text in orange. The text between the opening and closing font tags did not display at all. Seeing that the "red" font tag worked, I tried using the color name "orange". And it worked.


I then tried using the Alpha Color of  #FFFF8030 and it also worked.


I'm glad I was able to make the FastReport example work. The text object is very powerful. I experimented with several different Delphi Color name constants and they also worked. I did run into an issue with some of the obsolete color name constants, such as MoneyGreen. The FastReport designer did not recognize "MoneyGreen" as a valid integer. It did however take the MoneyGreen HEX equivalent of #FFC0DCC0.

I decided to create a the following cheat sheet of all the font color names that FastReport text object will recognize.

Name Color HEX Code

Aliceblue

Aliceblue

#FFF0F8FF

Antiquewhite

Antiquewhite

#FFFAEBD7

Aqua

Aqua

#FF00FFFF

Aquamarine

Aquamarine

#FF7FFFD4

Azure

Azure

#FFF0FFFF

Beige

Beige

#FFF5F5DC

Bisque

Bisque

#FFFFE4C4

Black

Black

#FF000000

Blanchedalmond

Blanchedalmond

#FFFFEBCD

Blue

Blue

#FF0000FF

Blueviolet

Blueviolet

#FF8A2BE2

Brown

Brown

#FFA52A2A

Burlywood

Burlywood

#FFDEB887

Cadetblue

Cadetblue

#FF5F9EA0

Chartreuse

Chartreuse

#FF7FFF00

Chocolate

Chocolate

#FFD2691E

Coral

Coral

#FFFF7F50

Cornflowerblue

Cornflowerblue

#FF6495ED

Cornsilk

Cornsilk

#FFFFF8DC

Crimson

Crimson

#FFDC143C

Cyan

Cyan

#FF00FFFF

Darkblue

Darkblue

#FF00008B

Darkcyan

Darkcyan

#FF008B8B

Darkgoldenrod

Darkgoldenrod

#FFB8860B

Darkgray

Darkgray

#FFA9A9A9

Darkgreen

Darkgreen

#FF006400

Darkgrey

Darkgrey

#FFA9A9A9

Darkkhaki

Darkkhaki

#FFBDB76B

Darkmagenta

Darkmagenta

#FF8B008B

Darkolivegreen

Darkolivegreen

#FF556B2F

Darkorange

Darkorange

#FFFF8C00

Darkorchid

Darkorchid

#FF9932CC

Darkred

Darkred

#FF8B0000

Darksalmon

Darksalmon

#FFE9967A

Darkseagreen

Darkseagreen

#FF8FBC8F

Darkslateblue

Darkslateblue

#FF483D8B

Darkslategray

Darkslategray

#FF2F4F4F

Darkslategrey

Darkslategrey

#FF2F4F4F

Darkturquoise

Darkturquoise

#FF00CED1

Darkviolet

Darkviolet

#FF9400D3

Deeppink

Deeppink

#FFFF1493

Deepskyblue

Deepskyblue

#FF00BFFF

Dimgray

Dimgray

#FF696969

Dimgrey

Dimgrey

#FF696969

Dodgerblue

Dodgerblue

#FF1E90FF

Firebrick

Firebrick

#FFB22222

Floralwhite

Floralwhite

#FFFFFAF0

Forestgreen

Forestgreen

#FF228B22

Fuchsia

Fuchsia

#FFFF00FF

Gainsboro

Gainsboro

#FFDCDCDC

Ghostwhite

Ghostwhite

#FFF8F8FF

Gold

Gold

#FFFFD700

Goldenrod

Goldenrod

#FFDAA520

Gray

Gray

#FF808080

Green

Green

#FF008000

Greenyellow

Greenyellow

#FFADFF2F

Grey

Grey

#FF808080

Honeydew

Honeydew

#FFF0FFF0

Hotpink

Hotpink

#FFFF69B4

Indianred

Indianred

#FFCD5C5C

Indigo

Indigo

#FF4B0082

Ivory

Ivory

#FFFFFFF0

Khaki

Khaki

#FFF0E68C

Lavender

Lavender

#FFE6E6FA

Lavenderblush

Lavenderblush

#FFFFF0F5

Lawngreen

Lawngreen

#FF7CFC00

Lemonchiffon

Lemonchiffon

#FFFFFACD

Lightblue

Lightblue

#FFADD8E6

Lightcoral

Lightcoral

#FFF08080

Lightcyan

Lightcyan

#FFE0FFFF

Lightgoldenrodyellow

Lightgoldenrodyellow

#FFFAFAD2

Lightgray

Lightgray

#FFD3D3D3

Lightgreen

Lightgreen

#FF90EE90

Lightgrey

Lightgrey

#FFD3D3D3

Lightpink

Lightpink

#FFFFB6C1

Lightsalmon

Lightsalmon

#FFFFA07A

Lightseagreen

Lightseagreen

#FF20B2AA

Lightskyblue

Lightskyblue

#FF87CEFA

Lightslategray

Lightslategray

#FF778899

Lightslategrey

Lightslategrey

#FF778899

Lightsteelblue

Lightsteelblue

#FFB0C4DE

Lightyellow

Lightyellow

#FFFFFFE0

Lime

Lime

#FF00FF00

Limegreen

Limegreen

#FF32CD32

Linen

Linen

#FFFAF0E6

Magenta

Magenta

#FFFF00FF

Maroon

Maroon

#FF800000

Mediumaquamarine

Mediumaquamarine

#FF66CDAA

Mediumblue

Mediumblue

#FF0000CD

Mediumorchid

Mediumorchid

#FFBA55D3

Mediumpurple

Mediumpurple

#FF9370DB

Mediumseagreen

Mediumseagreen

#FF3CB371

Mediumslateblue

Mediumslateblue

#FF7B68EE

Mediumspringgreen

Mediumspringgreen

#FF00FA9A

Mediumturquoise

Mediumturquoise

#FF48D1CC

Mediumvioletred

Mediumvioletred

#FFC71585

Midnightblue

Midnightblue

#FF191970

Mintcream

Mintcream

#FFF5FFFA

Mistyrose

Mistyrose

#FFFFE4E1

Moccasin

Moccasin

#FFFFE4B5

Navajowhite

Navajowhite

#FFFFDEAD

Navy

Navy

#FF000080

Oldlace

Oldlace

#FFFDF5E6

Olive

Olive

#FF808000

Olivedrab

Olivedrab

#FF6B8E23

Orange

Orange

#FFFFA500

Orangered

Orangered

#FFFF4500

Orchid

Orchid

#FFDA70D6

Palegoldenrod

Palegoldenrod

#FFEEE8AA

Palegreen

Palegreen

#FF98FB98

Paleturquoise

Paleturquoise

#FFAFEEEE

Palevioletred

Palevioletred

#FFDB7093

Papayawhip

Papayawhip

#FFFFEFD5

Peachpuff

Peachpuff

#FFFFDAB9

Peru

Peru

#FFCD853F

Pink

Pink

#FFFFC0CB

Plum

Plum

#FFDDA0DD

Powderblue

Powderblue

#FFB0E0E6

Purple

Purple

#FF800080

Red

Red

#FFFF0000

Rosybrown

Rosybrown

#FFBC8F8F

Royalblue

Royalblue

#FF4169E1

Saddlebrown

Saddlebrown

#FF8B4513

Salmon

Salmon

#FFFA8072

Sandybrown

Sandybrown

#FFF4A460

Seagreen

Seagreen

#FF2E8B57

Seashell

Seashell

#FFFFF5EE

Sienna

Sienna

#FFA0522D

Silver

Silver

#FFC0C0C0

Skyblue

Skyblue

#FF87CEEB

Slateblue

Slateblue

#FF6A5ACD

Slategray

Slategray

#FF708090

Slategrey

Slategrey

#FF708090

Snow

Snow

#FFFFFAFA

Springgreen

Springgreen

#FF00FF7F

Steelblue

Steelblue

#FF4682B4

Tan

Tan

#FFD2B48C

Teal

Teal

#FF008080

Thistle

Thistle

#FFD8BFD8

Tomato

Tomato

#FFFF6347

Turquoise

Turquoise

#FF40E0D0

Violet

Violet

#FFEE82EE

Wheat

Wheat

#FFF5DEB3

White

White

#FFFFFFFF

Whitesmoke

Whitesmoke

#FFF5F5F5

Yellow

Yellow

#FFFFFF00

Yellowgreen

Yellowgreen

#FF9ACD32

Osolete Color Names Use HEX Code

LtGray

LtGray

#FFC0C0C0

MedGray

MedGray

#FFA0A0A0

DkGray

DkGray

#FF808080

MoneyGreen

MoneyGreen

#FFC0DCC0

LegacySkyBlue

LegacySkyBlue

#FFF0CAA6

Cream

Cream

#FFF0FBFF



Enjoy!
Semper Fi
Gunny Mike

Thursday, January 2, 2025

Tip of the Day - Everyday is an Etch-A-Sketch

Sometimes all you need is a little motivation.

Everyday is an Etch-A-Sketch.



Sometimes, every hour is an Etch-A-Sketch.

And sometimes, every minute is an Etch-A-Sketch.


Happy New Year,
Gunny Mike

Saturday, September 14, 2024

Delphi Tip of the Day: The Delphi Magazine Total Collection

I'm always looking for ways to improve my Delphi skills. Sometimes, this takes me down a rabbit hole. And each time, these little side trips never answer "Yes" to the question "Will this help me ship?"  

Last week I went down the "global variables are bad" rabbit hole. 🐇🕳

Global Variables Are Bad

I opened my copy of "The Delphi Magazine Total Collection" looking for some inspiration. And, I found a 6 Part series called "Effective Delphi Class Engineering" written by David Baer. I'm slowly working my way through these articles.

Issue: 57 Effective Delphi Class Engineering 1:
Crossing The Chasm


David Baer kicks off a new series of articles aimed at all of us who are reluctant, confused or ill-informed on what object-oriented development is all about. The goal is to demonstrate, clearly and without jargon-loaded obfuscation, how to design, create and use Delphi classes to make your development more productive.
Issue: 59 Effective Delphi Class Engineering 2:
Welcome To The Machine


David Baer continues his series on practical object orientation by putting Delphi’s object machinery under a magnifying glass. He examines topics such as memory management, method calling, protocols and other compiler- related issues.
Issue: 60 Effective Delphi Class Engineering 3:
Skyrocketing Property


David Baer thinks properties are wonderful and this month gives us insights and advice on how they can best be put to use in our classes.
Issue: 62 Effective Delphi Class Engineering Part 4:
The TObject Of My


David Baer focuses on inheritance in this part of his popular series on object oriented development in Delphi.
Issue: 63 Effective Delphi Class Engineering Part 5:
You Are TEgg Man... I AM TWalrus


David Baer has not gone mad (though he may have been listening to too many old Beatles albums!): this instalment of his series continues his practical real-world discussion of polymorphism and inheritance.
Issue: 65 Effective Delphi Class Engineering Part 6:
To Talk Of Many Things


David Baer concludes his series on developing Delphi classes with a miscellany of sound advice, ranging from events to exceptions, RTTI and message handling.



Part 1 of Baer's series of articles, refenced short paper written by Marco Cantu called "When RAD is bad", which I found it on the internet archive. 

https://web.archive.org/web/20001120081900/http://community.borland.com/devnews/article/1,1714,10463,00.html  

But that's not all I found. I found a download link to the entire "The Delphi Magazine Total Collection Issues 1 - 139 (April 1995 to March 2007)" ⏬

https://archive.org/details/the-delphi-magazine-total-collection


Enjoy,
Semper Fi
Gunny Mike
https:\\zilchworks.com

Sunday, September 1, 2024

Delphi Tip of the Day: How to Keep Your Code Folded in Delphi 12

I like the "Code Folding" feature of  Delphi. However, I noticed that every time I reopened a project in Delphi 12 where I had previously folded the code, the code was no longer folded.

To keep your code folded in Delphi 12 you need to turn on the Save project desktop when closing option inside the IDE.

Tools > Options > IDE > Saving and Recovering

This option is unchecked in the default, out-of-the-box setup.


Delphi 12 also includes a new feature called Save editor state when closing a tab any time. 
https://docwiki.embarcadero.com/RADStudio/Athens/en/Saving_and_Recovering

Save editor state when closing a tab any time When selected, the current state for the views is saved before closing it. State info includes collapsed regions, cursor/caret position, and bookmarks.

This allows you to close and reopen a tab within the same editing session, and when the tab is reopened it will display exactly as it was when it was closed. This is similar to the Save project desktop when closing setting but functions all the time, not just when closing and reopening a whole project.

This option can only be enabled when Save project desktop when closing is checked.

Let me know in the comments what other out-of-the-box tweaks you like to make to a brand new Delphi install.

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


Saturday, July 13, 2024

Delphi Tip of the Day: Always Use the MenuBar for FMX Desktop Applications

A couple months ago, I watch the video replay "The fundamental secrets of good UI design" done by Ian Barker. Around the 33:15 mark, Barker talks about supporting "dark mode", have a listen:

Transcript:

"One of the things you really should do at a very bare minimum if you do nothing else please support dark mode. And this is kind of a personal beg from me. As I said before I do get these floaters in my eyes, I can see perfectly well you know, I'm not blind or anything like that. I'm shortsighted which is why I have glasses but if you support dark mode you will make my life a lot easier. And other people that have visual  issues as well some people get migraines and things like that dark mode helps."

https://www.youtube.com/live/TL2YVio_eTo?si=GUzsPoZriiIdyfbj&t=1995

I never considered supporting dark mode

Until I watched this video, I never considered supporting dark mode in the current rewrite of my Zilch software. So I began looking into how to incorporate FMX styles. It was confusing at first. Then I got the hang of it. I decided to go with the "Air.Style" that comes with Delphi.

David Cornenelius' book "Fearless Cross-Platform Development with Delphi" and Andrea Magni's book "Delphi GUI Programming with Delphi" were big helps understanding FMX styles.

There were a couple of tweaks I had to make. The Air.Style is a vector style which means it does not use the bitmap designer. It is similar to how Cascading Style Sheets are used in web development. The graphic elements are drawn using SVG paths. 

FMX Main Menu component can't be styled 

The biggest surprise was the TMainMenu component. It turns out the FMX Main Menu component can't be styled. The Embarcadero FMX Style Viewer was showing a Main Menu that was styled how come my Main Menu wasn't styled?

fmx-style-viewer-air
FMX Style Viewer - Air.Style

I didn't want my application to have some stuff styled and some stuff not styled. Then I discovered FMX includes a MenuBar component which does take styling. And that is what is used by the FMX Style Viewer. So, I slowly and methodically swapped out the MainMenu component for the MenuBar component.

Always use the MenuBar for FMX desktop applications


FMX MainMenu vs MenuBar

My recommendation is to skip using the MainMenu component when developing FMX desktop applications and ALWAYS use the MenuBar component.

You will be happy. Your customers will be happy.

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




Friday, January 5, 2024

Delphi Tip of the Day: Prevent SQLite Date Headaches by using a GetDateAs_YYYYMMDD Function

Working with Date data can be very tricky. I recently encountered an "Invalid argument to date encode", error while trying to update a SQLite database table.


This placed a value of 0000-00-00 into the date field of my SQLite table.

Here is the original code which caused the error.

function TForm1.GetOneOffDateAsDate: TDate;
begin
  Result := DateEdit1.Date;
end;

procedure TForm1.SQLInsertPayment;
begin
  qryO.SQL.Clear;

  qryO.SQL.Add( ' INSERT INTO OneOffPayments    ');
  qryO.SQL.Add( '             (                 ');
  qryO.SQL.Add( '             OneOffDate,       ');
  qryO.SQL.Add( '             OneOffPayment     ');
  qryO.SQL.Add( '             )                 ');
  qryO.SQL.Add( '      VALUES (                 ');
  qryO.SQL.Add( '             :ood,             ');
  qryO.SQL.Add( '             :oop              ');
  qryO.SQL.Add( '             );                ');

  qryO.ParamByName( 'ood' ).Value := GetOneOffDateAsDate;
  qryO.ParamByName( 'oop' ).Value := GetOneOffAmount;

  qryO.ExecSQL;
end;

The getter function GetOneOffDateAsDate passes in a TDate which doesn't play nicely with FireDAC. Fortunately, the fix is quite simple. I found a fantastic explanation for this error on stackoverflow which states FireDAC expects DATE data type values to be a string in the fixed format of YYYY-MM-DD.

FireDAC Expects DATE data types
to be strings formatted as YYYY-MM-DD

So I created another getter function to format the date data as a YYYY-MM-DD string.
Problem solved!

Updated code passing FireDAC a YYYY-MM-DD string

function TForm1.GetOneOffDateAs_YYYYMMDD: String;
begin
  Result := FormatDateTime('YYYY-MM-DD', DateEdit1.Date);
end;

procedure TForm1.SQLInsertPayment;
begin
  qryO.SQL.Clear;

  qryO.SQL.Add( ' INSERT INTO OneOffPayments    ');
  qryO.SQL.Add( '             (                 ');
  qryO.SQL.Add( '             OneOffDate,       ');
  qryO.SQL.Add( '             OneOffPayment     ');
  qryO.SQL.Add( '             )                 ');
  qryO.SQL.Add( '      VALUES (                 ');
  qryO.SQL.Add( '             :ood,             ');
  qryO.SQL.Add( '             :oop              ');
  qryO.SQL.Add( '             );                ');

  qryO.ParamByName( 'ood' ).Value := GetOneOffDateAs_YYYYMMDD;
  qryO.ParamByName( 'oop' ).Value := GetOneOffAmount;

  qryO.ExecSQL;
end;

Happy coding!


Enjoy!
Gunny Mike
https://zilchworks.com