AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TApplicationevents.onmessage

Ein Thema von Mattze · begonnen am 6. Mai 2016 · letzter Beitrag vom 9. Mai 2016
Antwort Antwort
Mattze

Registriert seit: 6. Jan 2005
664 Beiträge
 
#1

TApplicationevents.onmessage

  Alt 6. Mai 2016, 06:48
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)
  Mit Zitat antworten Zitat
Benutzerbild von milos
milos

Registriert seit: 14. Jul 2008
Ort: Bern (CH)
509 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 06:59
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
Milos
  Mit Zitat antworten Zitat
Mattze

Registriert seit: 6. Jan 2005
664 Beiträge
 
#3

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 07:35
Hallo,

tschja, habe ich. Aber das ist viel zu viel zum posten.
Hier nur applicationevents.onmessage:
Delphi-Quellcode:
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;
Das erste ist zwar nicht relevant für mein Problem, aber ich lasse es mal drin...

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
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 07:39
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;
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Mattze

Registriert seit: 6. Jan 2005
664 Beiträge
 
#5

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 08:55
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
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 09:32
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.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Mattze

Registriert seit: 6. Jan 2005
664 Beiträge
 
#7

AW: TApplicationevents.onmessage

  Alt 6. Mai 2016, 16:12
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
  Mit Zitat antworten Zitat
Mattze

Registriert seit: 6. Jan 2005
664 Beiträge
 
#8

AW: TApplicationevents.onmessage

  Alt 9. Mai 2016, 12:14
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
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#9

AW: TApplicationevents.onmessage

  Alt 9. Mai 2016, 13:08
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:
while not Abbruch do begin
  // mach was
  Application.ProcessMessages;
end;
oder (hier wird danach noch mehr gemacht)
Delphi-Quellcode:
while not Abbruch do begin
  Application.ProcessMessages;
  // mach was
end;
Im Application.ProcessMessages wird diese Message verarbeitet und erst nach Abarbeitung geht es in den ersten Code wieder rein.

Maximal mit einem Delphi-Referenz durchsuchenAbort im OnMessage könnte man hier nach der neuen Message das Äußere abschießen.
$2B or not $2B

Geändert von himitsu ( 9. Mai 2016 um 13:12 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:42 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz