![]() |
Überwachen von Objekteigenschaften
Hallo Gemeinde,
gibt es in Delphi die Möglichkeit eine Art Breakpoint/TraceTrigger zu setzen wenn die Eigenschaft eines Objekts geändert wird? Hintergrund der Frage: Ich erwarte z.B. dass ein Button disabled ist, er ist aber doch leider Enabled. Nun würde ich gerne herausfinden welche der ~500 Stellen die den Button enablen können denn nun fälschlicherweise zuschlägt(ohne 500 breakpoints zu setzen zu müssen) Danke im voraus für eure Hilfe. |
AW: Überwachen von Objekteigenschaften
Delphi-Quellcode:
tadaa 8-)/// Ganz oben type TButton = class(StdCtrls.TButton) procedure SetEnabled(Value: Boolean); override; end; /// ... /// Die eigentliche Unit... /// ... /// Vor end. dann: { TButton } procedure TButton.SetEnabled(Value: Boolean); begin inherited; if Self.Name = 'btnMeinBtnDerEnabledWird' then MessageDlg('Debugpoint hier setzen. :)', mtInformation, [mbOK], 0); end; |
AW: Überwachen von Objekteigenschaften
Was mir jetzt spontan einfällt: die Message CM_ENABLEDCHANGED abzufangen.
Delphi-Quellcode:
type
TButton = class(StdCtrls.TButton) private FOnEnabledChanged: TNotifyEvent; procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; public property OnEnabledChanged: TNotifyEvent read FOnEnabledChanged write FOnEnabledChanged; end; TFormTest = class(TForm) ... private { Private-Deklarationen } procedure DoOnChange(Sender: TObject); ... procedure TButton.CMEnabledChanged(var Message: TMessage); begin inherited; if Assigned(FOnEnabledChanged) then FOnEnabledChanged(Self); end; procedure TFormTest.DoOnChange(Sender: TObject); begin if Sender is TButton then ShowMessage(TButton(Sender).Name + ' hat sich geändert'); end; procedure TFormTest.FormCreate(Sender: TObject); begin Button1.OnEnabledChanged := DoOnChange; end; |
AW: Überwachen von Objekteigenschaften
Danke, kling schon mal echt gut und dürfte für den Einzelfall das Mittel der Wahl sein.
Schön wäre es natürlich nun, wenn man nicht jede einzelne Eigenschaft für jede einzlen Klasse, die man überwachen möchte überschreiben müsste, sondern in der Art z.B. eines ExceptionHandlers einfach zu überwachende Eigenschaften auswählen könnte. Kennt jemand dafür ein geeignetes Tooling/Expert/wizard? Zitat:
|
AW: Überwachen von Objekteigenschaften
Das stimmt, ich hätte mir einen solchen Breakpint auch schon oft gewünscht.
Das würde die Laufzeit natürlich sehr ausbremsen, aber in bestimmten Fällen würde ich das gern mal in Kauf nehmen - natürlich nicht auf Dauer. Der Debuger müsste an jeder Stelle (die einen Breakpoint erhalten KÖNNTE), die Erfüllung einer Bedingung prüfen und dann ggf. anhalten. |
AW: Überwachen von Objekteigenschaften
Zitat:
|
AW: Überwachen von Objekteigenschaften
Man könnte sich eine Klasse zusammenschreiben, welche die virtuellen Methoden, hier am Beispiel SetEnabled oder WndProc (die zentrale Nachrichtenbehandlung der Komponenten), zur Laufzeit "überschreibt", seinen eigenen Prüfcode einschleust und so leichter Debuggen kann.
Dieser Komponente wurde man dann sagen "Hooke mir die und die Methode jener Klasse". evtl. gibt's sowas aber auch schon :stupid: (über die neue 2010er/XE-RTTI würde sowas bestimmt ein Leichtes sein und davor nur einen Hauch umständlicher/aufwändiger) [add] - "mit Debug-DCUs" in den Projektoptionen aktivieren (neuere Delphiversionen) - in SetEnabled einen Haltepunkt sezten (wirkt natürlich nur, wenn die Änderung direkt über .Enabled reinkommt) - die Bedingung für den Haltepunkt auf "Name = 'name der komponente'" - und nun nur noch warten Nicht wundern, aber dieses könnte das Programm ein bissl ausbremsen, da dieses natürlich von jedem kleinen Komponentchen aufgerufen wird. |
AW: Überwachen von Objekteigenschaften
Jupp ist richtig, aber wenn man sich solche "Komponenten" wie z.B. Eureka anschaut ist eine solche Funktion ganz hilfreich.
Zitat:
|
AW: Überwachen von Objekteigenschaften
Ich muss zu meiner Schande gestehen: NEIN!
Aber wie sollte das bei diesen Probleme helfen? Zitat:
|
AW: Überwachen von Objekteigenschaften
Ja klingt plausibel.
Genau dieses "EVTL" suche ich :-D Zitat:
|
AW: Überwachen von Objekteigenschaften
Bitte zitiere nicht jeden Beitrag einzeln ... ein Beitrag hätte auch gereicht.
Mehrfachposts wären hier nicht nötig gewesen. :warn: Und komplette Beiträge zu zitieren ebenso wenig. PS: Ich hatte oben, in meinem letzen Beitrag, noch was dazugeschrieben. (ohne Garantie, ob's so funktioniert) |
AW: Überwachen von Objekteigenschaften
Manche Programmierer verbringen viel Zeit mir ihrem Debugger; Andere versuchen lieber ihre Software "wartungsfreundlich" und sauber zu designen.
Wenn ich einen Button en/disable dann achte ich darauf wie oft ich das tue. Beim ersten Mal schreibe ich direkt hin
Delphi-Quellcode:
.
BtnImport.Enabled := False;
Spätestens aber beim 3. Mal mache ich mir Gedanken und zentralisere die Geschichte. In folgendem Szenario gibt es z.B. 3 Buttons - Importieren, Stop und Schliesen.
Delphi-Quellcode:
Das ist die einzige Stelle im ganzen Programm, an der diese Buttons manipuliert werden.
procedure TImportDataForm.SetRunningState(running:Boolean);
begin BtnImport.enabled := not running; BtnStop.Enabled := running; BtnClose.Enabled := not running; LblZeitdauer.Visible := running; end; Was könnte einfacher sein als jetzt einen Breakpoint zu setzen? Ich würde auch nie auf die Idee kommt z.B. folgendes zu Schreiben:
Delphi-Quellcode:
Sobald man zwei Punkte auf der linke Seite braucht (also Formular.Komponente.Property := Irgendwas) ist was faul im Staate Dänemark!
// Beispiel für ganz schlechten Programmierstil
Form5.Button11.Enabled := False; Form5.Button3.Enabled := True; Form5.ShowModal; Also ich verzichte gerne auf einen Debugger der alles kann und investiere meine Zeit in sauberen Sourcecode. |
AW: Überwachen von Objekteigenschaften
@shima
Häng Dich doch mal nicht an dem Button auf... Es kann doch auch um andere Variablen oder Eigenschaften gehen, deren Werte "irgendwo" unerwartet verändert werden. Wenn Du keine Fehler in der Programmentwicklung machst, dann gehe ich mal bei Dir in Schulung :wink: Als Option fände ich eine solche Debug-Option durchaus nützlich. Man müsste sie ja nicht nutzen. |
AW: Überwachen von Objekteigenschaften
Darf ich bei diesem Punkt nochmals meine vormals gestellte Frage in den Raum werfen, warum keine Actions?
|
AW: Überwachen von Objekteigenschaften
Nepp, hier sind definitiv die Actions erste Wahl.
Vor allem das Event TAction.OnUpdate würde hier helfen diesen Bug in den Griff zu bekommen. Innerhalb des Events prüft man alle möglichen Statuswerte, die für die Action relevant sind und setzt dann die Eigenschaften (Enabled, Visible, Caption, etc.) für die Action, und der Drops ist gelutscht. Nun setzt keiner mehr die Eigenschaft des Buttons, sondern der Button passt sich von selbst an ;) |
AW: Überwachen von Objekteigenschaften
Das geht auch mit den Bordmitteln des Debuggers, ohne sich Code zu schreiben. Am Beispiel von TButton erklärt:
- Breakpoint in der Applikation an einer Stelle setzen wo das Ziel-Control schon existiert und inspiziert werden kann. Z.B. für einen Button im OnActivate des jeweiligen Forms, die Möglichkeiten sind zahlreich. Rechtsklick auf den Namen des Controls im Source und das Control inspizieren. Ganz oben im Inspektorfenster steht jetzt beispielsweise:
Code:
Die hintere der beiden Zahlen notieren, die brauchen wir später noch.
btn1: TButton $123456 : $789ABC
Nun auf den Reiter "Methoden" klicken, und dort - um im obigen Beispiel zu bleiben - "SetEnabled" suchen. Die Zeile sieht bei TButton z.B. so aus:
Code:
Jetzt haben wir alles zusammen. Nun setzen wir einen Breakpoint an der Adresse $00480834 und geben als Bedingung ein:
SetEnabled Controls.TControl.SetEnabled($480834)
Code:
Der Wert für EAX ist die oben notierte Zahl.
EAX=$00789ABC
Nun kann man den oben zuerst gesetzten Breakpoint wieder entfernen und das Programm laufen lassen. Immer wenn das Property Enabled des oben herausgesuchten TButton gesetzt wird, triggert nun der Breakpoint. Das lässt sich sicherlich auch in einen Experten gießen, aber wenn man das ein paar Mal gemacht hat, geht das so flott von der Hand dass ich bisher noch nicht weiter drüber nachgedacht hab, diese vier Schritte noch weiter zu automatisieren. Und es geht auf jeden Fall schneller als sich erst jedes Mal einen Class Helper zu schreiben. Nachtrag: Diese Methode funktioniert recht universell für alle möglichen Objekte (nicht nur Controls) und deren Properties, geht also in den Debuggingmöglichkeiten noch viel weiter als die Methode mit den Actions. |
AW: Überwachen von Objekteigenschaften
Hallo,
OldGrumpy: interessanter Aspekt des Debuggens, kannte ich noch nicht ... ;) Aber: Zitat:
Verändere ich an zwei unterschiedlichen Stellen eine Variable direkt (auch ein Property eines fremdem Objektes), habe ich was was falsch gemacht. -> Methode schreiben. Heiko |
AW: Überwachen von Objekteigenschaften
Zitat:
|
AW: Überwachen von Objekteigenschaften
Hallo liebe Delphi Gemeinde,
ich denke wir sollten den Thread an dieser Stelle beenden, weil doch viele hilfreiche Anregungen gekommen sind. Leider war nicht die "ultimative Lösung mit der alles von selbst geht:wink:" bei, aber dennoch vielen Dank an alle, die wieder einmal konstruktiv zu dem Problem beigetragen haben! DANKE!!! |
AW: Überwachen von Objekteigenschaften
Das ist wirklich DIE Antwort, die dem gewünschten am nähesten kommt!
Kannte ich bisher noch nicht und daher: Super Antwort:thumb: Schönen Dank auch nochmal für das hilfreich in Die Seite treten bzgl. "Irgendwo im Code gibt es nicht" Hast recht ist zwar kein gutes Design, manchmal muss es aber halt sein. |
AW: Überwachen von Objekteigenschaften
Zitat:
|
AW: Überwachen von Objekteigenschaften
Wenn man Projekte von anderen übernimmt, muss man wohl oder übel auch das ggf. miese Design übernehmen, es sei denn, man hat sehr viel Zeit (wer hat die schon?).
|
AW: Überwachen von Objekteigenschaften
Das ist was anderes. Aber offensichtlich handelt es sich um sein eigenes Projekt. Aber auch Refactoring kann Zeit sparen. Ich habe mal Code vom Kollegen bekommen, den er so runtergetippt hatte. Dieser Code sollte jetzt erweitert werden. Ich glaube es waren sechs Stunden veranschlagt. Ohne Refactoring hätte ich das in den sechs Stunden nicht geschafft. Weil keine Struktur drin war. Und beim verstehen ist das Refactoring fast von alleine gegangen. Vom ursprünglichen Code ist eigentlich nur der rein funktionale Code übrig geblieben.
|
AW: Überwachen von Objekteigenschaften
Zitat:
Dazu gehört z.B. die Windows API, ActiveX und Komponenten aus der VCL. Ja, man kann mit Debug-DCUs kompilieren aber es handelt sich doch um fremden Code. Im Laufe der Jahre habe ich gelernt mit diesem "Fremdcode" umzugehen. Falls nötig baue ich um diesen Fremdcode eine Schicht, die meistens aber nur hauchdünn ist. Es ist wichtig zu erkennen, wann man die Schicht braucht und wann nicht. Die Schicht kann manchmal auch nur eine Funktion sein, die ein Argument 1 zu 1 weiterleitet.
Delphi-Quellcode:
Diese Schicht ist sehr dünn, aber ich kann einen Breakpoint setzen oder die Fehlermeldung auf eine andere Weise anzeigen.
Beispiel
procedure TForm1.ShowError(const msg:string); begin ShowMessage(msg); // oder // Statusbar1.SimpleText := msg; end; Für den Zugriff auf Komponenten habe ich meistens keine Zwischenschicht. Nur falls nötig oder falls ein Spareffekt (z.B. mehrere Buttons auf einen Rutsch dis/enablen) eintritt würde ich eine Procedure/Funktion als Zwischenschicht einführen. Ganz anderst sieht das mit Handles und Zeigern der Windows API aus. Hier kapsele ich grundsätzlich immer mit einer Klasse, Procedure oder Funktion. Stellt euch vor es gäbe die Klassen TFont, TCanvas, TPen und TBrush nicht. Was wäre das für eine Qual irgendetwas zu zeichnen. Ähnlich sieht das bei Zeigern und Strukturen aus der Windows API aus. Ich würde z.B. niemals die Windows API-Funktion ![]() Nein, dieser Aufrauf braucht eine kleine Zwischenschicht:
Delphi-Quellcode:
Ich würde auch nie auf die Idee kommen meine Anwendung direkt mit WinSock-Funktionen (socket(),bind(),listen(),..) oder Funktionen für die serielle Schnittstelle reden zu lassen.
function GetLocalComputerName: string;
var Count: DWORD; begin Count := MAX_COMPUTERNAME_LENGTH + 1; SetLength(Result, Count); if GetComputerName(PChar(Result), Count) then StrResetLength(Result) else Result := ''; end; Hier braucht es unbedingt eine Klasse, die den Zugriff kapselt. Automatisch habe ich dadurch Code auf den ich Breakpoints setzen kann. Fazit: um Code, der nicht unter der eigenen Kontrolle steht sollte man (bei Bedarf) eine Zugriffsschicht legen. Die dünnstmögliche Schicht ist die 1:1 Weiterleitung einer Funktion/Procedure |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:27 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