Partage
  • Partager sur Facebook
  • Partager sur Twitter

PyQt , QThread et QProgressBar

    10 octobre 2019 à 4:04:36

    Bonjour à tous

    Je suis en train de faire une IU pour un programme de pathfinding ;j'utilise PyQt pour cela ; J'ai voulu mettre en place une ProgressBar pour l'utiliser j'utilise des QThreads sinon la fenêtre Qt n'est plus actualisé , Je fais tourné un thread pour savoir quand je dois actualiser la ProgressBar ; j’envoie donc un Signal d'un Thread à un autre car je ne peux pas actualiser la progressBar autre pars que dans son threads où elle a était initialisé ; et là plusieurs problème .

    Le premier étant que le programme ne réagit pas toujours pareil , des fois il plante avant que la barre arrive à 100 d'autres quand il arrive à 100 et des fois il continue sans probleme .

    Le code main

    # -*- coding: utf-8 -*-
    import sys,time,pickle,os
    from time import sleep
    from copy import deepcopy
    from random import choice
    
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import QSize,QRect,Qt,QMetaObject,QCoreApplication,QThread,QObject,pyqtSignal
    from PyQt5.QtGui import QIcon,QFont,QWindow,QPen,QBrush,QColor
    
    from Objet import RobFind,Robot,Tab
    
    class Ui(QObject):
    	RunPath = 0
    	ProgBar = 0
    
    	aSignal = pyqtSignal()
    
    	def __init__(self):
    
    		
    
    		super().__init__()
    		self.load()
    		self.initWidget()
    		self.initGraph()
    		self.initProperty()
    		self.initName()
    		self.initText()
    		self.initSize()
    		self.initConnect()
    		self.fenetre.show()
    
    		
    	def initWidget(self):
    
    		
    
    		self.fenetre = QWidget()
    		self.widget = QWidget(self.fenetre)
    		self.layoutWidget = QWidget(self.fenetre)
    		
    		
    		self.spacerItem = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
    		self.spacerItem1 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
    		self.spacerItem2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
    		self.spacerItem3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
    		self.spacerItem4 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
    
    
    		self.BtnDeleteMap = QPushButton(self.widget)
    		self.BtnReloadMap = QPushButton(self.widget)
    		self.BtnRunPath = QPushButton(self.widget)
    		self.BtnSaveMap = QPushButton(self.widget)
    		self.BtnCancelPath = QPushButton(self.widget)
    
    
    		self.horizontalSlider = QSlider(self.widget)
    		
    		
    
    		self.ProgBar = QProgressBar(self.layoutWidget)
    
    
    		self.ProgLabel = QLabel(self.layoutWidget)
    		self.ProgLabel2 = QLabel(self.layoutWidget)		
    		self.labelMaxPa = QLabel(self.widget)
    
    		self.verticalLayout = QVBoxLayout()
    		self.verticalLayout_2 = QVBoxLayout()
    
    		self.horizontalLayout = QHBoxLayout(self.layoutWidget)
    			
    		self.gridLayout = QGridLayout(self.widget)
    
    	def initGraph(self):
    
    		self.scene = QGraphicsScene(0, 0,698,698,self.fenetre) 
    		self.GraphView = QGraphicsView(self.scene,self.fenetre)
    
    
    		self.Taille_Fenetre = 698
    		self.Taille_case = self.Taille_Fenetre/self.Map.x
    		print("Taille Graph :\nX : {0} \nY : {0} `\nTaille Case :\nX : {1} \nY : {1} `\nNombre Case :\nX : {2} \nY : {3} `\n  ".format(self.Taille_Fenetre,self.Taille_case,self.Map.x,self.Map.y))
    
    		self.GraphView.setSceneRect(0,0,self.Taille_Fenetre,self.Taille_Fenetre)
    
    		BrushNoir = QBrush(QColor(0,0,0))
    		BrushBlanc = QBrush(QColor(255,255,255))
    		BrushMur = QBrush(QColor(0,0,255))
    		PenMur = QPen(BrushNoir,1,Qt.SolidLine,Qt.SquareCap,Qt.MiterJoin)
    		BrushLimit = QBrush(QColor(0,255,0))
    		PenLimit = QPen(BrushNoir,1,Qt.SolidLine,Qt.SquareCap,Qt.MiterJoin)
    		BrushCible = QBrush(QColor(255,0,0))
    		PenCible = QPen(BrushNoir,1,Qt.SolidLine,Qt.SquareCap,Qt.MiterJoin)
    
    		for x in range(self.Map.x):
    			for y in range(self.Map.y):
    				if self.Map.Etat((0,y,x)) == 1:
    					Rect = (x*self.Taille_case,y*self.Taille_case,self.Taille_case,self.Taille_case,PenMur,BrushMur)
    				elif self.Map.Etat((0,y,x)) == 2:	
    					Rect = (x*self.Taille_case,y*self.Taille_case,self.Taille_case,self.Taille_case,PenLimit,BrushLimit)
    				elif self.Map.Etat((0,y,x)) == -1:	
    					Rect = (x*self.Taille_case,y*self.Taille_case,self.Taille_case,self.Taille_case,PenCible,BrushCible)
    				elif self.Map.Etat((0,y,x)) == 0:	
    					Rect = (x*self.Taille_case,y*self.Taille_case,self.Taille_case,self.Taille_case,PenMur,BrushBlanc)
    				
    
    				self.scene.addRect(*Rect)
    
    	def initProperty(self):
    
    		#self.BtnRunPath.setEnabled(True)
    
    
    		self.ProgBar.setProperty("value", RobFind.AnciennePourcent)
    		self.ProgBar.setRange(0,100)
    
    		self.horizontalSlider.setOrientation(Qt.Horizontal)
    
    		self.labelMaxPa.setBuddy(self.horizontalSlider)
    
    		self.gridLayout.setContentsMargins(0, 0, 0, 0)
    		self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1)	
    		self.gridLayout.addWidget(self.BtnDeleteMap, 7, 0, 1, 1)
    		self.gridLayout.addWidget(self.BtnCancelPath, 3, 0, 1, 1)
    		self.gridLayout.addWidget(self.BtnSaveMap, 4, 0, 1, 1)
    		self.gridLayout.addWidget(self.BtnReloadMap, 6, 0, 1, 1)
    		self.gridLayout.addWidget(self.BtnRunPath, 2, 0, 1, 1)
    		self.gridLayout.addItem(self.spacerItem, 1, 0, 1, 1)
    		self.gridLayout.addItem(self.spacerItem2, 9, 0, 1, 1)
    		self.gridLayout.addItem(self.spacerItem3, 8, 0, 1, 1)
    		self.gridLayout.addItem(self.spacerItem4, 5, 0, 1, 1)	
    
    		self.verticalLayout.addWidget(self.ProgLabel)
    		self.verticalLayout.addWidget(self.ProgBar)
    		self.verticalLayout.addWidget(self.ProgLabel2)
    
    		self.verticalLayout_2.addWidget(self.labelMaxPa)
    		self.verticalLayout_2.addWidget(self.horizontalSlider)
    		self.verticalLayout_2.addItem(self.spacerItem1)
    
    		self.horizontalLayout.addLayout(self.verticalLayout)
    
    	def initSize(self):
    
    		self.fenetre.resize(900, 800)
    		self.GraphView.setGeometry(QRect(200, 100, 700, 700))
    		self.layoutWidget.setGeometry(QRect(1, 0, 900, 100))
    		self.widget.setGeometry(QRect(0, 98, 199, 700))
    		self.labelMaxPa.setMaximumSize(QSize(200, 100))
    
    	def initName(self):
    
    		QMetaObject.connectSlotsByName(self.fenetre)
    
    		self.GraphView.setObjectName("GraphView")
    		self.layoutWidget.setObjectName("layoutWidget")
    		self.horizontalLayout.setObjectName("horizontalLayout")
    		self.verticalLayout.setObjectName("verticalLayout")
    		self.ProgLabel.setObjectName("ProgLabel")
    		self.ProgBar.setObjectName("ProgBar")
    		self.ProgLabel2.setObjectName("ProgLabel2")
    		self.widget.setObjectName("widget")
    		self.gridLayout.setObjectName("gridLayout")
    		self.BtnDeleteMap.setObjectName("BtnDeleteMap")
    		self.verticalLayout_2.setObjectName("verticalLayout_2")
    		self.labelMaxPa.setObjectName("labelMaxPa")
    		self.horizontalSlider.setObjectName("horizontalSlider")
    		self.BtnCancelPath.setObjectName("BtnCancelPath")
    		self.BtnSaveMap.setObjectName("BtnSaveMap")
    		self.BtnReloadMap.setObjectName("BtnReloadMap")
    		self.BtnRunPath.setObjectName("BtnRunPath")
    
    	def initText(self):
    		_translate = QCoreApplication.translate
    		self.fenetre.setWindowTitle(_translate("self.fenetre", "Pathfinding"))
    		self.ProgLabel.setText(_translate("self.fenetre", "Le Meilleur Chemin est long de {}"))
    		self.ProgLabel2.setText(_translate("self.fenetre", "TextLabel"))
    		self.BtnDeleteMap.setText(_translate("self.fenetre", "Effacer Carte"))
    		self.labelMaxPa.setText(_translate("self.fenetre", "Max mouvement voulu :"))
    		self.BtnCancelPath.setText(_translate("self.fenetre", "Annuler Pathfinding"))
    		self.BtnSaveMap.setText(_translate("self.fenetre", "Sauvegarder Carte"))
    		self.BtnReloadMap.setText(_translate("self.fenetre", "Recharger Carte"))
    		self.BtnRunPath.setText(_translate("self.fenetre", "Lancer Pathfinding"))
    
    	def load(self):
    		self.MrLarbin = pickle.load(open('data/MrLarbin', 'rb'))
    		self.Map = self.MrLarbin.Maze
    		print("X : {} \nY : {} ".format(self.Map.x,self.Map.y))		
    
    	def initConnect(self):
    		self.BtnRunPath.clicked.connect(self.runPath)
    		self.BtnCancelPath.clicked.connect(self.stopPath)
    		
    		
    
    	def runPath(self):
    		print("Lancement Pathfinding")
    
    		self.aSignal.emit()
    
    		Ui.ProgBar = self.ProgBar
    
    	def stopPath(self):
    
    		print("Stop")
    		Ui.RunPath = 0
    
    	def progActu(self):
    
    		if RobFind.AnciennePourcent < 100 :
    			self.ProgBar.setValue(RobFind.AnciennePourcent)
    		else :
    			self.ProgBar.setValue(100)
    			print("Baam")
    
    
    	def Print(self):
    		print("print")
    
    
    
    
    class Path(QObject):
    
    	def Path(self):
    
    		print("Pathfinding Lancé")
    		MrLarbin = pickle.load(open('data/MrLarbin', 'rb'))
    		Sheer = MrLarbin
    
    		#Calcule du nombre de chemins max (Pas fiable)
    
    		NbCase = MrLarbin.Maze.y * MrLarbin.Maze.x
    		NbCNonLibre = 0
    		for y in range(MrLarbin.Maze.y-1):
    			for x in range(MrLarbin.Maze.x-1):
    				if MrLarbin.Maze.Search((0,y,x)).Etat > 0 :
    					NbCNonLibre += 1
    		NbCNonLibre
    		NbCLibre = NbCase-NbCNonLibre
    		Taux = NbCLibre//NbCNonLibre
    		if Taux == 0 :
    			Taux = 1
    		p = 0
    		for i in range(NbCLibre):
    			for o in range(Taux):
    				p += NbCLibre/10
    
    		RobFind.N_SuccessMax = p
    
    
    		#Lancement du pathfinding
    
    		RobFind.Registre = list()
    		RobFind.Registre.append(RobFind(Sheer,deepcopy(Sheer.Maze)))
    		print("fin path")
    		print(*RobFind.BonChemin)
    		Ui.RunPath = 0
    		os.system("pause")
    
    class refresh(QObject):
    
    	ProgBarSignal = pyqtSignal()
    
    	def Refresh(self):
    
    		i = -2
    
    		while 1 :
    			if (RobFind.AnciennePourcent != i):
    				i = RobFind.AnciennePourcent
    				self.ProgBarSignal.emit()
    
    if __name__ == "__main__":
    
    	app = QApplication(sys.argv)
     
    	Pathfinding = Path()
    	ui = Ui()
    	fresh = refresh()
    
    	thread1 = QThread()
    	thread2 = QThread()
    	thread3 = QThread()
    
    	fresh.moveToThread(thread3)
    	ui.moveToThread(thread1)
    	Pathfinding.moveToThread(thread2)
    	
    
    	thread1.start()
    	thread2.start()
    	thread3.start()
    
    	fresh.ProgBarSignal.connect(ui.progActu)
    	ui.aSignal.connect(Pathfinding.Path)
    	ui.aSignal.connect(fresh.Refresh)
    
    	print("Done.")
    
    	sys.exit(app.exec_())

    Et le code "Objet.py" qui contient le systeme de PathFinding

    # -*- coding: utf-8 -*
    import os,sys,pickle
    from time import sleep
    from copy import deepcopy
    from random import choice
    from math import *
    
    
    
    PinEntre =  [5,6,12,13,16]
    PinSortie = [18,17,27,22,23]
    
    
    class Objet:
    	TaillePente = 3
    	def __init__(self,positionZ,positionY,positionX,orientation,repere):
    		self.Maze = repere
    		self.Z = positionZ
    		self.Y = positionY
    		self.X = positionX
    		self.orientation = orientation
    		self.depart = (positionZ,positionY,positionX)
    		self.checkPoint = (positionZ,positionY,positionX)
    		self.Maze.Search((self.Z,self.Y,self.X)).Etat = 2
    
    	def Copy(self):
    		return (self.Z,self.Y,self.X)
    
    
    class Robot(Objet):
    
    	def Deplacement(self,Demande,Fin=0):
    		print(Demande)
    
    		if Demande == "N":
    			Demande = 1
    		elif Demande == "E":
    			Demande = 2
    		elif Demande == "S":
    			Demande = 3
    		elif Demande == "O":
    			Demande = 4
    
    		"""Reorientation des mouvement par rapport a l'orientation 
    			du robot """
    
    
    	def Avancer(self,Fin):
    		pass
    	def Arriere(self,Fin):
    		pass
    	def RotDroite(self,Fin):
    		pass
    	def RotGauche(self,Fin):
    		pass
    	def RotArriere(self,Fin):
    		pass
    	def PingMur(self):
    		pass
    	def PingCam(self):	
    		pass
    	def PingThermique(self):
    		pass
    	def PingSol(self):
    		pass
    
    class RobFind(Objet):
    
    	BonChemin = list()
    	Registre = list()
    	N_Instance = 0
    	N_Success = 0
    	N_SuccessMax = 0
    	AnciennePourcent = -1
    	Profondeur = 0
    	Stop = 0
    	
    
    	def __init__(self,Robcopie,repere,Chemin=list(),Depart=True,Pas=0):
    
    
    		RobFind.N_Instance += 1
    		self.Matricule = RobFind.N_Instance
    
    		self.Z = Robcopie.Z
    		self.Y = Robcopie.Y
    		self.X = Robcopie.X
    		
    		self.plan = repere
    
    		self.chemin = deepcopy(Chemin)
    		self.pas = Pas 
    
    
    		if Depart != True:
    			if Depart == "N":
    				self.Avancer()
    			elif Depart == "E":
    				self.Droite()
    			elif Depart == "S":
    				self.Arriere()
    			elif Depart == "O":
    				self.Gauche()
    
    
    		self.Pathfinding()
    
    		if RobFind.AnciennePourcent != (RobFind.N_Success/RobFind.N_SuccessMax*100//1) or RobFind.N_Instance > 100000  :
    			AncienneN_Instance = RobFind.N_Instance
    			RobFind.TriChemin()
    			RobFind.Avancement(AncienneN_Instance)
    
    
    
    
    
    	def TriChemin():
    
    		if RobFind.BonChemin == list():
    			for I in RobFind.Registre:
    				I = I.chemin
    				if I[-1] == 'Success':
    					RobFind.BonChemin = I
    					break
    		else:
    			decal = 0
    			for i in range(len(RobFind.Registre)):
    				i = i - decal
    				I = RobFind.Registre[i].chemin
    				if I[-1] == 'Success':
    					if len(I) == len(RobFind.BonChemin):
    						o = i
    					elif len(I) < len(RobFind.BonChemin):
    						RobFind.BonChemin = I
    						decal += 1
    					elif len(I) > len(RobFind.BonChemin):
    						del RobFind.Registre[i]
    						decal += 1
    					else :
    						del RobFind.Registre[i]
    						decal += 1
    				elif I[-1] == 'I':
    					del RobFind.Registre[i]
    					decal += 1
    
    
    
    	def Avancement(AncienneN_Instance):
    		RobFind.AnciennePourcent = int(RobFind.N_Success/RobFind.N_SuccessMax*100//1)
    		BonChemin = RobFind.BonChemin
    		print("{}/100 ".format(RobFind.AnciennePourcent))
    
    	def Dupli(self,Depart):
    		RobFind.Registre.append(RobFind(self,self.plan,self.chemin,Depart,self.pas))
    
    	def __del__(self):
    
    		RobFind.N_Instance -= 1
    
    	def Avancer(self):
    		#print('Avancer')
    		self.Y -= 1
    		self.pas += 1
    		self.chemin.append("N")
    		self.plan.Search((self.Z,self.Y,self.X)).Passage = self.pas
    
    	def Droite(self):	
    		#print('Droite')
    		self.X += 1
    		self.pas += 1
    		self.chemin.append("E")
    		self.plan.Search((self.Z,self.Y,self.X)).Passage = self.pas
    
    	def Gauche(self):
    		#print('Gauche')	
    		self.X -= 1
    		self.pas += 1
    		self.chemin.append("O")
    		self.plan.Search((self.Z,self.Y,self.X)).Passage = self.pas
    
    	def Arriere(self):
    		#print('Arriere')		
    		self.Y += 1
    		self.pas += 1
    		self.chemin.append("S")
    		self.plan.Search((self.Z,self.Y,self.X)).Passage = self.pas
    
    
    	def Pathfinding(self): 
    		"""Cherche un chemin vers une case inconnu,
    	a chaque intersection lance un nouveau RobFind partant de
    	l'intersection avec les meme information que son model """
    
    		while True:
    
    			#print( " Z:{}  Y:{}  X:{} \n ".format(self.Z,self.Y,self.X))
    			self.Sortie = 0
    			self.Action = 'Rien'
    			if self.plan.Etat((self.Z,self.Y,self.X)) == -1 : #Si case inconnue retourne self.Chemin
    				self.chemin.append("Success")
    				RobFind.N_Success += 1
    				return
    			""" 			Recherche d'une Sortie			"""
    
    			if self.plan.Etat((self.Z,self.Y-1,self.X)) <= 0 and self.plan.Pas((self.Z,self.Y-1,self.X)) > self.pas :
    				self.Sortie += 1
    				if self.Sortie > 1 :
    					self.Dupli("N")
    				else:
    					self.Action = self.Avancer
    
    			if self.plan.Etat((self.Z,self.Y,self.X+1)) <= 0 and self.plan.Pas((self.Z,self.Y,self.X+1)) > self.pas :
    				self.Sortie += 1
    				if self.Sortie > 1 :
    					self.Dupli("E")
    				else:
    					self.Action = self.Droite
    
    			if self.plan.Etat((self.Z,self.Y+1,self.X)) <= 0 and self.plan.Pas((self.Z,self.Y+1,self.X)) > self.pas :
    				self.Sortie += 1
    				if self.Sortie > 1 :
    					self.Dupli("S")
    				else:
    					self.Action = self.Arriere
    
    			if self.plan.Etat((self.Z,self.Y,self.X-1)) <= 0 and self.plan.Pas((self.Z,self.Y,self.X-1)) > self.pas :
    				self.Sortie += 1
    				if self.Sortie > 1 :
    					self.Dupli("O")
    				else:
    					self.Action = self.Gauche
    
    
    			if self.Sortie == 0 :
    				self.chemin.append("I")
    				return
    			else:
    				self.Action()
    
    class Case:
    	def __init__(self,positionZ,positionY,positionX,Etat=0):
    		self.Z = positionZ
    		self.Y = positionY
    		self.X = positionX
    		self.Etat = 0
    		self.Passage = 10000
    
    	def ModifEtat(self,Etat):
    		self.Etat = Etat
    
    	def __repr__(self):
    		pass
    
    
    class Tab:#Creation d'un tableau fait de l'objet Case 
    
    	def __init__(self,tailleZ,tailleY,tailleX):
    
    		self.z = tailleZ
    		self.y = tailleY
    		self.x = tailleX
    		self.Tableau = list()
    		for z in range(tailleZ):
    			Premiere_D = []
    			for y in range(tailleY):
    				Deuxieme_D = []
    				for x in range(tailleX):
    					Deuxieme_D.append(Case(z,y,x))
    				Premiere_D.append(Deuxieme_D)
    			self.Tableau.append(Premiere_D)
    
    	def Search(self,Position):
    		#print("{} {} {} ".format(Position[0],Position[1],Position[2]))
    		return self.Tableau[Position[0]][Position[1]][Position[2]]
    	def Etat(self,Position):
    		return self.Tableau[Position[0]][Position[1]][Position[2]].Etat
    	def Pas(self,Position):
    		return self.Tableau[Position[0]][Position[1]][Position[2]].Passage
    
    

    Ps : Le compteur pour la Progress bar ne s'arrete pas à 100 car j'ai pas encore de formules fiable pour trouver le nombre de Success_Max .

    désolé si c'est pas très digeste à lire ...





    • Partager sur Facebook
    • Partager sur Twitter

    PyQt , QThread et QProgressBar

    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
    • Editeur
    • Markdown