Autor Téma: Kapacitní dotykový displej se chová podivně u tlačítka TSpeedButton  (Přečteno 999 krát)

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Vážená komunito,

asi opět narážím na vlastní neznalost, ale již nevím co dělat. Mám vlastní FMX komponentu - tlačítko. V jednoduchém FMX projektu vše funguje jak má, respektive pokud klikám pomocí myši, nebo aplikaci zkouším na dotykovém odporovém displeji. Jak u Windows 7, 8 i 10.

Problém nastává pouze u kapacitního displeje. Patrně je zde problém v tom, že displej podporuje multitouch a moje tlačítko si to neumí přebrat. A kde je problém? Tlačítko se má při kliknutí rozsvítit po celou dobu stisku. Jenže u tohoto kapacitního displeje se rozsvítí jen někdy. Jednou při druhém kliku, jindy při šestém. Nezáleží na síle ani délce kliku.

Vzhledem k tomu, že je to moje komponenta, rozhodl jsem se provést test s TSpeedButton komponentou. A chová se to úplně stejně. Defaultně SpeedButton po označení (výběru) svítí. Při kliku se má ještě více prosvítit. To ale nastává jen občas. Opět nezáleží na délce kliku.

U obou komponent jsem si logoval klik událost a ta vždy reaguje správně. Tj. i když se tlačítko nerozsvítí, tak click událost přijde.

Setkal se s tím někdo?

Platforma: Windows 7, 8, 10
Vývojové prostředí: Delphi Berlin

Děkuji.

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
A jak se chová udalost OnTap ?

Nebo si muzes zkusit pomoci nejak jako pri kliknuti OnClick

Kód: Delphi [Vybrat]
  1. procedure TForm18.Button1Click(Sender: TObject);
  2. var
  3.   button: TButton;
  4. begin
  5.   button := Sender AS TButton;
  6.   button.StaysPressed := True;
  7.   button.IsPressed := True;
  8.  
  9.   TThread.CreateAnonymousThread(
  10.     procedure
  11.     begin
  12.       Sleep(500);
  13.       TThread.Synchronize(nil,
  14.         procedure
  15.         begin
  16.            button.IsPressed := False;
  17.         end);
  18.      end
  19.    ).Start;
  20. end;
  21.  
Embarcadero MVP - Czech republic

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
OnTap událost přijde vždy u dotykového displeje, tj. i když se tlačítko rozsvítí i nerozsvítí. Stejně jako OnClick událost.

Pokud je tlačítko skupinové, tak vše funguje jak má. Jakmile je ale samostatné a nezůstává stisknuté po uvolnění stisku, tak zlobí grafika.

Rád bych přišel na to, proč se tak děje. Jistě bych vymyslel nějaký kód co by to dokázal vizuálně vyřešit, ale to není ono.

