Fenster focus erzwingen

Plattformunabhängige GUIs mit wxWidgets.
Antworten
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Freitag 5. Januar 2007, 23:02

Hallo,

ich suche nach einer Möglichkeit, mit der sich der Fokus eines Fensters erzwingen lässt, auch wenn der Anwender ein anderes Fenster im Vordergrund hat. Ich brauche dies in einem Programm, das sich in gewissen Intervallen beim Benutzer melden soll und in der Zwischenzeit im Hintergrund oder minimiert läuft. SetFocus() funktioniert nicht, denn es bewirkt gar keine Veränderung.

Danke
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 6. Januar 2007, 00:17

basti33 hat geschrieben:ich suche nach einer Möglichkeit, mit der sich der Fokus eines Fensters erzwingen lässt
Hi basti33!

Die Fensterverwaltung ist Sache des Betriebsystems oder des Windowmanagers (oder so ähnlich)... und nicht die eines einzelnen Programmes.

Unter Windows ist die API-Funktion ``SetForegroundWindow`` dafür verantwortlich, ein Fenster in den Vordergrund zu bringen.:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import wx
import win32gui
import win32con
import time
from thread import start_new_thread

wx.SetDefaultPyEncoding("iso-8859-1")


class MyFrame(wx.Frame):
    
    def __init__(self, parent = None, id = -1, title = "Ich bin ganz oben auf..."):
        
        wx.Frame.__init__(
            self, parent, id, title, style = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP
        )
        
        panel = wx.Panel(self)
        
        vbox = wx.BoxSizer(wx.VERTICAL)
        panel.SetSizer(vbox)
        
        vbox.Add((0, 0), 1)
        
        btn_close = wx.Button(panel, -1, u"Schließen")
        btn_close.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
        vbox.Add(btn_close, 0, wx.ALIGN_CENTER | wx.ALL, 10)
        
        vbox.Add((0, 0), 1)
        
        self.Show()
        self.MakeModal() # Muss nicht unbedingt sein. Kann aber helfen, wenn
                         # mehrere Fenster (Frames) mit im Spiel sind.
        
        # Nur zum Demonstrieren --> Thread, der ein paar Sekunden wartet und
        # dann das Fenster aktiviert, falls es den Fokus noch nicht hatte.
        start_new_thread(self.nach_oben_damit, ())
    
    
    def nach_oben_damit(self):
        
        hwnd = self.GetHandle()
        time.sleep(2)
        win32gui.SetForegroundWindow(hwnd)


def main():
    """Hauptprozedur"""
    
    app = wx.PySimpleApp()
    f = MyFrame()
    app.MainLoop()


if __name__ == "__main__":
    main()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Samstag 6. Januar 2007, 22:18

Hallo Gerold,

ich habe es genauso gemacht wie du beschrieben hast, bekomme jedoch immer diese aussagelose Fehlermeldung
Traceback (most recent call last):
File "C:\Dokumente und Einstellungen\Basti\Desktop\Vokabeltrainer_13.py", line 243, in UeberpruefeAntwort
winxpgui.SetForegroundWindow(hwnd)
pywintypes.error: (0, 'SetForegroundWindow', 'No error message is available')
Ich weiß nicht, was ich da falsch mach, ich verwende auf jeden Fall auch

Code: Alles auswählen

hwnd = self.GetHandle()
winxpgui.SetForegroundWindow(hwnd)
Ich habe es auch schon mit winxpgui versucht, aber da ändert sich auch nichts. Ich hoffe du oder irgendwer anders kann mir weiter helfen.

Danke

PS: Wäre toll wenn noch jemand eine Lösung für Linux wüsste!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Samstag 6. Januar 2007, 22:39

basti33 hat geschrieben:ich habe es genauso gemacht wie du beschrieben hast, bekomme jedoch immer diese aussagelose Fehlermeldung
Hi basti33!

Funktioniert mein Beispiel?

Es könnte sein, dass du versuchst ein Unterfenster und kein Hauptfenster (wx.Frame) nach oben zu bekommen.

Vielleicht versuchst du ja auch etwas nach oben zu bekommen, was noch nicht angezeigt wird. Aber ausschlaggeben ist eigentlich zuerst mal, ob mein Beispiel, so wie es oben steht, funktioniert, oder nicht.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Samstag 6. Januar 2007, 23:31

Ja, es funktioniert. Aber weil das Fenster als Style wx.STAY_ON_TOP angegeben hat ist es immer im Vordergrund, was es aber nicht soll. Vielleicht liegt hier ein Missverständnis vor, aber ich möchte ein Fenter, das nach einer gewissen Zeit in den Vordergrund kommt, auch wenn es von einem anderen Programm, wie z.B. einem Browser überlagert ist. Wenn ich wx.STAY_ON_TOP entferne kommt dieser Traceback:
Unhandled exception in thread started by <bound method MyFrame.nach_oben_damit of <__main__.MyFrame; proxy of <Swig Object of type 'wxFrame *' at 0x46e2a78> >>
Traceback (most recent call last):
File "<Module1>", line 47, in nach_oben_damit
pywintypes.error: (0, 'SetForegroundWindow', 'No error message is available')
Danke für die Mühe
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 7. Januar 2007, 00:07

