Delphi Firemonkey TListView's Item rearrange - delphi

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 )

Related

Send Data from JavaScript to Delphi (firemonkey)

In Delphi , With below code I can send data to Javascript and it work well , but how can send data from Javascript to Delphi ?
first , I Use below code in Javascript but did not work :
JS_DELPHI._geta() ;
even below code did not work :
TMyExtension._geta() ;
I think my code in Delphi have not some essential 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.Controls.Presentation, FMX.StdCtrls, ceffmx, FMX.Edit , ceflib ,
uCEFBaseRefCounted, uCEFInterfaces, uCEFTypes, uCEFListValue, uCEFBrowser, uCEFFrame, uCEFRequest,
uCEFv8Context, uCEFv8Exception, uCEFv8StackTrace, uCEFDomNode, uCEFProcessMessage, uCEFApplicationCore;
type
TForm1 = class(TForm)
ChromiumFMX1: TChromiumFMX;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
//这里建议用class 不建议用class(TThread) 不然有些地方要报错
TMyExtension = class(TThread) // or just class, (extension code execute in thread)
public
class function _geta:string;
end;
TCustomRenderProcessHandler = class(TCefRenderProcessHandlerOwn)
protected
procedure OnWebKitInitialized; override;
end;
var
Form1: TForm1;
d : Integer ;
m : TMyExtension ;
CefRenderProcessHandler : TCustomRenderProcessHandler ;
implementation
{$R *.fmx}
{$R *.LgXhdpiPh.fmx ANDROID}
{$R *.XLgXhdpiTb.fmx ANDROID}
{$R *.SSW3.fmx ANDROID}
procedure TForm1.Button1Click(Sender: TObject);
begin
ChromiumFMX1.Load('http://localhost/index.html');
Edit1.Text := '555 ';
ShowMessage('hiiiiiiiiiiiiiiiii');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ChromiumFMX1.Browser.MainFrame.ExecuteJavaScript(' d1();',ChromiumFMX1.browser.MainFrame.GetURL, 0);
end;
class function TMyExtension._geta: string;
begin
ShowMessage('dddddddddddddddddddddddd');
Result:='salam';
end;
procedure TCustomRenderProcessHandler.OnWebKitInitialized;
begin
{$IFDEF DELPHI14_UP}
TCefRTTIExtension.Register('JS_DELPHI', TMyExtension);
{$ENDIF}
end;
initialization
CefRemoteDebuggingPort := 9000;
CefRenderProcessHandler := TCustomRenderProcessHandler.Create;
CefBrowserProcessHandler := TCefBrowserProcessHandlerOwn.Create;
end.
end.

Pointer to Control

I would like to create array of all listboxes and access them. I tried to do it using pointers, however my program crashes during runtime with error access violation at address...
type ControlsCount = 4;
type PLB = ^TListBox;
var listBoxes: array of PLB;
procedure TExport.FormCreate(Sender: TObject);
var i: word; n: integer;
begin
with FormExport do
begin
ListRowHeight := List_sex.height;
List_sex.items.add('---');
List_sex.items.add('Man');
List_sex.items.add('Woman');
List_sex.onmousemove:=ListMouseMove;
setLength(listBoxes, ControlsCount);
n := -1;
for i := 0 to ControlsCount - 1 do
if Components[i] is TWinControl then
if TWinControl(Components[i]).CanFocus then
begin
inc(n);
// mistake here: should be listBoxes[n] not listBoxes[i]
listBoxes[i] := PLB(Components[i]);
end;
realControlsCount := n;
end;
end;
procedure TExport.resetListBoxes;
var i: word;
begin
for i := 0 to realControlsCount-1 do
begin
TListBox(listBoxes[i]^).height := ListRowHeight;
end;
end;
So here I try to set the pointer of the control to listBoxes[i].
listBoxes[i] := PLB(Components[i]);
and here I try to access it:
TListBox(listBoxes[i]^).height := ListRowHeight;
this is the line where it generates error.
What am I doing wrong?
Just remove all pointer stuff and check whether control is really TListBox. Also you misused ControlsCount while accessed another list Components[i]
var listBoxes: array of TListBox;
...
for i := 0 to ControlsCount - 1 do
if Controls[i] is TListBox then //note strict constraint
listBoxes[n] := Controls[i] as TListBox;
...
listBoxes[i].height := ListRowHeight;
Aslso consider using TList<TListBox> instead of array
Regarding the answere MBo gave this is how I would use it with a TList
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, Generics.Collections,
FMX.Layouts, FMX.ListBox, FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
lst1: TListBox;
lst2: TListBox;
lst3: TListBox;
btn1: TButton;
pnl1: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
listboxes: TList<TListBox>; // Define list that will contain listboxes
implementation
{$R *.fmx}
procedure TForm1.btn1Click(Sender: TObject);
var
lstbx: TListBox;
begin
for lstbx in listboxes do
ShowMessage(lstbx.Height.ToString); Loop through all listboxes and show their height
end;
procedure TForm1.FormCreate(Sender: TObject);
var
control: TControl;
begin
listboxes := TList<TListBox>.Create; // Create the TList
for control in pnl1.Controls do
begin
if control is TListBox then
listboxes.Add(control as TListBox); // Loop through all listboxes on a panel and add then to the list if they are a listbox
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
listboxes.Free; // Free the list
end;
end.