Napsal jsem i výrobci kapacitního displeje, jak zrušit gesta. Bohužel jejich aplikace mě nepustí do nastavení.
« Poslední změna: 15-05-2020, 14:25:45 od age.new »

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Defaultně SpeedButton po označení (výběru) svítí. Při kliku se má ještě více prosvítit. To ale nastává jen občas. Opět nezáleží na délce kliku.
Ne, ze bych neco v Delphi delal s dotykovou obrazovkou (jen v C# ve WinForms), ale jak muze dojit na touch screenu k oznaceni (vyberu) tlacitka? Na hover ani focus se tam nehraje a prvni akci je click pri doteku na tlacitko. Ta tlacitka ve WinForms delal kolega a ja uz si to nepamatuju, jak to bylo udelany a ten projekt u sebe vubec nemam, takze se nepodivam, ale co me ted napadat, tak bych se zasade ridil OnMouseDown/OnMouseUp a nejak se zkusil vyporadat s dblclickem. Jak se presne chova OnTap v Delphi nevim.

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Defaultně SpeedButton po označení (výběru) svítí. Při kliku se má ještě více prosvítit. To ale nastává jen občas. Opět nezáleží na délce kliku.
Ne, ze bych neco v Delphi delal s dotykovou obrazovkou (jen v C# ve WinForms), ale jak muze dojit na touch screenu k oznaceni (vyberu) tlacitka? Na hover ani focus se tam nehraje a prvni akci je click pri doteku na tlacitko. Ta tlacitka ve WinForms delal kolega a ja uz si to nepamatuju, jak to bylo udelany a ten projekt u sebe vubec nemam, takze se nepodivam, ale co me ted napadat, tak bych se zasade ridil OnMouseDown/OnMouseUp a nejak se zkusil vyporadat s dblclickem. Jak se presne chova OnTap v Delphi nevim.

No některá zařízení s kapacitním displejem umožnují detekovat sílu stisku, ale pochybuji, že umí Windows. Nebo délku stisku, což je častejší a obecně používanější a FMX to myslím tak bere - resp. chování některých komponent (interně se hodně používají časovače) to velmi napovídá , takže klidně může lehký stisk označit a delší stisk stisknout.
Jelikož poslední dobou hodně s FMX pracuji, tak musím říct že mne některé věci překvapují a v některých oblastech hodně tomu přicházím na chut.

Takže myšlenka, že první akce je click nemusí být vůbec správná.

Každopadně OnTap - Occurs when a user taps the control using a finger or a similar device (not a mouse) a je vyvolán ještě před click a ve FMX je celkem dost použivána, hlavně na mobilních zařízeních.


Embarcadero MVP - Czech republic

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
No některá zařízení s kapacitním displejem umožnují detekovat sílu stisku, ale pochybuji, že umí Windows.
No nazdar... Doufam, ze to nikoho nenapadne pouzit v mobilech nebo autoradiich - uz dneska je to UI navrzene pro detske prstiky a nektere veci se s tim skoro nedaji udelat :-(

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
No některá zařízení s kapacitním displejem umožnují detekovat sílu stisku, ale pochybuji, že umí Windows.
No nazdar... Doufam, ze to nikoho nenapadne pouzit v mobilech nebo autoradiich - uz dneska je to UI navrzene pro detske prstiky a nektere veci se s tim skoro nedaji udelat :-(

On to umi iPhone 6s a novější (tj. 5 let zpátky), takže to není žádná raketová technologie :-)
Embarcadero MVP - Czech republic

Offline raul

  • Hrdina
  • ****
  • Příspěvků: 347
  • Karma: 15
    • Verze Delphi: FPC :D
Delali jsme aplikaci v Cordove (ex Phonegap) tzn js a html zkompilovane do aplikace. Na samsung tabletech ale nebylo mozne rozbehat eventy klikani apod. Nekteri lide nebyli schopni kliknout, nekteri v pohode. Kolega nakonec udelal nejakej tester, kterej vypisoval log vsech eventu a byl to vicemene jen bordel, ktery nebyl ani podobny jinym zarizenim. Nekdo na to dokonce psal patch, ktery ale opet fungoval nejak. Nakonec jsme to vyresili koupenim lenova, ktere tim netrpelo vubec. Mozna je tohle problem uplne jiny, ale mozna by to mohlo souviset. Zkusil bych tedy i jine zarizeni a posleze prozkoumaval hloubeji. (Btw efekt stisku tlacitka se objevil i na tom samsungu vzdy, jen to proste obcas dostalo event tap, click, a mix dalsich.)
Lazarus 1.6.3:), FPC, Intel/Arm, Windows/Linux

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
On to umi iPhone 6s a novější (tj. 5 let zpátky), takže to není žádná raketová technologie :-)
Tak iPhone bych nechtel ani zadarmo, leda bych se ho obratem ruky zbavil :-) Ale on s tim snad koketoval jeden cas i Android. Ale udajne lonsky model iPhonu uz to zase nema/nepouziva a misto toho reaguje na delku doteku. Jedina funkce, kde by mi to prislo prirozene, je nekde v malovani stetcem, ze by to reagovalo na tlak a prizpusobovalo mu sirku cary, ale jinak mi to prijde jako dost velka ptakovina.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Tak po důkladnějším logování jsem přišel na toto:

- když zmáčknu krátce, tak přijdou všechny události click, down, up
- když zmáčknu dlouze, tak události click, down, up přijdou až poté, co sundám prst

v obou výše uvedených případech se tlačítko nerozsvítí, i když kódem to projde.

- když zmáčknu dlouze a zároveň trochu prstem hnu (o pár pixelů), tak se tlačítko rozsvítí. Přijde totiž událost click, down a až prst uvolním, tak poté přijde událost up.

a zde jedna perlička. Při pokusech s rychlým stiskem a potažením prstu po tlačítku se cca 1x z deseti případů podaří tlačítko nechat rozsvícené i po uvolnění prstu. Přijdou jen události click a down. Událost up nenastane.

... příčina je patrně v tom, jak kapacitní displej posílá události např. kvůli gestům. U odporového displeje bez gest vše funguje jak má.

Možná mám nějakou hloupost v kódu při obsluze dědičnosti. Komponentu tlačítka jsem přepsal, vyházel co šlo a vznikla z toho velmi jednoduchá komponenta. Přijde Vám, že je něco špatně s obsluhou up / down stavů?

