Fire-Monkeyのヘルプとヒント





長年にわたり、Fire-Monkey(FMX)フレームワークには多くの変更が加えられ、当初から非常に生で信頼性の低いものであった場合、はるかに安定した信頼性の高いプラットフォームになりました。



このメモは、このフレームワークを使用する開発者にとって役立ついくつかのヒントのコレクションです。





コミュニティに投稿が好意的に受け取られた場合、この形式でFMXに関するメモを定期的に発行します。



テキストサイズの計算



テキストサイズに関する質問は非常に一般的です。次の関数を使用してテキストサイズを計算できます。



function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF;
      
      





この関数は、単一行テキストが占める長方形のサイズを計算するためのものです。



パラメータ:





ソースコード:



 uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; function CalcTextSize(Text: string; Font: TFont; Size: Single = 0): TSizeF; var TextLayout: TTextLayout; begin TextLayout := TTextLayoutManager.DefaultTextLayout.Create; try TextLayout.BeginUpdate; try TextLayout.Text := Text; TextLayout.MaxSize := TPointF.Create(9999, 9999); TextLayout.Font.Assign(Font); if not SameValue(0, Size) then begin TextLayout.Font.Size := Size; end; TextLayout.WordWrap := False; TextLayout.Trimming := TTextTrimming.None; TextLayout.HorizontalAlign := TTextAlign.Leading; TextLayout.VerticalAlign := TTextAlign.Leading; finally TextLayout.EndUpdate; end; Result.Width := TextLayout.Width; Result.Height := TextLayout.Height; finally TextLayout.Free; end; end;
      
      





指定された長方形に内接するテキストの最大可能フォントサイズ



 function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer;
      
      





この関数は、指定された長方形に内接するテキストの最大可能フォントサイズを返します。



パラメータ:





ソースコード:



 uses System.Types, FMX.Types, FMX.Graphics, FMX.TextLayout, System.Math, System.SysUtils; const cMaxFontSize = 512; function FontSizeForBox(Text: string; Font: TFont; Width, Height: Single; MaxFontSize: Single = cMaxFontSize): Integer; var Size, Max, Min, MaxIterations: Integer; Current: TSizeF; begin Max := Trunc(MaxFontSize); Min := 0; MaxIterations := 20; repeat Size := (Max + Min) div 2; Current := CalcTextSize(Text, Font, Size); if ((Abs(Width - Current.Width) < 1) and (Width >= Current.Width)) and ((Abs(Height - Current.Height) < 1) and (Height >= Current.Height)) then break else if (Width < Current.Width) or (Height < Current.Height) then Max := Size else Min := Size; Dec(MaxIterations); until MaxIterations = 0; Result := Size; end;
      
      





FindStyleResourceの問題点と対処方法



よくある質問:



私が出会った「bagofich」について説明します。



TStyledControlから継承するコンポーネント(またはTStyledControlから継承する他のコンポーネント)を記述すると仮定します。それらは通常、 FindStyleResource( 'ResourceName')を使用してスタイル要素にアクセスします( FindStyleResource <Class>( 'ResourceName'変数) )、たとえば、 TImageControlコンポーネントは次のようなImageオブジェクトを受け取ります:



 procedure TImageControl.ApplyStyle; begin inherited; if FindStyleResource<TImage>('image', FImage) then UpdateImage; end;
      
      





FindStyleResourceは、 問題のオブジェクトがTStyledControls (およびその子孫)以外にある限り正常に機能します。つまり、 FindStyleResourceTRectangleにあるオブジェクトを正常に検出できますが、 TPanelにはありません。



例:



ApplyStyleプロシージャのコード:



 procedure TEsImageSelection.ApplyStyle; var T: TControl; begin inherited ApplyStyle; if FindStyleResource<TControl>('selection', T) then ShowMessage('"selection" founded!'); end;
      
      





このコードは何をしますか? -スタイルオブジェクトが見つかると、対応するメッセージが表示されます。



スタイルを考慮してください:







オプションAでわかるように、 「選択」TStyledControl 継承者ではありません 。 プログラムを実行することにより、 FindStyleResource <TControl>( 'selection'、T)Selectionオブジェクトを確実に見つけることができます。



オプションBでは、起動時にFindStyleResource <TControl>( 'selection'、T)Selectionオブジェクトを見つけられないことに驚くかもしれません!



なぜそう



ソースコードから判断すると、埋め込まれたTStyledControlsの検索特別に壊れているため、さらにグリッチや問題が発生することはありません(ただし、この問題を詳細に調査しませんでした。 )



どうすれば問題を回避できますか?



FindStyleResourceとは異なり、いくつかの反復を通じてEsFindStyleResource関数が記述され、目的のスタイルオブジェクトを検索します。



 function EsFindStyleResource(Self: TStyledControl; StyleName: string): TFmxObject;
      
      





パラメータ:





ソースコード:



 type TOpenStyledControl = class(TStyledControl); function EsFindStyleResource(Self: TStyledControl; StyleName: string): TFmxObject; var StyleObject: TFmxObject; begin //  Self.ChildrenCount < 1      , // ..          . if (TOpenStyledControl(Self).ResourceLink = nil) or (Self.ChildrenCount < 1) then Exit(nil); StyleObject := nil; Self.Children[0].EnumObjects( function (Obj: TFmxObject): TEnumProcResult begin if Obj.StyleName.ToLower = StyleName.ToLower then begin Result := TEnumProcResult.Stop; StyleObject := Obj; end else Result := TEnumProcResult.Continue; end); Result := StyleObject; end;
      
      





TTrackBarでのリスク(ティック)



Fire-MonkeyではTTrackBarコンポーネントに 「リスク」を描画する機能が組み込まれていませんが、この機能が必要な場合があります。DrawTicks関数を使用すると、この機能をFMXに「戻す」ことができます

この関数は、 TTrackBarコンポーネントのOnPaintingハンドラで呼び出す必要があります。



関数の結果:









 procedure DrawTicks(Control: TTrackBar; Offset: Single; PageSize: Single; DrawBounds: Boolean; LineKind: TLineKind; LineWidth, LineSpace: Single; Color: TAlphaColor);
      
      





パラメータ:





ソースコード:



 type TLineKind = (Up, Down, Left, Right, Both); procedure DrawTicks(Control: TTrackBar; Offset: Single; PageSize: Single; DrawBounds: Boolean; LineKind: TLineKind; LineWidth, LineSpace: Single; Color: TAlphaColor); var Obj: TFmxObject; Cnt: TControl; L: TPointF; Coord, RealCoord: Single; function GetCoord(Value: Single): Single; begin if Control.Orientation = TOrientation.Horizontal then Result := Ceil(THTrackBar(Control).GetThumbRect(Value).CenterPoint.X)// + Crutch else Result := Ceil(THTrackBar(Control).GetThumbRect(Value).CenterPoint.Y);// + Crutch; end; procedure DrawLine(Coord: Single); begin if Control.Orientation = TOrientation.Horizontal then begin if (SameValue(LineSpace, 0)) and (LineKind = TLineKind.Both) then begin Control.Canvas.DrawLine( PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) - LineWidth + 0.5), PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) + LineWidth - 0.5), 1) end else begin if (LineKind = TLineKind.Down) or (LineKind = TLineKind.Both) then Control.Canvas.DrawLine( PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) + LineSpace + 0.5), PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) + LineSpace + LineWidth - 0.5), 1); if (LineKind = TLineKind.Up) or (LineKind = TLineKind.Both) then Control.Canvas.DrawLine( PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) - LineSpace - 0.5), PointF(Coord + 0.5, LY + Trunc(Cnt.Height / 2) - LineSpace - LineWidth + 0.5), 1); end; end else begin if (SameValue(LineSpace, 0)) and (LineKind = TLineKind.Both) then begin Control.Canvas.DrawLine( PointF(LX + Trunc(Cnt.Width / 2) - LineWidth + 0.5, Coord + 0.5), PointF(LX + Trunc(Cnt.Width / 2) + LineWidth - 0.5, Coord + 0.5), 1) end else begin if (LineKind = TLineKind.Right) or (LineKind = TLineKind.Both) then Control.Canvas.DrawLine( PointF(LX + Trunc(Cnt.Width / 2) + LineWidth + 0.5, Coord + 0.5), PointF(LX + Trunc(Cnt.Width / 2) + LineWidth + LineWidth - 0.5, Coord + 0.5), 1); if (LineKind = TLineKind.Left) or (LineKind = TLineKind.Both) then Control.Canvas.DrawLine( PointF(LX + Trunc(Cnt.Width / 2) - LineWidth - 0.5, Coord + 0.5), PointF(LX + Trunc(Cnt.Width / 2) - LineWidth - LineWidth + 0.5, Coord + 0.5), 1); end; end; end; begin if Control.Orientation = TOrientation.Horizontal then Obj := Control.FindStyleResource('htrack') else Obj := Control.FindStyleResource('vtrack'); if Obj = nil then Exit; Cnt := Obj.FindStyleResource('background') as TControl; if Cnt = nil then Exit; Control.Canvas.Stroke.Thickness := 1; Control.Canvas.Stroke.Kind := TBrushKind.Solid; Control.Canvas.Stroke.Color := Color; L := Cnt.LocalToAbsolute(PointF(0, 0)) - Control.LocalToAbsolute(PointF(0, 0)); if DrawBounds and not SameValue(Offset, 0.0) then DrawLine(GetCoord(Control.Min)); Coord := Offset + Control.Min; while Coord <= Control.Max - Control.Min do begin if (Coord >= Control.Min) and (Coord <= Control.Max) then begin RealCoord := GetCoord(Coord); DrawLine(RealCoord); end; Coord := Coord + PageSize; end; if DrawBounds and not SameValue(GetCoord(Control.Max), GetCoord(Coord - PageSize)) then DrawLine(GetCoord(Control.Max)); end;
      
      





この記事がお役に立てば幸いです。



投票することを忘れないでください:)



All Articles