[Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

[Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Nimral »

Ich wollte heute "nur mal schnell" einem Button OnDragOver und onDragDrop Handler zuweisen. Es handelt sich um einen SpeedButton, der bei Klick markierte Listeneinträge löscht, und ich fände es cool wenn man die Listeneinträge alternativ auch auf den SpeedButton ziehen könnte.

Alle LCL Komponenten müssten eigentlich onDragOver und onDragDrop unterstützten, und Speedbutton ist abgeleitet von TCustomSpeedButton von TGraphicControl von TControl, und da gibt es selbstverständlich

Code: Alles auswählen

Protected
   ...
    property OnDragOver: TDragOverEvent read FOnDragOver write FOnDragOver;
    ...
(controls.pp Z. 1496)

und die Doku zu Protected meint: "the members of a Protected section are also accessible to descendent types, even if they are implemented in other modules.". Schaut doch alles gut aus.

Dennoch scheitert dieser Code:

Code: Alles auswählen


  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    Panel1: TPanel;
    SpeedButton1: TSpeedButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure ListBox1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure Panel1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure SpeedButton1DragOver(Sender, Source: TObject;
  X, Y: Integer; State: TDragState; var Accept: Boolean);
  private

  public

  end;
  
procedure TForm1.FormCreate(Sender: TObject);

var
  i:integer;

begin
  for i := 1 to 8 do
      ListBox1.AddItem(Format('Item %d',[i]),nil);
  SpeedButton1.OnDragOver:=@SpeedButton1DragOver;
end; 
endet mit "unit1.pas(52,16) Error: identifier idents no member "OnDragOver""

Wie üblich begann die Odyssee mit einer Frage (wie bekomme ich Drag'n'Drop mit einem Speedbutton) und endet bei der Originalfrage plus vier Zusatzfragen:

- wie ist es möglich, diese beiden Properties in den abgeleiteten Klassen verschwinden zu lassen, und zwar nicht nur aus der GUI sondern überhaupt
- warum hat der Speedbutton kein Drag'n'Drop, ist das etwa Absicht?
- warum kann ich meinen Handler nicht wenigstens per Code zuweisen, und endlich:
- ist es möglich, die Drag'n'Drop Funktionalität auf anderem Weg an den Speedbutton zu kleben.

Armin
Zuletzt geändert von Nimral am Do 13. Mai 2021, 14:35, insgesamt 1-mal geändert.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von wp_xyz »

Ich weiß nicht, warum bei TSpeedButton die Drag-Events protected geblieben sind - vielleicht, weil es bei Delphi auch so ist, keine Ahnung.

Du kannst mit dem Type-Cast-Trick als Anwendungsentwickler auf protected-Properties zugreifen. Obwohl ich das selbst manchmal mache, kommt es mir nicht sehr sauber vor, und FPC weigert sich auch, das zu kompilieren, wenn man die Debug-Option -CR (Verify method calls) aktiviert hat. Also, auf eigenes Risiko - oder nimm einfach einen TBitBtn.

Code: Alles auswählen

type
  TSpeedButtonAccess = class(TSpeedButton);

procedure TForm1.SpeedButtonDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := true;
end;

procedure TForm1.SpeedButtonDragDrop(Sender, Source: TObject; X, Y: Integer);
begin
  if Listbox1.ItemIndex > -1 then
    Listbox1.Items.Delete(Listbox1.ItemIndex);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  TSpeedButtonAccess(SpeedButton1).OnDragOver := @SpeedButtonDragOver;
  TSpeedButtonAccess(SpeedButton1).OnDragDrop := @SpeedButtonDragDrop;
end;   
Zuletzt geändert von wp_xyz am Do 13. Mai 2021, 14:21, insgesamt 1-mal geändert.

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von kupferstecher »

Nimral hat geschrieben:
Do 13. Mai 2021, 11:26
- wie ist es möglich, diese beiden Properties in den abgeleiteten Klassen verschwinden zu lassen, und zwar nicht nur aus der GUI sondern überhaupt
[...]
- warum kann ich meinen Handler nicht wenigstens per Code zuweisen, und endlich:
Du versuchst von Form1 aus darauf zuzugreifen (Form1 is aber nicht vom SpeedButton abgeleitet). Die Properties müsste also 'public' sein, damit du von außerhalb (per Code) darauf zugreifen kannst. Und gar 'published' um im Objektinspektor zu erscheinen.

Protected heißt, du kannst von innerhalb einer abgeleiteten Klasse zugreifen, also aus einer Methode der Kindklasse heraus.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1432
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von fliegermichl »

oder aber eine eigene von TSpeedButton abgeleitete Klasse deklarieren in der die Property published wird.

Code: Alles auswählen

type
 TMySpeedButton = class ( TSpeedButton )
 publish
  property OnDragOver;
  property OnDragDrop;
 end;

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Nimral »

Dank euch wieder mal!

Im Kern mal wieder ein Eigenfehler im Zusammenhang mit Objekten. Ich hoffe, mir bleibt noch genügend Restnutzungsdauer um mich irgendwann an die Dinger zu gewöhnen.

Ich hab die beiden Ansätze inzwischen getestet.

Fliegermichis "regelkonformer" Ansatz hat bei mir anfangs nicht compiliert (der Compiler stört sich an "Published", wenn ich es rausnehme - ich dachte mich zu erinnern dass Published bei $mode=objFPC default ist - dann geht es). Leider schlägt das Imperium dann zurück, das Programm läuft in einen Laufzeitfehler, offenbar im Streamloader für die Formular-Ressource, wenn ich raten müsste würde ich schätzen, dass die Verbindung zwischen dem TMySpeedButton in der Formular-Typdefinition und dem TSpeedbutton in der Formular-Ressource zerbrochen ist --> ich müsste die Speedbuttons auch noch im Code erzeugen damit das klappt, oder auf die Schnelle lernen wie ich auch im Formular-Editor TSpeedButton gegen TMySpeedButton tausche. Ich wüsste nicht, dass das geht, ohne gleich eine ganze neue Lazarus Komponente zu bauen.

wp's Hack arbeitet dagegen prima. Da es sich um einen Hack handelt, der vermutlich einen anderen Mist kompensiert, habe ich diesmal kein Problem, damit zu arbeiten. Kommentar dazu und gut ist es. Der Lösungsansatz scheint mir die wenigsten Nebenwirkungen zu haben.

Armin.

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von PascalDragon »

Nimral hat geschrieben:
Do 13. Mai 2021, 14:04
Fliegermichis "regelkonformer" Ansatz hat bei mir anfangs nicht compiliert (der Compiler stört sich an "Published", wenn ich es rausnehme - ich dachte mich zu erinnern dass Published bei $mode=objFPC default ist - dann geht es).
published ist nicht standardmäßig aktiv. Entweder musst du {$M+} nehmen oder von einer Klasse ableiten, die {$M+} bereits hat, was beim Ableiten von TSpeedButton eigentlich der Fall sein sollte, da dieses letztlich von TComponent ableitet, das eben {$M+} hat.
Nimral hat geschrieben:
Do 13. Mai 2021, 14:04
Leider schlägt das Imperium dann zurück, das Programm läuft in einen Laufzeitfehler, offenbar im Streamloader für die Formular-Ressource, wenn ich raten müsste würde ich schätzen, dass die Verbindung zwischen dem TMySpeedButton in der Formular-Typdefinition und dem TSpeedbutton in der Formular-Ressource zerbrochen ist --> ich müsste die Speedbuttons auch noch im Code erzeugen damit das klappt, oder auf die Schnelle lernen wie ich auch im Formular-Editor TSpeedButton gegen TMySpeedButton tausche. Ich wüsste nicht, dass das geht, ohne gleich eine ganze neue Lazarus Komponente zu bauen.
Du musst dein TMySpeedButton in ein eigenes Package packen, in diesem über eine Register-Funktion deine Komponente mittels RegisterComponent registrieren und dann das Package in Lazarus installieren. Anschließend kannst du deinen TSpeedButton mit einem TMySpeedButton ersetzen (ich glaube der Designer hat eine Möglichkeit eine Klasse zu ersetzen).
Nimral hat geschrieben:
Do 13. Mai 2021, 14:04
wp's Hack arbeitet dagegen prima. Da es sich um einen Hack handelt, der vermutlich einen anderen Mist kompensiert, habe ich diesmal kein Problem, damit zu arbeiten. Kommentar dazu und gut ist es. Der Lösungsansatz scheint mir die wenigsten Nebenwirkungen zu haben.
Wenn du damit zufrieden bist nur zur Laufzeit auf OnDragOver und OnDragDrop zuzugreifen, dann kannst du auch einen class helper nehmen, da diese auf protected Bezeichner zugreifen können, das läuft dann nicht unter Hack:

Code: Alles auswählen

// interface Teil

type
  TSpeedButtonHelper = class helper for TSpeedButton
  private
    function GetOnDragOver: TDragOverEvent;
    function GetOnDragDrop: TDragDropEvent;
    procedure SetOnDragOver(aEvent: TDragOverEvent);
    procedure SetOnDragDrop(aEvent: TDragDropEvent);
  public
    property OnDragOver: TDragOverEvent read GetOnDragOver write SetOnDragOver;
    property OnDragDrop: TDragDropEvent read GetOnDragDrop write SetOnDragDrop;
  end;
  
// implementation Teil

function TSpeedButtonHelper.GetOnDragOver: TDragOverEvent;
begin
  Result := inherited OnDragOver;
end;

function TSpeedButtonHelper.GetOnDragDrop: TDragDropEvent;
begin
  Result := inherited OnDragDrop;
end;

procedure TSpeedButtonHelper.SetOnDragOver(aEvent: TDragOverEvent);
begin
  inherited OnDragOver := aEvent;
end;

procedure TSpeedButtonHelper.SetOnDragDrop(aEvent: TDragDropEvent);
begin
  inherited OnDragDrop := aEvent;
end;
Die Nutzung von Gettern/Settern ist notwendig, da Helper keine Felder definieren dürfen. Theoretisch könnte man sie als inline deklarieren, allerdings hat FPC noch keine Unterstützung dafür Methoden zu inlinen, die inherited verwenden. Da du die Events allerdings ja nur einmal setzt, sollte das jetzt eh keine großartigen Auswirkungen auf die Performance haben...

Du musst dann sicherstellen, dass der Helper im Scope ist (also zum Beispiel in eine eigene Unit packen und dann in die uses-Clause damit). Dann kannst du einfach per SpeedButton1.OnDragOver := ..., etc. darauf zugreifen.
FPC Compiler Entwickler

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von wp_xyz »

Nimral hat geschrieben:
Do 13. Mai 2021, 14:04
wp's Hack arbeitet dagegen prima. Da es sich um einen Hack handelt, der vermutlich einen anderen Mist kompensiert, habe ich diesmal kein Problem, damit zu arbeiten. Kommentar dazu und gut ist es. Der Lösungsansatz scheint mir die wenigsten Nebenwirkungen zu haben.
Konkret nicht ausprobiert, aber lucamar's Interposer-Class im internationalen Forum scheint mir die beste Lösung zu sein (https://forum.lazarus.freepascal.org/in ... #msg405649). Damit sparst du dir den Typecast, und (wahrscheinlich - wiegesagt: nicht getestet!) das Compiler-Problem, wenn -CR aktiv ist.

Der Trick funktioniert, weil hier eine gleichnamige Klasse TSpeedButton deklariert wird, so dass das Streaming-System damit klarkommt. Aber auch der Compiler kommt damit klar, weil die Namensgleichheit durch Herleitung vom qualifizierten Buttons.TSpeedbutton entschärft wird (type TSpeedButton = class(Buttons.TSpeedButton)). Genaugenommen benutzt des Formular mit dem SpeedButton den neuen TSpeedbutton, der aber identisch mit dem alten (Button.TSpeedButton) ist, bis auf die neuen published Events OnDragOver und OnDragDrop, die aber nicht in der LFM-Datei stehen und somit kein Problem machen.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: [Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Nimral »

Was mir bei beiden Ansätzen nicht klar ist: wieso funktioniert das überhaupt? Ich meine, es wird ja (vor allem bei Lucamars Variante) einfach nur eine neue Klasse abgeleitet, und schon sind alle protected Properties public?

Ich hätte erwartet, dass ich die beiden Handler in der abgeleiteten Klasse nochmal in die Public Sektion schreiben muss, und bin davon ausgegangen, dass Dein Typecast Hack sich da drum herum mogelt. Aber so wie es aussieht ist es eine normale Eigenschaft der Ableitung? Das kann doch eigentlich nicht sein, ich muss da was übersehen.

Armin.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: [Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Socke »

Nimral hat geschrieben:
Fr 14. Mai 2021, 10:47
Was mir bei beiden Ansätzen nicht klar ist: wieso funktioniert das überhaupt? Ich meine, es wird ja (vor allem bei Lucamars Variante) einfach nur eine neue Klasse abgeleitet, und schon sind alle protected Properties public?
Die Properties bleiben protected. Auf protected darf zugegriffen werden
  • aus einer abgeleiteten Klasse (egal welche Unit und egal wie viele Klassen dazwischen liegen)
  • In der selben Unit
Lucamars Variante definiet also eine Klasse TSpeedButton in der Unit des Formulars und nimmt damit auch die Sichtbarkeit der Properties mit.
Um so etwas zu verhindern kann man strict protected nutzen. Hier dürfen tatsächlich ausschließlich abgeleitete Klassen auf die Elemente zugreifen - egal in welcher Unit.

Edit: Ich war mal so frei ein Ticket (#38891) zu diesem Thema anzulegen. Obwohl schon mehrfach diskutiert hat das wohl noch niemanden bewogen, das Problem an der Ursache anzugehen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: [Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Nimral »

Socke hat geschrieben:
Fr 14. Mai 2021, 11:00
[*]In der selben Unit

...

Um so etwas zu verhindern kann man strict protected nutzen.
Danke! Hatte ich überlesen, oder vermutlich eher einfach als WTF??? zur Kenntnis genommen und verdrängt.

Ich nehme an, OOP Puristen gehen bei sowas zum k*****?

Armin.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: [Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von wp_xyz »

Socke hat geschrieben:
Fr 14. Mai 2021, 11:00
Edit: Ich war mal so frei ein Ticket (#38891) zu diesem Thema anzulegen. Obwohl schon mehrfach diskutiert hat das wohl noch niemanden bewogen, das Problem an der Ursache anzugehen.
Danke für den Report - ich habe nun OnDragDrop, OnDragOver, OnEndDrag und OnStartDrag für TSpeedButton in Trunk als "published" deklariert. Eigentlich fehlen nun noch "DragKind" und "DragMode". Gibt es gewichtige Gründe, die dagegen sprechen, diese auch zu "publishen"? TButton hat sie ebenfalls, TBitBtn allerdings nicht (im Gegensatz zu Delphi).

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: [Gelöst] Properties nicht verfügbar in abgeleiteten Klassen (SpeedButton)

Beitrag von Nimral »

Find ich gut!

Es fördert das was Einsteigern meiner Meinung nach das Leben am Meisten erleichtert: EInheitlichkeit. Ich würde es deswegen überall einbauen wo es nicht technische Hindernisse verhindern.

Daumen hoch!

HG, Armin

Antworten