Kód: Delphi [Vybrat]
  1. unit ImageButton;
  2.  
  3. interface
  4.  
  5. uses
  6.   FMX.Objects, FMX.Controls, FMX.Types, FMX.Layouts, FMX.Effects, System.UITypes, System.SysUtils, System.Classes;
  7.  
  8. type
  9.   TUpDownState = (udsUP, udsDOWN);
  10.   TEnableState = (esENABLED, esDISABLED);
  11.  
  12.   TImageButton = class(TLayout)
  13.   private
  14.     FUpDownState: TUpDownState;
  15.     FEnableState: TEnableState;
  16.     FAllowAllUp: boolean;
  17.     FGroupIndex: integer;
  18.  
  19.     FEnabledUpImage: TImage;
  20.     FEnabledDownImage: TImage;
  21.     FDisabledUpImage: TImage;
  22.     FDisabledDownImage: TImage;
  23.  
  24.     FEnabledUpText: TText;
  25.     FEnabledDownText: TText;
  26.     FDisabledUpText: TText;
  27.     FDisabledDownText: TText;
  28.  
  29.     FShowEnabledUpImage: boolean;
  30.     FShowEnabledDownImage: boolean;
  31.     FShowEnabledUpText: boolean;
  32.     FShowEnabledDownText: boolean;
  33.  
  34.     FShowDisabledUpImage: boolean;
  35.     FShowDisabledDownImage: boolean;
  36.     FShowDisabledUpText: boolean;
  37.     FShowDisabledDownText: boolean;
  38.  
  39.     IsClicked: boolean;
  40.  
  41.     procedure ChangeUpDownState(const Value: TUpDownState); overload;
  42.     procedure ChangeEnableState(const Value: TEnableState); overload;
  43.     procedure SetAllowAllUp(const Value: boolean);
  44.     procedure SetGroupIndex(const Value: integer);
  45.  
  46.     procedure ChangeShowEnabledUpImage(const Value: boolean);
  47.     procedure ChangeShowEnabledDownImage(const Value: boolean);
  48.     procedure ChangeShowEnabledUpText(const Value: boolean);
  49.     procedure ChangeShowEnabledDownText(const Value: boolean);
  50.  
  51.     procedure ChangeShowDisabledUpImage(const Value: boolean);
  52.     procedure ChangeShowDisabledDownImage(const Value: boolean);
  53.     procedure ChangeShowDisabledUpText(const Value: boolean);
  54.     procedure ChangeShowDisabledDownText(const Value: boolean);
  55.  
  56.     procedure Update;
  57.   public
  58.     constructor Create(AOwner: TComponent); override;
  59.     destructor  Destroy; override;
  60.  
  61.     procedure Click; override;
  62.     procedure ChangeUpDownState; overload;
  63.     procedure ChangeEnableState; overload;
  64.   protected
  65.     procedure SetName(const Value: TComponentName); override;
  66.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
  67.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
  68.     procedure DoMouseLeave; override;
  69.   published
  70.     property UpDownState: TUpDownState read FUpDownState write ChangeUpDownState;
  71.     property EnableState: TEnableState read FEnableState write ChangeEnableState;
  72.     property AllowAllUp: boolean read FAllowAllUp write SetAllowAllUp;
  73.     property GroupIndex: integer read FGroupIndex write SetGroupIndex;
  74.  
  75.     property EnabledUpImage: TImage read FEnabledUpImage;
  76.     property EnabledDownImage: TImage read FEnabledDownImage;
  77.     property EnabledUpText: TText read FEnabledUpText;
  78.     property EnabledDownText: TText read FEnabledDownText;
  79.  
  80.     property DisabledUpImage: TImage read FDisabledUpImage;
  81.     property DisabledDownImage: TImage read FDisabledDownImage;
  82.     property DisabledUpText: TText read FDisabledUpText;
  83.     property DisabledDownText: TText read FDisabledDownText;
  84.  
  85.     property ShowEnabledUpImage: boolean read FShowEnabledUpImage write ChangeShowEnabledUpImage;
  86.     property ShowEnabledDownImage: boolean read FShowEnabledDownImage write ChangeShowEnabledDownImage;
  87.     property ShowEnabledUpText: boolean read FShowEnabledUpText write ChangeShowEnabledUpText;
  88.     property ShowEnabledDownText: boolean read FShowEnabledDownText write ChangeShowEnabledDownText;
  89.  
  90.     property ShowDisabledUpImage: boolean read FShowDisabledUpImage write ChangeShowDisabledUpImage;
  91.     property ShowDisabledDownImage: boolean read FShowDisabledDownImage write ChangeShowDisabledDownImage;
  92.     property ShowDisabledUpText: boolean read FShowDisabledUpText write ChangeShowDisabledUpText;
  93.     property ShowDisabledDownText: boolean read FShowDisabledDownText write ChangeShowDisabledDownText;
  94.   end;
  95.  
  96. procedure Register;
  97.  
  98. implementation
  99.  
  100. procedure Register;
  101. begin
  102.   RegisterComponents('My FMX Components', [TImageButton]);
  103. end;
  104.  
  105. constructor TImageButton.Create(AOwner: TComponent);
  106. begin
  107.   inherited Create(AOwner);
  108.  
  109.   // default
  110.   HitTest      := true;
  111.   FUpDownState := udsUP;
  112.   fEnableState := esENABLED;
  113.   FAllowAllUp  := false;
  114.   FGroupIndex  := 0;
  115.   IsClicked    := false;
  116.  
  117.   FEnabledUpImage         := TImage.Create(Self);
  118.   FEnabledUpImage.Parent  := Self;
  119.   FEnabledUpImage.Name    := Self.Name + '_EnabledUpImage';
  120.   FEnabledUpImage.Align   := TAlignLayout.Center;
  121.   FEnabledUpImage.HitTest := false;
  122.   FEnabledUpImage.Locked  := true;
  123.   FEnabledUpImage.Stored  := false;
  124.   FEnabledUpImage.SetSubComponent(true);
  125.  
  126.   FEnabledDownImage         := TImage.Create(Self);
  127.   FEnabledDownImage.Parent  := Self;
  128.   FEnabledDownImage.Name    := Self.Name + '_EnabledDownImage';
  129.   FEnabledDownImage.Align   := TAlignLayout.Center;
  130.   FEnabledDownImage.HitTest := false;
  131.   FEnabledDownImage.Locked  := true;
  132.   FEnabledDownImage.Stored  := false;
  133.   FEnabledDownImage.SetSubComponent(true);
  134.  
  135.   FEnabledUpText         := TText.Create(Self);
  136.   FEnabledUpText.Parent  := Self;
  137.   FEnabledUpText.Name    := Self.Name + '_EnabledUpText';
  138.   FEnabledUpText.HitTest := false;
  139.   FEnabledUpText.Locked  := true;
  140.   FEnabledUpText.Stored  := false;
  141.   FEnabledUpText.SetSubComponent(true);
  142.  
  143.   FEnabledDownText         := TText.Create(Self);
  144.   FEnabledDownText.Parent  := Self;
  145.   FEnabledDownText.Name    := Self.Name + '_EnabledDownText';
  146.   FEnabledDownText.HitTest := false;
  147.   FEnabledDownText.Locked  := true;
  148.   FEnabledDownText.Stored  := false;
  149.   FEnabledDownText.SetSubComponent(true);
  150.  
  151.   FDisabledUpImage         := TImage.Create(Self);
  152.   FDisabledUpImage.Parent  := Self;
  153.   FDisabledUpImage.Name    := Self.Name + '_DisabledUpImage';
  154.   FDisabledUpImage.Align   := TAlignLayout.Center;
  155.   FDisabledUpImage.HitTest := false;
  156.   FDisabledUpImage.Locked  := true;
  157.   FDisabledUpImage.Stored  := false;
  158.   FDisabledUpImage.SetSubComponent(true);
  159.  
  160.   FDisabledDownImage         := TImage.Create(Self);
  161.   FDisabledDownImage.Parent  := Self;
  162.   FDisabledDownImage.Name    := Self.Name + '_DisabledDownImage';
  163.   FDisabledDownImage.Align   := TAlignLayout.Center;
  164.   FDisabledDownImage.HitTest := false;
  165.   FDisabledDownImage.Locked  := true;
  166.   FDisabledDownImage.Stored  := false;
  167.   FDisabledDownImage.SetSubComponent(true);
  168.  
  169.   FDisabledUpText         := TText.Create(Self);
  170.   FDisabledUpText.Parent  := Self;
  171.   FDisabledUpText.Name    := Self.Name + '_DisabledUpText';
  172.   FDisabledUpText.HitTest := false;
  173.   FDisabledUpText.Locked  := true;
  174.   FDisabledUpText.Visible := false;
  175.   FDisabledUpText.Stored  := false;
  176.   FDisabledUpText.SetSubComponent(true);
  177.  
  178.   FDisabledDownText         := TText.Create(Self);
  179.   FDisabledDownText.Parent  := Self;
  180.   FDisabledDownText.Name    := Self.Name + '_DisabledDownText';
  181.   FDisabledDownText.HitTest := false;
  182.   FDisabledDownText.Locked  := true;
  183.   FDisabledDownText.Visible := false;
  184.   FDisabledDownText.Stored  := false;
  185.   FDisabledDownText.SetSubComponent(true);
  186.  
  187.   FShowEnabledUpImage   := true;
  188.   FShowEnabledDownImage := true;
  189.   FShowEnabledUpText    := false;
  190.   FShowEnabledDownText  := false;
  191.  
  192.   FShowDisabledUpImage   := true;
  193.   FShowDisabledDownImage := true;
  194.   FShowDisabledUpText    := false;
  195.   FShowDisabledDownText  := false;
  196. end;
  197.  
  198. destructor TImageButton.Destroy;
  199. begin
  200.   if Assigned(FEnabledUpImage)   then FEnabledUpImage.Free;
  201.   if Assigned(FEnabledDownImage) then FEnabledDownImage.Free;
  202.   if Assigned(FEnabledUpText)    then FEnabledUpText.Free;
  203.   if Assigned(FEnabledDownText)  then FEnabledDownText.Free;
  204.  
  205.   if Assigned(FDisabledUpImage)   then FDisabledUpImage.Free;
  206.   if Assigned(FDisabledDownImage) then FDisabledDownImage.Free;
  207.   if Assigned(FDisabledUpText)    then FDisabledUpText.Free;
  208.   if Assigned(FDisabledDownText)  then FDisabledDownText.Free;
  209.  
  210.   inherited;
  211. end;
  212.  
  213. procedure TImageButton.SetName(const Value: TComponentName);
  214. begin
  215.   inherited SetName(Value);
  216.  
  217.   FEnabledUpImage.Name   := Value + '_EnabledUpImage';
  218.   FEnabledDownImage.Name := Value + '_EnabledDownImage';
  219.   FEnabledUpText.Name    := Value + '_EnabledUpText';
  220.   FEnabledDownText.Name  := Value + '_EnabledDownText';
  221.  
  222.   FDisabledUpImage.Name   := Value + '_DisabledUpImage';
  223.   FDisabledDownImage.Name := Value + '_DisabledDownImage';
  224.   FDisabledUpText.Name    := Value + '_DisabledUpText';
  225.   FDisabledDownText.Name  := Value + '_DisabledDownText';
  226. end;
  227.  
  228. procedure TImageButton.Click;
  229. begin
  230.   if IsClicked then inherited;
  231.   IsClicked := false;
  232. end;
  233.  
  234. procedure TImageButton.ChangeUpDownState;
  235. begin
  236.   case FUpDownState of
  237.     udsUP:   ChangeUpDownState(udsDOWN);
  238.     udsDOWN: ChangeUpDownState(udsUP);
  239.   end;
  240. end;
  241.  
  242. procedure TImageButton.ChangeEnableState;
  243. begin
  244.   case FEnableState of
  245.     esENABLED:  ChangeEnableState(esDISABLED);
  246.     esDISABLED: ChangeEnableState(esENABLED);
  247.   end;
  248. end;
  249.  
  250. procedure TImageButton.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  251. begin
  252.   if Button <> TMouseButton.mbLeft then exit;
  253.   if FEnableState = esDISABLED then exit;
  254.   if (FGroupIndex <> 0) and (FUpDownState = udsDOWN) and not FAllowAllUp then exit;
  255.  
  256.   IsClicked := true;
  257.   ChangeUpDownState;
  258.   Click;
  259.  
  260.   inherited;
  261. end;
  262.  
  263. procedure TImageButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  264. begin
  265.   if (FGroupIndex = 0) and (FUpDownState = udsDOWN) then ChangeUpDownState;
  266.  
  267.   inherited;
  268. end;
  269.  
  270. procedure TImageButton.DoMouseLeave;
  271. begin
  272.   if (FGroupIndex = 0) and (FUpDownState = udsDOWN) then ChangeUpDownState;
  273.  
  274.   inherited;
  275. end;
  276.  
  277. procedure TImageButton.ChangeUpDownState(const Value: TUpDownState);
  278. var
  279.   i: integer;
  280.   b: boolean;
  281. begin
  282.   if FUpDownState = Value then exit;
  283.  
  284.   // pokud jsem jediný down tak nelze jít na up
  285.   if (FGroupIndex <> 0) and not FAllowAllUp and (Value = udsUP) then
  286.   begin
  287.     b := true;
  288.     for i := 0 to Parent.ChildrenCount - 1 do
  289.       if Parent.Children[i] is TImageButton then
  290.         if TImageButton(Parent.Children[i]) <> Self then
  291.           if TImageButton(Parent.Children[i]).GroupIndex = FGroupIndex then
  292.             if TImageButton(Parent.Children[i]).UpDownState = udsDOWN then
  293.             begin
  294.               b := false;
  295.               break;
  296.             end;
  297.     if b then exit;
  298.   end;
  299.  
  300.   FUpDownState := Value;
  301.  
  302.   // změna stavu u zbylých tlačítek v groupě
  303.   if (FGroupIndex <> 0) and (FUpDownState = udsDOWN) then
  304.     for i := 0 to Parent.ChildrenCount - 1 do
  305.       if Parent.Children[i] is TImageButton then
  306.         if TImageButton(Parent.Children[i]) <> Self then
  307.           if TImageButton(Parent.Children[i]).GroupIndex = FGroupIndex then
  308.             if TImageButton(Parent.Children[i]).UpDownState = udsDOWN then
  309.               TImageButton(Parent.Children[i]).ChangeUpDownState;
  310.  
  311.   Update;
  312. end;
  313.  
  314. procedure TImageButton.ChangeEnableState(const Value: TEnableState);
  315. begin
  316.   if FEnableState = Value then exit;
  317.  
  318.   FEnableState := Value;
  319.  
  320.   Update;
  321. end;
  322.  
  323. procedure TImageButton.SetAllowAllUp(const Value: boolean);
  324. var
  325.   i: integer;
  326. begin
  327.   if FAllowAllUp = Value then exit;
  328.   FAllowAllUp := Value;
  329.  
  330.   // změna AllowAllUp u všech tlačíte v groupě
  331.   if FGroupIndex <> 0 then
  332.     for i := 0 to Parent.ChildrenCount - 1 do
  333.       if Parent.Children[i] is TImageButton then
  334.         if TImageButton(Parent.Children[i]) <> Self then
  335.           TImageButton(Parent.Children[i]).SetAllowAllUp(FAllowAllUp);
  336.  
  337.   Update;
  338. end;
  339.  
  340. procedure TImageButton.SetGroupIndex(const Value: integer);
  341. var
  342.   i: integer;
  343. begin
  344.   if FGroupIndex = Value then exit;
  345.   FGroupIndex := Value;
  346.  
  347.   // změna AllowAllUp u všech tlačíte v groupě
  348.   if FGroupIndex <> 0 then
  349.     for i := 0 to Parent.ChildrenCount - 1 do
  350.       if Parent.Children[i] is TImageButton then
  351.         if TImageButton(Parent.Children[i]) <> Self then
  352.           TImageButton(Parent.Children[i]).SetAllowAllUp(FAllowAllUp);
  353.  
  354.   Update;
  355. end;
  356.  
  357. procedure TImageButton.ChangeShowEnabledUpImage(const Value: boolean);
  358. begin
  359.   if FShowEnabledUpImage = Value then exit;
  360.   FShowEnabledUpImage := Value;
  361.  
  362.   Update;
  363. end;
  364.  
  365. procedure TImageButton.ChangeShowEnabledDownImage(const Value: boolean);
  366. begin
  367.   if FShowEnabledDownImage = Value then exit;
  368.   FShowEnabledDownImage := Value;
  369.  
  370.   Update;
  371. end;
  372.  
  373. procedure TImageButton.ChangeShowEnabledUpText(const Value: boolean);
  374. begin
  375.   if FShowEnabledUpText = Value then exit;
  376.   FShowEnabledUpText := Value;
  377.  
  378.   Update;
  379. end;
  380.  
  381. procedure TImageButton.ChangeShowEnabledDownText(const Value: boolean);
  382. begin
  383.   if FShowEnabledDownText = Value then exit;
  384.   FShowEnabledDownText := Value;
  385.  
  386.   Update;
  387. end;
  388.  
  389. procedure TImageButton.ChangeShowDisabledUpImage(const Value: boolean);
  390. begin
  391.   if FShowDisabledUpImage = Value then exit;
  392.   FShowDisabledUpImage := Value;
  393.  
  394.   Update;
  395. end;
  396.  
  397. procedure TImageButton.ChangeShowDisabledDownImage(const Value: boolean);
  398. begin
  399.   if FShowDisabledDownImage = Value then exit;
  400.   FShowDisabledDownImage := Value;
  401.  
  402.   Update;
  403. end;
  404.  
  405. procedure TImageButton.ChangeShowDisabledUpText(const Value: boolean);
  406. begin
  407.   if FShowDisabledUpText = Value then exit;
  408.   FShowDisabledUpText := Value;
  409.  
  410.   Update;
  411. end;
  412.  
  413. procedure TImageButton.ChangeShowDisabledDownText(const Value: boolean);
  414. begin
  415.   if FShowDisabledDownText = Value then exit;
  416.   FShowDisabledDownText := Value;
  417.  
  418.   Update;
  419. end;
  420.  
  421. procedure TImageButton.Update;
  422. begin
  423.   case FEnableState of
  424.     esENABLED:
  425.       case FUpDownState of
  426.         udsUP: begin
  427.           FDisabledUpImage.Visible   := false;
  428.           FDisabledDownImage.Visible := false;
  429.           FDisabledUpText.Visible    := false;
  430.           FDisabledDownText.Visible  := false;
  431.  
  432.           FEnabledUpImage.Visible   := FShowEnabledUpImage;
  433.           FEnabledDownImage.Visible := false;
  434.           FEnabledUpText.Visible    := FShowEnabledUpText;
  435.           FEnabledDownText.Visible  := false;
  436.  
  437.           FEnabledUpImage.BringToFront;
  438.           FEnabledUpText.BringToFront;
  439.         end;
  440.         udsDOWN: begin
  441.           FDisabledUpImage.Visible   := false;
  442.           FDisabledDownImage.Visible := false;
  443.           FDisabledUpText.Visible    := false;
  444.           FDisabledDownText.Visible  := false;
  445.  
  446.           FEnabledUpImage.Visible   := false;
  447.           FEnabledDownImage.Visible := FShowEnabledDownImage;
  448.           FEnabledUpText.Visible    := false;
  449.           FEnabledDownText.Visible  := FShowEnabledDownText;
  450.  
  451.           FEnabledDownImage.BringToFront;
  452.           FEnabledDownText.BringToFront;
  453.         end;
  454.       end;
  455.     esDISABLED:
  456.       case FUpDownState of
  457.         udsUP: begin
  458.           FEnabledUpImage.Visible   := false;
  459.           FEnabledDownImage.Visible := false;
  460.           FEnabledUpText.Visible    := false;
  461.           FEnabledDownText.Visible  := false;
  462.  
  463.           FDisabledUpImage.Visible   := FShowDisabledUpImage;
  464.           FDisabledDownImage.Visible := false;
  465.           FDisabledUpText.Visible    := FShowDisabledUpText;
  466.           FDisabledDownText.Visible  := false;
  467.  
  468.           FDisabledUpImage.BringToFront;
  469.           FDisabledUpText.BringToFront;
  470.         end;
  471.         udsDOWN: begin
  472.           FEnabledUpImage.Visible   := false;
  473.           FEnabledDownImage.Visible := false;
  474.           FEnabledUpText.Visible    := false;
  475.           FEnabledDownText.Visible  := false;
  476.  
  477.           FDisabledUpImage.Visible   := false;
  478.           FDisabledDownImage.Visible := FShowDisabledDownImage;
  479.           FDisabledUpText.Visible    := false;
  480.           FDisabledDownText.Visible  := FShowDisabledDownText;
  481.  
  482.           FDisabledDownImage.BringToFront;
  483.           FDisabledDownText.BringToFront;
  484.         end;
  485.       end;
  486.   end;
  487.  
  488.   inherited;
  489. end;
  490.  
  491. end.
  492.  