basti33 hat geschrieben:Ja, es funktioniert. Aber weil das Fenster als Style wx.STAY_ON_TOP angegeben hat ist es immer im Vordergrund, was es aber nicht soll.
Hi basti33!

Wenn ich im Beispiel die Initialisierung ändere....

Code: Alles auswählen

        wx.Frame.__init__(
            self, parent, id, title, #style = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP
        )
...und den den Thread vier Sekunden schlafen lege...

Code: Alles auswählen

    def nach_oben_damit(self):
       
        hwnd = self.GetHandle()
        time.sleep(4)
        self.Restore()
        win32gui.SetForegroundWindow(hwnd)
...dann wird nach exakt vier Sekunden das Fenster in den Vordergrund geholt. Egal ob es bereits den Fokus hat, oder nicht. Damit auch ein minimiertes Fenster angezeigt wird, habe ich noch ``self.Restore()`` mit eingebaut.

Irgendwie kann ich deine Fehler nicht nachvollziehen.

Meine Umgebung:
- Windows XP SP2
- Python 2.4.4
- wxPython 2.8.0.1 (msw-unicode)
- pywin32-210

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
basti33
User
Beiträge: 56
Registriert: Donnerstag 24. August 2006, 15:05

Sonntag 7. Januar 2007, 00:50

Hallo,

es funktioniert solange das Fenster von keinem anderen überdeckt ist problemlos. Wenn ich aber z.B. den Internet Explorer darüber habe, kommt wieder besagte Fehlermeldung. Ich weiß nicht, woran das liegen soll. Meine Liste mit der eingesetzten Software weicht nur in dem Punkt von deiner ab, dass ich Python 2.5 verwende.
Hier noch einmal die Meldung:
Unhandled exception in thread started by <bound method Hauptmenue.Schlafzeit of <__main__.Hauptmenue; proxy of <Swig Object of type 'wxFrame *' at 0x37e1740> >>
Traceback (most recent call last):
File "C:\Dokumente und Einstellungen\Basti\Desktop\Vokabeltrainer_13.py", line 256, in Schlafzeit
win32gui.SetForegroundWindow(hwnd)
pywintypes.error: (0, 'SetForegroundWindow', 'No error message is available')
Das ist der Thread:

Code: Alles auswählen

    def Schlafzeit(self):
        '''Dieser Thread sorgt dafür, dass der Vokabeltrainer
        eine bestimmte Zeit ruht'''
        hwnd = self.GetHandle()
        sleep(self.cfg.ReadFloat('Schlafzeit')*60)
        self.Restore()
        win32gui.SetForegroundWindow(hwnd)
        self.ZugVokabel()
        self.Eingabe.Enable(1)
Danke
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 7. Januar 2007, 01:22

basti33 hat geschrieben:es funktioniert solange das Fenster von keinem anderen überdeckt ist problemlos. Wenn ich aber z.B. den Internet Explorer darüber habe, kommt wieder besagte Fehlermeldung.
Hi basti33!

Ich konnte deinen Fehler nachvollziehen. :-) Aber nur, wenn ich den Internet Explorer über das Fenster gelegt habe. :mrgreen:

Deshalb habe ich es mal mit drei Versuchen probiert:

http://paste.pocoo.org/show/583/

mfg
Gerold
:-)
Zuletzt geändert von gerold am Sonntag 7. Januar 2007, 01:38, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Sonntag 7. Januar 2007, 01:33

...hinter dem Explorer oder hinter Winamp bleibt das Fenster im Hintergrund.

Ich würde mich damit abfinden, dass es Programme gibt, die verhindern, dass ein Fenster unerwünscht nach vorne geholt wird.

Zumindest blinkt dann das Programm in der Taskleiste.

Ich glaube, das hat damit etwas zu tun, dass sich viele Leute darüber aufgeregt haben, wenn sich ein Fenster in den Vordergrund schiebt, während man gerade mit einem Programm arbeitet (z.B. etwas im Editor schreibt).
Schreibst du gerade etwas und ein Fenster kommt unerwartet in den Vordergrund, dann ist alles, was du eingibst, bis du das neue Fenster bemerkst, umsonst eingegeben worden. Das ist mir schon ziemlich oft passiert. -- Ich habe da ein tägliches Backup, das sich einfach so in den Vordergrund schiebt. :-( Das ist ziemlich ärgerlich.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Antworten