Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Die Delphi-IDE (https://www.delphipraxis.net/62-die-delphi-ide/)
-   -   SetFocus will nicht ... (https://www.delphipraxis.net/211235-setfocus-will-nicht.html)

TERWI 19. Aug 2022 13:10

SetFocus will nicht ...
 
wenn mein Proggie startet, wird (zum Testen) noch ein weitere Form mit einem Logger aufgemacht.
Der Focus landet dann immer im Memo des Loggers - soll aber im Hauptfenster (auf einem Panel) bleiben.
Ich hab schon alles mögliche mit SetFous zur Form und zum Panel an allen möglichen Positionen im Text probiert.
Will einfach nicht.
Problem dabei ist:
Ich möchte/muss bei einem Tastendruck (Mausbewegung ist OK) in der MainForm reagieren und handeln.
Tippe ich z.B. nach dem Start 'ABC' landet das wie gesagt im Memo des Loggers.
Ich muss immer zwingend in die Form, bzw. auf das Panel klicken, dann ist 'alles schön'
Wo sehe ich den Wald vor lauter Bäumen nicht mehr ?

venice2 19. Aug 2022 13:16

AW: SetFocus will nicht ...
 
https://docs.microsoft.com/en-us/win...regroundwindow

TERWI 19. Aug 2022 13:29

AW: SetFocus will nicht ...
 
... das funzt nicht.
Bekomme immer false zurück, egal ob ich Handle von der MainForm oder dem Panel nehme.

venice2 19. Aug 2022 13:34

AW: SetFocus will nicht ...
 
Zitat:

Zitat von TERWI (Beitrag 1510311)
... das funzt nicht.
Bekomme immer false zurück, egal ob ich Handle von der MainForm oder dem Panel nehme.

Dann lese welche Bedingungen erfüllt sein müssen.. Siehe Remarks!

Alternativ trenne deinen Logger vom Prozeß deiner Anwendung.
Ich verwende dafür eine externe DLL.

TERWI 19. Aug 2022 13:57

AW: SetFocus will nicht ...
 
... wird dann wohl am Logger liegen ?!
Muss ich da unbedingt eine DLL von machen, eigenständige EXE/mit Send-/Postmessage oder geht das auch irgendwie 'einfach & schnell' ?

venice2 19. Aug 2022 14:06

AW: SetFocus will nicht ...
 
Zitat:

Zitat von TERWI (Beitrag 1510317)
... wird dann wohl am Logger liegen ?!
Muss ich da unbedingt eine DLL von machen, eigenständige EXE/mit Send-/Postmessage oder geht das auch irgendwie 'einfach & schnell' ?

Unbedingt nicht aber du darfst gerne meine DLL verwenden.
Projekt ist nicht kompiliert!

Bsp:

laden wo auch immer.
Delphi-Quellcode:
      if not Trace_Loaded then
      begin
        Trace_Loaded := Load_TRACEDLL(ExtractFilePath(paramstr(0)) + Tracerdllfile);
        if Trace_Loaded then
        begin
          Trace('');
          repeat
            TraceHandle := FindWindow('TRACER', 'TRACER');
            WinprocessMessages;
          until TraceHandle <> 0;
        end;
      end;
Delphi-Quellcode:
procedure LOG(S1, S2: string);
var
  s: string;
begin
  if Trace_Loaded then
  begin
    if GetTraceWinHandle then
      s := '[' + FormatDateTime('hh:nn:ss:zzz', Now) + ']';
      Trace(PWideChar(s + ' MAIN: ' + S1 + S2));
  end;
end;
Delphi-Quellcode:
      Log('Load Skin: ', DefSkin);
      Log('WindowPos: ', 'Left:' + IntToStr(gP.MainLeft) + ' Top:' + IntToStr(gP.MainTop));
      Log('WindowPos: ', 'Width:' + IntToStr(gP.MainWidth) +
        ' Height:' + IntToStr(gP.MainHeight));
      Log('CreateWindow: ', 'Handle:' + IntToStr(gP.MainHandle));
Kein Kommentar daher wieder entfernt.

Delphi.Narium 19. Aug 2022 14:14

AW: SetFocus will nicht ...
 
Welches Formular ist denn beim SetFocus im Vordergrund? Der Logger?

Wenn man ein Fenster per Show anzeigt, ist das im Vordergrund und dort hat dann die "erste" Komponente den Focus (TabStop = true und TabOrder = 0).

Soll das aufrufende Fenster aber den Focus behalten, also im Vordergrund bleiben, muss man es nach dem Aufruf des zweiten Fensters, wieder in den Vordergrund bringen.

Geht eventuell sowas?
Delphi-Quellcode:
procedure TForm1.FormCreate(sender : TObject);
begin
  ...
  FormLogger.Show;
  Self.BringToFront;
  ControlFuerDieEingabeABC.SetFocus;
  ...
end;

TERWI 19. Aug 2022 14:31

AW: SetFocus will nicht ...
 
Das wäre ja mal ne Idee.
Was muss ich den aus dem Proggie dem Logger (ich starte den über eine procedure) an eh schon zu übergebene Params auf der MainForm den noch geben ?
Hab das bisher noch nie gemacht und im Moment eher keinen Plan. (ControlFuerDieEingabeABC)

ADD:
OOPS - da kam zwischendurch noch was.
Das muss ich erst mal verarbeiten ....

Uwe Raabe 19. Aug 2022 14:35

AW: SetFocus will nicht ...
 
Kannst du das vielleicht auf ein Minimalbeispiel runterbrechen? Ich kann das hier mit einer schnell zusammengeklickten VCL-Applikation nämlich nicht nachvollziehen.

TERWI 19. Aug 2022 14:38

AW: SetFocus will nicht ...
 
@Delphi.Narium
Das hatte ich hier schon rauf und runter probiert.
Die MainForm und der OnKey... Event funzt erst, wenn ich in die Form klicke.

Delphi.Narium 19. Aug 2022 14:48

AW: SetFocus will nicht ...
 
Zeig' doch einfach mal Deinen nicht funktionierenden Quelltext.

Dann haben wir eine Chance einen eventuell enthaltenen Fehler zu finden oder einen Verbesserungsvorschlag zu machen.

Die MainForm muss hinter dem Show für den Logger wieder in den Vordergrund gebracht werden und zwar in der Routine, die das Show für den Logger enthält, nicht in irgendem Event.

himitsu 19. Aug 2022 14:49

AW: SetFocus will nicht ...
 
Das Fenster ohne Fokusänderung anzeigen.

Also statt Show aka ShowWindow(SW_SHOW)
ein ShowWindow(SW_SHOWNOACTIVATE).

Delphi-Quellcode:
//FormLogger := TFormLogger.Create(Application); // oder Application.MainForm oder sonstwas
ShowWindow(FormLogger.Handle, SW_SHOWNOACTIVATE);
FormLogger.Visible := True; // das Visible der VCL noch umstellen ... nicht nur im internen WinControl
Deine LogForm hat doch Visible standardmäßig auf False?
(vor vielen vielen Jahren waren Forms gern Visible=True ... inzwischen sind sie Visible=False und werden dann erst sichtbar gemacht)


Alternativ auch noch bei den Controls (Memo) das TabStop auf False setzen.

TERWI 19. Aug 2022 15:25

AW: SetFocus will nicht ...
 
Der Logger hat schon immer Visible := false gehabt.
Wenn ich die Initialiserung des Loggers weglasse, geht auch alles wie gewünscht.
... also eher nur ein Problem bei 'visuellen OnlineDegugger'.

TabStop := false beim Memo des Loggers bringt auch nix:
Eine Tastatur eingabe wird nur mehr nicht angezeigt - in der MainForm kommt immer noch nix an.

Wie/wo wäre im Logger bei erzeugter Form SW_SHOWNOACTIVATE anzuwenden ?
Überhaupt notwendig wenn visible = false ?

Für Uwe: Ich initialisiere mein ges. Projekt in der MainForm so:
Delphi-Quellcode:
procedure TZatMAIN.FormActivate(Sender: TObject);
begin
  if FIsInit then exit; // avoid furthermore callings ti initialize
  Logger.SetMode(FDoLogWin, FDoLogFile);  // Show Window ? / Write LogFile ?
  Log('ACTIVATE', 'ForeGround: ' + booltostr(SetForegroundWindow(handle), true));
  // da kommt immer false...
  Self.BringToFront;
  Videopanel.SetFocus;
  // bringt beides nichts ...

  // .... weitere Init's

  FIsInit := true;
end;

Uwe Raabe 19. Aug 2022 15:35

AW: SetFocus will nicht ...
 
Hier funktioniert das ganz ohne Code.
  • VCL-Forms Application
  • Zweites VCL-Form dazu
  • Zweites Form im OI Visible := True
  • Zweites Form im den Projektoptionen ins Auto-Create aufnehmen

Das erste Form hat eine
Delphi-Quellcode:
TEdit
, das zweite ein
Delphi-Quellcode:
TMemo
. Wenn ich das Projekt starte, werden beide Forms angezeigt und das
Delphi-Quellcode:
TEdit
im ersten Form hat den Focus.

TERWI 19. Aug 2022 16:24

AW: SetFocus will nicht ...
 
Kurios.
Der Logger ist eigentlich eine ganz normale unit - keine Klasse.
Die Unit wir automatisch via
'initialization' LOGGER := TLOG.Create();
erzeugt (dann ist die var LOGGER immer da) und via
'finalization' FreeAndNil(LOGGER);
freigegeben.
Create erzeugt einen Thread mit FLogThread.FreeOnTerminate := true;

Die Form wird die erst auf Anfrage via SetMode erzeugt.
Dito falls ein Logfile gewünscht ist.

Bisher war das LogWin immer fsStayOnTop, damit ich das immer oben habe.
Änderung zu fsNormal brachte keine Änderung.
Wenn das Log-Fenster startet nach SetMode ist der Tastaturfocus immer dort im Memo.
Wenn kein Log-Fenster erzeugt wird, ist alles schön ....

Verstehe ich nicht.
Was wäre mit dem Versuch, der SetMode-Procedure das Handel der Mainform mitzugeben, damit der Logger das Fenster nach vorne holt ?
(wurde so vorgeschlagen ?!)
Was wäre da zu übergeben und im Logger aufzurufen ?
Ich hab keinen Plan ....

himitsu 19. Aug 2022 16:42

AW: SetFocus will nicht ...
 
Soeinen Mist wie fsStayOnTop sollte man eh dringen entsorgen.

Stattdessen benutzt man Delphi-Referenz durchsuchenPopupMode/PopupParent.

Wobei (leider) in aktuellen Delphis standardmäßig jede Delphi-Form zwanghaft an (vor) die MainForm gelegt wird.

TERWI 19. Aug 2022 17:10

AW: SetFocus will nicht ...
 
(Richtig) lesen bildet !
Es liegt eben NICHT an fsStayOnTop !!!
Wirklich sachdienliche wären hilfreich.

venice2 19. Aug 2022 17:22

AW: SetFocus will nicht ...
 
Zitat:

Zitat von TERWI (Beitrag 1510351)
(Richtig) lesen bildet !

Freundlichkeit auch!
Hättest du meine DLL getestet wäre dein Problem längst erledigt.
Aber da kein Kommentar dazu kam habe ich es wieder entfernt.

Jeder wie er will.

TERWI 19. Aug 2022 18:05

AW: SetFocus will nicht ...
 
Sorry vielmals, wenn das irgendwie in den falschen Hals gekommen ist.
War definitiv nicht böse oder sonst wie persönlich oder abwertend gemeint !

Nur:
Deine Code-Schnipsel haben nicht wirklich weitergeholfen

Und:
Zitat:

laden wo auch immer.
... tja, was wo genau ? Link(s) ?

Wenn man helfen möchte, sehe ich das grundsätzlich als absolut positiv an.
Aber wenn der zu Helfende im Nirwana selbst recherchieren soll (was [hoffentlich !] die meisten vorher machen), dann ... eher 'nicht so positiv'.

jaenicke 19. Aug 2022 19:29

AW: SetFocus will nicht ...
 
Es ist keine gute Idee so viel im OnActivate zu machen, schon gar nicht Änderungen am Fokus. Denn das OnActivate passiert ja gerade erst beim Anzeigen des Fensters. Du könntest dir z.B. selbst mit PostMessage eine Nachricht an dein Fenster schicken, die dann erst hinterher abgearbeitet wird, und dort diese Aktionen ausführen.

Aber auch ich kann das Problem nicht nachvollziehen. Ohne Beispielprojekt sehe ich nicht, wie ich hier zielgerichtet helfen könnte.

himitsu 19. Aug 2022 20:10

AW: SetFocus will nicht ...
 
Zitat:

Zitat von jaenicke (Beitrag 1510359)
Denn das OnActivate passiert ja gerade erst beim Anzeigen des Fensters.

Angezeigt ist es schon ... das war OnShow.

OnActivate ist, wenn das Fenster den Fokus bekommen hat,

TERWI 19. Aug 2022 20:29

AW: SetFocus will nicht ...
 
OnActivate habe ich gerade deswegen genommen, weil:
- Alle Units/Klassen sind dann initialisiert.
- Die MainForm wird (das erste mal) gestartet.
... so weit ich das alles richtig verstanden habe.

Zitat:

OnActivate ist, wenn das Fenster den Fokus bekommen hat
KORREKT !
... durch was & wen auch immer ...
Beim Programmstart auf jeden Fall.
ABER EBEN NICHT (mehr) wenn die procedure durch ist und es das LOGWIN gibt !
Da kann ich zuweisen/intitalisieren was ich will - geht einfach nicht
Auch das MainHandle an den LOGGER geben und dort SetForeGround o. ä. machen hilft nicht

Damit hab ich mich mal ne Zeit lang selbst vereimert.
Und dass das erneute Ausführen meiner Initialisierung eben nicht noch passiert, gibt es das Flag "FIsInit".
... wenn ich das versehentlich auskommentiert hatte, .... oh weia.
Ich weiß, nicht ganz sauber aber wenn man drauf achtet funzt das 1A !

Was den Focus angeht, hatte ich da vorhin eine Idee...
Bastle grade dran und gebe noch "Bescheid".

himitsu 19. Aug 2022 20:40

AW: SetFocus will nicht ...
 
Das sind sie auch so.

OldCreateOrder sollte man aber auf False stellen, falls es das nicht ist. (das wird True, wenn man extrem uralte Units/Forms in der IDE öffnet und kein OldCreateOrder nicht in der DFM stand ... bei neuen Forms ist es False)
OnCreate wurde früher im Create ausgeführt, aber nun erst im AfterCreate.

TERWI 19. Aug 2022 20:58

AW: SetFocus will nicht ...
 
Zum besseren Verständnis:

Jede Unit/Klasse die ich verwende hat jeweils eigene Initialisierungen für sich selbst mit:
- OnCreate (Elementares intern)
- OnDestroy (Dito)
für eigenen internen Kram, automatisch beim Programmstart zur elementaren Initialisierung.
Dazu hat jede Klasse die Funktionen
- OnInit mit Parametern, die erst zum Programmstart bekannt werden (z.B. INI-File)
- OnExit zur sicherung zwischenzeitlicher Änderungen intern eigen erzeugter Daten
welche ich in der MainForm eben in Activate/OnDestroy vor der "Zerstörung" allem anderen aufrufe.
Da kann ich sicher sein, das alles Grundlegende sonstwie definitiv passiert ist und ich alles weitere passend einstellen kann.

Da wird nix verbogen, geschachert, manipuliert oder sonstwas - straight wie es das Proggie braucht wird initialisiert und umgekehrt ggf. gesichert und freigegeben.

Wenn alles an der richtigen Stelle richtig gemacht wird, lüppt dat wie anne Schnur getreckt.
Loggo... wenn da nicht manchmal so Kleinigkeiten einem den Spaß vermiesen.

jaenicke 19. Aug 2022 21:23

AW: SetFocus will nicht ...
 
Zitat:

Zitat von himitsu (Beitrag 1510362)
OnActivate ist, wenn das Fenster den Fokus bekommen hat,

Ich meinte im Prozess des Anzeigens, denn OnActivate wird ansonsten ja auch noch viel öfter beim Fokuswechsel aufgerufen.

Das Problem tritt bei mir auch auf, wenn ich das zweite Fenster direkt im OnActivate anzeige. Das ist aber ja auch logisch, dass man während des Wechsels des Fokus nicht sinnvoll weitere Fokuswechsel in den Griff bekommt...

Wenn ich das Fenster stattdessen wie vorgeschlagen einfach nach der kompletten Anzeige in einer eigenen Message anzeige, klappt es auch mit dem Fokus:
Delphi-Quellcode:
const
  WM_TEST = WM_APP + 100;

type
  TForm235 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  protected
    procedure WmTest(var Msg: TMsg); message WM_TEST;
  public
    { Public-Deklarationen }
  end;

var
  Form235: TForm235;

implementation

{$R *.dfm}

procedure TForm235.FormCreate(Sender: TObject);
begin
  PostMessage(Handle, WM_TEST, 0, 0);
end;

procedure TForm235.WmTest(var Msg: TMsg);
begin
  Form236.Show;
  SetFocus;
end;

himitsu 19. Aug 2022 21:36

AW: SetFocus will nicht ...
 
Stimmt, direkt in OnCreate und OnShow geht es nicht, wenn man sich alle Fenster beim Start erstellen lässt,
da die andere Form natürlich erst nach der MainForm erstellt wird.

Auch die zweite Form selber erstellen, hat einen Haken, denn PopupMode funktioniert noch nicht, weil die MainForm erst als MainForm registriert wird, nachdem sie vollständig erstellt wurde. (wobei man das eventuell mal als Bug melden könnte)

Ich mach es mit mit sowas einfach nur noch einfach. :duck:
Delphi-Quellcode:
procedure TForm10.FormCreate(Sender: TObject); // oder besser im OnShow
begin
  ...
  TThread.ForceQueue(nil, procedure // es war echt schwachsinnig den Bugfix für Queue als ForceQueue zu bennen, anstatt es "richtig" zu machen.
    begin
      //Form11.Show;
      //SetFocus;
      ShowWindow(Form11.Handle, SW_SHOWNOACTIVATE);
      Form11.Visible := True;
    end);
end;

jaenicke 19. Aug 2022 21:42

AW: SetFocus will nicht ...
 
Daran hatte ich auch gedacht, aber das gibt es ja noch nicht so lange.

Der Effekt ist ja der gleiche.

TERWI 21. Aug 2022 11:57

AW: SetFocus will nicht ...
 
Wenn ich ehrlich bin: Hab ich nicht wirklich verstanden ....
Was macht/bewirkt denn TThread.ForceQueue ?
@jaenicke
Welche Form hier (Main, Logger) entspricht denn bei deinem beispiel TForm235, TForm236 ?

Ich hab das hier momentan mal anders gelöst.
Inspiriert durch eine alte Splash-Screen-Demo habe ich meinem Logger eine Init-Prozedure spendiert und in die DPR eingetragen.
(Verkürzte Version meines "neuen" Projekts, nach MainForm-Problem)
Delphi-Quellcode:
program ZATTOO;

uses
  Vcl.Forms,
  Logger5 in 'Logger5.pas' {LOGWIN},
  ZAT_MAIN in 'ZAT_MAIN.pas' {ZATMain},
  LAV_Player in 'LAV_Player.pas' {LAV};

{$R *.res}

begin
  LOGGER.Init;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TZATMain, ZATMain);
  Application.CreateForm(TLAV, LAV);
  Application.Run;
end.
Das sieht zwar hier so aus, als wenn der Logger eine Form ist, ist aber eine normale Unit, die sich selbst de-/intialisiert und ihr Fenster selbst erzeugt.
(Das hat den Grund darin, das es den Logger bereits gibt, bevor alles weitere initialisiert/startet und ich auch schon FormCreate's mitloggen kann)

Das geht problem- und tadellos.
MainForm hat nun nach dem Start trotz Logger-Fenster den Fokus.

jaenicke 21. Aug 2022 17:28

AW: SetFocus will nicht ...
 
Zitat:

Zitat von TERWI (Beitrag 1510441)
Wenn ich ehrlich bin: Hab ich nicht wirklich verstanden ....
Was macht/bewirkt denn TThread.ForceQueue ?

Das steht gut erklärt in der Doku, was auch daran liegt, dass es erst mit Delphi 10.2 eingeführt wurde:
https://docwiki.embarcadero.com/Libr...ead.ForceQueue
Der Code wird außerhalb des aktuellen Kontexts ausgeführt, wenn die Anwendung idle ist. Das ist der gleiche Effekt wie in meinem Beispiel. Es wird einfach später ausgeführt, nicht in dem Moment des OnActivate-Ereignisses.

Zitat:

Zitat von TERWI (Beitrag 1510441)
@jaenicke
Welche Form hier (Main, Logger) entspricht denn bei deinem beispiel TForm235, TForm236 ?

235 = Main, 236 = Logger

himitsu 21. Aug 2022 17:50

AW: SetFocus will nicht ...
 
Es macht eigentlich das, was man von Delphi-Referenz durchsuchenTThead.Queue erwartet, und das gibt es schon länger.
-> Funktion in die Queue legen und später ausführen

Nur Queue macht, wenn im Hautpthread aufgerufen, garnicht das, was man denkt, sondern es führt den Code sofort aus, so als hätte man stattessen Synchronize benutzt.

jaenicke 21. Aug 2022 18:13

AW: SetFocus will nicht ...
 
Zitat:

Zitat von himitsu (Beitrag 1510471)
Nur Queue macht, wenn im Hautpthread aufgerufen, garnicht das, was man denkt, sondern es führt den Code sofort aus, so als hätte man stattessen Synchronize benutzt.

Laut Doku durfte man es früher gar nicht im Hauptthread aufrufen, da das eine Endlosschleife verursachen konnte. Erst seit ich glaube auch 10.2 geht das mit der genannten (und dokumentierten) Auswirkung.

Der Zweck ist eben nicht die Ausführung in der Warteschlange, sondern das Ausführen im Hauptthread. So ist es ja auch dokumentiert.


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