Jedná se o TLayout, který má 4 TImage jako subkomponenty pro stavy 1) enabled up 2) enabled down 3) disabled up 4) disabled down. Jednodušeji kód už snad ani nejde napsat.

Co mě ale trochu mate je použití inherited u Click, MouseDown a MouseUp. Nemůže se to zároveň nějak blokovat v případě, že přijdou události click, down a up naráz?

Děkuji.

 

Offline raul

  • Hrdina
  • ****
  • Příspěvků: 347
  • Karma: 15
    • Verze Delphi: FPC :D
To co popisujes je dost podobne vyse zminenemu prikladu s js a samsungem. Co je to za tablet ? Dela to i jinde ?
Lazarus 1.6.3:), FPC, Intel/Arm, Windows/Linux

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Je to průmyslový dotykový panel na principu kapacitní vrstvy. Od jiného výrobce máme podobný s odporovou vrstvou a ten to nedělá.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Nejde nějak v Delphi nastavit, aby dotyk prstem bral jako kliknutí myši? Bohužel se u multi-touch displeje chová klik prstem jinak než klik myší. Potřeboval bych nějak nastavit, aby byl dotyk prstem stejný jako obyčejná myš... :(

Pokud si chcete sami otestovat:

1) umístěte na FMX formulář TSpeedButton tlačítko a TMemo
2) na eventy tlačítka pro Click, MouseDown, MouseUp dejte logování do TMemo
3) spusťte aplikaci a klikejte na tlačítko nejdříve myší a poté na dotykové obrazovce - eventy budou přicházet jinak.

