FireMonkey TLine Demo

This video is created by connecting two planets orbiting the sun with different orbital periods with a line.

You can visually see the distance between two destination lines by the length of the line.



The length between the two points was calculated in the following way.

procedure TMForm.Draw_Line2P( x1,y1, x2,y2 : single;  setColor : cardinal );

var

  d, xtemp, ytemp, rAngle : single;

  drawLine : TLine;

begin

  if x1 > x2 then

  begin

    xtemp := x1;     ytemp := y1;

    x1 := x2;          y1 := y2;

    x2 := xtemp;     y2 := ytemp;

  end;


  d := SQRT( Power( x2-x1, 2 ) + Power( y2-y1, 2 ) );   // Uses System.Math

  rAngle := RadToDeg( ArcSin( (y2-y1)/d ));


  drawLine := TLine.Create( BLayout );

  drawLine.Parent := BLayout;

  drawLine.LineLocation := TLineLocation.Inner;

  drawLine.LineType := TLineType.Bottom;

  drawLine.RotationCenter.X := 0;

  drawLine.RotationCenter.Y := 0;

  drawLine.Stroke.Thickness := 1;

  drawLine.Stroke.Color := setColor;

  drawLine.Height := 1;

  drawLine.Width  := d;

  drawLine.Position.X := x1;

  drawLine.Position.Y := y1;

  drawLine.RotationAngle := rAngle;

end;

Using ChatGPT in Delphi

// ChatGPT Personal Key : https://beta.openai.com/account/api-keys





unit MainCGPT;

interface

uses

  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.JSON,

  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox,

  FMX.Memo, System.Net.URLClient, System.Net.HttpClient, System.Net.HttpClientComponent, FMX.Layouts;

type

  TMForm = class(TForm)

    Memo_Ans: TMemo;

    Memo_HanQ: TMemo;

    BT_Question: TButton;

    NetHTTPClient1: TNetHTTPClient;

    NetHTTPRequest1: TNetHTTPRequest;

    Label1: TLabel;

    Label3: TLabel;

    Layout1: TLayout;

    Layout3: TLayout;

    SpeedButton1: TSpeedButton;

    procedure BT_QuestionClick(Sender: TObject);

    procedure NetHTTPClient1RequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);

    procedure Memo_HanQDblClick(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;


var

  MForm: TMForm;


  // ChatGPT key :  https://beta.openai.com/account/api-keys

  Const MyGPTKey = 'mykey_1234abcd';   // Input your key


implementation

{$R *.fmx}

procedure TMForm.Memo_HanQDblClick(Sender: TObject);

begin

  Memo_HanQ.Lines.Clear;

end;


// Question *********************************************

procedure TMForm.BT_QuestionClick(Sender: TObject);

var

  LPostdata: string;

  LPostDataStream: TStringStream;

begin

  LPostData := '{' +

    '"model": "text-davinci-003",'+

    '"prompt": "' + Memo_HanQ.Text + '",'+

    '"max_tokens": 2048,'+

    '"temperature": 0'+

    '}';


  LPostDataStream := TStringStream.Create( LPostData, TEncoding.UTF8);


  NetHTTPClient1.CustomHeaders['Authorization'] := 'Bearer ' + MyGPTKey;

  NetHTTPClient1.CustomHeaders['Content-Type'] := 'application/json';


  LPostDataStream.Position := 0;

  NetHTTPClient1.Post('https://api.openai.com/v1/completions', LPostDataStream );

end;



// Answer ********************************************************************************

procedure TMForm.NetHTTPClient1RequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);

var

  LString, ansStr : string;

  LJson: TJsonObject;


begin

  if AResponse.StatusCode = 200 then

  begin

     LString := AResponse.ContentAsString;

     LJson := TJSONObject.ParseJSONValue(LString) as TJSONObject;

     try

       ansStr := LJson.GetValue('choices').A[0].FindValue('text').Value;

     finally

       LJson.Free;

     end;

  end

  else

    ansStr := 'HTTP response code: ' + AResponse.StatusCode.ToString;


  Memo_Ans.Lines.Clear;

  Memo_Ans.Lines.Add( ansStr );

end;

end.




Delphi FMX Android run time permission sample project demo

 



unit PMUnit;


interface


uses

  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,  System.Permissions,

  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls;


type

  TForm1 = class(TForm)

    Button1: TButton;

    Button2: TButton;

    Button3: TButton;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

    procedure DisplayRationale(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);

    procedure Loacation_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray;

      const AGrantResults: TClassicPermissionStatusDynArray);

    procedure Call_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray;

      const AGrantResults: TClassicPermissionStatusDynArray);

    procedure Camera_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray;

      const AGrantResults: TClassicPermissionStatusDynArray);

    { Private declarations }

  public

    { Public declarations }

    FPermissionLoacation, FPermissionCall, FPermissionCamera : string;

  end;


