Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Interface erstellen und rückgabe (https://www.delphipraxis.net/170128-interface-erstellen-und-rueckgabe.html)

EWeiss 2. Sep 2012 11:22

Interface erstellen und rückgabe
 
Ich habe jetzt mal mein letztes Control so erstellt das es übersichtlicher und besser anzusprechen ist
was die Properties und bedienung angeht.

Vorher so!
Delphi-Quellcode:
  ISkinDriveList = interface
    ['{6EB00DD0-CA49-4C92-A452-4D75FDAC2D91}']
    function GetHandle: hWnd;
    function GetDrawStyle: Integer;
    procedure SetFont(nPointSize: Integer; FontName: WideString; FontStyle: TFontStyle;
      AktForecolor: COLORREF; InAktForecolor: COLORREF; Shadow: Boolean;
      SOffset: Integer; ShadowColor: COLORREF);
    property Handle: hWnd read GetHandle;
    property DrawStyle: Integer read GetDrawStyle;
  end;

constructor TSkinDriveList.Create(hOwner: HWND; SelectedImg: WideString; ListButton: WideString;
  x, y, xW, yH, DriveListID: integer; Visible: Boolean; ItemHeight: Integer; BackColor: COLORREF);
Nun so!
Delphi-Quellcode:
  ISkinDriveList = interface
    ['{6EB00DD0-CA49-4C92-A452-4D75FDAC2D91}']
    function GetHandle: hWnd;
    function GetDrawStyle: Integer;
    function GetSelectedImg: WideString;
    procedure SetSelectedImg(const SelectedImg: WideString);
    function GetListButton: WideString;
    procedure SetListButton(const ListButton: WideString);
    function GetHeight: Integer;
    procedure SetHeight(const Height: Integer);
    function GetLeft: Integer;
    procedure SetLeft(const Left: Integer);
    function GetTop: Integer;
    procedure SetTop(const Top: Integer);
    function GetWidth: Integer;
    procedure SetWidth(const Width: Integer);
    function GetDlgItemID: integer;
    procedure SetDlgItemID(const DlgItemID: integer);
    function GetVisible: Boolean;
    procedure SetVisible(const Visible: Boolean);
    function GetListItemHeight: Integer;
    procedure SetListItemHeight(const ListItemHeight: Integer);
    function GetBackcolor: COLORREF;
    procedure SetBackcolor(const Backcolor: COLORREF);
    function CreateWindow(ParentHandle: HWND): HWND;
    procedure SetFont(nPointSize: Integer; FontName: WideString; FontStyle: TFontStyle;
      AktForecolor: COLORREF; InAktForecolor: COLORREF; Shadow: Boolean;
      SOffset: Integer; ShadowColor: COLORREF);
    property Handle: hWnd read GetHandle;
    property DrawStyle: Integer read GetDrawStyle;
    property SelectedImg: WideString read GetSelectedImg write SetSelectedImg;
    property ListButton: WideString read GetListButton write SetListButton;
    property Left: Integer read GetLeft write SetLeft;
    property Top: Integer read GetTop write SetTop;
    property Width: Integer read GetWidth write SetWidth;
    property Height: Integer read GetHeight write SetHeight;
    property DlgItemID: integer read GetDlgItemID write SetDlgItemID;
    property Visible: Boolean read GetVisible write SetVisible;
    property ListItemHeight: Integer read GetListItemHeight write SetListItemHeight;
    property BackColor: COLORREF read GetBackColor write SetBackColor;
  end;

constructor TSkinDriveList.Create();

begin
  inherited Create;

end;
Der sinn dabei ist das ich vorher alle propertys zuweisen kann bevor ich das Window erstelle.
So wie es normalerweise auch in der Designer umgebung mit PropertyEditor ist.

Delphi-Quellcode:
  lbDriveList := CTRL_DriveListCreate();
  lbDriveList.SelectedImg := (SKAERO_FOLDER + 'Search\ListSelect.png');
  lbDriveList.ListButton := (SKAERO_FOLDER + 'Search\combo.png');
  lbDriveList.Left := 18;
  lbDriveList.Top := 209;
  lbDriveList.Width := 105;
  lbDriveList.Height := 21;
  lbDriveList.DlgItemID := ID_DRIVELIST;
  lbDriveList.Visible := True;
  lbDriveList.ListItemHeight := 21;
  lbDriveList.BackColor := SKAERO_BTNTEXTCOLOR;
  DriveListHandle := lbDriveList.CreateWindow(SearchHandle);

  if DriveListHandle <> 0 then
  begin
    lbDriveList.SetFont(SKAERO_PUSHBUTFONTSIZE, PWideChar(SKAERO_TEXTFONT), FontStyleBoldItalic,
      SKAERO_ACTIVECAPTION, SKAERO_INACTIVECAPTION, TRUE, 2, 0);
    SKAERO_SetAnchorMode(DriveListHandle, ANCHOR_HEIGHT_WIDTH);
    SKAERO_SetZorder(DriveListHandle, HWND_TOP);
  end;
Die frage ist nun bei create

Delphi-Quellcode:
lbDriveList := CTRL_DriveListCreate();


Da exisitert ja ausgenommen von inherited Create;
kein weiterer Eintrag.

Constructor entfernen oder so lassen wie es ist.
Hab da noch ein verständis problem .. sorry

oops..
Denke die frage hat sich erübrigt.

gruss

s.h.a.r.k 3. Sep 2012 10:00

AW: Interface erstellen und rückgabe
 
Zitat:

Zitat von EWeiss (Beitrag 1181029)
oops..
Denke die frage hat sich erübrigt.

gruss

Und das heisst? :wink:

Wenn nichts weiteres im Konstruktur passiert, außer der Aufruf von inherited Create(), dann solltest du diesen weg lassen, da dies sonst nur zusätzliche CPU-Zyklen kostet und sonst nichts anderes passiert, als wenn du es weglassen würdest.

EWeiss 3. Sep 2012 10:37

AW: Interface erstellen und rückgabe
 
Und wie bekomme ich dann den zeiger auf das Interface zurück? ohne inherited
Denke mal gar nicht oder?

Sollte dann unweigerlich zum Absturz der Anwendung führen.

gruss

s.h.a.r.k 3. Sep 2012 10:59

AW: Interface erstellen und rückgabe
 
Verstehe ich jetzt nicht ganz?! :gruebel: Du brauchst das inherited Create(), da wenn du keinen Konstruktur definierst, immer der von der Super-Klasse aufgerufen wird. Beispiel: Hier wird automatisch der Konstruktor von TInterfacedObject aufgerufen:
Delphi-Quellcode:
IBlub = interface
  { GUID }
  procedure Bla();
end;

TBaseBlub = class(TInterfacedObject, IBlub)
public
  procedure Blub();
end;


var
  XYZ : IBlub;
begin
  XYZ := TBlub.Create();
  XYZ.Blub();
end;
Oder reden wir evtl. aneinander vorbei?!

EWeiss 3. Sep 2012 11:03

AW: Interface erstellen und rückgabe
 
Zitat:

Wenn nichts weiteres im Konstruktur passiert, außer der Aufruf von inherited Create(), dann solltest du diesen weg lassen
Wenn ich ein Property an das Interface übergebe ohne das ich den Pointer auf das Interface habe
also dieses nicht NIL ist kommt es beim entfernen oder nicht benutzen von create zum absturz.

Deshalb sagte ich auch das es sich erübrigt hat.

Ich könnte QueryInterface verwenden aber warum sollte ich das tun wenn über inherited Delphi das für mich übernimmt.

Es passiert nichts weiter außer das mein Interface zurück gegeben wird.

Delphi-Quellcode:
lbDriveList := CTRL_DriveListCreate();


Verzweigt auf

Delphi-Quellcode:
constructor TSkinDriveList.Create();


gruss

EWeiss 3. Sep 2012 11:21

AW: Interface erstellen und rückgabe
 
Alt mit Constructor

Delphi-Quellcode:
function CTRL_DriveListCreate(): ISkinDriveList; stdcall;
begin

  result := TSkinDriveList.Create();
end;

constructor TSkinDriveList.Create();

begin
  inherited Create;

end;
Neu ohne Constructor

Delphi-Quellcode:
function CTRL_DriveListCreate(): ISkinDriveList; stdcall;
var
  SkinDriveList : TSkinDriveList;
begin

  SkinDriveList := TSkinDriveList.Create;
  result := SkinDriveList;
end;
Und auch hier wird intern von Delphi inherited aufgerufen oder nicht ?
Dann stellt sich aber eine andere Frage was ist dann mit destructor wenn vorher kein Constructor aufgerufen wurde.

Delphi-Quellcode:
destructor TSkinDriveList.Destroy;
begin
  UnSubClass(Handle);
  lbFirstList := nil;

  inherited Destroy;
end;
Ohne Constructor mache ich ja das was Delphi mit inherited von selber macht.
Da ist mein verständnis problem ;)