Např. u dotykové obrazovky, když kliknete na tlačítko, tak nepřijde žádný event! Nerozumím tomu, proč klik prstem nevyvolá down event. Základní funkčnost je nefunkční. Třeba se to dá nějak vypnout / zapnout / změnit?

Pokud má někdo nějaký nápad, rád jej vyzkouším.

Děkuji.
 

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině

Pokud má někdo nějaký nápad, rád jej vyzkouším.


A co ten OnTap?
Embarcadero MVP - Czech republic

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
OnTap trpí stejnými problémy:

1) když se provede prstem klik a hned uvolní, tak přijde před Down eventem
2) když se provede prstem klik a neuvolní, tak OnTap event nepřijde nikdy, ani po pohybu prstem nebo uvolnění

Asi to už někdo řešil zde: https://stackoverflow.com/questions/50465050/start-touch-and-finish-touch-event-delphi

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Na stackoverflow stránce píše jeden uživatel, že to vyřešil takto:

It turns out that the MouseDown events were sent but the Pressed property of TControl in FMX returns false even if you are touching the screen. The Pressed property reads only the mouse buttons down. After implementing myPressed property by MouseDown and MouseUp, myPressed was returning true even if you touch the screen and then remove the touch.

Rozumíte někdo tomu, co udělal?

