![]() |
Code strukturieren! Wie macht man es richtig ..
Eine grundsätzliche frage
Wie strukturiert man seinen Quelltext richtig. Ich stelle fest das ich immer wieder in den alten trott von VB verfalle deshalb mal diese frage um sicher sein zu können es direkt von vornherein richtig zu machen. Ich lese eine zeile von einer Textdatei ein und übergebe diese wie folgt
Delphi-Quellcode:
zCAPTIONFONTHEIGHT(StrToInt(ParseThis(sBF, ',', 1)), 1);
Delphi-Quellcode:
function TSkinConfig.zCAPTIONFONTHEIGHT(N, RW : Integer): Integer;
begin if RW <> 0 then WasN := N; Result := WasN; end;
Delphi-Quellcode:
Den wert von zCAPTIONFONTHEIGHT lese ich so zurück!
TSkinConfig = class
private // public function zCAPTIONFONTHEIGHT(N, RW : Integer): Integer; end; Dafür habe ich in meiner SkinEngine Class eine extra Variable angelegt ebenfalls Public
Delphi-Quellcode:
Die abfrage oder wenn ich den wert verändern will läuft wie folgt
function SK_CAPTIONFONTHEIGHT: Integer;
Delphi-Quellcode:
Wird ein neuer wert RW übergeben wird dieser in WasN gespeicher solange bis ein neuer übergeben wird..
function TSkinEngine.SK_CAPTIONFONTHEIGHT: Integer;
begin Result := SkinConfig.zCAPTIONFONTHEIGHT(0, 0); end; Frage ich den wert ab wie angezeigt
Delphi-Quellcode:
bekomme ich als resultat den zuletzt übergeben Wert zurück geliefert.
SkinConfig.zCAPTIONFONTHEIGHT(0, 0);
Also in diesen Fall, den der aus meiner TextDatei eingelesen wurde. Grundsätzlich funktioniert das aber mein bedenken es ist einfach nicht optimiert. Da zu viel unnötiger Code geschrieben wird. zu dem Thema noch eine zusätzliche Frage.. Was kommt nun genau unter Privat, Public, Published ? Meine Frage deshalb damit ich nicht unötig langen Code abfragen muss.. So wie diesen hier.
Delphi-Quellcode:
Wie kann man sowas optimieren das man nicht immer SkinEngine davor schreiben muss.
SkinConfig.zAEROCOLOR(SkinEngine.zColorARGB(SkinEngine.zGetTrackValue(SkinEngine.zGetMainItem(ID_TRACK_OPACITY)),RGB(Red, Green, Blue)), WRITE);
Ich muss also immer zwischen SkinConfig und SkinEngine hin und her wandern und jedesmal den namen noch davor schreiben. Wenn ich alles ohne Class mache kann ich aus jeder unit auf alle Funktionen zugreifen. Denke aber das wäre auch nicht der richtige weg. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Delphi-Quellcode:
with SkinConfig, SkinEngine do
zAEROCOLOR(zColorARGB(zGetTrackValue(zGetMainItem(ID_TRACK_OPACITY)), RGB(Red, Green, Blue)), WRITE); |
Re: Code strukturieren! Wie macht man es richtig ..
Mal so nebenbei:
Zitat:
Zitat:
GetAeroColor SetAeroColor AeroColorToFoo ... |
Re: Code strukturieren! Wie macht man es richtig ..
Mir ging es eigentlich um die Strukturierung des Quelltextes
Wie würdet ihr das denn anhand des beispiel machen ? Irgendwie gehen wir am Thema vorbei. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Ich denke, da gibt es kein richtig oder falsch. Es ist hauptsächlich eine Geschmaksfrage, wie man es selbst am besten findet und man es selbst am besten lesen kann. Wenn du damit klar kommst, würde ich da nichts ändern.
Aber was die Benennung der Methoden angeht, würde ich den Tipp von Reinhardtinho beherzigen. Hinzukommt die Großschreibung der Bezeichner. Nur Großbuchstaben wählt man eigentlich nur für Konstanten, deswegen würde mich die Art der Bezeichnung bei dir ziemlich verwirren. Methoden benannt man nach dem was sie machen, bestehen also meistens aus zumindest einem Verb. Die ersten Buchstaben der Wortbestandteile schreibt man dann groß, wie auch schon im Beispiel:
Delphi-Quellcode:
Die Methoden sind GetAeroColor und SetAeroColor und haben entsprechend ein verb vorangestellt. Get für die Getter und Set für die Setter. Bei der Eigenschaft fehlt dann dieses Verb.
GetAeroColor
SetAeroColor AeroColor Bei dir würde das dann entsprechend aussehen:
Delphi-Quellcode:
Was soll eigentlich das kleine "z" vor den Methodennamen? Unter Delpjhi ist die Ungarische Notation eher nicht gebräuchlich, aufgrund der Typensicherheit der Sprache und der Codevervollständigung der IDE eigentlich auch überflüssig.
GetCaptionFontHeight // Getter
SetCaptionFontHeight // Setter CaptionFontHeight // Property |
Re: Code strukturieren! Wie macht man es richtig ..
Schau dir mal die Style Guides an, die von Borland mal empfohlen wurden. In deutsch findest du hier eine entsprechende
![]() Grüße Mikhal |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Aber irgendwie komm ich damit nicht zurecht. Es muss doch einen grund habe das ihr eure Classen anders aufbaut Beispiel:
Delphi-Quellcode:
Könnte man ersetzen wenn ich so überlege mit
function TSkinConfig.zCAPTIONFONTHEIGHT(N, RW : Integer): Integer;
begin if RW <> 0 then WasN := N; Result := WasN; end;
Delphi-Quellcode:
Theoretisch wäre das dass gleiche von der Funktionsweise.
property CaptionFontHeight: Integer read FGetCaptionFontHeight write FSetCaptionFontHeight;
Nur wo liegt der unterschied. Ist es sinnvoller über property zu gehen oder über eine Funktion gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Geht auch nur Online. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Es macht keinen all zu großen Unterschied. Properties sind ein sehr eleganter Weg das Geheimnisprinzip der OOP zu realiseren, und wie ich finde gerade in Delphi sehr angenehm implementiert. Getter/Setter Methoden ohne Properties würde ich in Delphi daher eher als nicht so schönen Stil ansehen, bei Sprachen die dieses Konstrukt nicht kennen sind sie halt der einzig sinnvolle Weg.
Das nette an Properties ist, dass man z.B. nur einen Weg (setzen/lesen) über eine Methode machen kann, und für den anderen Fall direkt auf die Variable verweist. Das spart in manchen Fällen einfach eine Methode die eh nur dem result den unveränderten Variableninhalt zuweisen würde. Zudem werden vom Compiler für Properties noch zusätzliche RTTI Informationen erzeugt, die ab und an auch hilfreich sein können - aber das sind nun schon sehr spezielle Dinge. Edith wollte den Hinweisen zur Benamsung nur noch ein wenig Nachdruck verleihen :) |
Re: Code strukturieren! Wie macht man es richtig ..
Man kann entweder mit der Property direkt das private Attribut abfragen und setzen oder man kann über private Methoden, den sogenannten Gettern und Settern gehen. Mit einem Getter oder Setter hat man die Möglichkeit die Daten noch zu verifizieren bevor man sie den privaten ASttributen zuweist bzw. bevor man sie ausgibt. Deswegen wähle ich immer den Weg über die Getter und Setter, auch wenn ich sie eigentlich nicht bräuchte, aber eventuell braucht man sie ja doch noch mal.
|
Re: Code strukturieren! Wie macht man es richtig ..
Verifizieren kann man sie und man könnte ein Event auslösen - auch oft ein guter Grund wenigstens für Setter.
|
Re: Code strukturieren! Wie macht man es richtig ..
Also würdet ihr lieber ein property verwenden anstelle der von mit gewählten funktion.
Zumindest hätte ich mir dann einiges an code gespart und muss nicht alles doppelt deklarieren. Reicht dann diese eine property zeile oder muss ich zusätzlich noch Funktionen einbauen mit dem ich den aktuellen status von FGetCaptionFontHeight erfrage ? Nur dann hätte ich nichts gewonnen. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Bei einer Property hast Du mehrere Möglichkeiten:
Delphi-Quellcode:
Die einfachste: indirekter Zugriff auf das private Feld FBlubb sowohl lesend als auch schreibend.
private
FBlubb: TBlubb; ... public property Blubb: TBlubb read FBlubb write FBlubb;
Delphi-Quellcode:
Lesender Zugriff immer noch indirekt, schreibender über einen Setter. Im Setter kann man Gültigkeitsprüfungen vornehmen und entsprechend reagieren.
private
FBlubb: TBlubb; procedure SetBlubb(const Value: TBlubb); ... public property Blubb: TBlubb read FBlubb write SetBlubb;
Delphi-Quellcode:
Lesender Zugriff über den Getter, schreibender über den Setter. Im Sinne der OOP ist dies der "amtliche" Weg (gerade in der Hinsicht auf andere Sprachen als Delphi). Ich persönlich spare mir eine Getter-Methode aus Faulheitsgründen, da sie IMO keinen echten Mehrwert bringt.
private
FBlubb: TBlubb; function GetBlubb: TBlubb; procedure SetBlubb(const Value: TBlubb); ... public property Blubb: TBlubb read GetBlubb write SetBlubb; [edit] Nachtrag: durch Weglassen von write bzw. read kannst Du eine Property zusätzlich noch als Read-/Write-Only definieren [/edit] |
Re: Code strukturieren! Wie macht man es richtig ..
Eine Getter-Methode erlaubt Dir eine sog. "Lazy-Initialization".
Angenommen, Du hast "teure" Daten im Speicher, brauchst diese aber entweder nicht sofort oder aber nicht immer. Dann kann Dir eine Getter-Methode helfen, diese Daten erst dann zu holen / zu erzeugen, wenn sie tatsächlich benötigt werden. |
Re: Code strukturieren! Wie macht man es richtig ..
OK, das Argument kann ich gelten lassen.
|
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
:mrgreen: |
Re: Code strukturieren! Wie macht man es richtig ..
Du bist sooo gut zu mir :oops: :mrgreen:
|
Re: Code strukturieren! Wie macht man es richtig ..
Danke für eure Informationen werd dann auf property umsteigen bei einigen Funktionen
Das erparrt mir einiges an Tip arbeit. Zumindest bei denen wo es nur um eine variable abspeichern/Lesen geht.. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Ja,
und die IDE unterstützt Dich Dabei auch noch. Einfach die Property definieren und über Klasse vervollständigen werden Getter und Setter automatisch eingefügt. (edit: bei bds2006 jedenfalls :roll: ) |
Re: Code strukturieren! Wie macht man es richtig ..
Warum funktioniert das nicht?
Was ist da Falsch
Delphi-Quellcode:
Also die Funktion als property
property AeroEmulate[FGetAeroEmulate, FSetAeroEmulate: Integer]: Integer read FGetAeroEmulate write FSetAeroEmulate;
Delphi-Quellcode:
gruss Emil
function TSkinConfig.zAEROEMULATE(nMode, RW : Integer): Integer;
begin if RW <> 0 then WasMode := nMode; Result := WasMode; end; |
Re: Code strukturieren! Wie macht man es richtig ..
Hi,
Ich verstehe grad leider nicht was du da tun willst :wiejetzt: Allgemein:
Delphi-Quellcode:
Beispiel:
property _Name_: _Datentyp_ read FVar write FVar;
Delphi-Quellcode:
Vor privaten Variablen steht ein F.
private
FName: String; public property Name: String read FName write FName; end; oder:
Delphi-Quellcode:
property _Name_[Index: Integer]: _Datentyp_ read GetVar write SetVar;
Delphi-Quellcode:
:arrow: Vor Getter/Setter-Methoden steht das Get/Set Prefix. Ohne F!
private
FWerte: Array of Integer; public property Werte[Index: Integer]: Integer read GetWert write SetWert; end; implementation function TKlasse.GetWert(Index: Integer): Integer; begin Result := FWerte[Index]; end; procedure TKlasse.SetWert(Index: Integer; const Value: Integer); begin FWerte[Index] := Value; end; Du kannst Setter und Getter auf für Nicht-Array-Properties benutzen:
Delphi-Quellcode:
In den Getter- und Setter Methoden kannst du zudem beeinflussen, was genau zurückgegeben, (gelesen) und geschrieben wird. z.B.
private
FName: String; function GetName: String; procedure SetName(const Value: String); public property Name: String read GetName write SetName; end; implementation function TKlasse.GetName: String; begin Result := FName; end; procedure TKlasse.SetName(const Value: String); begin FName := Value; end;
Delphi-Quellcode:
Das hier sind jetzt nur Beispiele. Ist jetzt evtl nicht das allersinnvollste. Aber ich denke es verdeutlicht den Sinn und Zweck von Properties. Und auch deren Funktionsweise ;)
function TKlasse.GetWert(Index: Integer): Integer;
begin if not (Index in [0..High(FWerte)]) then Result := -1 else Result := FWerte[Index]; end; procedure TKlasse.SetWert(Index: Integer; const Value: Integer); begin if Value < 0 then FWerte[Index] := 0 else FWerte[Index] := Value; end; |
Re: Code strukturieren! Wie macht man es richtig ..
Ich habe in meiner Funktion 2 Werte nicht einen
Beide möchte ich über properties zurücklesen geht das nicht? Ich möchte nicht
Delphi-Quellcode:
abfragen
if SkinEngine.AeroEmulate(0, 1) = 0
sondern so wie bisher
Delphi-Quellcode:
Du verstehst ?
if SkinEngine.AeroEmulate = 0
Und das über eine property Ich lese aus meiner Datei den wert
Delphi-Quellcode:
ein
nMode : Integer
ist RW > 0 wird dieser wert in WasMode gespeichert. andernfalls behält WasMode den alten wert.
Delphi-Quellcode:
ich kann also AeroEmulate gegenprüfen ohne den vorherigen wert zu löschen wenn RW
AeroEmulate(StrToInt(ParseThis(sBF, ',', 1)), 1);
den wert von 0 hat. gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
So habs jetzt so gemacht ..
Ist aber vom Code her sogar noch mehr als über die alte Funktion.
Delphi-Quellcode:
// SkinConfig
TSkinConfig = class private FAeroEmulate : Integer; function GetAeroEmulate(FMode, FReadMode: Integer): Integer; procedure SetAeroEmulate(FMode, FReadMode: Integer; const Value: Integer); public property AeroEmulate[FMode, FReadMode: Integer]: Integer read GetAeroEmulate write SetAeroEmulate; end; function TSkinConfig.GetAeroEmulate(FMode, FReadMode: Integer): Integer; begin if FReadMode > 0 then FAeroEmulate := FMode; Result := FAeroEmulate; end; // aus meiner TextDatei eingelesen case SkinType of stAeroEmulate: begin AeroEmulate[StrToInt(ParseThis(sBF, ',', 1)), 1]; end; end;
Delphi-Quellcode:
Und genau das meine ich extrem viel Code nur um eine Funktion abzufragen.
// SkinEngine
TSkinEngine = class private // public function SK_AEROEMULATE: Integer; end; function TSkinEngine.SK_AEROEMULATE: Integer; begin Result := SkinConfig.AeroEmulate[0, 0]; end; // im Code abgefragt if SK_AEROEMULATE > 0 then begin // end; gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Fällt dir nicht selber auf, dass du beim zweiten Aufruf der Funktion zwei sinnlose Parameter mitgeben musst, wo du doch nur einen Wert haben willst?
Und wo wir gerade mal so beim grübeln sind: kommt dir es nicht ein wenig komisch vor, dass Parameter für eine Bedingung sowie einen bedingungspezifischen Wert an eine Property gibst? Wird da nicht selbst ein wenige mulmig, wenn eine Property (ich übersetze nochmal explizit: Eigenschaft) eine Bedingung enthält, wann sie was übernimmt und die Bedingungsparameter ihr auch noch mitgegeben werden? Meinst du nicht auch, dass dieses lieber ausserhalb der Property gemacht werden sollte?
Delphi-Quellcode:
// SkinConfig
TSkinConfig = class private fAeroEmulate : Integer; public function ReadConfig: boolean; property AeroEmulate: integer read fAeroEmulate write fAeroEmulate; end;
Delphi-Quellcode:
Die Abfrage an sich ist schon hinfällig, da du fest 1 übergibst bei dem Aufruf. Und somit entscheidet allein der Case Zweig, ob die Variable zugewiesen wird oder nicht. Und da wir schon im spezifischen Case Zweig sind, ist die Abfrage sinnlos. Und da die Config eigentlich von der Klasse selbst eingelesen werden sollte, schliesslich hält sie die Config, kann sie direkt den Member setzen.
procedure TSkinConfig.ReadConfig;
begin // aus meiner TextDatei eingelesen case SkinType of stAeroEmulate: begin fAeroEmulate := StrToInt(ParseThis(sBF, ',', 1)); end; .... end; end; Und dein SkinEngine kann doch einfach nur die Instanz der TSkinConfig öffentlich anbieten und somit auch nutzen:
Delphi-Quellcode:
// SkinEngine
ESkinException = class(Exception); ESkinConfigError = class(ESkinException); TSkinEngine = class private fConfig: TSkinConfig; public constructor Create; destructor Destroy; override; property Config: TSkinConfig read fConfig; // kein write!!! end;
Delphi-Quellcode:
constructor TSkinEngine.Create;
begin inherited; fConfig := TSkinConfig.Create; if not fConfig.ReadConfig then raise ESkinConfigError.Create('Skin Config invalid or not available!'); end; destructor TSkinEngine.Destroy; begin fConfig.Free; inherited; end;
Delphi-Quellcode:
// im Code abgefragt
if fConfig.AeroEmulate > 0 then begin // end; |
Re: Code strukturieren! Wie macht man es richtig ..
was ist da sinnlos?
Die beiden parameter sind berechtigt da es sich hier um eine nonvcl anwendung handelt. Ich also auch innerhalb unabhängig von der Config die eigenschaften ändern kann .. muss
Delphi-Quellcode:
erste wert gibt das neue ergebnis zurück wenn der zweite auf 1 steht.
Result := SkinConfig.AeroEmulate[0, 0];
Result := SkinConfig.AeroEmulate[0, 0]; erste wert gibt das aktuelle(alte) ergebnis zurück wenn der abgefragte zweite wert = 0 ist. Der zweite wert ist nichts anderes als ein schalter EIN oder AUS verstehe nicht was da sinnlos ist. Bei den anderen Punkten muss ich sagen nicht schlecht ;) Werd das wohl in der art übernehmen.. Danke gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Auch schon in der prozeduralen Programmierung sind Funktionen, die nicht nur etwas liefern, sondern nebenbei auch verändernd wirken (=Seiteneffekte) ein absolutes 'No Go'. Eine Funktion (und nichts anderes ist ja eine Eigenschaft, auf die lesend zugegriffen wird) liefert Daten zurück, verändert aber keinesfalls die interne Semantik! Natürlich kann man beim erstmaligen Lesezugriff ein Flag prüfen und ggf. setzen, um z.B. redundante langsame Abfragen zu vermeiden ("Fetch on Demand"), aber der Flag ist ja nicht Bestandteil der Semantik.
Delphi-Quellcode:
Das ist ok, obwohl 'FLoaded' verändert wird.
Function GetProperty : TSomeType;
Begin If Not FLoaded Then Begin FProperty := ExternalAndSlowReadProperty; FLoaded := True; End; Result := FProperty; End; In Deinem Fall würde ich eine zweite Eigenschaft 'AlternateAeroEmulate' definieren. Der Lesezugriff auf 'AeroEmulate' besitzt dann einen Parameter 'ReadMode', der steuert, ob FAlternateAeroEmulate' oder 'AeroEmulate' geliefert wird. |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Wenn man für eine Aktion 5 Funktionen verwendet. Die Gesellschaft ist schwer verschwenderisch geworden scheint überall der Fall zu sein Selbst bei bit und byte gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Bei den heutigen Preisen von 10 cent je Gigabyte tendiert der Tradeoff zwischen Entwicklungskosten und Produktgröße eben immermehr dahin, dass die Entwicklung vereinfacht wird, und dafür das Ausgangsprodukt voluminöser wird ;)
.net Framework <> Assembler ;) Es komt natürlich immer auf den Einsatzzweck an, auch heute gibt es noch Anwendungen, wo es auf die Größe ankommt. Nicht jeder will schließlich ein paar Gigabyte in einen Kühlschrank einbauen. Aber in Zeiten billiger Festplatten kann man eben dadurch enorm Entwicklungszeit (= -kosten) sparen ;) |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Zitat:
Ich schreibe lieber eine Zeile mehr, wenn es dem Verständnis dient. Beim Codieren geht es doch nicht darum, mit möglichst wenig Zeilen zum Ziel zu kommen, sondern eher darum, eine Problemlösung mit formalen Mitteln (=Programmiersprache, OOP) allgemeinverständlich zu formulieren. Ein schönes und sonniges Wochenende! |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
![]() Dann habe ich jetzt schon bei weiten mehr an Code als über eine einfache Funktion Gut muss aber sagen so bin ich auf der sicheren seite. Addiere ich nun dein BEispiel hinzu sind es nicht nur zwei sondern für jede abrage der Config * x Das füllt ebend mal so die Seite locker mit mehr als 200 Zeilen. Ich frage mich ob man dann noch eine übersicht behält. Nur in der SkinConfig Unit habe ich jetzt schon 950 Zeilen. In der uSkin schon 2440 gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
|
Re: Code strukturieren! Wie macht man es richtig ..
Hab jetzt ne neue Klasse angefangen..
Eine non VCL CheckBox Was bietet sich da an, was man in create und destroy reinpacken kann?
Delphi-Quellcode:
Ja ich nerve ich weis :)
unit uCheckButton;
interface uses Windows, Classes, Messages; type TSkinCheckButton = class private FButtonHandle: HWND; Img : Cardinal; Style : DWORD; UseState : Integer; public constructor Create; destructor Destroy; override; function CheckButton(hOwner: HWND; FullpathImageName:PAnsiChar; stLabel: PAnsiChar; x, y, xW ,yH ,ButID: Integer; ARGBColor: COLORREF; StateMax: Integer): Integer; function GetCheckButtonStatus(hBut: DWORD): Integer; procedure SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool); end; implementation uses uSkin; function TSkinCheckButton.CheckButton(hOwner: HWND; FullpathImageName, stLabel: PAnsiChar; x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF; StateMax: Integer): Integer; begin with SkinEngine do begin if RegisterButton(SKBUTIMAGE) <> 0 then begin // Erstelle ein GDIPLUS Image von Datei Img := AddResource((FullpathImageName)); if Img <> 0 then Style := WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTOCHECKBOX; FButtonHandle := CreateWindowEx(WS_EX_TRANSPARENT, SKBUTIMAGE, stLabel, Style, x, y, xW, yH, hOwner, ButID, sInstance, nil); if FButtonHandle <> 0 then begin if StateMax < 1 then StateMax := 2; // Speichere das Image Handle in die Property SetImageProperty(FButtonHandle, PROP_IMAGE, Img); SetImageProperty(FButtonHandle, PROP_STYLE, BS_AUTOCHECKBOX); SetImageProperty(FButtonHandle, PROP_TEXT_COLOR, ARGBColor); SetImageProperty(FButtonHandle, PROP_STATEMAX, StateMax); Result := FButtonHandle; end else begin // Lösche das Image DeleteResource(Img); end; end; end; end; constructor TSkinCheckButton.Create; begin // end; destructor TSkinCheckButton.Destroy; begin // inherited Destroy; end; // Hole den Checkbutton status function TSkinCheckButton.GetCheckButtonStatus(hBut: DWORD): Integer; begin Result := 0; if SendMessage(hBut, BM_GETCHECK, 0, 0) = BST_CHECKED then Result := -1; end; // Setze den Checkbutton status procedure TSkinCheckButton.SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool); begin if TrueFalse then UseState := BST_CHECKED else UseState := BST_UNCHECKED; SendMessage(hBut, BM_SETCHECK, UseState, 0); end; end. Hoffe die Namensgebung ist so in Ordnung! gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Delphi-Quellcode:
unit uCheckButton;
interface uses Windows, Messages; // Classes, // ? type TSkinCheckButton = class private FButtonHandle: HWND; Img: Cardinal; Style: DWORD; UseState: Integer; public constructor Create(hOwner: HWND; FullpathImageName: PAnsiChar; stLabel: PAnsiChar; x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF; StateMax: Integer); destructor Destroy; override; function GetCheckButtonStatus(hBut: DWORD): Integer; procedure SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool); end; implementation uses uSkin; function TSkinCheckButton.Create(hOwner: HWND; FullpathImageName, stLabel: PAnsiChar; x, y, xW, yH, ButID: Integer; ARGBColor: COLORREF; StateMax: Integer); begin with SkinEngine do begin if RegisterButton(SKBUTIMAGE) <> 0 then begin // Erstelle ein GDIPLUS Image von Datei Img := AddResource((FullpathImageName)); if Img <> 0 then Style := WS_CHILD or WS_VISIBLE or WS_TABSTOP or BS_AUTOCHECKBOX; FButtonHandle := CreateWindowEx(WS_EX_TRANSPARENT, SKBUTIMAGE, stLabel, Style, x, y, xW, yH, hOwner, ButID, sInstance, nil); if FButtonHandle <> 0 then begin if StateMax < 1 then StateMax := 2; // Speichere das Image Handle in die Property SetImageProperty(FButtonHandle, PROP_IMAGE, Img); SetImageProperty(FButtonHandle, PROP_STYLE, BS_AUTOCHECKBOX); SetImageProperty(FButtonHandle, PROP_TEXT_COLOR, ARGBColor); SetImageProperty(FButtonHandle, PROP_STATEMAX, StateMax); Result := FButtonHandle; end else begin // Lösche das Image DeleteResource(Img); end; end; end; end; destructor TSkinCheckButton.Destroy; begin UnRegisterButton(SKBUTIMAGE); DeleteResource(Img); DestroyWiindow(FButtonHandle); inherited Destroy; end; // Hole den Checkbutton status function TSkinCheckButton.GetCheckButtonStatus(hBut: DWORD): Integer; begin Result := 0; if SendMessage(hBut, BM_GETCHECK, 0, 0) = BST_CHECKED then Result := -1; end; // Setze den Checkbutton status procedure TSkinCheckButton.SetCheckButtonStatus(hBut: DWORD; TrueFalse: Bool); begin if TrueFalse then UseState := BST_CHECKED else UseState := BST_UNCHECKED; SendMessage(hBut, BM_SETCHECK, UseState, 0); end; end. Vorschlag, frei Schanauzer. |
Re: Code strukturieren! Wie macht man es richtig ..
wäre eine idee aber wie sieht es bei den Create aus wenn du mehrere Checkboxen addierst ?
Wird dann nicht die alte gelöscht ? oder kann man unbegrenzt Create aufrufen. Danke für den Vorschlag gruss Emil |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Der Constructor wird für jede neue Instanz durchlaufen. Wenn du nun eine neue Checkbox brauchst, lege dir eine neue Instanz an. Pro Instanz sind alle Felder der Klasse eindeutig (also jede Instanz hat für ihre Felder ihren eigenen Speicherplatz), ausser du deklarierst die Felder explizit als "class var". Und auch würde ich den Status als property zusammenfassen:
Delphi-Quellcode:
Um das nochmals zu verdeutlichen: Wenn du dir 2x diese Klasse anlegst, haben beide ihre eigenes FButtonHandle und somit auch jeweils ein eigenes Handle. Deshalb kann der Getter/Setter auch immer auf FButtonHandle zugreifen, da er das Handle der jeweiligen Instanz hat.private function GetStatus: bool; procedure SetStatus(const AValue: bool); public ... property ButtonStatus: bool read GetStatus write SetStatus; end; ... function TSkinCheckButton.GetStatus: bool; begin Result := ( SendMessage(FButtonHandle, BM_GETCHECK, 0, 0) = BST_CHECKED ); end; procedure TSkinCheckButton.SetStatus(const AValue: Bool); const coStates: array[bool] of integer = (BST_UNCHECKED, BST_CHECKED); begin SendMessage(FButtonHandle, BM_SETCHECK, coStates[AValue], 0); end; |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
10 Checkboxen einbinde was passiert dann ? Seltsamer weise gibt es ein AV wenn ich das versuche bei der zweiten Checkbox schon. Danke für die Super infos werde davon verwenden was ich kann ;) Nebenbei .. gehört zum selben projekt Falls sich hier jeand mit PowerBasic auskennt ich weiß nicht wie ich die zeilen nach Delphi rüberbringen soll :)
Delphi-Quellcode:
gruss Emil
pBits AS BYTE PTR
CALL GetObject(hDIB, SIZEOF(bm), bm) pBits = bm.bmBits FOR P = (nWidth * nHeight) TO 1 STEP - 1 @pBits[3] = A? @pBits[2] = R? @pBits[1] = G? @pBits[0] = B? pBits = pBits + 4 NEXT |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
Delphi-Quellcode:
var
lPixel: PRGBQuad; lBM: BITMAPHEADER; // oder BITMAPINFOHEADER - das weisst du selber besser... i: integer; begin GetObject(hDIB, sizeof(lBM), lBM); // Rückgabewert beachten! lPixel := lBM.bmBits; for i := (nWidth*nHeight)-1 downto 0 do begin lPixel.rgbRed := R; lPixel.rgbGreen := G; lPixel.rgbBlue := B; lPixel.rgbReserved := A; Inc(lPixel); end; |
Re: Code strukturieren! Wie macht man es richtig ..
Danke für die übersetzung..
ja ich weiss hab da noch einige schwirigkeiten in Vb und konsorte gab es keine probleme damit. Ich sende zwei Checkboxen hintereinander bei der zweiten krachts ;) Na werd das schon noch geregelt bekommen. Da kann mir keiner helfen ;)
Delphi-Quellcode:
gruss Emil
hCtrl := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
'AERO Blur mode', 60, 286, 130, 22, ID_AEROBLUR, SK_BTNTEXTCOLOR, 0); SetAnchorMode(hCtrl, ANCHOR_CENTER_HORZ_BOTTOM); SetZorder(hCtrl, HWND_TOP); hCtrl := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'), 'STANDARD mode', 60, 308, 130, 22, ID_AERODISABLE, SK_BTNTEXTCOLOR, 0); SetCheckButtonStatus(hCtrl, TRUE); SetAnchorMode(hCtrl, ANCHOR_CENTER_HORZ_BOTTOM); SetZorder(hCtrl, HWND_TOP); Thanks für die Übersetzung :) |
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
TurboPascal hat dir nicht umsonst und sehr richtig als Änderung vorgeschlagen die CheckButton Methode zum Constructor umzuformen, also zu Create(). Und damit hättest du jedesmal eine richtige Instanz. Bei deinem Code: Warum gibst du immer wieder hCtrl weiter (SetAnchorMode(), SetZorder())? Warum definierst du das nicht als Methoden von TSkinCheckButton? Du übergibst selbst bei der SetCheckButtonStatus() immernoch die eigene Instanz. Wozu? Es ist eine Methode und braucht somit nichts übergeben zu bekommen, da sie eine Methode ist und sich somit nach den Membern richten kann. Ich kann mich nur nochmal wiederholen: Les dir Grundlagenartikel zum OOP durch! Wäre das nicht ein besser lesbarer Code?
Delphi-Quellcode:
CheckBox1 := TSkinCheckButton.Create(hMain, PChar(SK_FOLDER + 'BTN_Check.png'),
'AERO Blur mode', 60, 286, 130, 22, ID_AEROBLUR, SK_BTNTEXTCOLOR, 0); CheckBox1.SetAnchorMode(ANCHOR_CENTER_HORZ_BOTTOM); CheckBox1.SetZorder(HWND_TOP); CheckBox2 := CtrlCheckButton.CheckButton(hMain, PChar(SK_FOLDER + 'BTN_Check.png'), 'STANDARD mode', 60, 308, 130, 22, ID_AERODISABLE, SK_BTNTEXTCOLOR, 0); CheckBox2.ButtonStatus := true; CheckBox2.SetAnchorMode(ANCHOR_CENTER_HORZ_BOTTOM); CheckBox2.SetZorder(HWND_TOP); Zitat:
|
Re: Code strukturieren! Wie macht man es richtig ..
Zitat:
jemand anderer nicht genau weis was da abläuft. Nichts anderes habe ich damit aussagen wollen. EDIT: Zitat:
Bei dem erneuten aufruf wird ein neues Window für diese Checkbox erstellt erst dann geht es weiter in der eigentlichen CheckButton Funktion. gruss Emil |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:13 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