14

I skinned my software with Devexpress and I found that the labels were non-transparent causing them to have grey background.

There's just endless forms, so I was wondering whether there was a way to do this task (of setting labels to transparent) automatically.

I did a similar thing earlier, the Devexpress controls on the form had LookAndFeel.NativeStyle = True, I used Grep Search to replace it to False on all dfm forms. In the label's case however, the transparent property is not present.

Thank you.

Rosenberg
  • 2,284
  • 3
  • 26
  • 51
  • Are you committed to doing this in the IDE, or would you be okay with it being done at run-time? – RobertFrank May 25 '11 at 15:06
  • Robert, that would be fantastic - at run time I mean. What can I do to achieve that result? – Rosenberg May 25 '11 at 15:07
  • Rather than doing it at design time you could perhaps more easily do this at runtime – David Heffernan May 25 '11 at 15:09
  • Iterate across all the controls in the form and whenever you find a label change the properties as desired – David Heffernan May 25 '11 at 15:10
  • I've used GExperts for a massive search and replace. Can you use it to locate all occurences of TLabel in the dfm's and replace by TLabelTransparent=True - I dont know how to declare the bit though. – Brian Frost May 25 '11 at 15:34
  • In Delphi XE the default value for TLabel.Transparent is true. So if it doesn't appear in the DFM, it should already be OK. You have tagged three Delphi versions - which one has the problem? – Uwe Raabe May 25 '11 at 15:35
  • Delphi 7, I use XE as well, since there are multiple projects but for this one only 7 will do. – Rosenberg May 25 '11 at 15:54
  • 2
    +1 for a question inspiring several clever solutions. – Rob Kennedy May 25 '11 at 17:06

6 Answers6

15

The global Screen variable keeps track of all forms:

procedure MakeLabelsTransparent(AParent: TWinControl);
var
  I: Integer;
begin
  with AParent do
    for I := 0 to ControlCount - 1 do
      if Controls[I] is TLabel then
        TLabel(Controls[I]).Transparent := True
      else if Controls[I] is TWinControl then
        MakeLabelsTransparent(TWinControl(Controls[I]));
end;

procedure TMainForm.ActiveFormChange(Sender: TObject);
begin
  with Screen do
    if (ActiveCustomForm <> nil) and (ActiveCustomForm.Tag = 0) then
    begin
      MakeLabelsTransparent(ActiveCustomForm);
      ActiveCustomForm.Tag := 1;
    end;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Screen.OnActiveFormChange := ActiveFormChange;
end;

And if you have to use the Tag property for a particular form, then omit this check: it wouldn't really get that much slower.

NGLN
  • 41,230
  • 8
  • 102
  • 186
9

For this type of task, GExperts contains the Set Component Properties tool:

This tool waits in the background until you compile a project. It then scans the current project's forms to check for components with certain properties and changes those properties to a defined value. This tool is useful to deactivate datasets or database connections before you compile your applications, but it can be used for any similar situations as well. To activate the scanning, enable the checkbox next to this expert in the GExperts Configuration screen.

It can be used to set a property which is not yet in the DFM as well, and only requires one additional entry in the GExpert configuration, and a recompile.

I have just tested it and it works as expected.

mjn
  • 35,561
  • 24
  • 160
  • 351
5

At design time, you can just parse all .dfm then add the

  Transparent = True

line just after any

  object MyLabel : TLabel

line.

At runtime, you may override the TCustomForm.DoCreate and TCustomFrame.Create methods, as such:

type
  THookedForm = class(TCustomForm)
    procedure HookedDoCreate;
  end;

  THookedFrame = class(TCustomFrame)
    constructor Create(AOwner: TComponent); override;
  end;

var
  PatchForm, OriginalForm: TPatchEvent;
  PatchPositionForm: PPatchEvent = nil;
  PatchFrame, OriginalFrame: TPatchEvent;
  PatchPositionFrame: PPatchEvent = nil;

procedure PatchCreate;
var ov: cardinal;
begin
  // hook TForm:
  PatchPositionForm := PPatchEvent(@THookedForm.DoCreate);
  OriginalForm := PatchPositionForm^;
  PatchForm.Jump := $E9; // Jmp opcode
  PatchForm.Offset := PtrInt(@THookedForm.HookedDoCreate)-PtrInt(PatchPositionForm)-5;
  if not VirtualProtect(PatchPositionForm, 5, PAGE_EXECUTE_READWRITE, @ov) then
    RaiseLastOSError;
  PatchPositionForm^ := PatchForm; // enable Hook
  // hook TFrame:
  PatchPositionFrame := PPatchEvent(@TCustomFrame.Create);
  OriginalFrame := PatchPositionFrame^;
  PatchFrame.Jump := $E9; // Jmp opcode
  PatchFrame.Offset := PtrInt(@THookedFrame.Create)-PtrInt(PatchPositionFrame)-5;
  if not VirtualProtect(PatchPositionFrame, 5, PAGE_EXECUTE_READWRITE, @ov) then
    RaiseLastOSError;
  PatchPositionFrame^ := PatchFrame; // enable Hook
end;

{ THookedForm }

procedure THookedForm.HookedDoCreate;
var i: integer;
begin
  // enumerate all labels, then set Transparent := true
  for i := 0 to Components.Count-1 do
    if Components[i] is TLabel then
      TLabel(Components[i]).Transparent := true;
  DoCreate; // call initial code
end;

{ THookedFrame }

constructor THookedFrame.Create(AOwner: TComponent);
var i: integer;
begin
  // enumerate all labels, then set Transparent := true
  for i := 0 to Components.Count-1 do
    if Components[i] is TLabel then
      TLabel(Components[i]).Transparent := true;
  inherited Create(AOwner); // call normal constructor
end;

....

initialization
  PatchCreate;
Arnaud Bouchez
  • 40,947
  • 3
  • 66
  • 152
5

A related tip (I always forget to make use of this handy feature):

  1. Configure the label the way you want to have it;
  2. Select it on the form;
  3. Go to Component/Create component template;
  4. You can then a name for the template:

enter image description here

From then on, the template appears as a new component type in your tool palette, with the settings that you prefer.

(Yeah, I know this doesn't change current labels)

Wouter van Nifterick
  • 22,500
  • 7
  • 72
  • 117
  • nice, will try this out on one of my custom components whose defaults are set in stone – David Heffernan May 25 '11 at 22:25
  • 1
    Although this doesn't provide a solution to the question it's **really useful**. I never once thought about clicking the menu 'Create component template'. Thanks! – Rosenberg May 25 '11 at 23:49
1

You can set the BackColor property to Color.Transparent.

Blindy
  • 55,135
  • 9
  • 81
  • 120
1

The following should work: the transparent-property is present in the DFM-file only if the value is not the default. So you can us a Grep-Search to insert the "Transparent=TRUE" just in the next line after the "=TLabel". I have not tried this myself, but it is easy to try...

Johan
  • 71,222
  • 23
  • 174
  • 298
Andreas
  • 1,329
  • 1
  • 9
  • 19