![]() |
How to use Thread() ? - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: How to use Thread() ? (/thread-37192.html) |
How to use Thread() ? - Frankduc - May-10-2022 Hello, By any luck someone could tell me how i could fix my thread problem. In the while loop at the begging there is a thread. Its link to a function delai and sub function decompte or (counter in english) While the counter is in action nothing on my board will be of any use its lock. The thread() should let the other function run without disrupting the rest. The counter with the thread become eratic. Anyone know how to use the thread in that context? Thank you """ """ from time import sleep from threading import Thread import time import smtplib import RPi.GPIO as GPIO import pygame from pygame.locals import * import sys import time #Pygame code clock = pygame.time.Clock() pygame.init() pygame.display.set_caption('Panneau de contrôle') FPS_CLOCK = pygame.time.Clock() BLANC = (255, 255, 255) ROUGE = (255, 0, 0) GREEN = (0, 255, 0) GRIS = (200, 200, 200) NOIR = (0, 0, 0) JAUNE = (255, 255, 0) screen = pygame.display.set_mode([700, 500]) sysfont = pygame.font.get_default_font() font = pygame.font.SysFont(None, 48) def bouton_A(screen, pos, texte): rayon = 55 pygame.draw.circle(screen, GREEN, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn) def bouton_D(screen, pos, texte): rayon = 55 pygame.draw.circle(screen, ROUGE, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn) def bouton_nb(screen, pos, texte): rayon = 25 pygame.draw.circle(screen, GRIS, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn) class Etat(): def horloge(self): theFont=pygame.font.Font(None,42) theTime=time.strftime("%H:%M:%S", time.localtime()) timeText=theFont.render(str(theTime), True,(255,255,255),(0,0,0)) screen.blit(timeText, (448,428)) pygame.display.update() def image(self): image = pygame.image.load('3.png') screen.blit(image, (110, 406)) def Alert_image(self): image = pygame.image.load('Master-Warning-Light.png') image = pygame.transform.scale(image, (96, 96)) screen.blit(image, (600, -10)) #pygame.display.update() img_intrus = font.render("Alerte Intrus", True, JAUNE) screen.blit(img_intrus, (450, 20)) sysfont = pygame.font.get_default_font() font = pygame.font.SysFont(None, 36) #Rapsberry Pi code GPIO.setmode(GPIO.BOARD) senseur_Del2 = 12 DEL1 = 18 DEL2 = 22 GPIO.setwarnings(False) GPIO.setup(senseur_Del2,GPIO.IN,pull_up_down=GPIO.PUD_UP) GPIO.setup(DEL1,GPIO.OUT,) GPIO.setup(DEL2,GPIO.OUT) led_off1=False led_off2=False def decompte(t): while t: min , sec = divmod(t,60) timer = '{:02d}:{:02d}'.format(min, sec) print(timer, end='\r') time.sleep(1) t -= 1 if t == 0: print('Délai terminé!') t = 10 class Etat_ent: def delai(self): #délai d'entrée print('Vous avez 10 secondes avant l`enclenchement de l`alarme!') GPIO.output(DEL1,True) time.sleep(.1) decompte(int(t)) GPIO.output(DEL1,True) time.sleep(1) GPIO.output(DEL1,False) time.sleep(1) GPIO.output(DEL1,True) ent = Etat_ent() e = Etat() while(True): if led_off1==False and GPIO.input(senseur_Del2)==1: thread = Thread(target=ent.delai, args=()) <-----maybe at the wrong place or stop at the wrong time thread.start() GPIO.output(DEL1,True) time.sleep(.2) GPIO.output(DEL1,False) time.sleep(.2) led_off2=True sleep(.5) if GPIO.input(senseur_Del2)==1: GPIO.output(DEL2,True) led_off2=True e.Alert_image() sleep(.5) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False x , y = pygame.mouse.get_pos() #liste des boutons cliqués Bouton_A = x > 104 and x < 204 and y > 196 and y < 301 Bouton_D = x < 549 and x > 444 and y > 192 and y < 309 Chiffre_1 = x > 248 and x < 285 and y > 182 and y < 218 Chiffre_2 = x > 301 and x < 339 and y > 182 and y < 220 Chiffre_3 = x > 358 and x < 390 and y > 180 and y < 218 Chiffre_4 = x > 244 and x < 282 and y > 237 and y < 269 Chiffre_5 = x > 303 and x < 341 and y > 235 and y < 268 Chiffre_6 = x > 357 and x < 394 and y > 238 and y < 288 Chiffre_7 = x > 241 and x < 287 and y > 294 and y < 329 Chiffre_8 = x > 301 and x < 339 and y > 295 and y < 330 Chiffre_9 = x > 353 and x < 395 and y > 291 and y < 327 if event.type == pygame.MOUSEBUTTONDOWN: #print(x,y) if Bouton_A: img = font.render("Entrez votre code pour désarmer le systeme d'alarme!", True, NOIR) screen.blit(img, (20, 100)) img = font.render("Veuillez entrer votre code pour armer le systeme d'alarme!", True, BLANC) screen.blit(img, (20, 100)) GPIO.output(DEL1,True) led_off1=True sleep(.5) else: screen.fill(NOIR) pygame.draw.rect(screen, NOIR, (21, 75, 677, 51), 2) GPIO.output(DEL1,False) led_off1= False sleep(.5) if Bouton_D: img = font.render("Entrez votre code pour désarmer le systeme d'alarme!", True, BLANC) screen.blit(img, (20, 100)) GPIO.output(DEL1,False) led_off1=False sleep(.5) GPIO.output(DEL2,False) led_off2=False sleep(.5) thread.stop() if Chiffre_1: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) if Chiffre_2: img = font.render("*", True, BLANC) screen.blit(img, (298, 131)) if Chiffre_3: img = font.render("*", True, BLANC) screen.blit(img, (335, 131)) if Chiffre_4: img = font.render("*", True, BLANC) screen.blit(img, (370, 131)) screen.fill(NOIR) pygame.draw.rect(screen, NOIR, (21, 125, 677, 51), 2) img = font.render("Merci", True, BLANC) screen.blit(img, (295, 350)) if Chiffre_5: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) e.Alert_image() GPIO.output(DEL2,True) led_off1=True sleep(.5) if Chiffre_6: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) e.Alert_image() GPIO.output(DEL2,True) led_off1=True sleep(.5) if Chiffre_7: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) e.Alert_image() GPIO.output(DEL2,True) led_off1=True sleep(.5) if Chiffre_8: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) e.Alert_image() GPIO.output(DEL2,True) led_off1=True sleep(.5) if Chiffre_9: img = font.render("*", True, BLANC) screen.blit(img, (258, 131)) e.Alert_image() GPIO.output(DEL2,True) led_off1=True sleep(.5) #listes des boutons bouton_A(screen, (150, 250), "Activé") bouton_D(screen, (500, 250), "Désactivé") bouton_nb(screen, (265, 200), "1") bouton_nb(screen, (320, 200), "2") bouton_nb(screen, (375, 200), "3") bouton_nb(screen, (265, 255), "4") bouton_nb(screen, (320, 255), "5") bouton_nb(screen, (375, 255), "6") bouton_nb(screen, (265, 310), "7") bouton_nb(screen, (320, 310), "8") bouton_nb(screen, (375, 310), "9") img = font.render("Bienvenue", True, ROUGE) screen.blit(img, (20, 20)) pygame.display.flip() e.image() e.horloge() FPS_CLOCK.tick(30) pygame.quit() sys.exit() RE: How to use Thread() ? - deanhystad - May-10-2022 The thread doesn't help to prevent blocking when you run the code that does the blocking outside of the thread, RE: How to use Thread() ? - Frankduc - May-10-2022 for example horloge() or the clock in english will stop working once the counter is starting. What your saying even with a thread my clock will still freeze untill the 10 secondes is done. The fact that there is a while loop in decompte() and reuse in the main while for pygame is probably my problem. I tried to find a way on the web to create a countdown without while loop, a different way but nothing usefull. So my teacher is wrong the thread wont solve the problem. RE: How to use Thread() ? - deanhystad - May-10-2022 No, what I am saying is that none of this code executes inside the thread. if led_off1==False and GPIO.input(senseur_Del2)==1: thread = Thread(target=ent.delai, args=()) <-----maybe at the wrong place or stop at the wrong time thread.start() GPIO.output(DEL1,True) time.sleep(.2) # Not in a thread GPIO.output(DEL1,False) time.sleep(.2) # Not in a thread led_off2=True # Should this be led_off1 == True? sleep(.5) # Not in a threadThis may only be 0.9 seconds of delay, but it happens continuously as long as GPIO.input(senseur_Del1) == 1. And you have a bunch of other waits that don't happen inside the thread. RE: How to use Thread() ? - Frankduc - May-10-2022 The way i understand it. The thread isolate the problematic function in this case delai() which is the counter. Thread isolate and run independantly the function. I did erase all the other dels to test if it was the problem. But even if i run only the function as a thread or not, the trouble is still there. led_off1 is just a light and senseur_Del2 is if the door is open or not. In this case if the door is open start the counter delai() you have 10 seconds to enter your code. When this process is on the clock stop and it wont let activate the numbers on the keyboard. So its impossible to input the code. I got to fix this by friday. That part doesnt worth many points. Still its a challenge, at least for me. ![]() RE: How to use Thread() ? - deanhystad - May-12-2022 How many threads do you make? And before you say 1, maybe you should try a test. These are all the same function other than rayon and color. You have arguments for pos and texte, why don't you do the same with rayon and color? def bouton_A(screen, pos, texte): rayon = 55 pygame.draw.circle(screen, GREEN, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn) def bouton_D(screen, pos, texte): rayon = 55 pygame.draw.circle(screen, ROUGE, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn) def bouton_nb(screen, pos, texte): rayon = 25 pygame.draw.circle(screen, GRIS, pos, rayon) txtBtn = font.render(texte, True, NOIR) rectBtn = txtBtn.get_rect() rectBtn.center = (pos) screen.blit(txtBtn, rectBtn)Why did you make a class for this function? Why isn't delai a method of class Etat? class Etat_ent: def delai(self): #délai d'entrée print('Vous avez 10 secondes avant l`enclenchement de l`alarme!') GPIO.output(DEL1,True) time.sleep(.1) decompte(int(t)) GPIO.output(DEL1,True) time.sleep(1) GPIO.output(DEL1,False) time.sleep(1) GPIO.output(DEL1,True)Etat really isn't a class either. What is it's purpose? It doesn't have any instance variables, so it's purpose cannot be to store information. None of the methods have anything in common. It is just a collection of functions that was put inside a class. Etat_ent could be a class. It could have instance variables and methods that work togeter to accomplish something like Countdwn in this example. import pygame import threading import time pygame.init() FOREGROUND_COLOR = "White" BACKGROUND_COLOR = "Black" DEFAULT_FONT = pygame.font.SysFont(None, 32) display = pygame.display.set_mode((300, 300)) screen = pygame.display.set_mode([450, 350]) class Countdown: """A countdown timer that calls a function when it counts down to zero""" def __init__(self): self.callback = None self.counting = False def doit(self, start_count): """Does the countdown. Runs in its own thread so it doesn't block.""" self.counting = True for count in range(start_count, 0, -1): if not self.counting: break label.set_text(str(count)) time.sleep(1) else: if self.callback is not None: self.callback() def connect(self, func): """Specify the function called when the timer counts down to zero""" self.callback = func def start(self, start_count): """Start the countdown""" if not self.counting: threading.Thread(target=self.doit, args=(start_count,)).start() def stop(self): """Stop the countdown""" self.counting = False label.set_text("") class Widget(pygame.surface.Surface): """Base class for pygame widgets""" def __init__(self, parent, size, foreground=None): super().__init__(size) self.parent = parent self.foreground = FOREGROUND_COLOR if foreground is None else foreground self.background = BACKGROUND_COLOR self.rect = self.get_rect() def draw(self): """Draw (blit) self on parent surface.""" self.parent.blit(self, (self.rect.x, self.rect.y)) return self def at(self, x, y): """Set upper left corner at x, y""" self.rect.x = x self.rect.y = y return self def center_at(self, x, y): """Set center at x, y""" self.rect.centerx = x self.rect.centery = y return self class Label(Widget): """A tkinter Label like thing for pygame""" def __init__(self, parent, text, width=None, font=None, foreground=None): self.width = len(text) if width is None else width self.font = DEFAULT_FONT if font is None else font size = self.font.render("W"*self.width, True, BACKGROUND_COLOR).get_size() super().__init__(parent, size, foreground) self.set_text(text) def set_text(self, text): self.text = text text_img = self.font.render(self.text, True, self.foreground) y = (self.rect.height - text_img.get_height()) // 2 self.fill(self.background) self.blit(text_img, (0, y)) self.draw() return self class CircleButton(Widget): """A tkinter Button like think for pygame""" buttons = [] @classmethod def clicked(cls, x, y): """Call this method to find what button was pressed""" for button in cls.buttons: if button.click(x, y): return True return False def __init__(self, parent, text, radius, foreground=None, text_color=None, font=None): super().__init__(parent, (radius*2, radius*2), foreground) self.font = DEFAULT_FONT if font is None else font self.text_color = self.background if text_color is None else text_color self.callback = None self.buttons.append(self) self.set_text(text) def set_text(self, text): """Set my label text. Label is centered in button""" self.text = text text_img = self.font.render(self.text, True, self.text_color) x = (self.rect.width - text_img.get_width()) // 2 y = (self.rect.height - text_img.get_height()) // 2 self.fill(self.background) pygame.draw.ellipse(self, self.foreground, self.get_rect()) self.blit(text_img, (x, y)) return self def connect(self, func): """Set function to call when clicked""" self.callback = func return self def click(self, x, y): """Check if I was clicked. Execute callback method if clicked""" clicked = self.rect.collidepoint(x, y) if clicked and self.callback: self.callback(self) return clicked # Give the buttons something to do def button_pressed(button): label.set_text(label.text + button.text) label = Label(screen, "", width=20, font=pygame.font.SysFont(None, 36)).at(50, 50) # Create a countdown timer that goes BOOM!! when it counts all the way down. countdown = Countdown() countdown.connect(lambda: label.set_text("BOOM!!")) # Make some buttons for number in range(9): x = 50 + (number % 3) * 80 y = 260 - (number // 3) * 80 CircleButton(screen, str(number+1), 30, "Blue", "White") \ .connect(button_pressed).at(x, y).draw() CircleButton(screen, "Start", 55, "Green") \ .connect(lambda x: countdown.start(10)).at(300, 100).draw() CircleButton(screen, "Stop", 55, "Red") \ .connect(lambda x: countdown.stop()).at(300, 220).draw() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False break if event.type == pygame.MOUSEBUTTONUP: CircleButton.clicked(*pygame.mouse.get_pos()) pygame.display.flip() pygame.display.update() pygame.quit() RE: How to use Thread() ? - deanhystad - May-13-2022 Added in a clock display that makes it easier to see that the thread runs the countdown without blocking the pytgame event loop. import pygame import threading import time pygame.init() FOREGROUND_COLOR = "White" BACKGROUND_COLOR = "Black" DEFAULT_FONT = pygame.font.SysFont(None, 36) CLOCK_FONT = pygame.font.SysFont(None, 20) screen = pygame.display.set_mode([390, 300]) class Countdown: """A countdown timer that calls a function when it counts down to zero""" def __init__(self, display): self.display = display self.callback = None self.counting = False def doit(self, start_count): """Does the countdown. Runs in its own thread so it doesn't block.""" self.counting = True for count in range(start_count, 0, -1): if not self.counting: break self.display.set_text(f"Countdown: {count}") time.sleep(1) else: self.counting = False if self.callback is not None: self.callback() def connect(self, func): """Specify the function called when the timer counts down to zero""" self.callback = func def start(self, start_count): """Start the countdown""" if not self.counting: threading.Thread(target=self.doit, args=(start_count,)).start() def stop(self): """Stop the countdown""" self.counting = False self.display.set_text("") class Widget(pygame.surface.Surface): """Base class for pygame widgets""" def __init__(self, parent, size, foreground=None, background=None): super().__init__(size) self.parent = parent self.foreground = FOREGROUND_COLOR if foreground is None else foreground self.background = BACKGROUND_COLOR if background is None else background self.rect = self.get_rect() def draw(self): """Draw (blit) self on parent surface.""" self.parent.blit(self, (self.rect.x, self.rect.y)) return self def erase(self): """Draw (blit) background color on parent surface""" pygame.draw.rect(self.parent, BACKGROUND_COLOR, self.rect) return self def at(self, x, y): """Set upper left corner at x, y""" self.rect.x = x self.rect.y = y return self def center_at(self, x, y): """Set center at x, y""" self.rect.centerx = x self.rect.centery = y return self @property def x(self): return self.rect.x @x.setter def x(self, new_x): self.rect.x = new_x @property def y(self): return self.rect.y @y.setter def y(self, new_y): self.rect.y = new_y @property def width(self): return self.rect.width @width.setter def width(self, new_width): self.rect.width = new_width @property def height(self): return self.rect.height @height.setter def height(self, new_height): self.rect.height = new_height class Label(Widget): """A tkinter Label like thing for pygame""" def __init__(self, parent, text, width=None, font=None, foreground=None, background=None): width = width or len(text) self.font = DEFAULT_FONT if font is None else font size = self.font.render("W"*width, True, BACKGROUND_COLOR).get_size() super().__init__(parent, size, foreground, background) self.set_text(text) def set_text(self, text): self.text = text text_img = self.font.render(self.text, True, self.foreground) y = (self.rect.height - text_img.get_height()) // 2 self.fill(self.background) self.blit(text_img, (0, y)) self.draw() return self class CircleButton(Widget): """A tkinter Button like think for pygame""" buttons = [] @classmethod def clicked(cls, x, y): """Call this method to find what button was pressed""" for button in cls.buttons: if button.click(x, y): return True return False def __init__(self, parent, text, radius, foreground=None, text_color=None, font=None): super().__init__(parent, (radius*2, radius*2), foreground) self.font = DEFAULT_FONT if font is None else font self.text_color = self.background if text_color is None else text_color self.callback = None self.buttons.append(self) self.set_text(text) def set_text(self, text): """Set my label text. Label is centered in button""" self.text = text text_img = self.font.render(self.text, True, self.text_color) x = (self.rect.width - text_img.get_width()) // 2 y = (self.rect.height - text_img.get_height()) // 2 self.fill(self.background) pygame.draw.ellipse(self, self.foreground, self.get_rect()) self.blit(text_img, (x, y)) return self def connect(self, func): """Set function to call when clicked""" self.callback = func return self def click(self, x, y): """Check if I was clicked. Execute callback method if clicked""" clicked = self.rect.collidepoint(x, y) if clicked and self.callback: self.callback(self) return clicked # Give the buttons something to do def button_pressed(button): display.set_text(display.text + button.text) clock_display = Label(screen, "", width=8, font=CLOCK_FONT).at(300, 20) display = Label(screen, "", width=10, foreground="black", background="white") display.erase().at(20, 20).draw() # Create a countdown timer that goes BOOM!! when it counts all the way down. countdown = Countdown(display) countdown.connect(lambda: display.set_text("BOOM!!")) # Make some buttons for number in range(9): x = 20 + (number % 3) * 80 y = 220 - (number // 3) * 80 CircleButton(screen, str(number+1), 30, "Blue", "White") \ .connect(button_pressed).at(x, y).draw() CircleButton(screen, "Start", 50, "Green") \ .connect(lambda x: countdown.start(10)).at(270, 60).draw() CircleButton(screen, "Stop", 50, "Red") \ .connect(lambda x: countdown.stop()).at(270, 180).draw() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False break if event.type == pygame.MOUSEBUTTONUP: CircleButton.clicked(*pygame.mouse.get_pos()) clock_display.set_text(time.strftime("%H:%M:%S", time.localtime())) pygame.display.flip() pygame.display.update() pygame.quit() RE: How to use Thread() ? - Frankduc - May-17-2022 Quote:Why did you make a class for this function? Why isn't delai a method of class Etat? These are all good questions. Quick answer i still dont grasp the concept of classes and state machine. I gave it a try because the teacher ask us to input those concepts in the assigment. delai returned an error message that i could not fix. Anyway i am about to quit i dont really like programming. Thank you for your help and time. |