gruss

Medium 3. Sep 2012 11:34

AW: Interface erstellen und rückgabe
 
Zitat:

Zitat von EWeiss (Beitrag 1181216)
Neu ohne Constructor

Delphi-Quellcode:
function CTRL_DriveListCreate(): ISkinDriveList; stdcall;
var
  SkinDriveList : TSkinDriveList;
begin

  SkinDriveList := TSkinDriveList.Create;
  result := SkinDriveList;
end;

Du kannst ruhig auch hier direkt an "result" zuweisen.

Zitat:

Dann stellt sich aber eine andere Frage was ist dann mit destructor wenn vorher kein Constructor aufgerufen wurde.
Und auch hier wird intern von Delphi inherited aufgerufen oder nicht ?
OOP Grundlagen. Es wird immer ein Konstruktor aufgerufen, wenn man ein Create() macht. Wenn man in seiner Ableitung keinen selbst erstellt, wird der der Elternklasse genommen. Quasi ein implizites inherited (wenn technisch auch nicht ganz gleich, aber so kann man sich es mal vorstellen). Der Destruktor gehorcht der selben Mechanik. Da man aber beide immer zwangsweise von irgendwo erbt, ist man nicht zum Neuschreiben gezwungen, und man muss auch nicht zwangsweise paarweise implementieren. (Man kann durchaus nur einen Destruktor haben.) Vererbung macht u.a. genau dies möglich, bzw. ist das ein Fundament der OOP.