formatting data on TChart Delphi Seattle FMX

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.

How to update TeeChart

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.

FMX form in a DLL (firemonkey/delphi)

Im trying to make a FMX form in a dll, after about 17 hours (of trying diffrent approches) i got it working, except i get a exception trying to unload the dll. I have no idea how to make it work, maybe someone could help me and point out what im doing wrong?
side note:
i cant have a FMX form in my VCL application becouse of the AA drawing, i just need it on my text while drawing on a canvas and while having a FMX form on a VCL application, i dont get that cleartype on text :( im trying to make a some sort of OSD/HUD.
Project showing my problem:
exe unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
unitLoadDLL, Winapi.GDIPOBJ;
procedure TForm1.Button1Click(Sender: TObject);
begin
showme();
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
closeme();
end;
end.
exe unitLoadDll.pas
unit unitLoadDLL;
interface
uses Windows, Dialogs;
type
TShowme = procedure();
TCloseme = procedure();
var
showme : TShowme = nil;
closeme : TCloseme = nil;
DllHandle : THandle;
implementation
initialization
if DllHandle = 0 then begin
DllHandle := LoadLibrary('C:\Users\Ja\Desktop\dupa\dll\Win32\Debug\Project1.dll');
if DllHandle > 0 then begin
#showme := GetProcAddress(DllHandle,'showme');
#closeme := GetProcAddress(DllHandle,'closeme');
end
else begin
MessageDlg('Select Image functionality is not available', mtInformation, [mbOK], 0);
end;
end;
finalization
if DLLHandle <> 0 then
FreeLibrary(DLLHandle);
end.
dll project1.dpr
library Project1;
uses
FMX.Forms,
System.SysUtils,
System.Classes,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
procedure showme(); stdcall export;
begin
TForm1.showme;
end;
procedure closeme(); stdcall export;
begin
TForm1.closeme;
end;
exports
showme, closeme;
begin
end.
dll unit1.pas
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs;
type
TForm1 = class(TForm)
Label1: TLabel;
private
{ Private declarations }
public
class procedure showme();
class procedure closeme();
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
class procedure TForm1.showme();
begin
Form1 := TForm1.Create(Application);
Form1.Show;
end;
class procedure TForm1.closeme();
begin
Form1.Free;
end;
end.
EDIT (FIX):
All answers ware helpfull, but what i've done is, that the GDI+ was shutdown BEFORE the dll unload... that appear's to be the problem.
new unitLoadDll.pas
unit unitLoadDLL;
interface
uses Windows, Dialogs;
type
TShowme = procedure();
TCloseme = procedure();
var
showme : TShowme = nil;
closeme : TCloseme = nil;
DllHandle : THandle;
function LoadLib : Boolean;
procedure UnloadLib;
implementation
function LoadLib : Boolean;
begin
if DllHandle = 0 then begin
DllHandle := LoadLibrary('C:\Users\Ja\Desktop\dupa\dll\Win32\Debug\Project1.dll');
if DllHandle > 0 then begin
#showme := GetProcAddress(DllHandle,'showme');
#closeme := GetProcAddress(DllHandle,'closeme');
end
else begin
MessageDlg('Select Image functionality is not available', mtInformation, [mbOK], 0);
end;
end;
Result := DllHandle <> 0;
end;
procedure UnloadLib;
begin
if DLLHandle <> 0 then begin
FreeLibrary(DLLHandle);
DllHandle := 0;
end;
end;
initialization
LoadLib;
finalization
UnloadLib;
end.
new unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Winapi.GDIPOBJ;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
unitLoadDLL;
procedure TForm1.Button1Click(Sender: TObject);
begin
showme();
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
closeme();
end;
end.
in unit1.pas i moved the Winapi.GDIPOBJ to "uses" just after interface directive, and it worked...
Thank you all for your answers! See you soon! very soon...
Does it help if you import sharemem on both sides?
You are not using packages, so both sides probably have an own instance all RTL state, as well as VMT tables (though that is only a problem with certain IS and AS cases). And the memory manager is RTL state :-)

Resources