![]() |
TApplicationevents.onmessage
Hallo,
ein (für mich leider kein "kleines") Problem: Ich führe nach einem Click etwas aus, was evtl. länger dauert. (Größenberechnung für ein Dir.) Wenn ich nun irgendetwas anderes auf der Form anclicke, soll diese Berechnung abgebrochen werden und das, was bei diesem Click ausgeführt werden soll, auch ausgeführt werden. Der Abbruch klappt ohne Probleme in TApplicationevents.onmessage. Allerdings wird nichts ausgeführt. Erst wenn ich zum zweiten Mal auf dieses Control clicke, wird es auch ausgeführt. Was kann das sein? Ich nehme an, dass das control aus irgendeinem Grund den Focus verliert, aber warum? Wie kann man das verhindern? (Beispiel: Die Ordnergröße wird gerade berechnet und das kann dauern. Da mir das für diesen Ordner nicht wichtig ist, clicke ich auf einen Button und will etwas anderes machen. Beim ersten Click auf den Button wird die Berechung ordentlich abgebrochen. Erst beim zweiten Click wird aber die Prozedur des Buttons ausgeführt.) Gruß Mattze (Delphi 7 pro) |
AW: TApplicationevents.onmessage
Hallo,
hast du vielleicht den Teil des Codes den man braucht um den Fehler reproduzieren zu können? Ich kann mir nicht vorstellen dass das nicht funktioniert :? Freundliche Grüsse |
AW: TApplicationevents.onmessage
Hallo,
tschja, habe ich. Aber das ist viel zu viel zum posten. Hier nur applicationevents.onmessage:
Delphi-Quellcode:
Das erste ist zwar nicht relevant für mein Problem, aber ich lasse es mal drin...
procedure TFHaupt.AEMessage(var Msg: tagMSG; var Handled: Boolean);
var p: tpoint; wc: TWinControl; begin //mouse wheel scrolling for the control under the mouse if (Msg.message = WM_MOUSEWHEEL) then begin p.X:=Word(Msg.lParam); p.Y:=HiWord(Msg.lParam); wc := FindVCLWindow(p); if wc=nil then begin handled:=true; exit; end; if wc=lv then begin lv.setfocus; handled:=false; end else if wc=tree then begin tree.setfocus; handled:=false; end else if assigned(WndSearchFiles) and (wc=WndSearchFiles.searchresult) then begin WndSearchFiles.searchresult.setfocus; handled:=false end else handled:=false end; //Hier sitzt das Problem if (msg.message>WM_MOUSEFIRST) and (msg.message<WM_MOUSELast) then begin handled:=false; SizeAbbruch:=true; end; end; SizeAbbruch wird bei der Dir-Größenberechnung in einer Schleife immer wieder abgefragt. Wie gesagt: Abgebrochen wird ordentlich. Aber er führt die eigentliche Click-Prozedur erst beim zweiten Click aus. Das geht bis zum "Schließen-Kreuz" des Formulars. Auch da braucht man zwei Clicks. Gruß Mattze |
AW: TApplicationevents.onmessage
Wofür brauchst du da eigentlich OnMessage? Ein Beispiel:
Delphi-Quellcode:
TOnFinished = procedure(const ACancelled: Boolean; const AFolder: string; const AFolderSize: Int64) of object;
TTest = class(TThread) private FFolder: string; FFolderSize: Int64; FOnFinished: TOnFinished; function GetFolderSize(const AFolder: string): Int64; procedure SetOnFinished(const Value: TOnFinished); procedure DoFinished; protected procedure Execute; override; public constructor Create(const AFolder: string); property OnFinished: TOnFinished read FOnFinished write SetOnFinished; end; TfrmTest = class(TForm) btnStart: TButton; btnStop: TButton; procedure btnStartClick(Sender: TObject); procedure btnStopClick(Sender: TObject); private FThread: TTest; procedure CalculationFinished(const ACancelled: Boolean; const AFolder: string; const AFolderSize: Int64); public { Public-Deklarationen } end; var frmTest: TfrmTest; implementation {$R *.dfm} { TTest } constructor TTest.Create(const AFolder: string); begin inherited Create(False); FFolder := AFolder; end; procedure TTest.DoFinished; begin if Assigned(FOnFinished) then FOnFinished(FFolderSize = -1, FFolder, FFolderSize); end; procedure TTest.Execute; begin inherited; FFolderSize := GetFolderSize(FFolder); Synchronize(DoFinished); end; function TTest.GetFolderSize(const AFolder: string): Int64; var SearchResult: TSearchRec; SubFolderSize: Int64; begin Result := 0; if FindFirst(IncludeTrailingPathDelimiter(AFolder) + '*.*', faAnyFile, SearchResult) = 0 then begin repeat if Copy(SearchResult.Name, 1, 1) <> '.' then begin if SearchResult.Attr and faDirectory > 0 then Inc(Result, GetFolderSize(IncludeTrailingPathDelimiter(AFolder) + SearchResult.Name)) else Inc(Result, SearchResult.Size); end; if Terminated then Exit(-1); until FindNext(SearchResult) <> 0; FindClose(SearchResult); end; end; procedure TTest.SetOnFinished(const Value: TOnFinished); begin FOnFinished := Value; end; { TfrmTest } procedure TfrmTest.btnStartClick(Sender: TObject); begin FThread := TTest.Create('c:\'); FThread.OnFinished := CalculationFinished; btnStart.Enabled := False; btnStop.Enabled := True; end; procedure TfrmTest.btnStopClick(Sender: TObject); begin FThread.Free; btnStart.Enabled := True; btnStop.Enabled := False; end; procedure TfrmTest.CalculationFinished(const ACancelled: Boolean; const AFolder: string; const AFolderSize: Int64); begin if not ACancelled then ShowMessage(AFolder + ': ' + IntToStr(AFolderSize)); end; |
AW: TApplicationevents.onmessage
Hallo jaenicke,
genau darauf habe ich tatsächlich schon gewartet, dass mir jemand einen Thread vorschlägt. Daran gedacht habe ich natürlich auch und es ist sicherlich eine machbare Variante. Mit einem Thread hätte ich wahrscheinlich keine (großen) Probleme, aber ich wollte mal was anderes probieren. Und da ich stur bin... Ich habe jetzt rausbekommen, dass es tatsächlich an dem gesetzten Focus liegt. Es würde ausreichen, den Focus auf das angeclickte Control in Applicatioeventsmessages (aem) als letztes zu setzen. Dann scheint es zu funktionieren. Fragt sich nur, wie ich das VOR aem kriege... Ich probiere weiter. Wenn ich doch verzweifele, bleibt der Thread, den Du dankenswerter Weise geschrieben hast. Gruß Mattze |
AW: TApplicationevents.onmessage
Wenn du ein funktionierendes Beispiel hättest, würde ich mir das mal anschauen.
Bedenken solltest du aber noch zusätzlich, dass ein eigener Thread natürlich deutlich schneller ist. Denn da brauchst du nicht ständig Application.ProcessMessages zwischendurch aufrufen. |
AW: TApplicationevents.onmessage
Hallo,
ich hätte schon ein Beispiel, aber das ist einfach zu viel. Das Problem beim Thread ist: Die Berechnung soll bei jeder "MausButtonAktion" abgebrochen werden. Wo immer ich sie auf dem Formular ausführe. Das hieße aber, dass ich für jede noch so vage Möglichkeit eine Click-Methode bauen müsste, die oft nichts weiter tut, als den Thread abzubrechen und auf seine Beendigung zu warten. (Manchmal müsste er nämlich sofort mit anderen Daten neu gestartet werden!) Also, vielleicht auch für jedes Panel-Click, Label-Click usw. Im Grunde läuft es darauf hinaus, ein "MousePreview" des Formulars zu haben. Meines Wissens gibt es da nur zwei sinnvolle Varianten: Mousehook und eben Applicationeventsmessage (aem). Die Hookkanone finde ich für den Berechnungsspatzen zu groß. Bleibt aem. Momentan sehe ich als günstigste Variante den Thread, der in der aem abgebrochen wird an. Schaun mer mal... So, mit dem Focus, wie ich es zuerst wollte, scheint es nicht zu gehen. Ich müsste das Control, das ich angeclickt habe, in aem rauskriegen und es dann setzen. (So, wie vorher mit WM_MouseWheel gemacht ist, aber das scheint bei WM_LMouseDown und WM_LMouseup nicht zu funktionieren, jedenfalls kriege ich da immer nur das Hauptformular - FHaupt.) Sooo oft brauche ich da kein Application.processmessages. Ich berechne die Gesamtgröße des Dir, also die Summe der Größen aller - auch in den Unterverzeichnissen - enthaltenen Dateien ohne Rekursion. Geht sehr schnell, kann aber auch ziemlich lange dauern, z.B. bei einer ganzen Partition (C:\). Gruß Mattze |
AW: TApplicationevents.onmessage
Hallo,
ich bin nun einen Schritt weiter und damit wahrscheinlich am Ende. Dank Eures Tipps habe ich das mal gaaanz klein gemacht und nur das Allernötigste rausgezogen. Es ist nicht die Art der Berechnung bei mir. Das klappt ordentlich. Es ist die VirtualExplorerEasyListview! Dort stoße ich bei einem Click die Berechnung (für das selektierte Dir) an und da kommt es zu diesem komischen Verhalten in applicationevents.onmessage. Bsp.: Ein Schalter, dessen Click die Berechnung abbrechen soll (da das bei jedem Mousebutton überall im Formular passieren soll, in AEM. Das funktioniert!) und danach noch etwas macht. Tut er aber nicht. Erst, wenn ich ihn zum zweiten Mal anclicke wird die Click-Prozedur auch ausgeführt. Wenn ich mir AEM klemme und nur im Buttonclick den Abbruch aufrufe, funktioniert es auch. (Ich wollte mir das eben nur einfach machen, in dem ich "global" im Formular die Berechnung abbreche. Nun werde ich wohl wirklich für alles eine Clickprozedur schreiben, in dem nur der Abbruch steht. Na ja, man gönnt sich ja sonst nix...) Gruß Mattze |
AW: TApplicationevents.onmessage
Achtung, wenn du in der Behandlung (oder davor) irgendeiner anderen Message (d)eine Aktion abbrechen willst, aber wo in dieser Message schon das Andere ausgeführt wird, dann wird erst die andere Aktion ausgeführt und danach dann das Erste beendet, denn ...
Beispiele:
Delphi-Quellcode:
oder (hier wird danach noch mehr gemacht)
while not Abbruch do begin
// mach was Application.ProcessMessages; end;
Delphi-Quellcode:
Im Application.ProcessMessages wird diese Message verarbeitet und erst nach Abarbeitung geht es in den ersten Code wieder rein.
while not Abbruch do begin
Application.ProcessMessages; // mach was end; Maximal mit einem ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 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