La première fois que j'ai essayé d'écrire un processus d'attente avec wxpython
Je pense que vous suivrez le chemin. (N'est-ce pas?) J'ai noté ce processus d'attente car je l'utilise assez souvent.
Honnêtement, ce contenu est partout, alors j'espère que vous pourrez le voir dans l'un des articles de référence.
En gros, la cause est que la boucle principale exécutée derrière l'interface graphique s'arrête en mode veille.
Mac OS wxpython 4.1.0
Installez wxpython
python
pip install wxpython
le filetage peut être utilisé sans installation. Non utilisé lors de l'utilisation de wx.Timer, mais à la place du temps.
python
import wx
import threading
import time
Ceci est efficace lorsque le traitement est effectué à intervalles réguliers. Est-ce le plus simple à utiliser pour mettre à jour l'heure actuelle?
python
import wx
import threading #Non utilisé cette fois
import time #Non utilisé cette fois
#Utilisé pour l'affichage de l'heure
import datetime as dt
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(400, 200))
#Création d'instance TimerPanel
self.panel = TimerPanel(self, -1)
#Affichage avec l'écran centré
self.Center()
self.Show()
class TimerPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
#Créer une chaîne de l'heure actuelle, self.clock_création txt,Temps d'affichage
now = dt.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
self.clock_txt = wx.StaticText(self, -1, label=now)
#Paramètres de police,Après avoir changé la taille à 20 auto.clock_Reflété dans txt
font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
self.clock_txt.SetFont(font)
#Créer un calibreur, self.clock_Ajouter txt au sizer,Appliquer le calibreur au panneau
sizer = wx.GridSizer(1, 1, gap=(0, 0))
sizer.Add(self.clock_txt, flag=wx.ALIGN_CENTRE) # ALIGN_CENTRE: Installé au centre du calibreur
self.SetSizer(sizer)
self.timer = wx.Timer(self) #Créer une minuterie dans le panneau
self.Bind(wx.EVT_TIMER, self.clock) #Auto à intervalles spécifiés.Horloge de course
self.timer.Start(1000) #Minuterie de 1000 ms(=1s)Prêt à démarrer
# self.timer.Stop() #Si vous souhaitez arrêter le chronomètre
def clock(self, event):
#Obtenez l'heure actuelle et vous-même.clock_Définir dans txt
now = dt.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
self.clock_txt.SetLabel(now)
self.Refresh()
if __name__ == '__main__':
app = wx.App()
MainFrame(None, -1, 'TimeEvent')
app.MainLoop()
Créez une minuterie avec le cadre ou le panneau comme parent, définissez l'intervalle et commencez. Plusieurs minuteries peuvent être exécutées en même temps.
Le gif ci-dessus a deux panneaux, chacun affichant l'heure avec une minuterie.
Le panneau supérieur dure 1 seconde et le bas 2 secondes.
wx.Timer utilise threading.Thread pour un traitement difficile à implémenter. Cette fonction peut créer un autre thread et exécuter plusieurs processus en même temps. Vous ne devez pas utiliser time.sleep () dans le thread où l'interface graphique est exécutée, mais il n'y a aucun problème dans un autre thread.
Voici le processus que je trouve difficile avec wx.Timer --Exécution périodique (ex: signal) dont l'intervalle d'attente n'est pas le même --Traitement qui change d'état avec le temps -> Il est gênant de faire une branche conditionnelle à chaque fois lors d'une exécution régulière (ex: signal)
En d'autres termes, utilisez threadind.Thred lorsque vous faites un feu de signalisation (n'est-ce pas trop limité?)
Le bleu, le jaune et le rouge sont affichés pendant 4, 1 et 5 secondes chacun.
python
import wx
import time
import threading
class TrafficLight(threading.Thread):
def __init__(self, panel):
super().__init__()
self.panel = panel
#Démonisez le sous-thread, s'il n'est pas défini sur True, le sous-thread continuera à s'exécuter même si l'écran est fermé.
self.setDaemon(True)
def run(self):
while True:
#Panneau jaune->noir,Panneau rouge->rouge
self.panel.yellow_panel.SetBackgroundColour('#000000')
self.panel.red_panel.SetBackgroundColour('#ff0000')
self.panel.Refresh()
time.sleep(5)
#Panneau rouge->noir,Panneau bleu->Bleu
self.panel.red_panel.SetBackgroundColour('#000000')
self.panel.blue_panel.SetBackgroundColour('#00ff00')
self.panel.Refresh()
time.sleep(4)
#Panneau bleu->noir,Panneau jaune->Jaune
self.panel.blue_panel.SetBackgroundColour('#000000')
self.panel.yellow_panel.SetBackgroundColour('#ffff00')
self.panel.Refresh()
time.sleep(1)
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(600, 200))
self.main_panel = MainPanel(self, -1)
#Afficher l'écran au centre
self.Center()
self.Show()
class MainPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
#Panneau bleu, couleur spécifiée comme noir
self.blue_panel = wx.Panel(self, -1)
self.blue_panel.SetBackgroundColour('#000000')
#Panneau jaune, couleur spécifiée comme noir
self.yellow_panel = wx.Panel(self, -1)
self.yellow_panel.SetBackgroundColour('#000000')
#Panneau rouge, couleur spécifiée comme noir
self.red_panel = wx.Panel(self, -1)
self.red_panel.SetBackgroundColour('#000000')
#Bouton Start
self.button = wx.Button(self, -1, 'start')
#Mise en page liée
sizer1 = wx.FlexGridSizer(2, 1, gap=(0, 0))
sizer2 = wx.GridSizer(1, 3, gap=(0, 0))
sizer1.Add(sizer2, flag=wx.EXPAND)
sizer1.Add(self.button, flag=wx.ALIGN_RIGHT)
sizer1.AddGrowableCol(0)
sizer1.AddGrowableRow(0)
sizer2.Add(self.blue_panel, flag=wx.EXPAND)
sizer2.Add(self.yellow_panel, flag=wx.EXPAND)
sizer2.Add(self.red_panel, flag=wx.EXPAND)
self.SetSizer(sizer1)
#Création d'instances de sous-threads, auto-argument
self.traffic_light = TrafficLight(self)
#Événement de bouton
self.button.Bind(wx.EVT_BUTTON, self.start)
def start(self, event):
#Création d'instances de sous-threads, auto-argument
traffic_light = TrafficLight(self)
#L'opération de sous-thread a commencé
traffic_light.start()
self.start_button.Disable() #Bouton désactiver,Empêcher la création de plusieurs threads
if __name__ == "__main__":
app = wx.App()
MainFrame(None, -1, "feu de circulation")
app.MainLoop()
Remplacement de la méthode d'exécution de threading.Thread. Seul self peut être passé à la méthode run. Les attributs requis sont transmis lors de la création de l'instance. De plus, comme il ne peut être exécuté qu'une seule fois par thread, il est instancié lorsque le bouton est enfoncé.
Le feu de signalisation ci-dessus ne peut pas être arrêté car il se déplace alors que True. Mais je veux pouvoir l'arrêter. Par conséquent, réécrivez la classe TrafficLight et ajoutez des variables et des fonctions globales.
L'interface graphique a ajouté un bouton d'arrêt. Lorsque le bouton d'arrêt est enfoncé, thread_stop_flag devient True et l'opération de thread se termine.
python
import wx
import time
import threading
thread_stop_flag = False
def wait_time(seconds):
"""
Arrêtez pendant le temps d'attente écoulé_Attendez en regardant le drapeau
stop_Quitte l'instruction while lorsque l'indicateur est True
:param seconds: int
Temps d'attente
:return: None
"""
wait_start = time.time()
while time.time() - wait_start <= seconds:
if not thread_stop_flag:
time.sleep(1)
else:
break
class TrafficLight(threading.Thread):
def __init__(self, panel):
super().__init__()
self.panel = panel
#Démonisez le sous-thread, s'il n'est pas défini sur True, le sous-thread continuera à s'exécuter même si l'écran est fermé.
self.setDaemon(True)
def run(self):
while not thread_stop_flag: #Changement 2
#Panneau jaune->noir,Panneau rouge->rouge
self.panel.yellow_panel.SetBackgroundColour('#000000')
self.panel.red_panel.SetBackgroundColour('#ff0000')
self.panel.Refresh()
wait_time(5)
#Panneau rouge->noir,Panneau bleu->Bleu
self.panel.red_panel.SetBackgroundColour('#000000')
self.panel.blue_panel.SetBackgroundColour('#00ff00')
self.panel.Refresh()
wait_time(4)
#Panneau bleu->noir,Panneau jaune->Jaune
self.panel.blue_panel.SetBackgroundColour('#000000')
self.panel.yellow_panel.SetBackgroundColour('#ffff00')
self.panel.Refresh()
wait_time(1)
#Changement 3,Tout remettre en noir
self.panel.blue_panel.SetBackgroundColour('#000000')
self.panel.yellow_panel.SetBackgroundColour('#000000')
self.panel.red_panel.SetBackgroundColour('#000000')
self.panel.Refresh()
class MainFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(600, 200))
self.main_panel = MainPanel(self, -1)
#Afficher l'écran au centre
self.Center()
self.Show()
class MainPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
#Panneau bleu, couleur spécifiée comme noir
self.blue_panel = wx.Panel(self, -1)
self.blue_panel.SetBackgroundColour('#000000')
#Panneau jaune, couleur spécifiée comme noir
self.yellow_panel = wx.Panel(self, -1)
self.yellow_panel.SetBackgroundColour('#000000')
#Panneau rouge, couleur spécifiée comme noir
self.red_panel = wx.Panel(self, -1)
self.red_panel.SetBackgroundColour('#000000')
#début,Bouton d'arrêt
self.start_button = wx.Button(self, -1, 'start')
self.stop_button = wx.Button(self, -1, 'stop')
#Mise en page liée
sizer1 = wx.FlexGridSizer(2, 1, gap=(0, 0))
sizer2 = wx.GridSizer(1, 3, gap=(0, 0))
sizer3 = wx.GridSizer(1, 2, gap=(0, 0))
sizer1.Add(sizer2, flag=wx.EXPAND)
sizer1.Add(sizer3, flag=wx.ALIGN_RIGHT)
sizer1.AddGrowableCol(0)
sizer1.AddGrowableRow(0)
sizer2.Add(self.blue_panel, flag=wx.EXPAND)
sizer2.Add(self.yellow_panel, flag=wx.EXPAND)
sizer2.Add(self.red_panel, flag=wx.EXPAND)
sizer3.Add(self.start_button)
sizer3.Add(self.stop_button)
self.SetSizer(sizer1)
#Événement de bouton
self.start_button.Bind(wx.EVT_BUTTON, self.start)
self.stop_button.Bind(wx.EVT_BUTTON, self.stop)
def start(self, event):
global thread_stop_flag
thread_stop_flag = False
#Création d'instances de sous-threads, auto-argument
traffic_light = TrafficLight(self)
#L'opération de sous-thread a commencé
traffic_light.start()
self.start_button.Disable() #Empêche la création de plusieurs threads d'invalidation de bouton
def stop(self, event):
#Fil de variable global_stop_flag à True=Définissez la condition de l'instruction while du thread sur False
global thread_stop_flag
thread_stop_flag = True
self.start_button.Enable()
if __name__ == "__main__":
app = wx.App()
MainFrame(None, -1, "feu de circulation")
app.MainLoop()
Ce n'est pas un gros problème, mais ça fait longtemps. S'il vous plaît laissez-moi savoir s'il existe une autre bonne façon d'écrire ...
Merci pour la lecture. Naturellement, la méthode utilisant le filetage a d'autres utilisations que les feux de signalisation. Par exemple, lorsque vous souhaitez exécuter une série d'opérations une seule fois au lieu d'une exécution périodique. Je l'utilise pour les paramètres initiaux de l'appareil.
Je me réfère aux articles suivants.
Cause d'erreur Python-je suis un débutant. Après avoir inséré l'instruction de veille, l'application a cessé de fonctionner correctement. | teratail
Rupture de fil Votre threading.Event est mal utilisé-Qiita
Recommended Posts