How to fix RichEdit redraw bug in dialogs - delphi

I faced a redrawing bug that is not very pleasant to see (Delphi 5, Windows 7 64 bit, Classic theme)
If one creates resizable dialog with client-aligned RichEdit in it and provide the function
procedure TQueryDlg.ShowDialog(const Txt: string);
begin
RichEdit.Text:=Txt;
ShowModal;
end;
then at least on Windows 7 when resizing the dialog, the lines are not re-wrapped, but rather the pixels from the chars keeps filling the space and it looks like the whole area is never invalidated. The richedit starts working correctly when the control is activated with the mouse.
I suppose it has something to do with message queue of forms and dialogs in Delphi, but probably is specific to RichEdits of particular version. My
System32/Richedit32.dll - v6.1.7601.17514
System32/RichEdit20.dll - v3.1, 5.31.23.1230
Probably some workaround information would be great.

I had a similar problem with the TRichEdit control. I found it wouldn't paint itself unless it was visible (which wasn't always the case in my app). And I found times that it rendered incorrectly until the user set focus to it. Both very irritating.
What worked for me was to create my own class and add a Render() method to it. This way I could tell it to paint whenever I wanted (e.g., when resizing a form, or when the component wasn't visible).
Here is a very stripped down version of what I did:
interface
uses
Winapi.Messages, Vcl.ComCtrls;
type
TMyRichEdit = class(TRichEdit)
private
procedure WMPaint(var Message: TMessage); message WM_PAINT;
public
procedure DoExit; override;
procedure DoEnter; override;
procedure Render;
end;
var
PaintMsg: TMessage;
implementation
procedure TMyRichEdit.DoEnter;
begin
inherited;
WMPaint(PaintMsg);
end;
procedure TMyRichEdit.DoExit;
begin
inherited;
WMPaint(PaintMsg);
end;
procedure TMyRichEdit.Render;
begin
WMPaint(PaintMsg);
end;
procedure TMyRichEdit.WMPaint(var Message: TMessage);
begin
// eliminated custom code to tweak the text content...
inherited;
end;
initialization
PaintMsg.Msg := WM_PAINT;
PaintMsg.WParam := 0;
PaintMsg.LParam := 0;
PaintMsg.Result := 0;
end.
I added WMPaint() because I needed to tweak how the text content before it was rendered. But none of that code is needed for what you are doing. So, instead of declaring WMPaint() and handling the WM_PAINT message, you could probably just post the PaintMsg from the DoExit(), DoEnter() and Render() methods. Sorry I don't have time to compile the code or try eliminating WMPaint() and using PostMessage()...

Related

The helper method added to TScrollBox does not work

In one old project, which I was instructed to develop, there is a field of type TScrollBox.
FScroll : TScrollBox;
To be able to handle the events of navigation buttons, the class must contain a WM_GETDLGCODE message handler. So I created a new class:
TScrollBoxArrowBtn = class(TScrollBox)
protected
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
end;
Implementation
procedure TScrollBoxArrowBtn.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
Message.Result := DLGC_WANTARROWS;
end;
And replaced the TScrollBox type with TScrollBoxArrowBtn.
FScroll : TScrollBoxArrowBtn;
The component began to respond to pressing the arrow button. But the copy, delete, SelectAll methods stopped working. This happened because the previous developer added to the verification methods like this:
"VariableName".ClassType = TScrollBox
I replaced them for verification:
"VariableName" is TScrollBox
After this methods of editing began to work. But I'm not sure that such a test will not be applied elsewhere in the project. So I decided to leave
FScroll : TScrollBox;
And made TScrollBoxArrowBtn an helper class:
TScrollBoxArrowBtn = class helper for TScrollBox
protected
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
end;
Unfortunately this method does not work. Verifications like "VariableName".ClassType = TScrollBox began to work perfectly, but project stopped responding to events arrow button. What did I do wrong?
I'm convinced that my version of IDE supports helper methods.
I did not find the answer specifically about the message methods in the helpers classes, but I found a way to solve my problem. In addition, I learned about many other bad features of the helper class, which finally convinced me to abandon their use. So my answer is - do not use the class helpers. At this time this is a very unstable tool. Perhaps in the future it will be improved.
   Now about my decision. As I feared, the problem of checking the type of the following kind:
"VariableName".ClassType = TScrollBox
again appeared when merging the previously created branches. So I decided to replace the TScrollBox window procedure. I added field in the TScrollBox-field container class and I added a new window procedure for TScrollBox-field in the container class:
TCADParamsGroupBlockBaseScheme = class (TCADGroupBlockParams)
.....................................................
protected
Old_FScroll_WindowProc : TWndMethod;
procedure New_FScroll_WindowProc(var Message: TMessage);
.....................................................
end;
implementation
procedure TCADParamsGroupBlockBaseScheme.New_FScroll_WindowProc(var Message:
TMessage);
begin
//Для обработки событий нажатий Key_Up/Down/Left/Right в DoKeyDown
if Message.Msg = WM_GETDLGCODE then
Message.Result := DLGC_WANTARROWS
else Old_FScroll_WindowProc(Message);
end;
And in the constructor of the container class, I saved the pointer to the old TScrollBox-field window procedure and assigned it a new window procedure:
constructor TCADParamsGroupBlockBaseScheme.Create(const AOwner: TWinControl);
begin
...........................................
FScroll := TScrollBox.Create(FHost.Owner);
Old_FScroll_WindowProc := FScroll.WindowProc;
FScroll.WindowProc := New_FScroll_WindowProc;
............................................
end;

Where to free dynamically allocated TFrame's components' objects?

I have a form containing a TFrame. The TFrame contains a ComboBox that is dynamically populated. Each ComboBox entry has an associated object. By the time the overridden destructor for the TFrame is called, the Items in the ComboBox have already been cleared without freeing their associated objects. This happens whether I drop the ComboBox on the form in designer view, or dynamically create it in code with either nil or the TFrame as its owner. I currently use the OnDestroy event of the containing TForm to call a clean-up procedure of the contained TFrame.
Is there a better way that would not need an explicit procedure call by the TFrame's container? Where ideally should the objects added dynamically to the ComboBox be freed?
You say that when the destructor for the TFrame is called, the Items of the ComboBox have already been cleared. That's not the case, ComboBox items are never cleared. When Items is destroyed by the ComboBox, they've got a count of only 0.
When you exit your application and the VCL destroys the form containing the frame and the ComboBox, the native ComboBox control is also destroyed by the OS since it is placed in a window being destroyed. When you later access the items to be able to free your objects in the frame destructor, the VCL have to recreate a native ComboBox control, having an item count of 0.
The solution I'd propose is easy. Don't leave freeing your frame to the framework, instead, destroy your frame in the OnDestroy event of your form. That would be before the underlying window of the form is destroyed, hence you'll be able to access your objects.
form unit
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyFrame.Free;
end;
frame unit
destructor TMyFrame.Destroy;
var
i: Integer;
begin
for i := 0 to ComboBox1.Items.Count - 1 do
ComboBox1.Items.Objects[i].Free;
inherited;
end;
You could utilize the TFrame's WM_DESTROY handler like this:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Forms, StdCtrls;
type
TFrame1 = class(TFrame)
ComboBox1: TComboBox;
private
procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
procedure FreeComboBoxItems;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.dfm}
constructor TFrame1.Create(AOwner: TComponent);
begin
inherited;
// Add some object items to the ComboBox
ComboBox1.AddItem('a', TButton.Create(nil));
ComboBox1.AddItem('b', TMemoryStream.Create);
ComboBox1.AddItem('c', TList.Create);
end;
procedure TFrame1.WMDestroy(var Msg: TWMDestroy);
begin
// Make sure the TFrame is actually destroying - not recreated
if (csDestroying in ComponentState) then
FreeComboBoxItems;
inherited;
end;
procedure TFrame1.FreeComboBoxItems;
var
I: Integer;
begin
OutputDebugString('TFrame1.FreeComboBoxItems');
with Self.ComboBox1 do
for I := 0 to Items.Count - 1 do
begin
OutputDebugString(PChar(Items.Objects[I].ClassName + '.Free'));
Items.Objects[I].Free;
end;
end;
end.
Another option is to create a Base ancestor TAppBaseForm class and a TAppBaseFrame for the entire application, and derive all your Forms as TAppBaseForm and all Frames as TAppBaseFrame.
This way the TAppBaseForm could notify all it's child TAppBaseFrame that the owner Form is destroyed on TAppBaseForm.FormDestroy event handler. At that point the ComboBox items are still valid (as described by Sertac Akyuz's answer).
Your question isn't really usefull, because - generally speaking - it is discouraged to store data (or objects in your case) in a GUI control. See also David's comment on how to change your design.
What makes the question kind of interresting to answer though is the difference between the combo box being a child of a form directly and being a child of another child of the form (your frame in this case). Apparently, the combo box items are destroyed before the destructor of that frame is called. Obvious alternatives to explore are then: overriding Frame.BeforeDestruction, overriding Frame.DestroyWindowHandle, overriding Frame.DestroyWnd, or catching WM_DESTROY in an overridden Frame.WndProc, but none of them is called before the items are already gone.
The next thing to try is to repeat this for the combo box. It turns out that when WM_DESTROY arrives at the combo box that the items are still there. However, beware of catching that message ónly when the control really is being destroyed, because the VCL might recreate a combo box frequently. Implement it using an interposing class for TComboBox, as follows:
unit Unit2;
interface
uses
Windows, Messages, Classes, Controls, Forms, StdCtrls;
type
TComboBox = class(StdCtrls.TComboBox)
protected
procedure WndProc(var Message: TMessage); override;
end;
TFrame1 = class(TFrame)
ComboBox1: TComboBox;
end;
implementation
{$R *.dfm}
{ TComboBox }
procedure TComboBox.WndProc(var Message: TMessage);
var
I: Integer;
begin
if (Message.Msg = WM_DESTROY) and (csDestroying in ComponentState) then
for I := 0 to Items.Count - 1 do
Items.Objects[I].Free;
inherited WndProc(Message);
end;
end.
Now, to answer your question: "Is this a better way?"
Yes it is, because it offers assurance of the object's destruction at the frame's level. In other words: you don't have to remember to deal with this for every instance seperately.
And no it is not, because this solution requires that the objects in the combo box are allowed to be freed in whatever circumstance which restricts usage to an unnecessary extra boundary.
So, is this answer usefull? Well, if it prevents you from using your current approach, then it is.
Besides, I also found another alternative by setting the frame's Parent property to nil in the containing form OnDestroy handler:
procedure TForm2.FormDestroy(Sender: TObject);
begin
Frame1.Parent := nil;
end;
In this case, you can safely destroy the objects stored in the combo box within the frame's destructor. But this solution is even worse than your current one, because it is not descriptive. Then Frame1.FreeComboObjects is much better.
freeing Combobox.Items.Objects in destructor is too late.
so, according to previous answers it is better and safe to do that this way:
procedure TMyFrame.ClearCBObjects;
var
i: Integer;
begin
for i := 0 to ComboBox1.Items.Count - 1 do
ComboBox1.Items.Objects[i].Free;
end;
destructor TMyFrame.Destroy;
begin
//Free none Component objects
inherited;
end;
destructor TMyForm.Destroy;
begin
MyFrame.ClearCBObjects;
inherited;
end;

How to override loading a TImage from the object inspector (at run-time)?

Aplogies for top posting. This has buggged me for years and now I really need to know the answer. I put 150 points bounty to attract interest, but could increase for the right answer.
Here is what I need:
I use the TMS obejct inpsctor from TMS Scripter Pro to allow users to design a form at run-time. You can assume that it derives from the standard Delphi Object Inspector and adds a little functionality but 90% of it just calls inherited methods.
When I click the ellipsis next to the Picture property of a TImage it calls an inherited method - I don't know which - to allow me to load a picture. When I have done so, I do not know which file the image was loaded from and I want to save it with the same name in a different directory.
I could prompt the user for a file name, but that looks confusing to him and is just plain sloppy.
I could find a TImage / TPicture descendant which stores the file name and allows me to query it. Anyone who can point out such a FOSS component gets the bounty.
I could derive from TPicture and or TImage and code it myself, but am not certain what to change. Anyone who can tell me exactly how to code it gets the the bounty. By exactly, I mean naming classes and methods.
Thanks in advance for any help. This one really annoys me.
Further to my previous question, which did not get a useful answer despite a bounty, I will try rephrasing the question.
Basically, when the user clicks the ellipsis in the object inspector, Delphi opens a file/open dialog. I want to replace this handling with my own, so that I can save the image's path.
I would have expected that all I need to do is to derive a class from TImage and override the Assign() function, as in the following code. However, when I do the assign function is never called. So, it looks like I need to override something else, but what?
unit my_Image;
interface
uses
Classes, ExtCtrls, Jpeg, Graphics;
type
Tmy_Image = class(Timage)
private
FPicture : TPicture;
protected
procedure OnChange(Sender: TObject);
public { Public declarations }
Constructor Create(AOwner: TComponent); override;
procedure SetPicture(picture : TPicture);
procedure Assign(Source: TPersistent); override;
published { Published declarations - available in the Object Inspector at design-time }
property Picture : TPicture read FPicture write SetPicture;
end; // of class Tmy_Image()
procedure Register;
implementation
uses Controls, Dialogs;
procedure Register;
begin
RegisterComponents('Standard', [Tmy_Image]);
end;
Constructor Tmy_Image.Create(AOwner: TComponent);
begin
inherited; // Call the parent Create method
Hint := 'Add an image from a file|Add an image from a file'; // Tooltip | status bar text
AutoSize := True; // Control resizes when contents change (new image is loaded)
Height := 104;
Width := 104;
FPicture := TPicture.Create();
self.Picture.Bitmap.LoadFromResourceName(hInstance, 'picture_poperty_bmp');
end;
procedure Tmy_Image.OnChange(Sender: TObject);
begin
Constraints.MaxHeight := Picture.Height;
Constraints.MaxWidth := Picture.Width;
Self.Height := Picture.Height;
Self.Width := Picture.Width;
end;
procedure Tmy_Image.SetPicture(picture : TPicture);
begin
MessageDlg('Tmy_Image.SetPicture', mtWarning, [mbOK], 0); // never called
end;
procedure Tmy_Image.Assign(Source: TPersistent);
begin
MessageDlg('Tmy_Image.Assign', mtWarning, [mbOK], 0); // never called
end;
end.
See if this works:
[...]
procedure Tmy_Image.PictureChange(Sender: TObject);
begin
ShowMessage('Should work');
end;
[...]
constructor Tmy_Image.Create(AOwner: TComponent);
begin
inherited; // Call the parent Create method
Hint := 'Add an image from a file|Add an image from a file'; // Tooltip | status bar text
AutoSize := True; // Control resizes when contents change (new image is loaded)
Height := 104;
Width := 104;
FPicture := TPicture.Create();
FPicture.OnChange := PictureChange; /// <<<<
self.Picture.Bitmap.LoadFromResourceName(hInstance, 'picture_poperty_bmp');
end;
[...]
God bless you!
Ok, I hacked the TMS code. It seemed to be the only way.