EWeiss 3. Sep 2012 11:40

AW: Interface erstellen und rückgabe
 
Zitat:

Du kannst ruhig auch hier direkt an "result" zuweisen.
Habe es geändert.

Danke für die Erläuterungen.

gruss

EWeiss 5. Sep 2012 16:00

AW: Interface erstellen und rückgabe
 
Hab doch noch ein problem.

Delphi-Quellcode:
property Width: Integer read GetWidth write SetWidth;
Wird aufgerufen um beliebigen Window bsp.. Button die Weite zuzuweisen.

Nach dem erstellen der Anwendung darf oder sollte zumindest die Weite des Buttton nicht mehr verändert werden.

Aufgrund des Interface ist dies aber leider gegeben.

Wie könnte ich das trotzdem verhindern bzw. das diese Funktion nach dem erstellen
des Windows nicht mehr aufgerufen werden kann.

Ja ist jetzt etwas blöd aber einmal festgelegt Weiten eines Button kann man ja auch
zur Laufzeit ohne zusätzliche mittel nicht mehr verändern.

Bei meiner alten Funktion war das nicht möglich
da die weite im Interface nach außen nicht weitergegeben wurde.

Delphi-Quellcode:
constructor TSkinDriveList.Create(hOwner: HWND; SelectedImg: WideString; ListButton: WideString;
   x, y, xW, yH, DriveListID: integer; Visible: Boolean; ItemHeight: Integer; BackColor: COLORREF);

Wie man's macht macht's man falsch. ;)


gruss

implementation 5. Sep 2012 16:05

AW: Interface erstellen und rückgabe
 
Dann musst du in der SetWidth-Methode überprüfen, ob sie schonmal aufgerufen wurde.

EWeiss 5. Sep 2012 16:10

AW: Interface erstellen und rückgabe
 
