PyQt: pintar dintre d'un widget

De Cacauet Wiki
Salta a la navegació Salta a la cerca

Pintar en els widgets

Anem a pintar els nostres propis widgets en Qt. Per fer això es fa de la següent manera:

  • Creem la nostra classe derivant-la de QWidget (en el nostre exemple la classe Pantalla)
  • Reimplementem el mètode paintEvent que es crida automàticament quan es repinta el Widget.
  • Dintre de paintEvent(self,e) podem pintar el què vulguem mitjançant l'objecte QPainter.
  • L'objecte QPainter ve a ser un "llapis" per dibuixar en el Widget. Feu un cop d'ull a la documentació, veureu que a part de la funció drawEllipse que fem servir, n'hi ha un fotimer com drawRect, drawArc, drawPixmap, etc.


Classe derivada

class Pantalla(QtGui.QWidget):
    def __init__(self):
        # ULL: cridar el constructor de la classe base és IMPRESCINDIBLE
        # (si sobreescrivim el constructor __init__, si no, no cal)
        super(QtGui.QWidget,self).__init__()
        self.initUI()
    
    def initUI(self):
        # inicialitzem aqui si tenim objectes interns
        pass

    # la funció paintEvent es crida cada cop que es pinta la pantalla
    # no cal cap connect(), ja ve connectada per la QApplication
    def paintEvent(self,e):
        # podriem liar-nos a pintar aquí mateix, o examinar l'event "e"
        # anem al lio... necessitem un objecte QPainter
        qp = QtGui.QPainter()
        qp.begin( self )
        self.pintaPilota( qp )
        qp.end()
        
    def pintaPilota(self, qp):
        # podem optar per un Pen (pinta perifèric)
        color = QtGui.QColor( 0, 0, 0 )
        color.setNamedColor( '#d4d4d4' )
        qp.setPen( color )
        # o bé per un Brush (farcit). El color és RGB, òbviament
        qp.setBrush( QtGui.QColor(200, 0, 0) )

        # PER FI, PINTEM LA PILOTA!
        posx, posy = 20, 20
        radx, rady = 10, 10
        qp.drawEllipse( posx, posy , radx, rady )


Exercici: control d'una pilota

L'objectiu és pintar una pilota i controlar-la amb els sliders (posició vertical i horitzontal).

  1. Feu l'anterior exercici dels sliders (en la intro de PyQt).
    Qt-sliders1.png
  2. Canviem el textedit per una classe nova nostra (Pantalla) heretada de QWidget (detallada més amunt)
  3. Afegim paintEvent i el disparem (de moment un print) només al repintar la pantalla (canvi de task)
  4. Pintem al widget Pantalla() amb QPainter.
    Comença per la pilota amb un drawEllipse com el de l'exemple però també prova drawRect, drawArc o altres opcions del QPainter (caldrà que miris la documentació).
  5. Per poder seguir ens convé tenir els valors posx i posy com a atributs de l'objecte Pantalla (i no com a variables locals). Crea, doncs, aquests atributs en Pantalla i pinta la pilota amb aquests valors interns. Després modificarem aquests valors amb els sliders.
  6. Connectem els sliders amb funcions que modifiquin la posx i la posy. De moment assigna'ls el valor que t'arriba del slider i prou.
    • PyQt: connectant signals amb slots
    • IMPORTANT: quan canvieu el valor de posx o posy cal repintar la pantalla (no es fa automàticament). Utilitzeu la funció repaint() del widget per forçar una repintada.
    Qt-piloteta1.png
  7. Calculem la posx i posy d'acord amb els límits dels sliders i de la geometria de la pantalla (que pot variar, per exemple, al maximitzar-la). Es tracta d'una senzilla regla de 3:
    x = valor_slider * amplada / total_ticks_slider
    100 és el total de ticks del slider, i l'amplada la podeu esbrinar del propi widget amb width()
  8. Per canviar el color del background teniu aquest link. A mi m'ha funcionat el del QPalette i no el de QStyleSheet.
  9. PyQt: Events de teclat: opcionalment pots afegir control del teclat als sliders.


Timers i pilotetes

Ens proposem l'objectiu de fer un widget on aparegui una pilota que rebota a les seves parets.

Seguiu el següent article: PyQt: Timers i pilotes rebotant