![]() |
Rätselhaftes Konstrukt in Unit Dialogs
Hallo, auf der Suche nach einer etwas flexibleren Routine als ShowMessage und MessageDlg bin ich zwar im Quelltext der Unit Dialogs fündig geworden, da gibt es z.B. messageDlgPos, bei dem man die Position des Dialogs am Bildschirm festlegen kann, und überladene Routinen, denen man noch den Titel der Messagebox mitgeben kann - ich bin aber dabei über ein Delphi konstrukt gestolpert, das ich noch nie gesehen habe, und würde gerne wissen, was das eigentlich ist:
Delphi-Quellcode:
Was bedeutet jeweils die Zeile vor der Funktionsdeklaration mit den eckigen Klammern?
[UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.SafeSubWindows)]
function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer; begin Result := MessageDlgPosHelp(Msg, DlgType, Buttons, HelpCtx, X, Y, ''); end; [UIPermission(SecurityAction.LinkDemand, Window=UIPermissionWindow.SafeSubWindows)] function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer; DefaultButton: TMsgDlgBtn): Integer; overload; begin Result := MessageDlgPosHelp(Msg, DlgType, Buttons, HelpCtx, X, Y, '', DefaultButton); end; |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Was das ist, kann ich dir auch nicht sagen. Würde mich aber auch interessieren. Aber hast du schon mal an die Windows API Funktion Messagebox gedacht oder den VLC Wrapper als Methode von TApplication: Applicatiuon.Messagebox? Bzw. was sollte der Dialog denn können?
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Eigentlich genügt mir das, was ich in der Unit Dialogs gefunden habe: Die Messagebox beliebig am Bildschirm positionieren und ihr einen Titel verpassen - Diesbezüglich bin ich ganz glücklich.
Aber ich habe noch nie in einem Delphi-Programm eine Zeile gesehen, die so in eckigen Klammern herumschwirrt, und hätte gerne gewusst, was das soll - einfach nur interesse halber. |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Meinst du UIPermission? Dürfte sich um Überbleibsel der gescheiterten VCL.NET-Implementierung handeln. Damit teilst du mit welche Rechte die Methode/Funktion benötigt.
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
das ist schon einmal eine interessante information - aber die Syntax ist mir trotzdem rätselhaft: nach allem was ich bis jetzt an Delphi Syntax kenne müsste der Compiler doch bei den eckigen Klammern streiken???
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Das sind "Attribute".
Such einfach mal in der Unit RTTI nach "Attribute" oder schau dich beim DataSnap um (aktuelles Beispiel in der Nutzung) Auch wenn ich dieses vollkommen krank finde, denn wer sollte schon auf die blöde Idee kommen Gruppen und Passwörter Hardgecodes im Queltext anzulegen, wo doch alle mehr mit dynamischen Strukturen arbeitet, wie z.B. Datenbanken. Oder kommt das wirklich so cool, wenn man die Anwendung neu kompilieren soll, nur um eine neue Rolle anzulegen oder ein Passwort zu ändern? :wall: ![]() Dort kann man also zusätzliche Infos zu Funktionen/Prozeduren, Klassen/Typen, Methoden, Propertys und Variablen hinterlegen, welche sich dann via RTTI auslesen lassen. Das wurde auch an ein/zwei Stellen in den Delphi-Quellcodes angewendet. (aber ich weiß nicht mehr wo ich das gesehn hatte und Aufgrund der Syntax läßt es sich nicht grade leicht suchen)
Delphi-Quellcode:
Und nun kann man sich die Klassen und eventuelle Parameter via RTTI auslesen/verarbeiten.
type
TMyAttribute = class(TCustomAttribute) constructor Create(S: string); end; [TMyAttribute('7')] TMySet = set of TMyEnum; ['direkt als Text'] TMyEnum = type TMyEnum; [TMyAttribute('1')] TMyClass = class [TMyAttribute('8')] FMyField: Integer; [TMyAttribute('2')] [TMyAttribute('3')] procedure MyMethod2; [TMyAttribute('2'), TMyAttribute('3')] function MyMethod: Boolean; [TMyAttribute('4')] property MyProperty: Boolean read MyMethod; end; var [TMyAttribute('5')] MyVar: Integer; [TMyAttribute('6')] procedure MyProcdure; |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Danke - wieder einiges dazugelernt :)
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Beispiel für die Nutzung bei uns:
Per Attribut wird festgelegt welche XML-Knoten oder Datenbankeinträge zu den Feldern der Klasse gehören. Danach kann man die einfach an eine Funktion übergeben, die dann die Daten liest oder schreibt. Benutzen tun wir das z.B. bei Einstellungsklassen. Auf diese Weise müssen die Einstellungsklassen nichts über die Datenstrukturen wissen, in denen die Daten liegen. |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Könnt ihr da mal ein beispiel zeigen?
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zum beispiel sowas:
Delphi-Quellcode:
Passend dafür gibts einen Serializer der auf der neuen RTTI aufbaut und wenn ich eine Liste habe, weiß ich durch das Attribute, wie der Knoten in der XML heißt und welche Klasse ich dafür erzeugen muss.
type
ListAttribute = class(TCustomAttribute) private FTagName: String; FClass: TClass; public constructor Create(const ATagName: String; AClassType: TClass); end; type TMyClass = class [ ListAttribute('SubPositions', TPositionInformation) ] property SubPositions : TObjectList<TPositionInformation> read FSubPositions write FSubPositions; [ ListAttribute('DatabaseVersions', TDatabaseVersion) ] property DatabaseVersions : TObjectList<TDatabaseVersion> read FDatabaseVersions write FDatabaseVersions; [ ListAttribute('ProductionUnits', TProductionUnit) ] property ProductionUnits : TObjectList<TProductionUnit> read FProductionUnits write FProductionUnits; [ ListAttribute('Segments', TPositionSegment) ] property Segments : TObjectList<TPositionSegment> read fSegments write FSegments; end; |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
@Luckie: Wie scheinbar auch andere, handhabe ich das Mapping von Datenbank-Tabellen auf Objekte via Attribute. Beispiel:
Delphi-Quellcode:
So könnte das ganze aussehen. Du brauchst somit quasi nur eine Load-Methode schreiben, die via (der neuen) RTTI die abgeleitete Klasse TBlub analysiert und dann via PrimaryKey entsprechend lädt. Ist halt eine stark simplifizierte Version, aber ich denke, dass es schon aussagekräftig genug ist, bzw. das will ich mal hoffen ;)
// Tablle Blub:
// Spalte1 // Spalte2 // Spalte3 TModel = class abstract public // Diese Methode analysiert die Klasse und lädt aus der zugewiesenen // Tabelle den nötigen Datensatz procedure Load(const PrimaryKey: Integer); virtual; end; // Dazu gehörige Klasse [TTableAttribute('Blub')] // Zuweisung einer Tabelle TBlubModel = class(TModel) private [TTableColumnAttribute('Spalte1')] FValue1: String; [TTableColumnAttribute('Spalte1')] FValue2: Integer; [TTableColumnAttribute('Spalte1')] FXyz: Variant; end; -- Edit: Alternativ könnte man auch einen "Loader" verwenden -- bin in Sache Patterns bzgl sowas leider nicht all zu fit. Hier mal mein Gedankengang:
Delphi-Quellcode:
Für etwaige Fehler wird nicht gehaftet :stupid: habe gerade alles nur schnell aus dem Kopf runtergeschrieben, ohne es zu testen.
// Es liegt hier selbige Tabelle, wie oben beschrieben, zugrunde!
// Basis-Model-Klasse TModel = class abstract end; TModelClass = class of TModel; // Konkretes Model TBlubModel = class(TModel) private [TTableColumnAttribute('Spalte1')] FValue1: String; [TTableColumnAttribute('Spalte1')] FValue2: Integer; [TTableColumnAttribute('Spalte1')] FXyz: Variant; end; // Loader TBaseModelFactory = class private procedure AnalyseModel(Model: TModelClass); public function LoadByPk(Model: TModelClass; PrimaryKey: Integer): TModel; function LoadByAttributes(Model: TModelClass; Attributes: TArray<TModelAttribute>): TArray<Model>; function LoadbyWhereClause(Model: TModelClass; WhereClause: String): TArray<TModel>; end; // Nutzung: var Model : TBlubModel; Models : TArray<TBlubModel>; begin // Laden, über die Angabe des PK. Durch Angabe der klasse TBlubModel ist klar, // auf welche Tabelle zugegriffen werden muss. Model := TBaseModelFactory.LoadByPk(TBlubModel, 10); // Laden via "Filter", d.h. über Angabe von Attributen, die dann entsprechend // zu einer Where-Clause zusammengebaut werden. // WICHTIG: Die Attribute sind hier nicht in korrekter Delphi-Syntax angegeben // sondern entsprechend Pseudocode. Models := TBaseModelFactory.LoadbyAttributes(TBlubModel, ['Spalte1' = 10, 'Spalte2' = 'DP']); // ... und dann noch via selbst modelliertem Where-Clause. Models := TBaseModelFactory.LoadByWhereClause(TBlubModel, 'Spalte1 > 15 AND Spalte2 LIKE "%dp%"'); |
AW: Rätselhaftes Konstrukt in Unit Dialogs
IIRC macht Microsoft das ähnlich, wenn man z.B. in VS ein Dataset zu einer bestehenden Tabelle erstellen lässt.
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Delphi-Quellcode:
Wobei man hier uch wieder von doppelten Informationen reden könnte.
type
TMyClass = class [ ListAttribute('SubPositions', TPositionInformation) ] property SubPositions : TObjectList<TPositionInformation> read FSubPositions write FSubPositions; [ ListAttribute('DatabaseVersions', TDatabaseVersion) ] property DatabaseVersions : TObjectList<TDatabaseVersion> read FDatabaseVersions write FDatabaseVersions; [ ListAttribute('ProductionUnits', TProductionUnit) ] property ProductionUnits : TObjectList<TProductionUnit> read FProductionUnits write FProductionUnits; [ ListAttribute('Segments', TPositionSegment) ] property Segments : TObjectList<TPositionSegment> read fSegments write FSegments; end; TagName entpsricht ja dem Property-Namen, so daß man diesen Namen doch auch direkt verwenden könnte? OK, an die Klasse in dem Generic ranzukommen ist nicht so einfach, aber Möglich wäre es bestimmt auch. :stupid: |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Diese Attribute sind insbesondere spannend, wenn man sich aus der DB-Struktur komplette Quellcodes erzeugen lässt. Dann fügt man die Attribute hinzu, um später dynamisch auf allen erzeugten Klassen zugreifen zu können, ohne dass man diese alle untereinander verlinken muss.
Delphi-Quellcode:
Später kann man im Code diese Klassen alle wieder auffinden und nutzen:
type
/// <summary> /// Definitionen für das DB-Schema [inject] /// </summary> [DefineSchema('inject', '{12543F95-68E1-4F42-BA5D-479AFBBA12E1}')] TSchemaInject = class(TSchemaDefinition) public type /// <summary> /// Definitionen für die DB-SProc [inject].[Base_Login_Write] /// </summary> [DefineStoredProc(TSchemaInject, 'Base_Login_Write')] TSProcBase_Login_Write = class(TStoredProcDefinition) public ...
Delphi-Quellcode:
Aus meiner Sicht eine der besten Neuerungen in der Delphi-Language seit langer Zeit (zusammen mit den Generics)
Ctx := TRttiContext.Create;
try for Typ in Ctx.GetTypes do begin if Typ.TypeKind <> tkClass then Continue; // load schemata if not Typ.AsInstance.MetaclassType.InheritsFrom(TSchemaDefinition) then Continue; for Attr in Typ.GetAttributes do begin if not (Attr is DefineSchemaAttribute) then Continue; FKnownSchemata.Add(TSchemaDefinitionClass(Typ.AsInstance.MetaclassType)); Break; end; end; finally Ctx.Free; end; ...:cat:... |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
|
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
Oder ist das bei XE2 eventuell ergänzt worden, dass so etwas wie @Scope ElementType.FIELD auch in Delphi geht: ![]() |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Überall?
Ich kenn viele Stellen, wo ich Kommentare machen kann, aber keine Attribute. Das geht immer nur vor irgendwelchen Deklarationen, wozu es eine RTTI gibt und scheinbar auch bei Variablen und Prozeduren. Auch wenn ich jetzt nicht wüßte, wie man an deren RTTI rankommt, bzw. daß sie überhaupt eine haben. Aber da die neue RTTI rießig ist und dort jeder mögliche Scheiß drinsteht, könnte ich auch glauben, daß sich dazu auch 'ne RTTI finden ließe. :wall: |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Zitat:
Hier ist eine Stackoverflow Frage und eine Aufstellung möglicher Einsatzorte: ![]() Genannt werden: Enums Function type Procedure type Event type (closure, procedure of object) Aliased type Record type Class type Record type that's internal to a class Record field Record method Class instance field Class class field (class var) Class method Global variable Global function Local variable Doch RTTI ist ja schon einen Schritt zu spät. Was ich meinte bezieht sich auf den Zeitpunkt des Compilierens, bevor RTTI erzeugt wird. Man kann in Delphi nicht angeben, dass ein selbst definiertes Attribut ausschliesslich an bestimmten Quelltextelementen wie Properties erlaubt ist - so dass Anwender des Attributes beim Versuch, es z.B. vor einer Klassendefinition oder einem Parameter zu verwenden, einen Compilerfehler erhält. Der Zweck ist offensichtlich, falsche Verwendung eines Attributes zu verhindern. In Delphi kann man erst zur Laufzeit, per RTTI, erkennen ob ein Attribut auch da steht, wo es bestimmungsgemäß hingehört. |
AW: Rätselhaftes Konstrukt in Unit Dialogs
Achso.
Dann wirst du dir einen PostCompile-Assistenten schreiben müssen, welche das nach dem Kopilieren in der EXE prüft und eine Fehlermeldung anzeigt. Oder einen Pre-Compiler-Assistenten, wo du den Quelltext parst und es dort abprüfst. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:01 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-2025 by Thomas Breitkreuz