Using the style of the inherited control - delphi

My first firemonkey component is inherited from a TSpinBox but I cannot figure out how to get it to use the same style as the base component.
At design time in my app I can set the StyleLookup to "spinboxstyle" and get the correct style but if I try to do that in the constructor for the new component it ignores it.
What is the correct procedure for this?

The constructor is the correct place.
You have to use FStyleLookup := 'spinboxstyle'; (Note the F)
Not StyleLookup := 'spinboxstyle';

Related

How to programatically set designtime height / width of TDatamodule in Delphi?

I generate a TDatamodule with a bunch of TFDQueries that it contains. Then, I save this Datamodule .DFM like so
lFileStream := TFileStream.Create('Datamodule.dfm', fmCreate);
lMemoryStream := TMemoryStream.Create;
lMemoryStream.WriteComponent(lDataModule);
lMemoryStream.Seek(0, soFromBeginning);
ObjectBinaryToText(lMemoryStream, lFileStream);
lFileStream.Free;
lMemoryStream.Free;
To be user-friendly, I need to set the width and height of this TDatamodule when I generate it. But I cannot use
lDatamodule.Width := 500; // Does not compile
lDatamodule.Height := 500; // Does not compile
Because Width and Height are registered design time properties. A similar strategy allowing to set the designtime Left and Top properties of TComponents is done using the DesignInfo property as such
procedure BootyShakin;
var
NewDesignInfo : LongRec;
begin
NewDesignInfo.Lo := Word(100);
NewDesignInfo.Hi := Word(100);
lComponent.DesignInfo := Longint(NewDesignInfo);
end;
I am looking for an analogous solution for setting the design time width and height of a TDatamodule before it is saved to .DFM
TDataModule offers a public property DesignSize, which is of type TPoint.
Documentation says:
Specifies the design size for the data module at design time.
An application should never need to set this value. It controls the size of the data module window at design time.
Despite the documentation does not recommend it - for normal applications, which use the TDataModule, I think - you can archieve what you are looking for with this property.

Adding label to custom component as a child

I have a custom component TCard = class(TGraphicControl) I would like for when its created it would have a label inside it's area ex (top := 5 ) (left :=5) and it would always put a TLabel on that TCard at that spot when created.
type
TCard = class(TGraphicControl)
private
FLPower:TLabel;
procedure SetLPower(value:TLabel);
protected
procedure Paint; override;
public
property LPower: TLabel read FLpower write SetLPower;
...
constructor Tcard.Create(AOwner: Tcomponent);
begin
inherited Create(AOwner);
FLPower := TLabel.Create(self);
end
procedure TCard.SetLPower(value: TLabel);
begin
FLPower.Assign(value);
end;
procedure Tcard.Paint;
begin
FLPower.Left := 5;
FLPower.Top := 5;
end;
I know what i have is not right, but i wanted to show something. Also if it helps, i plan in future to beable to do TCard.LPower.Caption := inttostr(somenumber); So if you can work that in then bonuse .. if not i can figure that out later..but wanted to give a heads up incase something you suggest would not work due to that.
Thanks
glen
A TGraphicControl cannot be used as a parent control and so you cannot adopt this approach.
A label is essentially something very simple. It's just text. You have chosen to use TGraphicControl so that implies that you are going to implement a Paint method.
So, instead of creating a label control, add a Text property of type string to your control. Then, in the Paint method, draw the text to the paint canvas. When the Text property is modified, invalidate your control so that it can be repainted.
In any case, doing it this way is the right way to do it. Adding extra controls just to draw text is over the top. You've picked the lightest weight control which is fine. Paint your card's background, and then paint any text that is required. Job done.

Font consistency throughout Project?

Is there a quick and effective way of applying a global Font to be used in a project?
By this I mean I would like to set a specific Font name that all controls in my project will use such as TButton, TEdit, TLabel etc.
Typically setting the Font for the Form rather than a specific control will change all the controls on that Form to the Font specified.
There is a slight issue with this however, if you have manually changed a Font on a specific control, then setting the Font by the Form will no longer update those controls that have previously been changed manually.
Idea 1
I was thinking of using a For loop and iterating through each component on my Forms and setting the Font this way, such as:
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
with TForm(Self) do
begin
for i := 0 to ComponentCount - 1 do
begin
if Components[i] is TButton then
begin
TButton(Components[i]).Font.Name := 'MS Sans Serif';
TButton(Components[i]).Font.Size := 8;
TButton(Components[i]).Font.Style := [fsBold];
end;
if Components[i] is TLabel then
begin
TLabel(Components[i]).Font.Name := 'MS Sans Serif';
TLabel(Components[i]).Font.Size := 8;
TLabel(Components[i]).Font.Style := [fsBold];
end;
end;
end;
end;
But doing this seems very messy, it will also be a considerable amount of code for a simple task.
Idea 2
I know I could manually change the fonts at design time one by one for each control, but with several forms to go through this could take time and even then I might of missed a control.
Idea 3
Similar to Idea 2, another way could be to view the Form as Text (DFM) and Find and Replace the font that way.
Basically I am going for consistency within my Application, and having one Font used throughout is what I was looking to achieve.
Am I missing something completely obvious here, is what I am trying to do overkill for such a task?
As discussed in the comments, the key to this is the ParentFont property. This property is defined at various points in the VCL hierarchy. If you set ParentFont to be True for all components in the chain, then you can change the fonts for the entire application simply by modifying
Application.DefaultFont
By default most components set ParentFont to True and so you have nothing to do. The odd one out though is TForm. A brand new default form has ParentFont set to False. This is somewhat disappointing but I suspect reflects the fact that the original designers of the VCL did not anticipate this and that ParentFont was grafted on relatively late in the development of the VCL.
No matter, in an ideal world, all forms in your application should be derived from a common base class that you control. If that is so then you can simply make the change there, set ParentFont to be True, make sure no explicit font settings are applied to any components on you forms, and you are golden. Control the entire application's fonts through a single property. If you don't have a common base class for your forms, here's an ideal time to add it. If you don't want to do that then you need to set ParentFont for each form.
Other related properties are Screen.MessageFont and Screen.MenuFont. These provide global control over the fonts used in message boxes and menus. However, recent versions of Delphi have handed back to Windows control over the painting of message boxes and menus and so these properties have no effect.
The real key, as was mentioned, is to ensure that all your forms descend from your own application base form.
Then, you can view each form and button etc, and review the properties, where any modified font property should be displayed in bold, and is easily identified. Most properties have a "Revert to inherited" menu choice. This should essentially undo any previous selection, without having to go to the text version for editting. (Although it probably does exactly that, deleting any text entry resulting from previous font-setting).
I would definitely want to fix each form once rather than leaving it defined incorrectly and adding more code to fix it at runtime. That change will leave you with a worse problem if you later decide to do something different.
If you want to do this runtime, like you describe it in Idea 1, you should consider making it a recursive function, like this:
procedure SetFontProperties(Control: TControl; Name: TFontName; Size: Integer; Styles: TFontStyles);
// Set font properties
var
Index: Integer;
Font: TFont;
AnObject: TObject;
ChildControl: TControl;
begin
// Set font properties
AnObject := GetObjectProp(Control, 'Font', nil);
if AnObject is TFont then
begin
// Set properties
Font := TFont(AnObject);
Font.Name := Name;
Font.Size := Size;
Font.Style := Styles;
end;
// Set child font properties
if Control is TWinControl then
begin
// Set
for Index := 0 to TWinControl(Control).ControlCount - 1 do
begin
// Child control
ChildControl := TWinControl(Control).Controls[Index];
// Set font properties
SetFontProperties(ChildControl, Name, Size, Styles);
end;
end;
end;
You can then switch fonts for all controls within a form by using it like this:
SetFontProperties(Self, 'Courier', 14, []);
The function will then set the font properties of the form, and the font properties of all child controls on the form, including controls nested within TPanels or other container controls.
However I do agree with you that it's sort of a half messy way of doing it.

Make/reuse a custom component in delphi with fixed layout properties (design)