var

  Form1: TForm1;


implementation


uses

{$IFDEF ANDROID}

   Androidapi.JNI.Os,

   Androidapi.Helpers,

   AndroidApi.Jni.JavaTypes,

   FMX.DialogService;

{$ENDIF}



{$R *.fmx}


procedure TForm1.FormCreate(Sender: TObject);

begin

  FPermissionLoacation := JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION );

  FPermissionCall      := JStringToString(TJManifest_permission.JavaClass.CALL_PHONE );

  FPermissionCamera    := JStringToString(TJManifest_permission.JavaClass.CAMERA );

end;




procedure TForm1.Button1Click(Sender: TObject);

begin

  PermissionsService.RequestPermissions([FPermissionLoacation], Loacation_PermissionRequestResult, DisplayRationale);

end;


procedure TForm1.Button2Click(Sender: TObject);

begin

  PermissionsService.RequestPermissions([FPermissionCall], Call_PermissionRequestResult, DisplayRationale);

end;



procedure TForm1.Button3Click(Sender: TObject);

begin

  PermissionsService.RequestPermissions([FPermissionCamera], Camera_PermissionRequestResult, DisplayRationale);

end;


procedure TForm1.DisplayRationale(Sender: TObject; const APermissions: TClassicStringDynArray; const APostRationaleProc: TProc);

var

  I: Integer;

  RationaleMsg: string;

begin

  for I := 0 to High(APermissions) do

  begin

    if APermissions[I] = FPermissionLoacation then

      RationaleMsg := RationaleMsg + 'The app needs to access the Permission Location' + SLineBreak + SLineBreak


    else if APermissions[I] = FPermissionCall then

      RationaleMsg := RationaleMsg + 'The app needs to access the Permission Call' + SLineBreak + SLineBreak


    else if APermissions[I] = FPermissionCamera then

      RationaleMsg := RationaleMsg + 'The app needs to access the Permission Camera';


  end;


  // Show an explanation to the user *asynchronously* - don't block this thread waiting for the user's response!

  // After the user sees the explanation, invoke the post-rationale routine to request the permissions

  TDialogService.ShowMessage(RationaleMsg,

    procedure(const AResult: TModalResult)

    begin

      APostRationaleProc;

    end)

end;



procedure TForm1.Loacation_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);

begin

  // 3 permissions involved: CAMERA, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE

//  if (Length(AGrantResults) = 3) and

//     (AGrantResults[0] = TPermissionStatus.Granted) and

//     (AGrantResults[1] = TPermissionStatus.Granted) and

//     (AGrantResults[2] = TPermissionStatus.Granted) then


  if ( Length(AGrantResults) = 1) and

     (AGrantResults[0] = TPermissionStatus.Granted) then

    TDialogService.ShowMessage('Location permissions OK ' )

  else

    TDialogService.ShowMessage('The required permissions are not granted');

end;



procedure TForm1.Call_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);

begin

  if ( Length(AGrantResults) = 1) and

     (AGrantResults[0] = TPermissionStatus.Granted) then

    TDialogService.ShowMessage('Call permissions OK ' )

  else

    TDialogService.ShowMessage('The required permissions are not granted');

end;


procedure TForm1.Camera_PermissionRequestResult(Sender: TObject; const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray);

begin

  if ( Length(AGrantResults) = 1) and

     (AGrantResults[0] = TPermissionStatus.Granted) then

    TDialogService.ShowMessage('Camera permissions OK ' )

  else

    TDialogService.ShowMessage('The required permissions are not granted');

end;




end.

[FMX] Firemonkey delphi android beep sound

 Uses

   Androidapi.Helpers,

   Androidapi.JNIBridge,

   Androidapi.JNI.Media,

   AndroidApi.Jni.JavaTypes,

   AndroidApi.Jni.App;


procedure BeepSound();

{$IFDEF ANDROID}

var

  AudioObj: JObject;

  Audio: JAudioManager;

{$ENDIF}

begin

{$IFDEF ANDROID}

  AudioObj:= TAndroidHelper.Activity.getSystemService( TJActivity.JavaClass.AUDIO_SERVICE);

  Audio := TJAudioManager.Wrap((AudioObj as ILocalObject).GetObjectID);

  Audio.loadSoundEffects;

  Audio.playSoundEffect( 8 );  // 0 ~ 9 

{$ENDIF}

end;


[TMS] Introduction of TAdvStringGrid function - How to link to cell and use balloon help


TAdvStringGrid 의 cell 항목에 외부링크를 연결하여 웹브라우저를 호출 할 수 있고
Grid 내부에서 특정셀로 이동하도록 하는 링크를 넣을 수 있습니다.
하단 샘플 소스와 같이 하이퍼링크 방식의 텍스트를 입력 합니다


