I'm porting over one of my Delphi 5 VCL, desktop applications to FMX. The target audience are Windows and macOS users. I'm not focused on mobile at this juncture. I'm spending quite a bit of time on the User Experience (UX). I guess you would call this approach "Desktop UX First".
I want to give the user the option of showing or hiding panels. I've decided to place this functionality in two places:
- On the main menu as an option.
- On the bottom tool bar as a button.
The first thing that came to mind was testing the "IsChecked" state of the main menu option. I slept on it and came back to the drawing board the next day. Instead of thinking about trapping clicks, I thought about what the intent of the click really was. And the answer is to show or hide the panel.
If the user clicks either the main menu option or the toolbar button I want the panel to show or hide. Both of these options need to work together behind the scenes. The intent of either click focuses on the "visibility" of the panel. And wouldn't you know, TPanel has a Visible property.
Visible is a boolean value, meaning it has only two states. True/False. And in Delphi there is a very cleaver way to toggle the state of a boolean value. This can be a little tricky to wrap your had around at first. However, once you understand it, you'll love it.
Boolean Value becomes not Boolean Value;
Boolean Value (True) becomes not Boolean Value (True);
Boolean Value (False) becomes not Boolean Value (False);
Boolean Value := not Boolean Value;
Panel.Visibile becomes not Panel.Visibile;
Panel.Visibile (True) becomes not Panel.Visibile (True);
Panel.Visibile (False) becomes not Panel.Visibile (False);
Panel.Visibile := not Panel.Visibile;
The statement Panel.Visibile := not Panel.Visibile;
toggles the value, back and forth between True and False.
Let's see how to put this to use in the real world. In Delphi create a new FMX application.
Click File > New > Multi-Device Application - Delphi and choose Blank Application.
Add the following components:
TMainMenu
TPanel x2
TToolbar
TButton
TSplitter
TStatusBar
Structure the components so they are parented like this:
Your form should look similar to this:
The goal is to toggle the Left Panel visibility. When you first run the application the form opens with the default settings. We want both the MenuItem (Show Left Panel) and the ToolBar Button to work together.
Hiding the Left Panel the form changes accordingly.
Regardless of which method was used to Show/Hide the left panel both items stay in synch by calling on procedure ToggleLeftPanelOnOff.
I'm testing the Sender to make sure it was invoked by either a TMenuItem or a TButton control before I toggle the panel visibility. Although it's not displayed here this allows for calling ToggleLeftPanelOnOff from inside the form's OnShow method in essence setting the correct values without toggling the panels visibility.
Here is the program code:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
FMX.Controls.Presentation, FMX.Menus;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
StatusBar1: TStatusBar;
pnlLeft: TPanel;
pnlMain: TPanel;
splLeft: TSplitter;
tbarMain: TToolBar;
btnTBarLeft: TButton;
mnuFile: TMenuItem;
menuOptions: TMenuItem;
mnuShowLeftPanel: TMenuItem;
mnuClose: TMenuItem;
procedure mnuCloseClick(Sender: TObject);
procedure mnuShowLeftPanelClick(Sender: TObject);
procedure btnTBarLeftClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure ToggleLeftPanelOnOff(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.btnTBarLeftClick(Sender: TObject);
begin
ToggleLeftPanelOnOff(Sender);
end;
procedure TForm1.mnuCloseClick(Sender: TObject);
begin
Close;
end;
procedure TForm1.mnuShowLeftPanelClick(Sender: TObject);
begin
ToggleLeftPanelOnOff(Sender);
end;
procedure TForm1.ToggleLeftPanelOnOff(Sender: TObject);
begin
// ==================================================================
// Only toggle visibility if invoked by a menuitem or button click.
// ==================================================================
if (Sender is TMenuItem) or (Sender is TButton) then
pnlLeft.Visible := not pnlLeft.visible;
// ==================================================================
// Set menuitem and button properties
// ==================================================================
if pnlLeft.Visible then
begin
mnuShowLeftPanel.IsChecked := True;
btnTBarLeft.StyleLookup := 'arrowlefttoolbutton';
end
else
begin
mnuShowLeftPanel.IsChecked := False;
btnTBarLeft.StyleLookup := 'arrowrighttoolbutton';
end;
end;
end.
Here is the text version of the Form:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Toggle Demo'
ClientHeight = 480
ClientWidth = 640
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object StatusBar1: TStatusBar
Position.Y = 458.000000000000000000
ShowSizeGrip = True
Size.Width = 640.000000000000000000
Size.Height = 22.000000000000000000
Size.PlatformDefault = False
TabOrder = 1
end
object pnlLeft: TPanel
Align = Left
Size.Width = 161.000000000000000000
Size.Height = 458.000000000000000000
Size.PlatformDefault = False
TabOrder = 2
end
object pnlMain: TPanel
Align = Client
Size.Width = 475.000000000000000000
Size.Height = 458.000000000000000000
Size.PlatformDefault = False
TabOrder = 3
object tbarMain: TToolBar
Align = Bottom
Position.Y = 418.000000000000000000
Size.Width = 475.000000000000000000
Size.Height = 40.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
object btnTBarLeft: TButton
Align = Left
Size.Width = 40.000000000000000000
Size.Height = 40.000000000000000000
Size.PlatformDefault = False
StyleLookup = 'arrowlefttoolbutton'
TabOrder = 0
Text = 'btnTBarLeft'
OnClick = btnTBarLeftClick
end
end
end
object splLeft: TSplitter
Align = Left
Cursor = crHSplit
MinSize = 20.000000000000000000
Position.X = 161.000000000000000000
Size.Width = 4.000000000000000000
Size.Height = 458.000000000000000000
Size.PlatformDefault = False
end
object MainMenu1: TMainMenu
Left = 304
Top = 224
object mnuFile: TMenuItem
Text = 'File'
object mnuClose: TMenuItem
Locked = True
Text = 'Close'
OnClick = mnuCloseClick
end
end
object menuOptions: TMenuItem
Text = 'Options'
object mnuShowLeftPanel: TMenuItem
Locked = True
IsChecked = True
Text = 'Show Left Panel'
OnClick = mnuShowLeftPanelClick
end
end
end
end
Enjoy,
Gunny Mike