Salut à tous,
J'instancie plusieurs QWidget dans une QFrame, je souhaiterais definir l'ordre de visibilité des widgets sur la fenêtre. Savez-vous comment fait-on cela?
Merqui.
Ju.
Plusieurs Widgets sur un QFrame. Ordre d'affichage.
mar, 05/06/2007 - 10:19
#1
Plusieurs Widgets sur un QFrame. Ordre d'affichage.
C'est une question qui concerne Python ça ? Ou alors tu codes en PyQT sans rien dire à personne ? ;)
Quoi qu'il en soit, comment ça ordre de visibilité ? Tu veux qu'il apparaissent les uns après les autres tes widgets ? Dans quel but ?
Hmm désolé ne ne pas avoir précisé, oui c'est du pyQT
Je dessine dans des qwidget, je peux déplacer avec la souris ces qwidget dans la qframe. Sauf que lorsque 2 qwidgets se superposent celui qui reste visible est le dernier à avoir été instancié. J'aimerais pouvoir donner la visibilité à celui qui est en mouvement.
Alors pour illustrer un peu mes dires, voici une capture de mon appli
C'est un peu le même fonctionnement que simulink pour matlab
Lorsque je déplace un bloc, je souhaite qu'il soit au dessus de tous les autres.
Donc tu nous caches sans doute que tu appelles une routine de rafraîchissement de la fenêtre. Je veux dire que tu demandes à QT de dessiner au lieu de le faire toi même. Et sans doute aussi que QT maintient une liste des widgets ordonnés dans l'ordre de leur création et les redessine systématiquement dans cet ordre. Et c'est AMHA ton approche du *je* dessine qui est a repenser.
J'ai t'y raison ?
Mais bon va savoir, parce que petit cachotier que tu es, ton code aussi tu le caches soigneusement. Pas un petit bout, pas une ligne, rien, nada, (void *)null.
Ca ne fait pas beaucoup pour déterminer ce qui ne va pas :twisted: :D
Ca fait plaisir d'avoir des méssages comme le tiens, tu n'es pas modérateur pour rien je pense !! Et ça donne envie de s'abonner ^^...
Tous mes objets graphiques dessinés dérivent de cette classe :
def setSize(self,_QSSize):
""" set the size of the current object user interface """
self.QSSize = _QSSize
def getSize(self):
""" return the size of the current object user interface """
return self.QSSize
def getPainter(self):
""" return the qpainter """
return(self.QPaint)
#=================================
# Manage the mouse
#=================================
def mousePressEvent(self, event):
""" action performed when the mouse is clicked """
raise NotImplementedError("Method mousePressEvent not defined in class " + self.__class__.__name__)
def mouseMoveEvent(self, event):
""" action performed when the mouse is moved """
raise NotImplementedError("Method mouseMoveEvent not defined in class " + self.__class__.__name__)
def mouseReleaseEvent(self, event):
""" action performed when the mouse is released """
raise NotImplementedError("Method mouseReleaseEvent not defined in class " + self.__class__.__name__)
Et voici le code d'un widget graphique qui dessine un carré:
#=================================
# Public painting
#=================================
def paintEvent(self, event):
# Go to the position where to draw the object
self.move(self.getPosition().x(), self.getPosition().y())
self.painter = QtGui.QPainter()
self.painter.begin(self)
#painter.setRenderHint(QtGui.QPainter.Antialiasing)
self.painter.fillRect(event.rect(), QtGui.QBrush(self.colorFix))
self.drawShape(self.painter)
self.painter.end()
def drawShape(self, painter):
self.painter.fillPath(self.shape, QtGui.QBrush(self.colorFix))
def setupShape(self):
QPpath = QtGui.QPainterPath()
QPpath.setFillRule(QtCore.Qt.OddEvenFill)
QPpath.addRect(0, 0, self.getSize().width(), self.getSize().height())
self.shape = QPpath
#=================================
# Public accessors
#=================================
def setPlace(self, _place):
self.m_place = _place
def getPlace(self):
return self.m_place
def setAscendant(self, _asc):
self.m_ascendant = _asc
def addDescendant(self, _desc):
self.m_descendants.append(_desc)
def getAscendant(self):
return self.m_ascendant
#=================================
# Public functions
#=================================
def getNbDescendants(self):
return len(self.m_descendants)
def getDescendant(self, _position):
return self.m_descendants[_position]
def removeAscendant(self):
self.m_ascendant = 0
#=================================
# Manage the mouse
#=================================
def mouseMoveEvent(self, event):
""" Redraw the current block when the mouse is being moved """
# shape of the cursor
self.setCursor(QtCore.Qt.SizeAllCursor)
# Catch the position of the mouse
position = event.pos()
# newPosition is the new position of the QLabel
newPosition = QtCore.QPointF(self.getPosition().x()+position.x(),self.getPosition().y()+position.y())
# Move to the current position of the mouse
self.move(newPosition.x(),newPosition.y())
# update the position of the QLabel
self.QPPosition = newPosition
self.color = self.colorMoving
self.update()
def mousePressEvent(self, event):
return
def mouseReleaseEvent(self, event):
# shape of the cursor
self.setCursor(QtCore.Qt.SizeAllCursor)
self.color = self.colorFix
self.update()
Premier bien sur, il n'y a pas d'ironie dans ce que j'ai dit.
Tu as pris le temps de me répondre ainsi que d'éclaircir mon post ! J'ai peine à trouver des forums python avec des forumeurs actifs. D'autant plus que dans la boite dans laquelle je suis (stagiaire), personne ne fait directement du graphique pythonQT.
A lire (pas très attentivement je le confesse :oops: ) ton code, il me semble que ton problème est bel et bien dans le *je* de "je dessine".
Si je comprends bien tu ne dessines pas mais chaque composant réagit à un paintEvent et se redessine à ce moment. Le problème est que tu n'es pas maître que l'ordre dans lequel QT envoie les événements. Je ne pense pas que l'on puisse avoir la maîtrise là-dessus. Je dirais même au contraire (si je me rappelle un bout de doc de Qt que j'ai lu il y a longtemps) Pour résoudre le problème Il me semble que tu dois (par exemple) capturer les mouvements de la souris en amont,, c'est à dire au dessus de la fenêtre sans te soucier des widgets et à chaque déplacement tu dois appeler les méthodes drawShape de tes composants (dans un sandwich QtGui.QPainter(), etc ce la va de soit) . Comme ça tu pourras les dessiner comme tu voudras, surtout si tu maintiens une liste dans laquelle ils seront classés selon leur z-order.
Ok je pense voir ce que tu m'as expliqué.
Je dois donc redessiner tout le graphe même si je ne déplace qu'un seul widget ?
J'ai un autre soucis, mon widget "lien" qui représente le trait sur l'image se redessine à chaque déplacement d'une boite, ça marche mais il y à des scintillements. Je me demande si ma conception est bien adaptée pour ce que je souhaite faire? Je n'ai trouvé sur le net aucun tutorial pour faire du dessin interactif un peu évolué avec pyQT, je trouve ceci fort domage car python à l'air d'être puissant mais pas encore utilisé dans les entreprises.
ps: pour mon problème de "Z", on m'a parlé de QStackedWidget, mais la doc dit que ca sert à n'afficher que le widget en tete de la liste. Peux-tu m'en dire un peu plus sur ses fonctionnalités.
ps: j'espere ne pas abuser avec mes questions de débutant, mais j'ai fait pas mal de recherches google et RTFM...
J'éssaye de m'attaquer au Double Buffer en premier pour une v0, je verrai ensuite de revoir la conception.
Je ne suis pas sur d'appliquer la bonne méthode du double buffer. Sur certains sites ils parlent de la fonction bitblt qui existe uniquement avec qt3, or j'utilise qt4. Avec qt4 il paraitrait que la technique du double buffer ne sert à rien puisque qt le ferait tout seul comme un grand, je n'en suis pas convaincu.
Est-ce que je procède bien pour faire un double buffer avec mon code, pas sur...car ca scintille encore !
En effet. L'idée est de dessiner TOUS les composants dans UNE image. Je t'ai parlé d'une boucle de dessin de tous les widgets d'un coup en réponse aux événements souris.
Si, au contraire, d'une manière ou d'une autre, tu provoques un repaint de la fenêtre ça scintillera toujours.
"il paraîtrait"... Moi je connais pas les "il paraîtrait".
Mais qu'une image QT4 soit double-bufferisée n'implique pas que ça te dispense de coder la boucle que j'essaie de t'expliquer. Si tu afficher n images double-bufferisées dans ta fenêtre, tu ne fais pas ce qu'il faut. Ce qu'il faut est que le fond de ta fenêtre soit constitué d'une seule image double-bufferisée entièrement dessinée en arrière plan.
Ok je me lance dans le dessin sur une seule image double buffeurisée.
J'ai un soucis pour afficher un simple carré. Lorsque ce code marchera, j'aurais compris comment fonctionne exactement les qpainterpath et je pourrais alors me lancer dans la nouvelle conception.
class DrawWidget(QtGui.QLabel):
def __init__(self, parent=None):
super (DrawWidget, self).__init__ (parent)
QPath = QtGui.QPainterPath()
painter = QtGui.QPainter()
QPath.setFillRule(QtCore.Qt.OddEvenFill)
# Partie qui sera encapsulee dans les fonctions setupShape de mes objets graphiques
QPath.lineTo(0.0,87)
QPath.lineTo(0.0,60)
QPath.lineTo(10.0,60)
QPath.lineTo(35,35)
QPath.lineTo(100.0,35)
QPath.lineTo(100, 87)
QPath.lineTo(0.0, 87)
painter.begin(self)
# Utile ou pas? :
painter.fillRect(0,0,800,600, QtCore.Qt.white)
painter.fillPath(QPath, QtGui.QBrush(QtCore.Qt.BDiagPattern))
painter.end()
class DrawGraph(QtGui.QFrame):
def __init__(self, parent=None):
QtGui.QFrame.__init__(self, parent)
self.move(0, 0)
self.setMinimumSize(800, 600)
self.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.StyledPanel)
self.setWindowTitle(self.tr("Test AFPy Objets Graphique"))
dw = DrawWidget(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = DrawGraph()
window.show()
sys.exit(app.exec_())
Avec tout ça rien ne s'affiche...
*
Merci encore
Juste, mais toujours pas ! Rah, je vais faire des tutos à la fin de mon stage en francais et complets.
class DrawGraph(QtGui.QFrame):
def __init__(self, parent=None):
QtGui.QFrame.__init__(self, parent)
self.move(0, 0)
self.setMinimumSize(800, 600)
self.setFrameStyle(QtGui.QFrame.Sunken | QtGui.QFrame.StyledPanel)
self.setWindowTitle(self.tr("Test AFPy Objets Graphique"))
dw = DrawWidget(self)
oui, ok ca marche chui naze des fois (ou plutot chui pas trop bête de temps en temps rarement)
Bon allé reconcevons.... :lol:
painter = QtGui.QPainter(***un_QPaintDevice_ici***)
Je viens de comprendre à quoi servait le parametre du contructeur QPainter.
Maintenant je fais passer en parametre ma qpixmap à mon qpainter,
ensuite j'ajoute un rectangle au qpainterpath, ce qpainterpath je le dessine dans le qpainter qui est sensé le dessiner dans mon qpixmap, puis je termine par demander le dessin du qpixmap....
Rien...
J'ai du oublier quelque chose, même si ce que j'ai codé me semble logique...
Tu ne dessinerais pas l'image sur elle même là par hasard ? ;)
:lol:
Hmm, j'ai du mal à interpreter le role de la fonction drawpixmap, pour moi elle doit dessiner le qpixmap passé en paramètres dans l'objet sur lequel on appelle la méthode soit le qpainter.
Me trompais-je? ^^
self.QPixMap
Il existe comme tu le sait, un type QPixmap. Déclarer un membre du nom de QPixMap, même nom à une majuscule près, ça s'appelle de l'obfuscation, c'est à dire un très mauvais style d'écriture.En programmation nommer des variables, c'est un vrai art :)
Je suis entierement d'accord avec toi pour le nom self.QPixMap, j'ai corrigé dans mon code.
D'apres ta remarque, je pense que je ne dois pas faire de drawpixmap ou bien creer un autre qpixmap temporaire puis le copier dans celui du qpainter?
Non, désolé, mais je ne vois pas la logique. Je donne ma langue au chat
Lol :lol:
Toute la magie est dans le OTHER. Une fenêtre est (par héritage) un QPaintDevice. Si tu instancies un **AUTRE** QPainter en passant la fenêtre en argument au constructeur, quand tu ferasPardonne moi de me marrer, mais :lol:
Bon on a dit au tout début des explications sur le double-buffering que ton image, une fois constituée en arrière plan (ce qui est fait présentement et à priori), doit être dessinée **DANS LA FENETRE** screugneugneu.
Alors comment ?
Maintenant tu as ta Pixmap.
La doc Qt dit
self.autre.drawPixmap(QtCore.QPointF(0,0), self.QPixMap)
Dans la fenêtre tu dessineras
:lol:
Hmm, je commence à comprendre la logique !
Je sens que j'y suis presque, MAIS... ça n'affiche toujours rien et je commence à culpabiliser de monopoliser ton temps pour ces broutilles.
Je cris fort, mais j'ai l'impression que c'est un minimum là :lol:
Et toi kektufé ?
Tu fait ta petite bidouille comme ca dans le constructeur.
Alors si ça se trouve ta pixmap elle est dessinée au moment de la construction et tu ne la vois JAMAIS, même pas pendant une fraction d'éclair atomisé.
parce que:
window.show ça fait apparaître la fenêtre avec sa routine de dessin par défaut et ta bidouille hein où est-elle ? A la trappe, aux oubliettes, dans un trou noir.
Faut structurer code comme ça
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = DrawGraph()
window.show()
window.ma_methode_de_dessin() #!!!!!!!!!!
sys.exit(app.exec_())
Réfléchi à ce profond enseignement petit scarabée et la lumière t'apparaîtra ... et ta Pixmap aussi :lol:
okok, je vois mieux, mais je dois avoir une mauvaise vision car je le trouve pas ce :evil: :evil: :evil: :evil: :evil: de carré.
lol et re-lol :lol:
Quand tu auras fini, tu pourras en effet écrire un tutorial. Mais pas sur PyQT; Sur l'art de ne pas en louper une.
Tiens pendant que j'y pense, les appeles aux méthode end comme self.newQP.end() n'ont rien à faire dans le code si tu lis *bien* la doc de QT.
keskondizai au fait, à propos de l'obfuscation :?: un carré 10*10. Lol Microscopique. Si ça se trouve il est dessiné (en 10,10) dans la barre de la fenêtre.Bon tu ne t'es pas addressé à moi avec le respect qui m'est du, je me retire méditer dans ma grotte au Tibet :)
Oh grand magnat pythonesque...
Si je n'appelle pas la fonction end sur mes deux qpainter, lorsque je ferme la fenêtre un warning apparait :
Même avec un gros gros rectangle, il n'affiche rien :
self.QPath.addRect(50,50,400,400)
Le truc c'est que je comprends lentement au début, mais après lorsque j'ai compri je roxxe ^^ :evil:
Traduction : je comprends vite mais il faut m'expliquer longtemps. Le soucis c'est que je n'ai certains reflexes ou mécanismes pour comprendre ou utiliser la doc à 100 %.
- il faut réorganiser ton code. Dessiner en dehors de l'événement de dessin oui, je l'ai dit et je le maintiens. Mais essaie de dessiner en réponse à un clic ou un déplacement de souris. (D'ailleurs au final c'est bien ce que tu veux avoir alors raison de plus pour essayer comme ça)
Et là tu devrais avoir satisfaction.
Si j'ai le temps j'essaierai d'écrire un petit bout de code, mais je ne peux pas promettre. Toujours le problème du temps.
Je tenais à apporter quelques précisions suite à ces posts, parce que je me suis heurté aux mêmes problèmes.
Premièrement, on dit Qt et non QT... on ne parle pas de QuickTime, ici. Quitte à être rigoureux, autant l'être jusqu'au bout. Non mais !
Ensuite, attention : je fais partie de la masse qui s'est noyée dans l'imbuvable café américain et il se trouve que la solution à ce problème est d'utiliser la méthode "raise" du widget correspondant pour l'envoyer en avant-plan. C'est super simple, efficace et mis en place en 30 secondes... mais en Java avec Qt Jambi, donc.
Cette méthode est-elle disponible avec PyQt ? Je pense que ce serait intéressant de vérifier.
Au plaisir...