Díky.

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
OnTap trpí stejnými problémy:

1) když se provede prstem klik a hned uvolní, tak přijde před Down eventem
2) když se provede prstem klik a neuvolní, tak OnTap event nepřijde nikdy, ani po pohybu prstem nebo uvolnění

Asi to už někdo řešil zde: https://stackoverflow.com/questions/50465050/start-touch-and-finish-touch-event-delphi


Ale to spravne chovani, lehky stisk (Tap) se zavola aby jsi na to mohl reagovat, treba provest skrolovani bez toho aby se provedl vyber.
Embarcadero MVP - Czech republic

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
It turns out that the MouseDown events were sent but the Pressed property of TControl in FMX returns false even if you are touching the screen. The Pressed property reads only the mouse buttons down. After implementing myPressed property by MouseDown and MouseUp, myPressed was returning true even if you touch the screen and then remove the touch.
Jo. Chtel pouzit TControl.Pressed a nefungovalo mu to. Nakonec prisel na to, ze se mu MouseDown objevi, ale hodnota Pressed tomu neodpovida, tak is udelal vlastni Pressed (MyPressed) a jeho hodnotu odvodil od MouseDown/Up.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Ale to spravne chovani, lehky stisk (Tap) se zavola aby jsi na to mohl reagovat, treba provest skrolovani bez toho aby se provedl vyber.

