Window back on the Top - Gadget

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Window back on the Top - Gadget

Beitrag von X360 Andy »

Hallo Zusammen,


Ich hoffe ich habe eine Anfänger Frage.


Meine Software startet eine externe Anwendung, der Benutzer muss hier ein paar Sachen klicken.
[Mein Programm verliert hier den Focus]

Nachdem der Benutzer fertig ist [diese Abfrage bekomme vom Programm] soll meine Software wieder den Focus bekommen, und "setactiveGadget()" aufgrufen werden, leider bringt mir das ohne Focus nichts.

Wie kann ich nun in der Z-Order von Windows rumspielen und mein Programm/Fenster nach ganz oben bekommen.

Super wäre es wenn mir jemand helfen kann.

Gruß´Andreas
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Window back on the Top - Gadget

Beitrag von Kiffi »

SetActiveWindow()?

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Window back on the Top - Gadget

Beitrag von ts-soft »

Code: Alles auswählen

SetForeGroundWindow_(hWnd)
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Re: Window back on the Top - Gadget

Beitrag von X360 Andy »

Funktioniert leider nicht.


Was ich nun gerade getestet habe

Code: Alles auswählen

        SetForegroundWindow_(WindowID(#Window_0))
        SetActiveWindow(#Window_0)
        SetActiveWindow_(WindowID(#Window_0))
        SetWindowPos_(WindowID(#Window_0), #HWND_TOPMOST, 0, 0, 0, 0, #SWP_NOSIZE | #SWP_NOMOVE)
        SetActiveGadget(GetRightGadget(#_1String_1, #_2String_1, #_3String_1, #_4String_1))
SetWindowPos_ funktioniert teilweise, nur nicht unter allen System [hab 2 getestet], unter WIN Server 2008 läufts, auf Windows 7 nicht.
[Und das auch nicht immer]

Als Info
Alle Befehle werden in einer externem Thread abgebearbeitet

Vereinfachtest Beispiel

Code: Alles auswählen

Procedure Alive_System(Para)

  Repeat
    
    Select Befehl
        
      Case 1
      ; Hier kommen Befehle die auf die Daten von anderen Programm warten , hier verliert das Programm den Focus


      ; Hier sollte es den Focus es wieder bekommen, damit der Benutzer sofort weiterarbeiten kann 
      Befehl = 0

      Case 2 


      Befehl = 0


Endselect
delay(10)

Until Exit = 1
Endprocedure
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Window back on the Top - Gadget

Beitrag von Danilo »

Probiere mal diese Funktion von MSDN: Fenster in den Desktop-Vordergrund bringen

Code: Alles auswählen

; Verwenden Sie die Funktion SetForegroundWindowEx statt der 
; API Funktion SetForegroundWindow ausschließlich, wenn das 
; betroffene Fenster tatsächlich in den Vordergrund gebracht 
; werden muss. 
Procedure SetForegroundWindowEx(hWndWindow)
    ; Dient dem Setzen des Vordergrundfensters mit der Funktion 
    ; SetForegroundWindow, die sich unter neueren Windows-Versionen 
    ; anders verhält als unter Windows 95 und Windows NT 4.0. 
    ; Der Rückgabewert ist True, wenn das Fenster erfolgreich in den 
    ; Vordergrund gebracht werden konnte. 
    Protected SetForegroundWindowEx
    Protected lThreadForeWin.l  ; Thread-ID für das aktuelle Vordergrundfenster 
    Protected lThreadWindow.l   ; Thread-ID für das in hWndWindow spezifizierte 
                                ; Fenster, das in den Vordergrund des Desktops 
                                ; gebracht werden soll. 
    ; Falls das Fenster dem gleichen Thread wie das aktuelle 
    ; Vordergrundfenster angehört, ist kein Workaround erforderlich: 
    lThreadWindow  = GetWindowThreadProcessId_(hWndWindow, 0) 
    lThreadForeWin = GetWindowThreadProcessId_(GetForegroundWindow_(), 0) 
    If lThreadWindow = lThreadForeWin
        ; Vordergrundfenster und zu aktivierendes Fenster gehören zum 
        ; gleichen Thread. SteForegroundWindow allein reicht aus: 
        SetForegroundWindowEx = SetForegroundWindow_(hWndWindow)
    Else 
        ; Das Vordergrundfenster gehört zu einem anderen Thread als das 
        ; Fenster, das neues Vordergrundfenster werden soll. Mittels 
        ; AttachThreadInput erhaten wir kurzzeitig Zugriff auf die 
        ; Eingabeverarbeitung des Threads des Vordergrundfensters, 
        ; so dass SetForegroundWindow wie erwartet arbeitet: 
        AttachThreadInput_(lThreadForeWin, lThreadWindow, #True)
        SetForegroundWindowEx = SetForegroundWindow_(hWndWindow) 
        AttachThreadInput_(lThreadForeWin, lThreadWindow, #False) 
    EndIf
    ProcedureReturn SetForegroundWindowEx
EndProcedure
Oder noch etwas erweitert von dort: How to bring window to top with SetForegroundWindow()

Code: Alles auswählen

Procedure SetForegroundWindowInternal(hWnd)
    If Not IsWindow_(hWnd) : ProcedureReturn : EndIf
     
    ; relation time of SetForegroundWindow lock
    lockTimeOut.l = 0;
    hCurrWnd = GetForegroundWindow_();
    dwThisTID.l = GetCurrentThreadId_()
    dwCurrTID.l = GetWindowThreadProcessId_(hCurrWnd,0);
     
    ; we need To bypass some limitations from Microsoft :)
    If (dwThisTID <> dwCurrTID)
        AttachThreadInput_(dwThisTID, dwCurrTID, #True);
         
        SystemParametersInfo_(#SPI_GETFOREGROUNDLOCKTIMEOUT,0,@lockTimeOut,0);
        SystemParametersInfo_(#SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,#SPIF_SENDWININICHANGE | #SPIF_UPDATEINIFILE);
         
        #ASFW_ANY = -1
        AllowSetForegroundWindow_(#ASFW_ANY);
    EndIf
     
    SetForegroundWindow_(hWnd);
     
    If (dwThisTID <> dwCurrTID)
        SystemParametersInfo_(#SPI_SETFOREGROUNDLOCKTIMEOUT,0,lockTimeOut,#SPIF_SENDWININICHANGE | #SPIF_UPDATEINIFILE);
        AttachThreadInput_(dwThisTID, dwCurrTID, #False);
    EndIf
EndProcedure
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Re: Window back on the Top - Gadget

Beitrag von X360 Andy »

Klappt leider auch nicht.

Ich werde morgen mal schauen ob ich ein Code hinkriege der das Problem ausführbar zeigt.
Die Software hat aktuell etwa 7.000 selbstgeschrieben Zeilen Code sowie müssen viele Extra Programme auf dem Rechner sein.

Gruß
Benutzeravatar
Sicro
Beiträge: 964
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Window back on the Top - Gadget

Beitrag von Sicro »

Hat bei mir bis jetzt immer geklappt:

Code: Alles auswählen

SetForegroundWindow_(WindowID(#Window_Main))
BringWindowToTop_(WindowID(#Window_Main))
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Window back on the Top - Gadget

Beitrag von Danilo »

X360 Andy hat geschrieben:Klappt leider auch nicht.
Mach mal aus diesem Code eine .exe mit Compileroption threadsafe:

Code: Alles auswählen

EnableExplicit
; http://msdn.microsoft.com/de-de/library/bb979463.aspx
;
; Verwenden Sie die Funktion SetForegroundWindowEx statt der 
; API Funktion SetForegroundWindow ausschließlich, wenn das 
; betroffene Fenster tatsächlich in den Vordergrund gebracht 
; werden muss. 
Procedure SetForegroundWindowEx(hWndWindow)
    ; Dient dem Setzen des Vordergrundfensters mit der Funktion 
    ; SetForegroundWindow, die sich unter neueren Windows-Versionen 
    ; anders verhält als unter Windows 95 und Windows NT 4.0. 
    ; Der Rückgabewert ist True, wenn das Fenster erfolgreich in den 
    ; Vordergrund gebracht werden konnte. 
    Protected SetForegroundWindowEx
    Protected lThreadForeWin.l  ; Thread-ID für das aktuelle Vordergrundfenster 
    Protected lThreadWindow.l   ; Thread-ID für das in hWndWindow spezifizierte 
                                ; Fenster, das in den Vordergrund des Desktops 
                                ; gebracht werden soll. 
    ; Falls das Fenster dem gleichen Thread wie das aktuelle 
    ; Vordergrundfenster angehört, ist kein Workaround erforderlich: 
    lThreadWindow  = GetWindowThreadProcessId_(hWndWindow, 0) 
    lThreadForeWin = GetWindowThreadProcessId_(GetForegroundWindow_(), 0) 
    If lThreadWindow = lThreadForeWin
        ; Vordergrundfenster und zu aktivierendes Fenster gehören zum 
        ; gleichen Thread. SteForegroundWindow allein reicht aus: 
        ;SetForegroundWindowEx = SetForegroundWindow_(hWndWindow)
    Else 
        ; Das Vordergrundfenster gehört zu einem anderen Thread als das 
        ; Fenster, das neues Vordergrundfenster werden soll. Mittels 
        ; AttachThreadInput erhaten wir kurzzeitig Zugriff auf die 
        ; Eingabeverarbeitung des Threads des Vordergrundfensters, 
        ; so dass SetForegroundWindow wie erwartet arbeitet: 
        AttachThreadInput_(lThreadForeWin, lThreadWindow, #True)
        SetForegroundWindowEx = SetForegroundWindow_(hWndWindow) 
        AttachThreadInput_(lThreadForeWin, lThreadWindow, #False) 
    EndIf
    ProcedureReturn SetForegroundWindowEx
EndProcedure




; http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo
;
Procedure SetForegroundWindowInternal(hWnd)
    If Not IsWindow_(hWnd) : ProcedureReturn : EndIf
     
    ; relation time of SetForegroundWindow lock
    Protected lockTimeOut.l = 0;
    Protected hCurrWnd = GetForegroundWindow_();
    Protected dwThisTID.l = GetCurrentThreadId_()
    Protected dwCurrTID.l = GetWindowThreadProcessId_(hCurrWnd,0);
     
    ; we need To bypass some limitations from Microsoft :)
    If (dwThisTID <> dwCurrTID)
        AttachThreadInput_(dwThisTID, dwCurrTID, #True);
         
        SystemParametersInfo_(#SPI_GETFOREGROUNDLOCKTIMEOUT,0,@lockTimeOut,0);
        SystemParametersInfo_(#SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,#SPIF_SENDWININICHANGE | #SPIF_UPDATEINIFILE);
         
        #ASFW_ANY = -1
        AllowSetForegroundWindow_(#ASFW_ANY);
    EndIf
     
    SetForegroundWindow_(hWnd);
    ;SetFocus_(hWnd)
     
    If (dwThisTID <> dwCurrTID)
        SystemParametersInfo_(#SPI_SETFOREGROUNDLOCKTIMEOUT,0,lockTimeOut,#SPIF_SENDWININICHANGE | #SPIF_UPDATEINIFILE);
        AttachThreadInput_(dwThisTID, dwCurrTID, #False);
    EndIf
EndProcedure

Global myMsg = RegisterWindowMessage_("MyWindowMessage")

Procedure run(v.i)
    Protected program
    program = RunProgram("calc.exe","","",#PB_Program_Open)
    
    While ProgramRunning(program)
      Delay(100)
    Wend
    CloseProgram(program)
    PostMessage_(v,myMsg,0,0)
EndProcedure

Procedure winthread(v)
    Protected win
    win = OpenWindow(#PB_Any,100,100,500,300,"main")
    CreateThread(@run(),WindowID(win))
    Repeat
        Select WaitWindowEvent()
            Case #PB_Event_CloseWindow
               Break
            Case myMsg
               ;SetForegroundWindowEx(WindowID(win))
               SetForegroundWindowInternal(WindowID(win))
        EndSelect
    ForEver
    CloseWindow(win)
EndProcedure

Define t
t = CreateThread(@winthread(),0)
WaitThread(t)
Funktioniert hier. Das Fenster kommt immer in den Vordergrund,
sobald Calc beendet wurde. Aber als EXE kompilieren und diese
ohne geöffnete PB IDE testen.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Re: Window back on the Top - Gadget

Beitrag von X360 Andy »

Klappt in meinem Beispiel alles nicht.

Hier ein einfaches Beispiel wie es funktionieren sollte
- Hier funktioniert es nicht

[Egal welchen Befehl ich einsetze vor dem SetActiveGadget()]

Code: Alles auswählen

Global Exit
Global Befehl

#W1=1
#G1=2
#G2=3

Procedure A1(P)
  
  Repeat
    
    Select Befehl
        
      Case 1
        Debug "Befehl 1"
        
        Befehl=0
        
      Case 2
        Debug "Befehl 2 ---"
        
        Debug "Run Calc.exe"
        program=RunProgram("calc.exe", "", "", #PB_Program_Open)
        
        While ProgramRunning(program)
          Delay(100)
        Wend
        CloseProgram(program)
        Debug "Calc Closed"
        
        SetActiveGadget(#G1)
        
        Debug "SetActiveGadget State to G1"
        Debug "realy ?"
        Befehl=0
    EndSelect
    
    Delay(10)
    
  Until Exit=1
  Exit=2
EndProcedure

OpenWindow(#W1, 100, 100, 200, 200, "Main")
StringGadget(#G1, 10, 10, 100, 20, "ABC")
ButtonGadget(#G2, 10, 40, 100, 20, "Klick mich")

CreateThread(@A1(), 1)

Repeat
  
  event=WaitWindowEvent(50)
  Select event
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #G1
          Befehl=1
        Case #G2
          Befehl=2
      EndSelect
    Case #PB_Event_CloseWindow
      Select GetActiveWindow()
        Case #W1
          Exit=1
      EndSelect
  EndSelect
  
Until Exit=2


Benutzeravatar
HeX0R
Beiträge: 3042
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: Window back on the Top - Gadget

Beitrag von HeX0R »

Aus einem Thread heraus ist meistens schlecht, probier es mal so:

Code: Alles auswählen

Global Exit
Global Befehl

#W1=1
#G1=2
#G2=3

Procedure A1(P)
 
  Repeat
   
    Select Befehl
       
      Case 1
        Debug "Befehl 1"
       
        Befehl=0
       
      Case 2
        Debug "Befehl 2 ---"
       
        Debug "Run Calc.exe"
        program=RunProgram("calc.exe", "", "", #PB_Program_Open)
       
        While ProgramRunning(program)
          Delay(100)
        Wend
        CloseProgram(program)
        Debug "Calc Closed"
       
        PostMessage_(WindowID(#W1), #WM_APP, 1, 1)
       
        Befehl=0
    EndSelect
   
    Delay(10)
   
  Until Exit=1
  Exit=2
EndProcedure

OpenWindow(#W1, 100, 100, 200, 200, "Main")
StringGadget(#G1, 10, 10, 100, 20, "ABC")
ButtonGadget(#G2, 10, 40, 100, 20, "Klick mich")

CreateThread(@A1(), 1)

Repeat
 
  event=WaitWindowEvent(50)
  Select event
  	Case #WM_APP
  		SetActiveWindow(#W1)
  		SetActiveGadget(#G1)
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #G1
          Befehl=1
        Case #G2
          Befehl=2
      EndSelect
    Case #PB_Event_CloseWindow
      Select GetActiveWindow()
        Case #W1
          Exit=1
      EndSelect
  EndSelect
 
Until Exit=2
[Edit]
Oder gleich aus dem Thread ein

Code: Alles auswählen

SendMessage_(GadgetID(#G1), #WM_SETFOCUS, 1, 1)
aufrufen.
Antworten