In this Python GUI article, we will learn How to Create Paint Application in PyQt5 that
allows us to draw lines on a canvas with different brush sizes and colors. We will also learn
how to use the QImage class and the mouse events in order to construct the paint program.
also you can watch the video tutorial for this article at the end.
Also you can check more Python GUI articles in the below links
1: Kivy GUI Development Tutorials
2: Python TKinter GUI Development
5: PyQt5 GUI Development Course
So now this is the complete code for Python GUI How to Create Paint Application in PyQt5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu, QMenuBar, QAction, QFileDialog from PyQt5.QtGui import QIcon, QImage, QPainter, QPen, QBrush from PyQt5.QtCore import Qt, QPoint import sys class Window(QMainWindow): def __init__(self): super().__init__() title = "Paint Application" top = 400 left = 400 width = 800 height = 600 icon = "icons/pain.png" self.setWindowTitle(title) self.setGeometry(top, left, width, height) self.setWindowIcon(QIcon(icon)) self.image = QImage(self.size(), QImage.Format_RGB32) self.image.fill(Qt.white) self.drawing = False self.brushSize = 2 self.brushColor = Qt.black self.lastPoint = QPoint() mainMenu = self.menuBar() fileMenu = mainMenu.addMenu("File") brushSize = mainMenu.addMenu("Brush Size") brushColor = mainMenu.addMenu("Brush Color") saveAction = QAction(QIcon("icons/save.png"), "Save",self) saveAction.setShortcut("Ctrl+S") fileMenu.addAction(saveAction) saveAction.triggered.connect(self.save) clearAction = QAction(QIcon("icons/clear.png"), "Clear", self) clearAction.setShortcut("Ctrl+C") fileMenu.addAction(clearAction) clearAction.triggered.connect(self.clear) threepxAction = QAction( QIcon("icons/threepx.png"), "3px", self) brushSize.addAction(threepxAction) threepxAction.triggered.connect(self.threePixel) fivepxAction = QAction(QIcon("icons/fivepx.png"), "5px", self) brushSize.addAction(fivepxAction) fivepxAction.triggered.connect(self.fivePixel) sevenpxAction = QAction(QIcon("icons/sevenpx.png"),"7px", self) brushSize.addAction(sevenpxAction) sevenpxAction.triggered.connect(self.sevenPixel) ninepxAction = QAction(QIcon("icons/ninepx.png"), "9px", self) brushSize.addAction(ninepxAction) ninepxAction.triggered.connect(self.ninePixel) blackAction = QAction(QIcon("icons/black.png"), "Black", self) blackAction.setShortcut("Ctrl+B") brushColor.addAction(blackAction) blackAction.triggered.connect(self.blackColor) whitekAction = QAction(QIcon("icons/white.png"), "White", self) whitekAction.setShortcut("Ctrl+W") brushColor.addAction(whitekAction) whitekAction.triggered.connect(self.whiteColor) redAction = QAction(QIcon("icons/red.png"), "Red", self) redAction.setShortcut("Ctrl+R") brushColor.addAction(redAction) redAction.triggered.connect(self.redColor) greenAction = QAction(QIcon("icons/green.png"), "Green", self) greenAction.setShortcut("Ctrl+G") brushColor.addAction(greenAction) greenAction.triggered.connect(self.greenColor) yellowAction = QAction(QIcon("icons/yellow.png"), "Yellow", self) yellowAction.setShortcut("Ctrl+Y") brushColor.addAction(yellowAction) yellowAction.triggered.connect(self.yellowColor) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = True self.lastPoint = event.pos() #print(self.lastPoint) def mouseMoveEvent(self, event): if(event.buttons() & Qt.LeftButton) & self.drawing: painter = QPainter(self.image) painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(self.lastPoint, event.pos()) self.lastPoint = event.pos() self.update() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = False def paintEvent(self, event): canvasPainter = QPainter(self) canvasPainter.drawImage(self.rect(),self.image, self.image.rect() ) def save(self): filePath, _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*) ") if filePath == "": return self.image.save(filePath) def clear(self): self.image.fill(Qt.white) self.update() def threePixel(self): self.brushSize = 3 def fivePixel(self): self.brushSize = 5 def sevenPixel(self): self.brushSize = 7 def ninePixel(self): self.brushSize = 9 def blackColor(self): self.brushColor = Qt.black def whiteColor(self): self.brushColor = Qt.white def redColor(self): self.brushColor = Qt.red def greenColor(self): self.brushColor = Qt.green def yellowColor(self): self.brushColor = Qt.yellow if __name__ == "__main__": app = QApplication(sys.argv) window = Window() window.show() app.exec() |
So now at the top these are the important classes that we are going to use in this simple project.
1 2 3 4 |
from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu, QMenuBar, QAction, QFileDialog from PyQt5.QtGui import QIcon, QImage, QPainter, QPen, QBrush from PyQt5.QtCore import Qt, QPoint import sys |
And this is our main window class that inherits from QMainWindow, in that class we are going to add the window title , window geometry and minimum width and height for the window. also you can check Python Object Oriented Programming Articles in the link. Python Object Oreinted Programming. also we are going to create our Menu and Menu Items in this class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
class Window(QMainWindow): def __init__(self): super().__init__() title = "Paint Application" top = 400 left = 400 width = 800 height = 600 icon = "icons/pain.png" self.setWindowTitle(title) self.setGeometry(top, left, width, height) self.setWindowIcon(QIcon(icon)) self.image = QImage(self.size(), QImage.Format_RGB32) self.image.fill(Qt.white) self.drawing = False self.brushSize = 2 self.brushColor = Qt.black self.lastPoint = QPoint() mainMenu = self.menuBar() fileMenu = mainMenu.addMenu("File") brushSize = mainMenu.addMenu("Brush Size") brushColor = mainMenu.addMenu("Brush Color") saveAction = QAction(QIcon("icons/save.png"), "Save",self) saveAction.setShortcut("Ctrl+S") fileMenu.addAction(saveAction) saveAction.triggered.connect(self.save) clearAction = QAction(QIcon("icons/clear.png"), "Clear", self) clearAction.setShortcut("Ctrl+C") fileMenu.addAction(clearAction) clearAction.triggered.connect(self.clear) threepxAction = QAction( QIcon("icons/threepx.png"), "3px", self) brushSize.addAction(threepxAction) threepxAction.triggered.connect(self.threePixel) fivepxAction = QAction(QIcon("icons/fivepx.png"), "5px", self) brushSize.addAction(fivepxAction) fivepxAction.triggered.connect(self.fivePixel) sevenpxAction = QAction(QIcon("icons/sevenpx.png"),"7px", self) brushSize.addAction(sevenpxAction) sevenpxAction.triggered.connect(self.sevenPixel) ninepxAction = QAction(QIcon("icons/ninepx.png"), "9px", self) brushSize.addAction(ninepxAction) ninepxAction.triggered.connect(self.ninePixel) blackAction = QAction(QIcon("icons/black.png"), "Black", self) blackAction.setShortcut("Ctrl+B") brushColor.addAction(blackAction) blackAction.triggered.connect(self.blackColor) whitekAction = QAction(QIcon("icons/white.png"), "White", self) whitekAction.setShortcut("Ctrl+W") brushColor.addAction(whitekAction) whitekAction.triggered.connect(self.whiteColor) redAction = QAction(QIcon("icons/red.png"), "Red", self) redAction.setShortcut("Ctrl+R") brushColor.addAction(redAction) redAction.triggered.connect(self.redColor) greenAction = QAction(QIcon("icons/green.png"), "Green", self) greenAction.setShortcut("Ctrl+G") brushColor.addAction(greenAction) greenAction.triggered.connect(self.greenColor) yellowAction = QAction(QIcon("icons/yellow.png"), "Yellow", self) yellowAction.setShortcut("Ctrl+Y") brushColor.addAction(yellowAction) yellowAction.triggered.connect(self.yellowColor) |
OK now in this method we are going to tell PyQt5 what to do when the left mouse button is
pressed .
1 2 3 4 5 |
def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = True self.lastPoint = event.pos() #print(self.lastPoint) |
Then, we will create the mouseMoveEvent() event and tell Qt what to do when the mouse is
moving. In this case, we want to draw the lines on the canvas if the left
1 2 3 4 5 6 7 |
def mouseMoveEvent(self, event): if(event.buttons() & Qt.LeftButton) & self.drawing: painter = QPainter(self.image) painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine(self.lastPoint, event.pos()) self.lastPoint = event.pos() self.update() |
After that, we will also construct the mouseReleaseEvent() event, which will be triggered
when the mouse button is released:
1 2 3 4 |
def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.drawing = False |
Once you’re done with that, we will proceed to the paintEvent() event.
1 2 3 |
def paintEvent(self, event): canvasPainter = QPainter(self) canvasPainter.drawImage(self.rect(),self.image, self.image.rect() ) |
Also these are the menu item for the application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
def save(self): filePath, _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*) ") if filePath == "": return self.image.save(filePath) def clear(self): self.image.fill(Qt.white) self.update() def threePixel(self): self.brushSize = 3 def fivePixel(self): self.brushSize = 5 def sevenPixel(self): self.brushSize = 7 def ninePixel(self): self.brushSize = 9 def blackColor(self): self.brushColor = Qt.black def whiteColor(self): self.brushColor = Qt.white def redColor(self): self.brushColor = Qt.red def greenColor(self): self.brushColor = Qt.green def yellowColor(self): self.brushColor = Qt.yellow |
How it Works
In this example, we have created a QImage widget when the program started. This widget acts as the canvas and it will follow the size of the window whenever the window gets resized. In order to draw something on the canvas, we will need to use the mouse events provided by PyQt5. These events will tell us the position of the cursor and we will be able to use this information to change the pixels on the canvas. We use a Boolean variable called drawing to let the program know whether it should start drawing when a mouse button is pressed. In this case, when the left mouse button is pressed, the variable drawing will be set to true. We also save the current cursor position to the lastPoint variable when the left mouse button is pressed, so that PyQt5 will know where it should start drawing. When the mouse moves, the mouseMoveEvent() event will be triggered by PyQt5. This is where we need to check whether the drawing variable is set to true. If it is, then QPainter can start drawing the lines onto the QImage widget based on the brush settings that we provide. The brush settings consist of the brush color as well as the brush size. These settings are being saved as variables and can be altered by selecting a different setting from the menu bar. Please remember to call the update() function when the user is drawing on the canvas. Otherwise, the canvas will remain empty even though we have changed the pixel information of the canvas.
So now run the complete code and this will be the result.
Also you can watch the complete video for this article
Subscribe and Get Free Video Courses & Articles in your Email