How can you change the font color of a theme-enabled control?

Yes, this is again this question:
How can I change the font color of a TCheckBox (or any handled control) with Delphi7->Delphi2007 on a themes enabled application?
After reading a lot on the internet and on this site, I found 4 kinds of answer:
and Most populare (even from QC): You can't, it's designed like that by Microsoft.
Create a component that let you draw it like you want.
Buy expensive component set that draws like you want.
Do not use themes.
OK, but I am still unhappy with that.
Giving a user colored feedback for the status of a property/data he has on a form, seems legitimate to me.
Then I just installed the MSVC# 2008 Express edition, and what a surprise, they can change the color of the font (property ForeColor of the check box) Then what?
It does not seem to be a "it's designed like that, by Microsoft." then now the question again:
How can I change the font color of a TCheckBox (or any handled control) with Delphi 7 through Delphi 2007 on a theme-enabled application?
This needs some tweak to be perfect solution but worked for me:
Add 2 method to your checkbox component
FOriginalCaption: string;
_MySetCap: Boolean;
procedure WMPaint(var msg: TWMPaint); message WM_PAINT;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
and implement this way:
procedure TMyCheckbox.CMTextChanged(var Message: TMessage);
begin
inherited;
if _MySetCap then Exit;
FOriginalCaption := Caption;
end;
procedure TMyCheckbox.WMPaint(var msg: TWMPaint);
var
BtnWidth: Integer;
canv: TControlCanvas;
begin
BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);
_MySetCap := True;
if not (csDesigning in ComponentState) then
Caption := '';
_MySetCap := False;
inherited;
canv := TControlCanvas.Create;
try
canv.Control := Self;
canv.Font := Font;
SetBkMode(canv.Handle, Ord(TRANSPARENT));
canv.TextOut(BtnWidth + 1, 2, FOriginalCaption);
finally
canv.Free;
end;
end;
Oh, but you can!
Just place this before the declaration of your form :
TCheckBox = class(StdCtrls.TCheckBox)
public
procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
end;
This re-declaration of TCheckBox is now used at runtime as the type streamed from your form's DFM. Now implement the message like this :
procedure TCheckBox.CNCtlColorStatic(var Message: TWMCtlColorStatic);
begin
SetTextColor(Message.ChildDC, ColorToRGB(clRed)); // or RGB(255,0,0));
SetBkMode(Message.ChildDC, TRANSPARENT);
Message.Result := GetStockObject(NULL_BRUSH);
end;
This traps the WM_CTLCOLORSTATIC message and changes the text color to red. This works in non-themed mode for me (using WinXP classic) - but not in themed mode.
You should know that in order to let themed controls send you this message, the control should supply the DTPB_USECTLCOLORSTATIC flag to the Theme-drawing API's. Sadly, that's not default behaviour, and I don't know how to do it either. Look at this question too.
Here's how I solved this in my app:
Remove the caption from the checkbox and make it smaller--just big enough to show the actual checkbox without the caption.
Put a TLabel next to the checkbox to act as the caption.
In the Label's OnClick event, toggle the state of the checkbox.
If the label has an Alt+letter keyboard accelerator, make the form handle the CM_DIALOGCHAR message. Copy the message handler from the TLabel source code and add a line to toggle the state of the checkbox.
It's not a real checkbox, and it's a bit more work than I'd like, but it works well enough in my app (which has only one checkbox that needs this treatment).
Option 5. Use the control tyou like as a base option and override all the painting messages in the control (yes you can call it a component but control is the name for visible components so you should rather use that). Simply catch the WM_PAINT, possibly the WM_NCPAINT you can draw the control in your own style. At least you can reuse the whole functionality from the control. As long as you do not change the lay-out, only the colors you won't need to change the hittests mousedowns. up moves etc etc.
Note: I have the experience with overriding TCustomEdit to allow for all kind of colors, background text, extra buttons etc. It took quite some time to get it right and read all the documents from MSDn and KB to make sure the control did what I wanted it to do.
this code is improved code from #FLICKER than support BidiMode and the correct position of the text:
interface
TMSCheckBox = class(TCheckBox)
private
FOriginalCaption: string;
_MySetCap: Boolean;
procedure WMPaint (var Message: TWMPaint); message WM_PAINT;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
end;
implementation
procedure TMSCheckBox.CMTextChanged(var Message: TMessage);
begin
inherited;
if _MySetCap then Exit;
FOriginalCaption := Caption;
end;
procedure TMSCheckBox.WMPaint(var Message: TWMPaint);
const
SPACE :Integer = 2;
var
txtW, txtH, txtX,
BtnWidth: Integer;
canv: TControlCanvas;
begin
BtnWidth := GetSystemMetrics(SM_CXMENUCHECK);
_MySetCap := True;
if not (csDesigning in ComponentState) then
Caption := '';
_MySetCap := False;
inherited;
canv := TControlCanvas.Create;
try
canv.Control := Self;
canv.Font := Font;
txtW:= canv.TextWidth(FOriginalCaption);
txtH:= canv.TextHeight(FOriginalCaption);
if BiDiMode in [bdRightToLeft, bdRightToLeftReadingOnly] then
txtX:= Width - BtnWidth - SPACE - txtW
else
txtX:= BtnWidth + SPACE;
SetBkMode(canv.Handle, Ord(TRANSPARENT));
canv.TextOut(txtX, (Height - txtH) div 2 + 1, FOriginalCaption);
finally
canv.Free;
end;
end;