Is it possible to create a custom component, not only by adding extra functionality like methods and events, but also design the custom component (so that color, font, ... shouldn't be set when adding that component).
I would like to use this to construct a custom TDBGrid which I reuse and can just add to a form properly designed.
Thanks in advance!
Everything you can do in the designer you can "code into your component". Generally you just redeclare the new default values for properties and set / initialize them in the overriden constructor. Ie to create custom panel with red color as default you'd do
type
TMyPanel = class(TPanel)
public
constructor Create(AOwner: TComponent); override;
published
property Color default clRed;
end;
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
Color := clRed;
end;
Component templates should serve the task.
After you're created and installed the component, drop it on the form, adjust every property you want to, go Component-Create Component Template, choose name and palette page. Starting this moment you can select and drop your customized variant on the form
Since the copied component is a simple text inside clipboard, you can also copy-paste your customized component to a text file and when you need this copy, just select this fragment and copy it as a simple text, Delphi form will accept this object when you paste it. You even can organize a little storage for your saved component after the "end." in the module or inside comments, both will be safely bypassed by the compiler.

Making a TPageControl flat in Delphi 7

I don't know whether this question can be answered here, but I hope it will.
I wrote a simple text editor in Delphi 7 that serves as my primary IDE for writing C code under Windows. I run Windows in a VM and I needed something light.
In any case, it uses a TpageControl that gets a new tab whenever you open or create a new file. Pretty standard.
Now, the TPageControl under Delphi has no flat property.
NO I don't mean setting the tab style to tsButtons or tsFlatButtons
the borders cannot be set to "none" and it looks pretty bad when you add a text editor into the tab control.
Is there any way to make a TpageControl flat?
EDIT:
On an open source PageControl that supports flat here's what I found:
procedure TCustomTabExtControl.WndProc(var Message: TMessage);
begin
if(Message.Msg=TCM_ADJUSTRECT) and (FFlat) then
begin
Inherited WndProc(Message);
Case TAbPosition of
tpTop : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Top:=PRect(Message.LParam)^.Top-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpLeft : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Left:=PRect(Message.LParam)^.Left-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
tpBottom : begin
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=ClientWidth;
PRect(Message.LParam)^.Bottom:=PRect(Message.LParam)^.Bottom-4;
PRect(Message.LParam)^.Top:=0;
end;
tpRight : begin
PRect(Message.LParam)^.Top:=0;
PRect(Message.LParam)^.Left:=0;
PRect(Message.LParam)^.Right:=PRect(Message.LParam)^.Right-4;
PRect(Message.LParam)^.Bottom:=ClientHeight;
end;
end;
end else Inherited WndProc(Message);
end;
The thing is when I tried something similar on the main application it won't work. It won't even compile.
When the tabs are drawn as buttons, no border is drawn around the display area, so set the Style property to tsButtons or tsFlatButtons. (For non-VCL programmers, this is equivalent to including the tcs_Buttons window style on the tab control.)
An alternative is to use a TNotebook. It holds pages, but it doesn't do any painting at all. You'd have to provide the tabs yourself, such as by setting the tab control's height equal to the height of the tabs, or by using a TTabSet. (TTabSet is available in Delphi 2005; I'm not sure about Delphi 7.)
Regarding the code you found, it would be helpful if you indicated why it doesn't compile, or if you gave a link to where you found it, since I suppose the compilation error was because it refers to fields or properties of the custom class rather than the stock one. Here's what you can try to put it in your own code, without having to write a custom control.
Make two new declarations in your form like this:
FOldTabProc: TWndMethod;
procedure TabWndProc(var Msg: TMessage);
In the form's OnCreate event handler, assign that method to the page control's WindowProc property:
FOldTabProc := PageControl1.WindowProc;
PageControl1.WindowProc := TabWndProc;
Now implement that method and handle the tcm_AdjustRect messsage:
procedure TForm1.TabWndProc(var Msg: TMessage);
begin
FOldTabProc(Msg);
if Msg.Msg = tcm_AdjustRect then begin
case PageControl1.TabPosition of
tpTop: begin
PRect(Msg.LParam)^.Left := 0;
PRect(Msg.LParam)^.Right := PageControl1.ClientWidth;
Dec(PRect(Msg.LParam)^.Top, 4);
PRect(Msg.LParam)^.Bottom := PageControl1.ClientHeight;
end;
end;
end;
end;
You can fill in the other three cases if you need them. Tcm_AdjustRect is a message identifier declared in the CommCtrl unit. If you don't have that message in that unit, declare it yourself; its value is 4904.
I suspect this doesn't stop the control from drawing its borders. Rather, it causes the contained TTabSheet to grow a little bigger and cover up the borders.
I'm using Delphi XE8 and the following seems to do the trick:
ATabControl.Tabs.Clear;
ATabControl.Style := TTabStyle.tsFlatButtons;
ATabControl.Brush.Color := clWhite;
You could always use a commercial solution. I would strongly recommend Raize components, which support flat TPageControls with tabs. The component set is very easy to work with, and supports numerous visual enhancements which in my opinion give a better feel to any application.
(source: raize.com)
Drop two TPageControls, one with tabs as Tabs, with a global height equal to the tabs, and one with flatbuttons and Tabvisible properties set to false, which would be aligned under the first one. Then make sure the tab change on the first TPagecontrol makes the tabs also change in the second one.

Resources