Using a TChart, on the yAxis, I have data ranging in integer value from 0 - 100,000. How can I format the label on the TChart in such a way that if the range of the current series is from 10,000-100,000 it reads on the chart as 10k, 50k, 90, 100k, etc. This is for a mobile app so the purpose of this is to conserve space on phones to maximize the chart display.
Using Delphi Seattle, FMX, developing for iOS/Android
There appears to be a number of possibilities, here is one approach using GetAxisLabel. The key for me was setting the label style to talText.
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMXTee.Engine,
FMXTee.Series, FMXTee.Procs, FMXTee.Chart;
type
TForm1 = class(TForm)
Chart1: TChart;
procedure Chart1GetAxisLabel(Sender: TChartAxis; Series: TChartSeries;
ValueIndex: Integer; var LabelText: string);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
fSeries: TPointSeries;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Chart1GetAxisLabel(Sender: TChartAxis; Series: TChartSeries;
ValueIndex: Integer; var LabelText: string);
begin
if (fSeries = Series) then
begin
LabelText := IntToStr(Round(Series.YValue[ValueIndex] / 1000)) + 'K';
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: NativeInt;
begin
fSeries := TPointSeries.Create(self);
fSeries.ParentChart := Chart1;
for i := 1 to 10 do
begin
fSeries.Add(i * 10000);
end;
Chart1.Axes.Left.LabelStyle := talText;
end;
end.
Related
I am trying to build a project which uses Mapview component with a draggable Mapmarker. The problem is that the onMarkerDrag and onMarkerDragEnd events both return the Mapmarker created MapCoordinate and not the dragged one (Marker is Moving normally on the map and Google Maps component shows map without problem - API key is working perfectly).
Here is the code:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Maps,
FMX.Controls.Presentation, FMX.StdCtrls, System.Sensors,
System.Sensors.Components, FMX.ScrollBox, FMX.Memo;
type
TForm1 = class(TForm)
MapView1: TMapView;
LocationSensor1: TLocationSensor;
Memo1: TMemo;
procedure FormShow(Sender: TObject);
procedure MapView1MarkerDrag(Marker: TMapMarker);
procedure MapView1MarkerDragEnd(Marker: TMapMarker);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Androidapi.JNI.Os,
Androidapi.JNI.JavaTypes,
Androidapi.Helpers,
System.Permissions, FMX.DialogService;
{$R *.fmx}
procedure TForm1.FormShow(Sender: TObject);
var
MapDescr: TMapMarkerDescriptor;
marker: TMapMarker;
coord: TMapCoordinate;
begin
coord := TMapCoordinate.Create(42,17);
MapDescr := TMapMarkerDescriptor.Create(coord, 'Test');
MapDescr.Draggable := True;
MapView1.AddMarker(MapDescr);
{$IF defined(Android)}
PermissionsService.RequestPermissions
([JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION)],
procedure(const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 1) and
(AGrantResults[0] = TPermissionStatus.Granted) then
{ activate or deactivate the location sensor }
begin
LocationSensor1.Active := True;
end
else
begin
LocationSensor1.Active := false;
TDialogService.ShowMessage('Location permission not granted');
end;
end);
sleep(100);
{$ENDIF}
sleep(200);
{$IF defined(Android)}
PermissionsService.RequestPermissions
([JStringToString(TJManifest_permission.JavaClass.ACCESS_LOCATION_EXTRA_COMMANDS)],
procedure(const APermissions: TArray<string>;
const AGrantResults: TArray<TPermissionStatus>)
begin
if (Length(AGrantResults) = 1) and
(AGrantResults[0] = TPermissionStatus.Granted) then
{ activate or deactivate the location sensor }
begin
LocationSensor1.Active := True;
end
else
begin
LocationSensor1.Active := false;
TDialogService.ShowMessage('Location permission not granted');
end;
end);
sleep(100);
{$ENDIF}
end;
procedure TForm1.MapView1MarkerDrag(Marker: TMapMarker);
begin
Memo1.BeginUpdate;
Memo1.Lines.Add('Dragging:'+FloatToStr(Marker.Descriptor.Position.Latitude)+'-'+FloatToStr(Marker.Descriptor.Position.Longitude));
Memo1.EndUpdate;
end;
procedure TForm1.MapView1MarkerDragEnd(Marker: TMapMarker);
begin
Memo1.BeginUpdate;
Memo1.Lines.Add('End:'+FloatToStr(Marker.Descriptor.Position.Latitude)+'-'+FloatToStr(Marker.Descriptor.Position.Longitude));
Memo1.EndUpdate;
end;
end.
After executing code on Android mobile device both event procedures returns: 42,17.
I have built the app using SDK 25.2.5 32bit and 26.1.1 32bit with the same result, i have also tried adding to manifest xml file the following:
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
without any success.
In target platforms libraries i use the default: com-google-android-gms.play-services-maps.16.1.0.dex.jar.
Thanks in advance.
I want to rearrange TListView's Items dynamically such as, I have following items:
Item #1 Apple
Item #2 Banana
Item #3 Orange
and so on.....
I want to set Orange in Item #1, is it possible?
I've used something like this in 10.2 and 10.3 not sure when the TComparer came about
Here is a unit with two basic sorters - you can change the code to do whatever in the compare function
unit MyFMXListView_ItemSorters;
interface
uses
System.Generics.Defaults
, FMX.ListView.Appearances
;
type
TMyListViewItemComparer_AscendingItemText = class( TComparer<TListViewItem> )
function Compare(const Left, Right: TListViewItem): Integer; override;
end;
TMyListViewItemComparer_DescendingItemText = class( TComparer<TListViewItem> )
function Compare(const Left, Right: TListViewItem): Integer; override;
end;
implementation
uses
sysutils;
{ TMyListViewItemComparer_Ascending }
function TMyListViewItemComparer_AscendingItemText.Compare(const Left,
Right: TListViewItem): Integer;
begin
result := CompareText(Left.Text,Right.Text);
end;
{ TMyListViewItemComparer_DescendingItemText }
function TMyListViewItemComparer_DescendingItemText.Compare(const Left,
Right: TListViewItem): Integer;
begin
result := CompareText(Right.Text,Left.Text);
end;
end.
if you use this unit in your form then all you need to do is call the TListView.Items.Sort( TMyListViewItemComparer_AscendingItemText.Create );
e.g.Basic Form
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base,
FMX.StdCtrls, FMX.Controls.Presentation, FMX.ListView;
type
TForm1 = class(TForm)
lv1: TListView;
pnlTop: TPanel;
btnAscending: TButton;
btnDescending: TButton;
procedure FormShow(Sender: TObject);
procedure btnAscendingClick(Sender: TObject);
procedure btnDescendingClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
MyFMXListView_ItemSorters
;
{$R *.fmx}
procedure TForm1.btnAscendingClick(Sender: TObject);
begin
lv1.Items.Sort( TMyListViewItemComparer_AscendingItemText.Create );
end;
procedure TForm1.btnDescendingClick(Sender: TObject);
begin
lv1.Items.Sort( TMyListViewItemComparer_DescendingItemText.Create );
end;
procedure TForm1.FormShow(Sender: TObject);
var
myTListViewItem : TListViewItem;
begin
lv1.ItemAppearance.ItemHeight := 24;
lv1.Items.Add.Text := 'Banana';
lv1.Items.Add.Text := 'Apple';
lv1.Items.Add.Text := 'Orange';
end;
Three images below ( After Create, After Ascending click and after Descending click )
I am a newbie with Firemonkey and XE3 environment.
My program does some calculations and should give feedback to user with a TeeChart component.
OnClick()
begin
while(boolContinue) do
begin
NextStep(boolContinue);
DoSomeCalculations();
UpdateTeeChart();
end;
end;
I used Application.ProcessMessage in Delphi7. In a FireMonkey application it seems to take almost a second to make a single ProcessMessage call.
What is proper way to update TChart (TLineSeries / TeeChart Lite v 2012.06.120613)?
I tryied:
- HandleMessage (works, but slow)
- process paint messages only (works, but slow)
- Invalidate (doesnt work)
- Repaint (doesnt work)
I also tryied to use threads with no success.
Edit:
Added a simple test program:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
FMXTee.Engine, FMXTee.Procs, FMXTee.Chart, FMXTee.Series;
type
TForm1 = class(TForm)
Chart1: TChart;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
var
line : TLineSeries;
ii, x1, x2 : integer;
begin
line := TLineSeries.Create(chart1);
line.ParentChart := chart1;
for ii := 1 to 100 do
begin
line.AddXY(ii, random(20));
// Do some calculations...
self.Caption := IntToStr(ii);
for x1 := 1 to 10000 do
for x2 := 1 to 1000 do
begin
end;
end;
end;
end.
Solution found!
The subject is also discussed here and solution was found there:
https://forums.embarcadero.com/message.jspa?messageID=427282
Now the charts repaints and it takes only ~2 seconds to run.
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
FMXTee.Engine, FMXTee.Procs, FMXTee.Chart, FMXTee.Series, Windows;
type MyThread = class(TThread)
protected
procedure Execute; override;
public
line : TLineSeries;
constructor Create; overload;
destructor Destroy; override;
end;
type
TForm1 = class(TForm)
Chart1: TChart;
Button1: TButton;
Label2: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
constructor MyThread.Create;
begin
inherited Create(true);
FreeOnTerminate := true;
end;
destructor MyThread.Destroy;
begin
inherited;
end;
procedure MyThread.Execute;
var
ii, x1, x2 : integer;
begin
for ii := 1 to 100 do
begin
line.AddXY(ii, random(20));
// Do some calculations...
for x1 := 1 to 10000 do
for x2 := 1 to 1000 do
begin
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MT : MyThread;
line : TLineSeries;
begin
chart1.BottomAxis.Minimum := 0;
chart1.BottomAxis.Maximum := 100;
chart1.BottomAxis.AutomaticMinimum := false;
chart1.BottomAxis.AutomaticMaximum := false;
chart1.Legend.Visible := false;
line := TLineSeries.Create(chart1);
line.ParentChart := chart1;
MT := MyThread.Create;
MT.line := line;
MT.Start;
end;
end.
I am having one Delphi XE2 project to show scrolling text. My code is as follows :
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Caption := 'This is right scrolling text ';
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
S: String;
begin
S := Label1.Caption;
S := S[Length(S)] + Copy(S, 1, Length(S) - 1);
Label1.Caption := S;
end;
end.
Using the following code the text scrolls perfectly in 2d along to Y axis.
How to scroll text in Sinusoidal Wave ?
Angus Johnson's excellent GR32_Text extension to the fine graphics32 library appears to do what you need. The demos that you can download from the link above show just the effect you are asking for. All that remains is for you to animate the text in a paint box or similar control.
I am trying to make a chessboard gui in DelphiXE4 with TRectangle & TText using unicode chess pieces (see StackOverflow Delphi chess unicode linkand drag and drop but I cannot get DND to work properly! My test project is FireMonkey FMX.
I have tried various code additions to DragDrop/DragOver Events including using Accept & Source in code but to no result.
I set dragdrop to auto on TRectangle & TText components & can get drag function but no drop function! What code do I need to enter in Events DragDrop DragOver on target TRectangle to accept the drop event? (I am very confused with this & cannot find clear instruction on Google search anywhere!)
Here is my basic test code (on Form):
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
FMX.StdCtrls, FMX.Objects;
type
TForm1 = class(TForm)
Rectangle1: TRectangle;
Rectangle2: TRectangle;
Rectangle3: TRectangle;
Rectangle4: TRectangle;
Rectangle5: TRectangle;
Rectangle6: TRectangle;
Rectangle7: TRectangle;
Rectangle8: TRectangle;
Rectangle9: TRectangle;
Text1: TText;
procedure Rectangle7DragOver(Sender: TObject; const Data: TDragObject;
const Point: TPointF; var Accept: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Rectangle7DragOver(Sender: TObject; const Data: TDragObject;
const Point: TPointF; var Accept: Boolean);
begin
if Sender is TText then
Accept := True;
end;
end.
Most grateful for help & look forward to replies-thanks
EDIT/UPDATE
Here is code from bummi:
unit Unit3;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
FMX.Objects, FMX.Edit;
type
TForm3 = class(TForm)
Rectangle1: TRectangle;
Text1: TText;
Edit1: TEdit;
procedure Rectangle1DragOver(Sender: TObject; const Data: TDragObject;
const Point: TPointF; var Accept: Boolean);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form3: TForm3;
implementation
{$R *.fmx}
procedure TForm3.Rectangle1DragOver(Sender: TObject;
const Data: TDragObject; const Point: TPointF; var Accept: Boolean);
begin
Caption := Data.Source.ClassName ;
Accept := Data.Source is TText;
end;
end.
However even with this I still cannot get my chess example to work for me! Oh dear aaargh!
You will have to Accept if the Source of then TDragObject is TText.
Accept := Data.Source is TText;
Sender would be your Rectangle7, or any component Rectangle7DragOver is assigned to.