Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Klassennamen ändern (https://www.delphipraxis.net/215678-klassennamen-aendern.html)

Marco Steinebach 20. Aug 2024 08:38

Klassennamen ändern
 
Hallo zusammen,
Ich habe eine von TRichEdit abgeleitete Klasse, TMyRichEdit.
Kann ich den Klassennamen irgendwie ändern?
Folgender Hintergrund:
Ich verwende, weil ich blind bin, einen Screenreader zum Auslesen des Bildschirms.
Nutze ich ein Delphi-Prog mit einem TRichEdit funktioniert der Screenreader wunderbar, liest alles vor, markiert Text richtig, etc.
Mache ich das selbe mit meiner abgeleiteten Klasse TMyRichEdit, funktioniert entweder nix, oder zumindest nicht richtig.
Dem Screenreader kann ich zwar beibringen, das Elemente des Typs TMyRichEdit ein Edit sind, hilft aber nix.
Ich weiß leider nicht, woher der Screenreader den Namen bezieht, aber lese ich den Namen aus, wenn ich auf dem Feld stehe, erhalte ich TMyRichEdit, was ja richtig ist.
Kann ich in Delphi irgendwo sagen:
Du, falls dich jemand fragt, von welcher Klasse du bist, sag ihm, du seist ein TRichEdit.

Das würde mir echt doll helfen, wenn jemand eine Antwort, oder zumindest eine Idee hätte.
Ach so: falls man da mit Inline ran muss, kann mir das bitte gleich jemand machen ich hab nämlich sowas von keine Ahnung von inline...

Herzlich grüßt
Wandogau

sh17 20. Aug 2024 08:45

AW: Klassennamen ändern
 
Du könntest eine weitere DummiUnit einführen, die nur

Code:
uses
  MyRichEditUnit;

type
  TRichEdit = class(TMyRichEdit)

  end;
enthält.

Im Form änderst du die Deklaration dann so ab bzw bindest nur die MyRichEditUnitDummi Unit in den Uses ein

Code:
  TForm1 = class(TForm)
    re: MyRichEditUnitDummi.TRichEdit;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;
sollte eigentlich klappen

Kas Ob. 20. Aug 2024 09:19

AW: Klassennamen ändern
 
Hi,


Zitat:

Zitat von sh17 (Beitrag 1539982)
sollte eigentlich klappen

Most likely hill not help with that screen reader, the reason is :

The trick with the interposer will work internally on Delphi compiler and generated code locally, yet the class name is still TMyRichEdit, and when i say class name, i mean the created Windows class using the OS APIs.
Screen Reader can't enumerate or access an application internal naming, but will access the created windows classes and declared externally, and will only see TMyRichEdit.

I might be wrong though, in all cases, please test what Sven suggested, and in case didn't help, i am offering what is needed to find a solution, though the easiest and best solution is configuring the Screen Reader to handle TMyRichEdit as TRichEdit, yet there are few things i can think of, but does need little more.. lets say an unorthodox approaches, like memory patching and hooking and doing nasty stuff, yet again i volunteering to do it for you whatever it takes.

I hope your screen reader have better language than me :oops:

himitsu 20. Aug 2024 10:36

AW: Klassennamen ändern
 
Ein "ordentlicher" Screenreader sollte doch aber eigentlich auf die "innere" Fensterklasse / den Real-ClassName achten, bzw. eigentlich besser auf auf Funktionen, also ob eine API zum Auslesen des Textes vorhanden ist.

Wenn der wirklich auf den "aktuellen" Klassenname achtet, müsste er ja "Delphi" kennen und sonst auch jedes GUI-Framework, welches das RichEdit jeweils in einer eigenen Klasse kapselt.


Ich weiß leider nicht, wie es bezüglich VCL aussieht.
Insgesamt hab ich da eigentlich keine Ahnung, was dieses "Accessibility"-Thema für Blinde und Schlechtsehende betrifft.

OK, einmal kann man bei FMX angeben, dass es echte Windowskomponenten nutzt, anstatt selbst zu malen,
für einige wenige Komponenten, wie Edits und Buttons ... k.A. ob auch RichEdit.
Wo also unter Windows quasi die VCL-Komponente im FMX verwendet wird, welche wiederum Windows und somit auch ScreenReader finden können.
[edit] OH, FMX kennt kein RichEdit, aber erstmal egal [/edit]
ControlType = Platform
https://docwiki.embarcadero.com/Libr...on.ControlType

Für FMX/FireMonkey gibt es aber ein Addon, um die "selbstgemalte" GUI, ala JAVA, für ScreenReader zugänglich zu machen.
Es gibt im Windows eine API dafür, um dem Reader explizit "selbst" den Inhalt der Form zu sagen, anstatt er die Form abscannt.
https://docwiki.embarcadero.com/RADS...bility_Package

Prinzipiell gibt es dieselbe API auch für die VCL,
denn z.B. TLabel und Grids malen sich auch selbst, wo der ScreenReader nur die Pixel/Canvas via OCR analysieren müsste,
oder das Programm sagt ihm via API, was dort wo drin steht.

Es gibt auch einige andere proprietäre Schnittstellen, für spezielle ScreenReader.


PS: statt TLabel, was in Delphi kein WinControl ist, sondern sich selbst auf den Canvas seines Patents malt,
kann man hier auch TStaticText verwenden, welches das "echte" Windows-TextanzeigeControl "STATIC" ist.

Marco Steinebach 20. Aug 2024 10:56

AW: Klassennamen ändern
 
Hello,
@Sven:
Super-Idee, scheitert bei mir leider daran, das mein gutes altes D5 noch keine Referenzierung unit.Typ kann. Ja, ja, dann nimm D11.3, würde ich ja, wenn es auch nur halb so gut mit einem Screenreader zu bedienen wäre.

@Kas:
I think you're right. I tried to tell my screenreader (JAWS) to treat TMyEdit as an edit or multiLineEdit, but it makes no difference. So we have to find a way while creating the corresponding elements to change the class name.

@Himitsu:
Ich geb dir recht, ein Screenreader sollte, tut er in vielen Fällen auch, aber beim RichEdit spinnt er komplett.

Herzlich grüßt (with best regards)
Wandogau

Mavarik 20. Aug 2024 11:02

AW: Klassennamen ändern
 
Ich denke es heißt Superimposing oder so...

Ich mach das z.B. für TForm.

Deine Unit die TRichEdit Implementiert muss "nur" in der Uses hinter der original Unit stehen und schon wird Deine Implementation verwenden.

Mavarik

Kas Ob. 20. Aug 2024 11:16

AW: Klassennamen ändern
 
OK, then hooking it is.

I have few errands to attend now with few phone calls, in other words will be busy for few hours, but the solution is very easy as i think a simple hook for RegisterClassW/RegisterClassExW/RegisterClassA/RegisterClassExA and changing the ClassName will do the trick with the screen reader.

One thing though, i might didn't understand it right, you need the fix for Delphi 5 application?

If yes then the approach will still doable but will need some cut corners, i would go with using the great DDetours library from https://github.com/MahdiSafsafi/DDetours , alas it doesn't support Delphi 5, so either the hooking will be less general or a DLL can solve this easily.

Do you have problem in adding a small DLL to benefit form the wide range compatibility in hooking ? (in case Delphi 5 is the one needed)

By adding, i mean this DLL could copied to the system directory and for any or all of your application, all what you need is add one unit to uses without adding any code, also this DLL could be tweakable without rebuilding, like using one line in your application to change any ClassName, not just TMyRichEdit.

Kas Ob. 20. Aug 2024 11:22

AW: Klassennamen ändern
 
Zitat:

Zitat von Mavarik (Beitrag 1539994)
Ich denke es heißt Superimposing oder so...

Ich mach das z.B. für TForm.

Deine Unit die TRichEdit Implementiert muss "nur" in der Uses hinter der original Unit stehen und schon wird Deine Implementation verwenden.

Mavarik

No sure i do understand this,
Do you mean introducing the interposer for TMyRichEdit itself ?
, one level before, like,
Code:
uses
  MyRichEditUnit;

type
  TRichEdit = class(Vcl.ComCtrls.TRichEdit) // TRichEdit on the left side is TMyRichEdit but renamed, and MyRichEditUnit must be in uses clauses before Vcl.ComCtrls in the form that uses it
....
This might work !

sh17 20. Aug 2024 11:38

AW: Klassennamen ändern
 
Zitat:

Zitat von Mavarik (Beitrag 1539994)
Ich denke es heißt Superimposing oder so...
Ich mach das z.B. für TForm.
Deine Unit die TRichEdit Implementiert muss "nur" in der Uses hinter der original Unit stehen und schon wird Deine Implementation verwenden.

genau, dann so

Code:
uses
  ..,MyRichEditUnitDummi;

  TForm1 = class(TForm)
    re: TRichEdit;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

Marco Steinebach 20. Aug 2024 11:50

AW: Klassennamen ändern
 
Hi Mavarik,
Jep! So funktioniert es, auch wenn man dann darauf verzichten muß, das TMyRichEdit im Formulardesigner bearbeiten zu können, aber jetzt glaubt der Screenreader es sei ein TRichEdit und alles ist schön!
Ganz herzlichen Dank an alle für die rasche Hilfe!!!

Es grüßt
Wandogau

himitsu 20. Aug 2024 12:16

AW: Klassennamen ändern
 
Prinzipiell kann man hier auch mit Alias arbeiten, wo entweder der VCL-Designer die Klasse anders benennt (TMyRichEdit als TRichEdit nutzt, wo das normale TRichEdit natürlich aus der Registrierung entfernt werden muß)
oder wo im Designer ein "normales" TRichEdit genutzt wird, aber zur Laufzeit dann das TMyRichEdit über den "gleichen" Namen TRichEdit verwendet wird.

Letzteres z.B. damals hier benutzt,
https://www.delphipraxis.net/141895-...phi-other.html
wo im FormDesigner ein normales TEdit platziert wurde, aber zur Laufzeit im Kompilat beim DFM-Laden das imbenannte TTntEdit anstatt dem TEdit geladen wurde
und im Quellcode zur DesignTime auch die Codevervollständigung die Property des TntEdit sieht. (entsprechend siehe hier Post #2 und #9)

Kas Ob. 20. Aug 2024 14:15

AW: Klassennamen ändern
 
Yes, interposer did the job, while keeping the Window Class name as TRichEdit, so Screen Reader or any inspector application will see that.

example
Code:
unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ComCtrls,
  Vcl.StdCtrls, uMyRichEdit;

type
  TForm10 = class(TForm)
    RichEdit1: TRichEdit;     // if uMyRichEdit not the last in uses clauses then "uMyRichEdit.TRichEdit" should be used
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form10: TForm10;

implementation

{$R *.dfm}

end.
Code:
unit uMyRichEdit;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.ComCtrls;

type
  //TMyRichEdit = class;                         // foreward declaration

  TRichEdit = class(Vcl.ComCtrls.TRichEdit)
  protected
    procedure KeyPress(var Key: Char); override;
  end;

  //TMyRichEdit = class(uMyRichEdit.TRichEdit);  // just naming override, will work for runtime creation only and for internal naming usage

implementation

{ TRichEdit }

procedure TRichEdit.KeyPress(var Key: Char);
begin
  Key := '*';
  inherited;
end;

end.

Marco Steinebach 27. Aug 2024 08:47

AW: Klassennamen ändern
 
Hallo Himitsu,
Ich brauch bitte nochmal deine Hilfe!
Zitat:

Zitat von himitsu (Beitrag 1540006)
Prinzipiell kann man hier auch mit Alias arbeiten, wo entweder der VCL-Designer die Klasse anders benennt (TMyRichEdit als TRichEdit nutzt, wo das normale TRichEdit natürlich aus der Registrierung entfernt werden muß)

Ich weiß nicht, ob mein D5 das kann, aber wie kriege ich eine Komponente aus der Registrierung????

Zitat:

Zitat von himitsu (Beitrag 1540006)
... oder wo im Designer ein "normales" TRichEdit genutzt wird, aber zur Laufzeit dann das TMyRichEdit über den "gleichen" Namen TRichEdit verwendet wird.

Letzteres z.B. damals hier benutzt,
https://www.delphipraxis.net/141895-...phi-other.html
wo im FormDesigner ein normales TEdit platziert wurde, aber zur Laufzeit im Kompilat beim DFM-Laden das imbenannte TTntEdit anstatt dem TEdit geladen wurde
und im Quellcode zur DesignTime auch die Codevervollständigung die Property des TntEdit sieht. (entsprechend siehe hier Post #2 und #9)

Okay, hab mir, natürlich, deine TNTHacks angesehen, aber ich bin, und das passiert mir nicht oft, echt zu blöd. ;-)
Also:
Ich nehme in meiner Form ein stinknormales TRichEdit, kann die Eigenschaften also ganz normal über den Form-Designer setzen, das wäre ja schonmal schön.
Und nu? Wie kriege ich das mit dem Überschreiben hin?
Meine Klasse ist
Code:
TMSRichEdit = class (TRichEdit)
Kannst du mich bitte mal schupsen?

Es bedankt sich
Wandogau

Marco Steinebach 27. Aug 2024 11:02

AW: Klassennamen ändern
 
Huhu,
Da ich nix gefunden habe, um meinen vorigen Beitrag zu löschen...
Hat sich erledigt, einfach die Hack als letzte in die Uses einbinden, und alles ist schön.
Sorry!

himitsu 27. Aug 2024 12:46

AW: Klassennamen ändern
 
https://docwiki.embarcadero.com/RADS...nents_aufrufen

Delphi-Referenz durchsuchenRegisterClass
Delphi-Referenz durchsuchenRegisterClassAlias
Delphi-Referenz durchsuchenRegisterClasses

Delphi-Referenz durchsuchenRegisterComponents
Delphi-Referenz durchsuchenRegisterNoIcon
Delphi-Referenz durchsuchenRegisterNonActiveX

Delphi-Referenz durchsuchenUnRegisterClass
Delphi-Referenz durchsuchenUnRegisterClasses
Delphi-Referenz durchsuchenUnRegisterModuleClasses


Man kann seine Klassen auch ableiten
Delphi-Quellcode:
type
  TRichEdit = class(TMyRichEdit);
Diese Ableitung im Delphi registrieren und damit das originale TRichEdit überdecken.



Oder,
ich weiß zwar dass es geht, aber nicht wie.
Man kann für die DesignTime EINE Klasse registrieren, welche nur im FormDesigner genutzt wird,
aber so, dass im Code dann eine andere gleichnamige Runtime-Klasse eingefügt wird (inkl. der abweichenden Unit im USES).



Wie gesagt, wenn es im Designer reicht, wenn die originale TRichEdit dort vorkommt,
aber zur Laufzeit im Programm dann deine Ableitung, dann wurde ja schon gezeigt,
wie man in der selben Unit vor der Form-Klasse, oder als "letztes" im USES in einer Unit, dieses TRichEdit durch ein anderes ersetzt werden kann.

Letztes: die Unit mit dem originalen TRichEdit muß vor der Unit mit dem neuen TRichEdit stehen, oder halt nach dem USES direkt im Code das "neue" TRichEdit.
Das "Letzte", also was von unten nach oben als Erstes gefunden wird, das wird verwendet.





Zitat:

schubs
In der Form (DFM) befindet sich z.B. ein TRichEdit.
Im FormDesigner des Delphi liegt dieses TRichEdit auf der Form drauf.

In der DFM steht nur als String "TRichEdit".
In deiner TForm-Ableitung findet sich dazu eine "Variable" vom Typ TRichEdit (
Delphi-Quellcode:
RichEdit1: TRichEdit;
)
und dieser Typ ist das, was benutzt wird, um die Form-Instanz und draufbefindliche Komponenten zu erstellen.

Hier wurde nun einfach im Code diese TRichEdit-Typ, welchen der Compiler an "dieser" Stelle sieht, durch einen anderen ersetzt.
Delphi-Quellcode:
type TRichEdit = class(TMSRichEdit);

(entweder in selber Unit, oberhalb der Form, oder in einer Unit, welche möglichst als Letztes im USES steht)

Somit ist zwar im Designer die andere/originale Komponente auf der Form,
aber im laufenden Programm stattdessen dann eine Andere.


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:23 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz