Search code examples
pythonlinepyqt5qpushbuttonpaintevent

PyQt5: Draw a line by clicking QPushButton


I am trying to make it such that when I click a QPushButton a line is drawn. However the code I have right now makes the line at the beginning when the code is initiated and not after. The QPushButton doesn't seem to do any drawing.

I also don't quite understand why when drawing you need an 'event' argument in the function.

enter image description here

import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QGridLayout,QPushButton, QApplication, QWidget
from PyQt5.QtCore import QSize, QCoreApplication, Qt
from PyQt5.QtGui import QPainter, QPen

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.setMinimumSize(QSize(300, 300)) 

        pybutton = QPushButton('button', self)
        pybutton.clicked.connect(self.paintEvent)
        pybutton.resize(100,100)
        pybutton.move(100, 100) 

    def paintEvent(self,event):
        print('click')
        painter = QPainter(self)
        pen = QPen(Qt.red, 3)
        painter.setPen(pen)
        painter.drawLine(0,0,100,100)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit( app.exec_() )

Solution

  • You should not call the paintEvent method directly, this should be handled by Qt because in addition to what you want the GUI needs to repaint it on other occasions like when the widget is resized, moved, etc. the event that receives paintEvent is a QPaintEvent returns a rectangle where it is required to repaint, this is to optimize the redrawing, sometimes simple as in this case it is not necessary to use it.

    In the paintEvent method you must draw the line when it is not null, so what you should do in the slot that connects to the clicked signal, is to replace that null line with a valid one, and force paintEvent to be called using the update() method that notifies the GUI that it needs to be repainted.

    import sys
    from PyQt5.QtWidgets import QMainWindow,QPushButton, QApplication
    from PyQt5.QtCore import QSize, Qt, QLine, QPoint
    from PyQt5.QtGui import QPainter, QPen
    
    class MainWindow(QMainWindow):
        def __init__(self):
            QMainWindow.__init__(self)
    
            self.setMinimumSize(QSize(300, 300)) 
    
            pybutton = QPushButton('button', self)
            pybutton.clicked.connect(self.draw_line)
            pybutton.resize(100,100)
            pybutton.move(100, 100) 
            self.line = QLine()
    
        def draw_line(self):
            button = self.sender()
            self.line = QLine(QPoint(), button.pos())
            self.update()
    
        def paintEvent(self,event):
            QMainWindow.paintEvent(self, event)
            if not self.line.isNull():
                painter = QPainter(self)
                pen = QPen(Qt.red, 3)
                painter.setPen(pen)
                painter.drawLine(self.line)
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        mainWin = MainWindow()
        mainWin.show()
        sys.exit(app.exec_())