Make dialogs compatible with "large fonts". [duplicate]

This question already has answers here:
How do I make my GUI behave well when Windows font scaling is greater than 100%
(4 answers)
Closed 8 years ago.
Which do you think are best practices for making a windows dialog compatible both with standard fonts (96 dpi) and "large fonts" setting (120 dpi) so that objects don't overlap or get cut off?
BTW: Just in case it's relevant, I'm interested in doing this for Delphi dialogs.
Thanks in advance!
In general one should use layout managers for this purpose. That what they are designed for.
Delphi (did not work with it for a long time) does not have such managers but is able to handle different dpi ever since. You have to use the autosize propery of the components to ensure that they have the right size for the text they display. To prevent overlapping of components arrange them on the form using the alignment and anchor properties. Eventually you have to group components in containers to achieve a proper layout.
There's a pretty good article in the D2007 help file, under "Considerations When Dynamically Resizing Forms and Controls" (note that the URL is to the help file itself, and not a web page as such).
The same topic, under the same name, can be found in the D2010 help file (same caveat about the URL as above), or on the docwiki.
It also is worthwhile (at least a little bit) to examine TForm.Scaled and TForm.ScaleBy.
This is how I try to deal with Delphi VCL's pixels regardless of Window's font size setting.
unit App.Screen;
interface
uses Controls;
type
TAppScreen = class(TObject)
private
FDefaultPixelsPerInch: integer;
FPixelsPerInch: integer;
function GetPixelsPerInch: integer;
procedure SetPixelsPerInch(const Value: integer);
public
procedure AfterConstruction; override;
function DefaultPixelsPerInch: integer;
function InAcceptableRange(const aPPI: integer): boolean;
procedure ScaleControl(const aControl: TWinControl);
property PixelsPerInch: integer read GetPixelsPerInch write SetPixelsPerInch;
end;
TAppScreenHelper = class helper for TAppScreen
private
class var FInstance: TAppScreen;
class function GetInstance: TAppScreen; static;
public
class procedure Setup;
class procedure TearDown;
class property Instance: TAppScreen read GetInstance;
end;
implementation
uses
TypInfo, Windows, SysUtils, Forms, Graphics;
type
TScreenEx = class(TScreen)
published
property PixelsPerInch;
end;
TScreenHelper = class helper for TScreen
public
procedure SetPixelsPerInch(Value: integer);
end;
procedure TScreenHelper.SetPixelsPerInch(Value: integer);
begin
PInteger(Integer(Self) + (Integer(GetPropInfo(TScreenEx, 'PixelsPerInch').GetProc) and $00FFFFFF))^ := Value;
end;
procedure TAppScreen.AfterConstruction;
begin
inherited;
FDefaultPixelsPerInch := Screen.PixelsPerInch;
FPixelsPerInch := FDefaultPixelsPerInch;
end;
function TAppScreen.DefaultPixelsPerInch: integer;
begin
Result := FDefaultPixelsPerInch;
end;
function TAppScreen.GetPixelsPerInch: integer;
begin
Result := FPixelsPerInch;
end;
function TAppScreen.InAcceptableRange(const aPPI: integer): boolean;
begin
if DefaultPixelsPerInch > aPPI then
Result := DefaultPixelsPerInch * 0.55 < aPPI
else if DefaultPixelsPerInch < aPPI then
Result := DefaultPixelsPerInch * 1.55 > aPPI
else
Result := True;
end;
procedure TAppScreen.ScaleControl(const aControl: TWinControl);
begin
aControl.ScaleBy(PixelsPerInch, DefaultPixelsPerInch);
end;
procedure TAppScreen.SetPixelsPerInch(const Value: integer);
begin
FPixelsPerInch := Value;
Screen.SetPixelsPerInch(FPixelsPerInch);
end;
class function TAppScreenHelper.GetInstance: TAppScreen;
begin
if FInstance = nil then
FInstance := TAppScreen.Create;
Result := FInstance;
end;
class procedure TAppScreenHelper.Setup;
begin
TAppScreen.Instance;
end;
class procedure TAppScreenHelper.TearDown;
begin
FInstance.Free;
FInstance := nil;
end;
initialization
TAppScreen.Setup;
finalization
TAppScreen.TearDown;
end.
Try the following to test the effects of different pixels value:
TAppScreen.Instance.PixelsPerInch := 120;
TAppScreen.Instance.PixelsPerInch := 96;
TAppScreen.Instance.PixelsPerInch := 150;
You should change the PixelsPerInch before instantiate TForm's descendant including Delphi's VCL dialogs.
Never put a control and its describing label side by side, always put the label on top of it.
But apart from that? Maybe:
Leave enough space to the right and bottom of labels so they will not overlap with other controls when large fonts are used.
I have never tried using TLabeledEdit in that scenario, maybe they do that automatically?
There are purported commercial solutions (Developer Express VCL Layout Manager). But I do not trust any of them. I suspect that Embarcadero should address this as a critical weakness in the current UI component set (VCL).
I think that the third-party component set might be your fastest solution right now. It's commercial but not hugely expensive.
http://www.devexpress.com/products/VCL/ExLayoutControl/

Resources