풍선 도움말은 TAdvStringGrid 의 Balloon 옵션의 Enable를 TRUE 로  먼저 설정 해야 합니다.
옵션 항목 중 ShowCell 항목은 입력된 데이터도 풍선 도움말로 보여주므로 불 필요시 FALSE 로 지정 하면 됩니다.
AddBalloon 메소드를 사용하여 필요한 메시지를 입력 하면 됩니다.


 with AdvStringGrid1 do begin
      Cells[2, 2] := '<A href="http://www.devgear.co.kr">Click here</A><BR>for more';    // 웹페이지 연결
      Cells[2, 3] := '<A href="CELL://R8C1">Link to cell 1,8</A>';                       // 특정 셀로 이동
      Cells[1, 8] := '<A href="CELL://R3C2">Link to cell 2,3</A>';                       // 특정 셀로 이동

      AddBalloon(1,1,'Title A','Cell 1,1 is here', biError);     //   TBalloonIcon = (biNone, biInfo, biWarning, biError);
      AddBalloon(3,3,'Title B','Cell 3,3 is here', biWarning);
   end;








[TMS] TAdvStringGrid function introduction - How to specify cell item data color

 image.png

TAdvStringGrid에 입력된 데이터 종류에 따라 폰트 색상을 지정 하는 방법에 대한 샘플 입니다.

값을 양수와 음수로 구별하여 각기 다른 색상을 지정 하게 하였고 앱이 실행된 런타임 상태에서도 색상을 변경 할 수 있게 합니다.

TAdvStringGrid 의 OnGetCellColor 메소드가 사용 되었습니다.



procedure TForm1.Button1Click(Sender: TObject);

var

  i, j: Integer;

begin

  for i := 1 to AdvStringGrid1.RowCount - 1 do

    for j := 1 to AdvStringGrid1.ColCount - 1 do

      AdvStringGrid1.Ints[j, i] := Random(1000) - 500;

end;


procedure TForm1.AdvStringGrid1GetCellColor(Sender: TObject; ARow, ACol: Integer; AState: TGridDrawState; ABrush: TBrush; AFont: TFont);

begin

  if AdvStringGrid1.Cells[ACol, ARow] <> '' then

    if AdvStringGrid1.Ints[ACol, ARow] < 0 then

    begin

      ABrush.Color := ColorGrid2.BackgroundColor;

      AFont.Color := ColorGrid2.ForegroundColor;

    end

    else

    begin

      Abrush.Color := Colorgrid1.BackgroundColor;

      AFont.Color := Colorgrid1.ForegroundColor;

      AFont.Style := [fsBold];

    end;

end;


procedure TForm1.ColorGrid1Change(Sender: TObject);

begin

  AdvStringGrid1.Invalidate;

end;


procedure TForm1.FormCreate(Sender: TObject);

begin

  Button1Click(Sender);

end;



[TMS] TAdvStringGrid function introduction - csv file import and sorting

 ​




TMS 의 TAdvStringGrid 에서  LoadFromCSV 메소드를 사용하면  csv 파일을 불러 올 수 있습니다.

Grid 의 Column 과 Row 는 csv 데이터 항목 수에 맞게 자동으로 세팅 됩니다.

 

컬럼 헤드 클릭시 Sorting 명령을 수행 하기 위해서 아래와 같이 설정 힙니다.

AdvStringGrid1.SortSettings.Show := TRUE;  

Sorting 관련해서 다양한 옵션들이 제공 됩니다. 상세 기능은 세부 메뉴얼을 참고 하시기 바랍니다.


Grid Column 의 헤드 타이틀 항목을 클릭하여 soting 하기 위해서는 다음의 3가지 이벤트 메소드가 활용 됩니다.
dosort 항목을 TRUE 로 지정하면 Sorting이 가능해지며 아래 코드는 0 번 Column 은 클릭 Disable 됨을 의미 합니다.

dosort := acol > 0;   

procedure TMvForm.Button1Click(Sender: TObject);
begin
  AdvStringGrid1.LoadFromCSV( 'c:\temp\cdata.csv' );
  AdvStringGrid1.SortSettings.Show := TRUE;
  AdvStringGrid1.ColWidths[ 2 ] := 100;
end;

procedure TMvForm.AdvStringGrid1CanSort(Sender: TObject; ACol: Integer; var DoSort: Boolean);
begin
  dosort := acol > 0;

  Cursor := crHourGlass;
end;

procedure TMvForm.AdvStringGrid1ClickSort(Sender: TObject; ACol: Integer);
begin
  Cursor := crDefault;
end;


procedure TMvForm.AdvStringGrid1GetFormat(Sender: TObject; ACol: Integer; var AStyle: TSortStyle; var aPrefix, aSuffix: string);
begin
  case acol of
    1:  AStyle := ssAlphabetic;   // ssAlphanocase;
    2:  AStyle := ssNumeric;
    3:  AStyle := ssNumeric;
    4:  AStyle := ssDate;
  end;
end;