Dobře. Tak co mám dělat, když chci zachytit nějakou libovolnou událost na stisk prstem bez následného pohybu a uvolnění. Prostě jen stisku a budu držet prst hodinu na tlačítku. Jakou událostí mám toto zachytiti, když žádná z diskutovaných nepřijde?


Jo. Chtel pouzit TControl.Pressed a nefungovalo mu to. Nakonec prisel na to, ze se mu MouseDown objevi, ale hodnota Pressed tomu neodpovida, tak is udelal vlastni Pressed (MyPressed) a jeho hodnotu odvodil od MouseDown/Up.

Tak to mě MouseDown event nechodí, resp. po stisku prstu bez uvolnění nepřijde nic. :(

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Tak to mě MouseDown event nechodí, resp. po stisku prstu bez uvolnění nepřijde nic. :(
Tak to mas blby...

Zkus se podivat na ten zminovany TGestureManager a ev. si dat bkpt/trasovat zdrojovky pri zapnutem Debug DCU.
Ja o tom nic nevim, ani nic vedet nechci :-)

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Pro lepší debug jsem si kód z komponenty vložil přímo do zdrojáku. Nenašel jsem nic, jak zachytit obyčejný stisk prstem (bez pohybu a nechat stisknutý) na kapacitní dotykové obrazovce.

Po vyřešení tohoto problému pak bude zbývat ještě vyřešit proč tlačítko neproblikne, respektive problikne jen někdy.

Vše to ale souvisí s kapacitní dotykovou vrstvou, tj. která umožňuje gesta.

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2697
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Pro lepší debug jsem si kód z komponenty vložil přímo do zdrojáku. Nenašel jsem nic, jak zachytit obyčejný stisk prstem (bez pohybu a nechat stisknutý) na kapacitní dotykové obrazovce.

Po vyřešení tohoto problému pak bude zbývat ještě vyřešit proč tlačítko neproblikne, respektive problikne jen někdy.

Vše to ale souvisí s kapacitní dotykovou vrstvou, tj. která umožňuje gesta.

A zavola se ti OnTap? V tom pripade na OnTap dej stejnou udalost jako na OnClick.
Embarcadero MVP - Czech republic

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Ne OnTap v tomto případě NIKDY nepřijde. Ani po uvolnění prstu.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
A to se mi ještě povede udělat rychlý klik prstem (mouse down + click event) bez up eventu.

Prostě v Delphi je něco špatně co neumí správně obsluhovat multitouch displeje. 

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Tak po přidání AutoCapture := true; do komponenty tlačítka zmizel problém s chybějícím MouseUp eventem, který nastal občas při rychlém stisku s potažením prstu. Od té doby se mi to nepodařilo zopakovat.

Zbývá chybějící MouseDown event, který nikdy nepřijde v momentě, když se stiskne prstem dotyková obrazovka. Napadlo mě nějak zachytit message s dotykem, zjistit komponentu pod prstem a poslat ji MouseDown signál. To samé pak i s MouseUp. U Windows bych použil WindowsMessage. U FMX to musím vygooglovat...

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 2914
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
A dival ses, jak mas nastavena napr. standard gestures (http://docwiki.embarcadero.com/Libraries/Rio/en/FMX.Types.TStandardGestures) aj. v TouchManageru ev. GestureManageru?

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Gesta, tj. GestureManager nepoužívám. Pokud vím, tak gesta přicházejí až po jejich dokončení a to by bylo stejně pozdě - navíc se mi nikdy nepodařilo je rozběhat.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Asi jsem přišel na způsob, jak problém s Mouse eventy na touch displeji vyřešit. Hlavní formulář má event OnTouch, který registruje i to první stisknutí. Takže na tuto Touch akci Down a Up zavolám v tlačítku, ležící v místě pod kurzorem (využívám ObjectAtPoint), patřičnou obsluhu. Zatím to vypadá dobře, akorát musím předělat samotné tlačítko tak, aby nedocházelo např. k dvojitému zavolání stisku a podobně.


Kdo by řekl, že obyčejný stisk na touch displeji vyvolá tolik komplikací. Pak mi nikdo nechce veřit, s čím vším se u Firemonkey setkávám :(
« Poslední změna: 19-05-2020, 15:05:16 od age.new »

Offline chaloup

  • Plnoletý
  • ***
  • Příspěvků: 101
  • Karma: 11
    • Verze Delphi: Delphi 10.2
Klasické aplikace windows se chovají normálně? Když uděláš VCL aplikaci, tak se to chová stejně blbě jako FMX? Když jsem si hrál s FMX na androidu, tak jsem vysledoval, že se to chovalo jinak na různejch verzích Androidu, speciálně na Samsung telefonech. Stisknutí tlačítka bez efektů, tlačítko zůstávalo jakoby stisknutý...
Jestli jsem si dobře všimnul, používáš Berlin, kterej není úplně novej, zkus se s někým domluvit kdo má poslední verzi (třeba Radek) aby ti přeložil nějaký demo a otestovat jestli se v nový verzi to chování nezměnilo.

Offline age.new

  • Plnoletý
  • ***
  • Příspěvků: 217
  • Karma: 0
Tak příčina není v Delphi ale typu displeje. Po komunikaci s výrobcem nám byl zaslán spec. driver, který z multi-touch displeje udělal pouze single-touch a v tu chvíli vše fungovalo jak má. Klikání prstem se pak chová 100% jako u myši a asi je to i reakčně rychlejší  (možná jen můj pocit).

Pokud i tak někdo bude potřebovat zprovoznit správné posílání eventů i u multi-touch displeje, tak cesta přes Form.OnTouch je funkční. Akorát se musí ošetřit zamezení dvojitého vyvolání MouseDown eventů a případě i vyvolání MouseDown eventu na dvou různých tlačítek blízko sebe.