Zitat:

Zitat von implementation (Beitrag 1181703)
Dann musst du in der SetWidth-Methode überprüfen, ob sie schonmal aufgerufen wurde.

Mach ich mehr oder weniger ja auch..

Delphi-Quellcode:
procedure TSkinPanel.SetWidth(const Width: Integer);
begin

  FWidth := Width;
end;
Ich behandle nachfolgende veränderungen der Weite einfach nicht.
Aber mein problem hinsichtlich der möglichen Eingabe lößt das nicht.

Eine behandlung sähe dann so aus

Delphi-Quellcode:
procedure TSkinPanel.SetWidth(const Width: Integer);
begin
  MoveWindow(bla.. bala..

  FWidth := Width;
end;

gruss

geskill 5. Sep 2012 16:58

AW: Interface erstellen und rückgabe
 
Hallo,
wegen der unerwünschten Eingaben. Du könntest ja 2 Interfaces bauen:
Delphi-Quellcode:
type
  ISimpleButton = interface
    ['{B7281ABB-ED9A-4018-B651-41DFBFAE730A}']

    function GetText: WideString;
    procedure SetText(Value: WideString);

    property Text: WideString read GetText write SetText;
  end;

  IAdvancedButton = interface(ISimpleButton)
    ['{6C10BCC7-87BE-45B1-9613-44EF840DE4AA}']

    function GetWidth: Integer;
    procedure SetWidth(Value: Integer);

    function GetSimpleButton: ISimpleButton;

    property Width: Integer read GetWidth write SetWidth;
  end;
Dann könntest du von einem TAdvancedButton Objekt dir intern das IAdvancedButton speichern, extern aber nur ISimpleButton zur Verfügung stellen.

Delphi-Quellcode:
type
  TSimpleButton = class(TInterfacedObject, ISimpleButton)
  private
    FText: WideString;
  protected
    function GetText: WideString;
    procedure SetText(Value: WideString);

  public
    constructor Create;

    property Text: WideString read GetText write SetText;
  end;

  TAdvancedButton = class(TSimpleButton, IAdvancedButton)
  private
    FWidth: Integer;
  protected
    function GetWidth: Integer;
    procedure SetWidth(Value: Integer);

  public
    constructor Create;

    function GetSimpleButton: ISimpleButton;

    property Width: Integer read GetWidth write SetWidth;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TSimpleButton }

constructor TSimpleButton.Create;
begin
  inherited Create;
end;

function TSimpleButton.GetText: WideString;
begin
  Result := FText;
end;

procedure TSimpleButton.SetText(Value: WideString);
begin
  FText := Value;
end;

{ TAdvancedButton }

constructor TAdvancedButton.Create;
begin
  inherited Create;
end;

function TAdvancedButton.GetSimpleButton: ISimpleButton;
begin
  Result := Self;
end;

function TAdvancedButton.GetWidth: Integer;
begin
  Result := FWidth;
end;

procedure TAdvancedButton.SetWidth(Value: Integer);
begin
  FWidth := Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  AdvancedButton: IAdvancedButton;

  SimpleButton: ISimpleButton;
begin
  AdvancedButton := TAdvancedButton.Create;

  AdvancedButton.Width := 126;
  AdvancedButton.Text := 'lalala';

  ShowMessage(IntToStr(AdvancedButton.Width) + ' ' + AdvancedButton.Text);

  SimpleButton := AdvancedButton.GetSimpleButton;

  ShowMessage(SimpleButton.Text);

  SimpleButton.Text := 'blubblub';

  ShowMessage(IntToStr(AdvancedButton.Width) + ' ' + AdvancedButton.Text);
end;
Grüße

EWeiss 5. Sep 2012 17:10

AW: Interface erstellen und rückgabe
 
Danke ;)
Werde mir das gleich mal anschauen ob etwas in der art mein problem beseitigt.

EDIT:
So wie das aussieht ist das ein mehr an schreibarbeit aber letztendlich ist Width trotzdem public.
Muss das wohl innerhalb der function Width selbst händeln.
Die Weite ignorieren wenn sie schon gesetzt ist.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:46 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