2

I am having trouble maintaining previously drawn lines after I draw a new line. Right now if I click one button it will draw a line but once I click the second button a new line is drawn and the initial one is removed. I would like that both remain.

enter image description here

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(0, 0) 

        pybutton2 = QPushButton('button2', self)
        pybutton2.clicked.connect(self.draw_line)
        pybutton2.resize(100,100)
        pybutton2.move(200, 0) 
        self.line = QLine()

    def draw_line(self):
        button = self.sender()
        x = int(button.x()) + int(button.width())/2
        y = int(button.y())+100
        self.line = QLine(x, y, x, y+100)
        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_())
riyadude
  • 337
  • 6
  • 18

1 Answers1

4

Short solution:

Store the QLine in a list and redraw:

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(0, 0) 

        pybutton2 = QPushButton('button2', self)
        pybutton2.clicked.connect(self.draw_line)
        pybutton2.resize(100,100)
        pybutton2.move(200, 0) 
        self.lines = []

    def draw_line(self):
        button = self.sender()
        r = button.geometry()
        p1 = QPoint(r.left() + r.width()/2, r.height())
        p2 = p1+QPoint(0, 100)
        line = QLine(p1, p2)
        if line not in self.lines:
            self.lines.append(line)
            self.update()

    def paintEvent(self,event):
        QMainWindow.paintEvent(self, event)
        painter = QPainter(self)
        pen = QPen(Qt.red, 3)
        painter.setPen(pen)
        for line in self.lines:
            painter.drawLine(line)

Long solution:

These kinds of questions have been asked countless times so I'm going to take the time to expand and give a general perspective of the problem so that I do not answer this type of question every time, so this question It will be improved and updated.

paintEvent() is a method that handles Qt to perform the repainting of the GUI, this method redraws everything, therefore the drawing does not save memory, so you must store the instructions and make the drawing with those instructions.

The paintEvent() method I recommend using to create custom widgets, not to make a GUI that performs the painting task as a main function, for this Qt offers class QGraphicsView, QGraphicsScene and QGraphicsItems.


The task of redrawing using the instructions of QPainter as drawLine(), fillRect(), etc consume resources, if you want to make a more efficient implementation it is appropriate to create a QPixmap that you must update whenever necessary, and repaint in the paintEvent() using the mentioned QPixmap:

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(0, 0) 

        pybutton2 = QPushButton('button2', self)
        pybutton2.clicked.connect(self.draw_line)
        pybutton2.resize(100,100)
        pybutton2.move(200, 0)
        self.pixmap = QPixmap(self.size())
        self.pixmap.fill(Qt.transparent)

    def draw_line(self):
        button = self.sender()
        r = button.geometry()
        p1 = QPoint(r.left() + r.width()/2, r.height())
        p2 = p1+QPoint(0, 100)
        line = QLine(p1, p2)

        p = QPainter(self.pixmap)
        pen = QPen(Qt.red, 3)
        p.setPen(pen)
        p.drawLine(line)
        p.end()

        self.update()

    def paintEvent(self,event):
        QMainWindow.paintEvent(self, event)
        painter = QPainter(self)
        painter.drawPixmap(QPoint(), self.pixmap)

    def resizeEvent(self, event):
        if self.width() > self.pixmap.width() or self.height() > self.pixmap.height():
            pixmap = QPixmap(self.size())
            pixmap.fill(Qt.transparent)
            p = QPainter(pixmap)
            p.drawPixmap(QPoint(), self.pixmap)
            self.pixmap = pixmap
        QMainWindow.resizeEvent(self, event)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241