Delphi XE2 and LiveBindings between controls - delphi

Is it possible to do LiveBinding between controls, i.e. take 2 edit boxes and get the result of adding their contents together into a label. I'm sure it is, I just don't know where to start
Thanks

Have a look at the samples. SVN repository URL: https://radstudiodemos.svn.sourceforge.net/svnroot/radstudiodemos/branches/RadStudio_XE2/LiveBindings
An example:
----- Unit1.dfm -----
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 286
ClientWidth = 426
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 8
Top = 62
Width = 48
Height = 13
Caption = 'Edit1Edit2'
end
object Edit1: TEdit
Left = 8
Top = 8
Width = 121
Height = 21
TabOrder = 0
Text = 'Edit1'
OnChange = EditChange
end
object Edit2: TEdit
Left = 8
Top = 35
Width = 121
Height = 21
TabOrder = 1
Text = 'Edit2'
OnChange = EditChange
end
object BindingsList1: TBindingsList
Methods = <>
OutputConverters = <>
UseAppManager = True
Left = 20
Top = 5
object BindExpressionLabel11: TBindExpression
Category = 'Binding Expressions'
ControlComponent = Label1
SourceComponent = BindScope1
SourceExpression = 'Edit1.Text + Edit2.Text'
ControlExpression = 'Caption'
NotifyOutputs = False
Direction = dirSourceToControl
end
end
object BindScope1: TBindScope
Left = 192
Top = 16
end
end
----- Unit1.pas -----
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.Bind.EngExt, Vcl.Bind.DBEngExt,
System.Rtti, System.Bindings.Outputs, Vcl.Bind.Editors, Data.Bind.Components,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
BindingsList1: TBindingsList;
BindExpressionLabel11: TBindExpression;
BindScope1: TBindScope;
procedure EditChange(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
System.Bindings.Helper;
procedure TForm1.EditChange(Sender: TObject);
begin
TBindings.Notify(Sender, 'Text');
end;
end.
How to use the IDE designer to produce the result:
put two edits (Edit1, Edit2), a label (Label1) and a TBindScope (BindScope1) on your form (Form1).
create an event handler for both edits' OnChange event (EditChange).
select Label1, expand the drop-down of LiveBindings property, select 'New Live Binding...', select TBindExpression
edit properties of the newly created BindExpressionLabel11: assign Caption to ControlExpression, BindScope1 to SourceComponent, Edit1.Text + Edit2.Text to SourceExpression

The sample project at the (Default) location of:
C:\Users\Public\Documents\RAD Studio\9.0\Samples\Delphi\LiveBinding\Components\bindexpression\fmx\BindExpressionSampleProject.dproj
does precisely that.

You don't need to TBindScope to bind components together. Say you have edit1 and edit2 on the form. If you set edit2 BindingSource to edit1 it will be link to changes to edit1

Related

How to add multiple-column Items to TListBox?

In a 32-bit VCL Application in Windows 10 in Delphi 11.1 Alexandria, I am trying to add multiple-column Items to TListBox. The CHM Libraries Reference for VCL in the Vcl.StdCtrls.TCustomListBox.Items topic has the following tip:
So I created the following VCL Application test project:
DPR:
program TListBoxMultiColumn;
uses
Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
PAS:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add('First Column'^I'Second Column');
ListBox1.Items.Add('1'^I'2');
ListBox1.Items.Add('4'^I'5');
end;
end.
DFM:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'TListBox MultiColumn Test'
ClientHeight = 191
ClientWidth = 368
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -15
Font.Name = 'Segoe UI'
Font.Style = []
Position = poScreenCenter
PixelsPerInch = 120
TextHeight = 20
object ListBox1: TListBox
Left = 0
Top = 0
Width = 241
Height = 191
Margins.Left = 4
Margins.Top = 4
Margins.Right = 4
Margins.Bottom = 4
Align = alLeft
Columns = 2
ItemHeight = 20
TabOrder = 0
ExplicitHeight = 413
end
object Button1: TButton
Left = 260
Top = 20
Width = 94
Height = 31
Margins.Left = 4
Margins.Top = 4
Margins.Right = 4
Margins.Bottom = 4
Caption = 'Button1'
TabOrder = 1
OnClick = Button1Click
end
end
However, the result is not what is promised in the documentation:
So how can I add multiple-column Items to a TListBox?
You must set the TabWidth property to a suitable, large enough value:
ListBox1.TabWidth := 100;
ListBox1.Items.Add('First Column'^I'Second Column');
ListBox1.Items.Add('1'^I'2');
ListBox1.Items.Add('4'^I'5');
Bonus information: You may wonder why ^I is used here. Well, since I is the 9th letter in the English alphabet, ^I is equal to #9, that is, the tabulator character.
I would write this
ListBox1.TabWidth := 100;
ListBox1.Items.Add('First Column'#9'Second Column');
ListBox1.Items.Add('1'#9'2');
ListBox1.Items.Add('4'#9'5');
Actually, the current version of the documentation states
Tip: If you have a list box with tab stops enabled (TabStop property) and you want to add data to specific columns, you can set the TabWidth property to obtain a list box in which individual lines can be displayed in columns, as long as they use tabs in their text, as shown in the snippet below (notice #9 is the tab character).
This is a better description, since it mentions the TabWidth property, uses #9 instead of ^I, and doesn't misuse the word "parameter". However, its reference to TabStop is utterly nonsense. The TabStop property is about the form's tab order.

VCL style theme cutting form borders when maximized

Delphi version: 10.1 update 2 (Berlin)
When applying a vcl theme to an application. When maximizing the form, it removes the borders causing border-aligned objects like: labels, menus, buttons to have a "cut" part.
In the example in question, the theme has a 6-pixel border (left, right, bottom).
You may also notice that the title bar appears with the top "cut off".
Is there any way to get around this situation, and make sure that the measures of borders and title bar are respected as specified in the theme?
Normal Window
Maximized Window
Unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.StdCtrls, Vcl.Menus;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
este1: TMenuItem;
este2: TMenuItem;
este3: TMenuItem;
este4: TMenuItem;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
end.
Unit1.dfm
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 441
ClientWidth = 704
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Menu = MainMenu1
OldCreateOrder = False
Position = poScreenCenter
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 0
Top = 0
Width = 704
Height = 13
Align = alTop
Caption = 'Novo Teste'
end
object Label2: TLabel
Left = 0
Top = 428
Width = 704
Height = 13
Align = alBottom
Caption = 'Novo Teste'
end
object Label3: TLabel
Left = 0
Top = 13
Width = 704
Height = 13
Align = alTop
Alignment = taRightJustify
Caption = 'Novo Teste'
end
object Label4: TLabel
Left = 0
Top = 415
Width = 704
Height = 13
Align = alBottom
Alignment = taRightJustify
Caption = 'Novo Teste'
end
object MainMenu1: TMainMenu
Left = 384
Top = 152
object este1: TMenuItem
Caption = 'Teste'
object este2: TMenuItem
Caption = 'Teste'
end
object este3: TMenuItem
Caption = 'Teste'
end
object este4: TMenuItem
Caption = 'Teste'
end
end
end
end

How to correctly use TGridPanel when display PPI scaling is active?

I have written a small test VCL application with a monitor PPI of 96.
The application has a TGridPanel on it with a absolute pixel sized column.
On that column I placed a TComboBox and aligned it alClient.
Here is the DFM code:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 182
ClientWidth = 514
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object GridPanel1: TGridPanel
Left = 0
Top = 0
Width = 514
Height = 182
Align = alClient
Caption = 'GridPanel1'
ColumnCollection = <
item
Value = 100.000000000000000000
end
item
SizeStyle = ssAbsolute
Value = 150.000000000000000000
end>
ControlCollection = <
item
Column = 0
Control = Button1
Row = 0
end
item
Column = 1
Control = ComboBox1
Row = 0
end
item
Column = 0
Control = Edit1
Row = 1
end>
RowCollection = <
item
Value = 50.000000000000000000
end
item
Value = 50.000000000000000000
end>
TabOrder = 0
object Button1: TButton
Left = 1
Top = 1
Width = 362
Height = 21
Align = alTop
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ComboBox1: TComboBox
Left = 363
Top = 1
Width = 150
Height = 21
Align = alClient
TabOrder = 1
Text = 'ComboBox1'
end
object Edit1: TEdit
Left = 1
Top = 91
Width = 362
Height = 21
Align = alTop
TabOrder = 2
Text = 'Edit1'
end
end
end
and the PAS code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;
type
TForm1 = class(TForm)
GridPanel1: TGridPanel;
Button1: TButton;
ComboBox1: TComboBox;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
PPI: Integer;
begin
PPI := Integer.Parse(Edit1.Text);
GridPanel1.ScaleForPPI(PPI);
end;
procedure TForm1.FormShow(Sender: TObject);
begin
Edit1.Text := Screen.PixelsPerInch.ToString;
end;
end.
I then changed the custom scaling factor to 125 in Windows 10 in the advanced scaling settings.
After signing off and signing on again when I run the application again the drop down button of the combo box is not visible any more.
How do you deal with this problem?
I tried to call GridPanel1.ScaleForPPI(96) which restores the drop down button on the combo box. This kind of defeats the purpose of PPI scaling though, doesn't it?
The problem is gone in Delphi 10.3.1.
So this is a bug in at least Delphi 10.1 (and possible other older versions).

Delphi FMX - How to stop a TStringGrid from scrolling both horizontally and vertically

I have a TStringGrid, however if I click and drag on it, it can be panned vertically and horizontally, I don't want the user to be able to do this, how can I stop this from happening?
You can use the OnTopLeftChanged event to catch whenever any sort of "scrolling" has occurred, and decide how to proceed. If you don't want user to go out of range in certain circumstances, you can reset the range as needed. Here's a rough example...
uStringGridTestMain.dfm:
object frmStringGridTestMain: TfrmStringGridTestMain
Left = 0
Top = 0
Caption = 'String Grid Test'
ClientHeight = 416
ClientWidth = 738
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object StringGrid1: TStringGrid
Left = 72
Top = 32
Width = 513
Height = 329
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine]
TabOrder = 0
OnTopLeftChanged = StringGrid1TopLeftChanged
ColWidths = (
64
64
64
64
64)
RowHeights = (
24
24
24
24
24)
end
end
uStringGridTestMain.pas:
unit uStringGridTestMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids;
type
TfrmStringGridTestMain = class(TForm)
StringGrid1: TStringGrid;
procedure StringGrid1TopLeftChanged(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmStringGridTestMain: TfrmStringGridTestMain;
implementation
{$R *.dfm}
procedure TfrmStringGridTestMain.FormCreate(Sender: TObject);
begin
StringGrid1.Align:= alClient;
//Let's put a big scroll in both directions...
StringGrid1.RowCount:= 50;
StringGrid1.ColCount:= 50;
end;
procedure TfrmStringGridTestMain.StringGrid1TopLeftChanged(Sender: TObject);
begin
//You can change the "current" cell...
StringGrid1.Row:= 1;
StringGrid1.Col:= 1;
//Or you can change the scrolled cell on top-left...
StringGrid1.TopRow:= 1;
StringGrid1.LeftCol:= 1;
end;
end.
To prevent panning on drag you can set the TouchTracking property of TStringGrid to TBehaviorBoolean.False

RichEdit control stop drawing text when it became a parent for other control

RichEdit control stop drawing text when it became a parent for other control.
Is this a feature or a bug?
Is it possible to make RichEdit to be a parent for other control?
Check out next app:
-- Form1.dfm ---
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 282
ClientWidth = 418
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 24
Top = 8
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object RichEdit1: TRichEdit
Left = 16
Top = 72
Width = 145
Height = 105
Font.Charset = RUSSIAN_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Lines.Strings = (
'RichEdit1')
ParentFont = False
TabOrder = 1
end
end
-- Form1.dfm ---
--- Unit1.pas ---
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls;
type
TForm3 = class(TForm)
Button1: TButton;
RichEdit1: TRichEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject);
begin
Button1.Parent := RichEdit1;
RichEdit1.Invalidate;
end;
end.
--- Unit1.pas ---
Test under Delphi XE5 + Win 7.
I want to create RichEdit with Edit button like this
This is the result that I want to get - RichEdit with DropDown Editor:
Use an interposer class that handles the WM_PAINT message like so:
type
TRichEdit = class(Vcl.ComCtrls.TRichEdit)
protected
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
end;
procedure TRichEdit.WMPaint(var Message: TWMPaint);
begin
DefaultHandler(Message);
end;
For reasons lost in the mists of time, TCustomRichEdit does some special handling of WM_PAINT that was only actually needed for the original version of the rich edit DLL. Moreover, this special handling breaks normal painting when another control is parented to the rich edit. As such, fixing the issue requires re-establishing standard VCL/Windows paint handling, which is what the code above does.
That said, I doubt nesting a button inside a rich edit is really what you want - the text won't wrap around it, for example.

Resources