Adding widget to QMainWindow from context menu - python

I can add QWidget to QMainWindow and set its position to cursor position.
But every single time, I want to add new QWidget to QMainWindow. I don't maybe given codes add new QWidget but at canvas, I see just one QWidget. Here my codes:
from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu, QMenuBar, QAction, QFileDialog, QWidget, QLabel
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
self.objStr = "berkayy"
self.count = 0
# icon = "icons/pain.png"
self.setAcceptDrops(True)
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 rectangle(self, e, pos):
print(pos)
painter = QPainter(self)
painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
painter.setBrush(QBrush(Qt.green, Qt.DiagCrossPattern))
painter.drawRect(100, 15, 400, 200)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drawing = True
self.lastPoint = event.pos()
#print(self.lastPoint)
def contextMenuEvent(self, event):
contextMenu = QMenu(self)
newAct = contextMenu.addAction("New")
openAct = contextMenu.addAction("Open")
closeAct = contextMenu.addAction("Close")
action = contextMenu.exec_(self.mapToGlobal(event.pos()))
if action == closeAct:
self.close()
elif action == openAct:
self.berkay(event.pos())
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 berkay(self, pos):
wid = QWidget(self)
btn = QLabel(wid)
btn.setText("skjdf")
btn.setObjectName(self.objStr + str(self.count) )
btn.move(pos)
self.setCentralWidget(wid)
self.count += 1
# btn.setDragEnabled(True)
print(btn.objectName())
# self.show()
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()
I want to create new QWidget when user clicked context menu item every single time.

A QMainWindow can have only one central widget. So, adding the new QLabel as central widget will remove the previous. That's why you can see only the last label.
Create a single widget and define it as central widget. Then, add the label as child of the central widget:
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.area = QWidget(self)
self.setCentralWidget(self.area)
def berkay(self, pos):
btn = QLabel("BOOH", self.area)
btn.move(self.area.mapFromParent(pos)) # Map the pos in the coord system of self.area
btn.show()

First, for every single widget, store x and y value in a list. After that, adding new and current widgets to window central widget.
Edit
We do not need store widget x and y, anymore.
Thank you Romha for optimisation suggestion.
import sys
from PyQt5.QtWidgets import QMainWindow, QMenu, QApplication, QWidget, QPushButton, qApp
from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import Qt
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.area = QWidget(self)
self.setCentralWidget(self.area)
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Context menu')
self.setStyleSheet("QMainWindow {background: 'white';}")
self.show()
def contextMenuEvent(self, event):
cmenu = QMenu(self)
addBtnAct = cmenu.addAction("Add Button")
quitAct = cmenu.addAction("Quit")
action = cmenu.exec_(self.mapToGlobal(event.pos()))
if action == quitAct:
qApp.quit()
elif action == addBtnAct:
self.addLabel(event.pos())
def addLabel(self, pos):
btn = QLabel("BOOH", self.area)
btn.move(self.area.mapFromParent(pos)) # Map the pos in the coord system of self.area
btn.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Related

PyQt/PySide, QGraphicsView, Draw Line (Pipe) with mouse with ports on each side to attach other elements, (pipeline network)

I am trying to use PyQt (PySide6) to draw a Pipeline network like in this example gif
[1]: https://i.stack.imgur.com/uQsRg.gif
I know i have to use the QGraphicsView class with QGraphicsScene to draw elements in the screen.
What i dont know how to do is how to handle all the mouse click and move events as well as having Ports on each side of the pipe to be able to attach other pipes/elements to pipes.
i also have to be able to double click on elements to configure them.
Is there any good documentation where i can learn how to achieve this ? or any tutorials ?
Thank you.
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
)
from PySide6.QtGui import QAction
from PySide6.QtCore import Qt
class GraphicsScene(QGraphicsScene):
def __init__(self):
super().__init__()
def mousePressEvent(self, event) -> None:
if event.button() == Qt.LeftButton:
print("Left button pressed")
pos_x = event.scenePos().x()
pos_y = event.scenePos().y()
print(f"Position: {pos_x}, {pos_y}")
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec())
EDIT/UPDATE :
Here's a solution. Thanks for the help
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
QGraphicsEllipseItem,
)
from PySide6.QtGui import QPainterPath, QTransform, QPen, QBrush, QColor, QPainter
from PySide6.QtCore import Qt
PORT_PEN_COLOR = "#000000"
PORT_BRUSH_COLOR = "#ebebeb"
EDGE_PEN_COLOR = "#474747"
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(0, 0, 800, 600)
self.setCentralWidget(GraphicsView())
self.show()
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.setMouseTracking(True)
self.setScene(GraphicsScene())
self.setRenderHint(QPainter.RenderHint.Antialiasing)
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(-10000, -10000, 20000, 20000)
self._port_pen = QPen(QColor(PORT_PEN_COLOR))
self._port_brush = QBrush(QColor(PORT_BRUSH_COLOR))
self._edge_pen = QPen(QColor(EDGE_PEN_COLOR))
self._edge_pen.setWidth(4)
def mousePressEvent(self, event):
clicked_item = self.itemAt(event.scenePos(), QTransform())
if event.buttons() == Qt.MouseButton.LeftButton:
if clicked_item is not None:
# edge item
pos = clicked_item.scenePos()
pos.setX(pos.x() + 6)
pos.setY(pos.y() + 6)
self.edge = self.addPath(QPainterPath())
self.edge.setPen(self._edge_pen)
self.start_pos = pos
self.end_pos = self.start_pos
self.update_path()
else:
x = event.scenePos().x()
y = event.scenePos().y()
# port item
start_port = Ellipse()
start_port.setPos(x - 6, y - 6)
start_port.setPen(self._port_pen)
start_port.setBrush(self._port_brush)
start_port.setZValue(10000.0)
self.addItem(start_port)
# edge item
self.edge = self.addPath(QPainterPath())
self.edge.setPen(self._edge_pen)
self.start_pos = event.scenePos()
self.end_pos = self.start_pos
self.update_path()
def mouseMoveEvent(self, event):
if event.buttons() == Qt.MouseButton.LeftButton:
print(f"moving, x : {event.scenePos().x()}, y : {event.scenePos().y()}")
self.end_pos = event.scenePos()
try:
self.update_path()
except AttributeError:
pass
def mouseReleaseEvent(self, event) -> None:
released_item = self.itemAt(event.scenePos(), QTransform())
if event.button() == Qt.MouseButton.LeftButton:
if released_item is not None and released_item.type() != 2:
self.end_pos = released_item.scenePos()
self.end_pos.setX(self.end_pos.x() + 6)
self.end_pos.setY(self.end_pos.y() + 6)
if not self.start_pos.isNull() and not self.end_pos.isNull():
path = QPainterPath()
path.moveTo(self.start_pos.x() - 1, self.start_pos.y() - 1)
path.lineTo(self.end_pos)
self.edge.setPath(path)
else:
x = event.scenePos().x() + 1
y = event.scenePos().y() + 1
end_port = QGraphicsEllipseItem(0, 0, 10, 10)
end_port.setPos(x - 6, y - 6)
end_port.setPen(self._port_pen)
end_port.setBrush(self._port_brush)
end_port.setZValue(10000.0)
self.addItem(end_port)
def update_path(self):
if not self.start_pos.isNull() and not self.end_pos.isNull():
path = QPainterPath()
path.moveTo(self.start_pos.x() - 1, self.start_pos.y() - 1)
path.lineTo(self.end_pos)
self.edge.setPath(path)
class Ellipse(QGraphicsEllipseItem):
def __init__(self):
super().__init__()
self.setRect(0, 0, 10, 10)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec())
It may need to write all code on your own - check button, check if there is object in small distance, remeber this object, draw this object as selected (with some extra color), update object position when move mouse, redraw all objects, etc. So it may need some list to keep all objects, search if mouse is near of one of object on list, update objects on list, use list to redraw objects on screen (in new positions)
Minimal code which use left click to add item (rectangle), and right click to delete it.
EDIT:
I found out that scene has function .items() to access all items and I don't have to use own list objects for this.
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
QGraphicsRectItem,
)
from PySide6.QtGui import QAction
from PySide6.QtCore import Qt
#objects = []
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(-100, -100, 200, 200)
def mousePressEvent(self, event) -> None:
if event.button() == Qt.LeftButton:
#print("Left button pressed")
x = event.scenePos().x()
y = event.scenePos().y()
#print(f"Position: {x}, {y}")
rectitem = QGraphicsRectItem(0, 0, 10, 10)
# set center of rectangle in mouse position
rectitem.setPos(x-5, y-5)
self.addItem(rectitem)
#objects.append(rectitem)
elif event.button() == Qt.RightButton:
#print("Right button pressed")
x = event.scenePos().x()
y = event.scenePos().y()
#print(f"Position: {x}, {y}")
#for item in objects:
for item in self.items():
pos = item.pos()
if abs(x-pos.x()) < 10 and abs(y-pos.y()) < 10:
print('selected:', item)
self.removeItem(item)
#objects.remove(item)
break
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
EDIT:
Example which use
left click to add rectangle (white background, black border)
first right click to select rectangle (red background)
second right click to put selected rectangle in new place (white background, black border)
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
QGraphicsRectItem,
)
from PySide6.QtGui import QAction
from PySide6.QtCore import Qt
from PySide6.QtGui import QColor, QPen, QBrush
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(-100, -100, 200, 200)
self.selected = []
def mousePressEvent(self, event) -> None:
if event.button() == Qt.LeftButton:
#print("Left button pressed")
x = event.scenePos().x()
y = event.scenePos().y()
#print(f"Position: {x}, {y}")
rectitem = QGraphicsRectItem(0, 0, 10, 10)
# set center of rectangle in mouse position
rectitem.setPos(x-5, y-5)
rectitem.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
rectitem.setBrush(QBrush(QColor(255, 255, 255, 255)))
self.addItem(rectitem)
elif event.button() == Qt.RightButton:
#print("Right button pressed")
x = event.scenePos().x()
y = event.scenePos().y()
#print(f"Position: {x}, {y}")
if self.selected:
print('moved')
for item in self.selected:
item.setPos(x-5, y-5)
item.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
item.setBrush(QBrush(QColor(255, 255, 255, 255)))
self.selected.clear()
else:
for item in self.items():
pos = item.pos()
if abs(x-pos.x()) < 10 and abs(y-pos.y()) < 10:
print('selected:', item)
self.selected.append(item)
item.setPen(QPen(QColor(255, 0, 0), 1.0, Qt.SolidLine))
item.setBrush(QBrush(QColor(255, 0, 0, 255)))
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
EDIT:
Version which uses mouseMoveEvent and mouseReleaseEvent to drag rect (keeping right click)
Based on code in answer to pyqt add rectangle in Qgraphicsscene
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
QGraphicsRectItem,
QGraphicsItem,
)
from PySide6.QtGui import QAction
from PySide6.QtCore import Qt
from PySide6.QtGui import QColor, QPen, QBrush, QTransform
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(-100, -100, 200, 200)
self.selected = None
self.selected_offset_x = 0
self.selected_offset_y = 0
def mousePressEvent(self, event) -> None:
if event.button() == Qt.LeftButton:
x = event.scenePos().x()
y = event.scenePos().y()
rectitem = QGraphicsRectItem(0, 0, 10, 10)
rectitem.setPos(x-5, y-5)
rectitem.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
rectitem.setBrush(QBrush(QColor(255, 255, 255, 255)))
#rectitem.setFlag(QGraphicsItem.ItemIsMovable, True)
self.addItem(rectitem)
elif event.button() == Qt.RightButton:
x = event.scenePos().x()
y = event.scenePos().y()
if not self.selected:
item = self.itemAt(event.scenePos(), QTransform())
#print(item)
if item:
print('selected:', item)
self.selected = item
self.selected.setBrush(QBrush(QColor(255, 0, 0, 255)))
self.selected_offset_x = x - item.pos().x()
self.selected_offset_y = y - item.pos().y()
#self.selected_offset_x = 5 # rect_width/2 # to keep center of rect
#self.selected_offset_y = 5 # rect_height/2 # to keep center of rect
#super().mousePressEvent(event)
def mouseMoveEvent(self, event):
#print('move:', event.button())
#print('move:', event.buttons())
if event.buttons() == Qt.RightButton: # `buttons()` instead of `button()`
if self.selected:
print('moved')
x = event.scenePos().x()
y = event.scenePos().y()
self.selected.setPos(x-self.selected_offset_x, y-self.selected_offset_y)
#super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
#print('release:', event.button())
#print('release:', event.buttons())
if event.button() == Qt.RightButton:
if self.selected:
print('released')
self.selected.setBrush(QBrush(QColor(255, 255, 255, 255)))
self.selected = None
#super().mouseReleaseEvent(event)
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
I was thinking about changing color when mouse hover item (using mouseMoveEvent) but at this moment I don't have it.
I found this code on here:
https://python.tutorialink.com/drawing-straight-line-between-two-points-using-qpainterpath/
which lets you create a line with mousePress and move events
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
)
from PySide6.QtGui import QAction, QPainterPath
from PySide6.QtCore import Qt, QPointF
class GraphicsScene(QGraphicsScene):
def __init__(self, *args, **kwargs):
super(GraphicsScene, self).__init__(*args, **kwargs)
self.path_item = self.addPath(QPainterPath())
self.start_point = QPointF()
self.end_point = QPointF()
def mousePressEvent(self, event):
self.start_point = event.scenePos()
self.end_point = self.start_point
self.update_path()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.end_point = event.scenePos()
self.update_path()
super(GraphicsScene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.end_point = event.scenePos()
self.update_path()
super(GraphicsScene, self).mouseReleaseEvent(event)
def update_path(self):
if not self.start_point.isNull() and not self.end_point.isNull():
path = QPainterPath()
path.moveTo(self.start_point)
path.lineTo(self.end_point)
self.path_item.setPath(path)
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
EDIT :
I combined it with Furas's code and got this
import sys
from PySide6.QtWidgets import (
QApplication,
QMainWindow,
QGraphicsView,
QGraphicsScene,
QGraphicsRectItem,
)
from PySide6.QtGui import QAction, QPainterPath
from PySide6.QtCore import Qt
from PySide6.QtGui import QColor, QPen, QBrush, QTransform
class GraphicsScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setSceneRect(-100, -100, 200, 200)
self.selected = None
self.selected_offset_x = 0
self.selected_offset_y = 0
def mousePressEvent(self, event) -> None:
if event.button() == Qt.LeftButton:
x = event.scenePos().x()
y = event.scenePos().y()
# rectangle
rectitem = QGraphicsRectItem(0, 0, 10, 10)
rectitem.setPos(x - 5, y - 5)
rectitem.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
rectitem.setBrush(QBrush(QColor(255, 255, 255, 255)))
# rectitem.setFlag(QGraphicsItem.ItemIsMovable, True)
# Line
self.path_item = self.addPath(QPainterPath())
self.start_point = event.scenePos()
self.end_point = self.start_point
self.update_path()
self.addItem(rectitem)
elif event.button() == Qt.RightButton:
x = event.scenePos().x()
y = event.scenePos().y()
if not self.selected:
item = self.itemAt(event.scenePos(), QTransform())
# print(item)
if item:
print("selected:", item)
self.selected = item
self.selected.setBrush(QBrush(QColor(255, 0, 0, 255)))
self.selected_offset_x = x - item.pos().x()
self.selected_offset_y = y - item.pos().y()
# self.selected_offset_x = 5 # rect_width/2 # to keep center of rect
# self.selected_offset_y = 5 # rect_height/2 # to keep center of rect
# super().mousePressEvent(event)
def mouseMoveEvent(self, event):
# print('move:', event.button())
# print('move:', event.buttons())
if event.buttons() == Qt.RightButton: # `buttons()` instead of `button()`
if self.selected:
print("moved")
x = event.scenePos().x()
y = event.scenePos().y()
self.selected.setPos(
x - self.selected_offset_x, y - self.selected_offset_y
)
elif event.buttons() == Qt.LeftButton:
self.end_point = event.scenePos()
self.update_path()
# super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
# print('release:', event.button())
# print('release:', event.buttons())
if event.button() == Qt.RightButton:
if self.selected:
print("released")
self.selected.setBrush(QBrush(QColor(255, 255, 255, 255)))
self.selected = None
elif event.button() == Qt.LeftButton:
self.end_point = event.scenePos()
x = event.scenePos().x()
y = event.scenePos().y()
rectitem = QGraphicsRectItem(0, 0, 10, 10)
rectitem.setPos(x - 5, y - 5)
rectitem.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
rectitem.setBrush(QBrush(QColor(255, 255, 255, 255)))
self.addItem(rectitem)
self.update_path()
# super().mouseReleaseEvent(event)
def update_path(self):
if not self.start_point.isNull() and not self.end_point.isNull():
path = QPainterPath()
path.moveTo(self.start_point)
path.lineTo(self.end_point)
self.path_item.setPath(path)
class GraphicsView(QGraphicsView):
def __init__(self):
super().__init__()
self.scene = self.setScene(GraphicsScene())
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
"""Set up the application's GUI."""
self.setMinimumSize(450, 350)
self.setWindowTitle("Main Window")
self.setup_main_window()
self.create_actions()
self.create_menu()
self.show()
def setup_main_window(self):
"""Create and arrange widgets in the main window."""
self.setCentralWidget(GraphicsView())
def create_actions(self):
"""Create the application's menu actions."""
# Create actions for File menu
self.quit_act = QAction("&Quit")
self.quit_act.setShortcut("Ctrl+Q")
self.quit_act.triggered.connect(self.close)
def create_menu(self):
"""Create the application's menu bar."""
self.menuBar().setNativeMenuBar(False)
# Create file menu and add actions
file_menu = self.menuBar().addMenu("File")
file_menu.addAction(self.quit_act)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())

PyQt5 Custom Title Bar Doesn't Show

I am trying to make my first program. I'm hoping for custom dark mode design, and that requires me to make a custom title bar.
I copied the code for the title bar from someone else, it worked perfectly - custom movable window.
I have carefully merged it with my previous code, though title bar doesn't appear.
Now my guess is I have to call it at the end of my code, but it ends up with errors, as I'm not sure how to properly call it.
Note: removing the QtCore.Qt.FramelessWindowHint part is NOT the answer, as it just brings back the stock Win title bar, that's supposed to be hidden and replaced by dark title bar.
Part of code copied from: https://stackoverflow.com/a/44249552/12221725
Image:
import sys
from PyQt5 import QtGui, QtCore
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QTextEdit
#fCol = "#e0e0e0"
#bCol = "#212121"
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.layout = QHBoxLayout()
self.textArea = QTextEdit("Lorem ipsum...")
self.layout.addWidget(self.textArea)
self.textArea.setStyleSheet("QTextEdit {color:white;background-color:#212121;border-radius:+16px;}")
self.sans = QFont("Segoe UI",20)
self.textArea.setFont(self.sans)
self.btnLayout = QVBoxLayout()
self.btnLayout.addWidget(QPushButton("Open"))
self.btnLayout.addWidget(QPushButton("Setup"))
self.btnLayout.addWidget(QPushButton("Find"))
self.setStyleSheet("QPushButton {max-width:200px;color:#4fc3f7;background-color:#424242;border:2px solid #4fc3f7;border-radius:16px;font-size:35px;font-weight:bold;}" + "QPushButton:hover {color:#212121;background-color:#4fc3f7;}" + "QPushButton:pressed {color:white;background-color:#212121;border-color:white;}")
self.status = QTextEdit()
self.status.insertPlainText("Successfully loaded" + "\nOpen a file...")
self.status.setReadOnly(1)
self.status.setStyleSheet("QTextEdit {color:white;background-color:#212121;border-radius:+16px;font-size:14px;max-width:200px;}")
self.btnLayout.addWidget(self.status)
self.layout.addLayout(self.btnLayout)
self.setLayout(self.layout)
#self.setFixedSize(650, 320)
self.setFixedSize(800, 400)
self.setWindowTitle("Py Program")
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)# | QtCore.Qt.WindowStaysOnTopHint)
#self.layout.setContentsMargins(0,0,0,0)
#self.layout.addStretch(-1)
#self.pressing = False
print("MainWindow Loaded")
#self.show()
class MyBar(QWidget):
def __init__(self, parent):
super(MyBar, self).__init__()
self.parent = parent
print(self.parent.width())
self.layout = QHBoxLayout()
self.layout.setContentsMargins(0,0,0,0)
self.title = QLabel("My Own Bar")
btn_size = 35
self.btn_close = QPushButton("x")
self.btn_close.clicked.connect(self.btn_close_clicked)
self.btn_close.setFixedSize(btn_size,btn_size)
self.btn_close.setStyleSheet("background-color: red;")
self.btn_min = QPushButton("-")
self.btn_min.clicked.connect(self.btn_min_clicked)
self.btn_min.setFixedSize(btn_size, btn_size)
self.btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
self.title.setFixedHeight(35)
self.title.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.title)
self.layout.addWidget(self.btn_min)
self.layout.addWidget(self.btn_max)
self.layout.addWidget(self.btn_close)
self.title.setStyleSheet("background-color: black;color: white;")
self.setLayout(self.layout)
self.start = QPoint(0, 0)
self.pressing = False
print("MyBar Loaded")
def resizeEvent(self, QResizeEvent):
super(MyBar, self).resizeEvent(QResizeEvent)
self.title.setFixedWidth(self.parent.width())
def mousePressEvent(self, event):
self.start = self.mapToGlobal(event.pos())
self.pressing = True
def mouseMoveEvent(self, event):
if self.pressing:
self.end = self.mapToGlobal(event.pos())
self.movement = self.end-self.start
self.parent.setGeometry(self.mapToGlobal(self.movement).x(),
self.mapToGlobal(self.movement).y(),
self.parent.width(),
self.parent.height())
self.start = self.end
def mouseReleaseEvent(self, QMouseEvent):
self.pressing = False
def btn_close_clicked(self):
self.parent.close()
def btn_max_clicked(self):
self.parent.showMaximized()
def btn_min_clicked(self):
self.parent.showMinimized()
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon("icon.png"))
app.setStyleSheet("QWidget {background-color:#424242;border-radius:12px;}")
app.setFont(QFont("Consolas"))
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
The problem is that you have not created or placed a Bar() inside the window. You must also restructure your layout so that the titlebar is displayed at the top and your content at the bottom using a QVBoxLayout.
On the other hand I have improved the original titleBar so that it is not necessary to set the parent directly but instead use the window():
import sys
from PyQt5.QtGui import QFont, QIcon
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QTextEdit, QLabel
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowFlags(Qt.FramelessWindowHint)
hlayout = QHBoxLayout()
self.textArea = QTextEdit("Lorem ipsum...")
hlayout.addWidget(self.textArea)
self.textArea.setStyleSheet("QTextEdit {color:white;background-color:#212121;border-radius:+16px;}")
self.sans = QFont("Segoe UI",20)
self.textArea.setFont(self.sans)
self.btnLayout = QVBoxLayout()
self.btnLayout.addWidget(QPushButton("Open"))
self.btnLayout.addWidget(QPushButton("Setup"))
self.btnLayout.addWidget(QPushButton("Find"))
self.setStyleSheet("QPushButton {max-width:200px;color:#4fc3f7;background-color:#424242;border:2px solid #4fc3f7;border-radius:16px;font-size:35px;font-weight:bold;}" + "QPushButton:hover {color:#212121;background-color:#4fc3f7;}" + "QPushButton:pressed {color:white;background-color:#212121;border-color:white;}")
self.status = QTextEdit()
self.status.insertPlainText("Successfully loaded" + "\nOpen a file...")
self.status.setReadOnly(1)
self.status.setStyleSheet("QTextEdit {color:white;background-color:#212121;border-radius:+16px;font-size:14px;max-width:200px;}")
self.btnLayout.addWidget(self.status)
self.setFixedSize(800, 400)
self.setWindowTitle("Py app")
hlayout.addLayout(self.btnLayout)
custom_titlebar = TitleBar()
lay = QVBoxLayout(self)
lay.addWidget(custom_titlebar)
lay.addLayout(hlayout)
class TitleBar(QWidget):
def __init__(self, parent=None):
super(TitleBar, self).__init__(parent)
self.title = QLabel("My Own Bar")
btn_size = 35
self.btn_close = QPushButton("x")
self.btn_close.clicked.connect(self.btn_close_clicked)
self.btn_close.setFixedSize(btn_size,btn_size)
self.btn_close.setStyleSheet("background-color: red;")
self.btn_min = QPushButton("-")
self.btn_min.clicked.connect(self.btn_min_clicked)
self.btn_min.setFixedSize(btn_size, btn_size)
self.btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
self.title.setFixedHeight(35)
self.title.setAlignment(Qt.AlignCenter)
self.title.setStyleSheet("background-color: black;color: white;")
lay = QHBoxLayout(self)
lay.setContentsMargins(0,0,0,0)
lay.addWidget(self.title)
lay.addWidget(self.btn_min)
lay.addWidget(self.btn_max)
lay.addWidget(self.btn_close)
self.pressing = False
self.dragPosition = QPoint()
def resizeEvent(self, QResizeEvent):
super(TitleBar, self).resizeEvent(QResizeEvent)
self.title.setFixedWidth(self.window().width())
def mousePressEvent(self, event):
self.start = event.globalPos()
self.pressing = True
def mouseMoveEvent(self, event):
if self.pressing:
self.end = event.globalPos()
delta = self.end - self.start
self.window().move(self.window().pos() + delta)
self.start = self.end
def mouseReleaseEvent(self, QMouseEvent):
self.pressing = False
def btn_close_clicked(self):
self.window().close()
def btn_max_clicked(self):
self.window().showMaximized()
def btn_min_clicked(self):
self.window().showMinimized()
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("icon.png"))
app.setStyleSheet("QWidget {background-color:#424242;border-radius:12px;}")
app.setFont(QFont("Consolas"))
mw = MainWindow()
mw.show()
sys.exit(app.exec_())

How to draw line with brush on image with PyQt5

I want to draw a line (or paint) on an image that I already opened. I can open the image, but I can't draw on the image. But if I don't open any image, I can draw anything I want on blank space.
So, How can I draw with a brush on an image ? For now eraser or etc. It's not important. I just want to do something with a brush on an image, which image I already open in my computer.
I didn't get any error or something. So I can't search specifically.
Here is my code;
from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu, QMenuBar, QAction, QFileDialog, QLabel
from PyQt5.QtGui import QIcon, QImage, QPainter, QPen, QBrush, QPixmap
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")
openAction = QAction('Open Image', self)
openAction.triggered.connect(self.openImage)
fileMenu.addAction(openAction)
closeAction = QAction('Exit', self)
closeAction.triggered.connect(self.close)
fileMenu.addAction(closeAction)
self.label = QLabel()
self.setCentralWidget(self.label)
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 openImage(self):
imagePath, _ = QFileDialog.getOpenFileName()
pixmap = QPixmap(imagePath)
self.label.setPixmap(pixmap)
self.resize(pixmap.size())
self.adjustSize()
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()
Instead of constructing a QPixmap from the filepath, construct a QImage and assign it to the variable self.image. You won't have to change anything else as the paintEvent will draw the QImage object that pointed to by self.image.
def openImage(self):
imagePath, _ = QFileDialog.getOpenFileName()
self.image = QImage(imagePath)
self.resize(self.image.size())

points are drawn on main window not on the label in the GUI

i'm loading an image on a label supposed after that
a mouse click event that draws dots on the label but dots are drawn on the main window ( behind the label )
GUI Image
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
uic.loadUi('MainWindow.ui', self)
self.setFixedSize(self.size())
self.show()
self.points = QtGui.QPolygon()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def mousePressEvent(self, e):
self.points << e.pos()
self.update()
def paintEvent(self, ev):
qp = QtGui.QPainter(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing)
pen = QtGui.QPen(QtCore.Qt.red, 5)
brush = QtGui.QBrush(QtCore.Qt.red)
qp.setPen(pen)
qp.setBrush(brush)
for i in range(self.points.count()):
# qp.drawEllipse(self.points.point(i), 5, 5)
# or
qp.drawPoints(self.points)
def main():
app = QtWidgets.QApplication(sys.argv)
application = ApplicationWindow()
application.show()
sys.exit(app.exec_())
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = ApplicationWindow()
sys.exit(app.exec_())
main()
You are calling QPainter(self) so the paint device is the MainWindow. Instead call QPainter on the QPixmap. Here is an example.
class Template(QWidget):
def __init__(self):
super().__init__()
self.lbl = QLabel()
self.pix = QPixmap('photo.jpeg')
grid = QGridLayout(self)
grid.addWidget(self.lbl, 0, 0)
self.points = QPolygon()
def mousePressEvent(self, event):
self.points << QPoint(event.x() - self.lbl.x(), event.y() - self.lbl.y())
def paintEvent(self, event):
qp = QPainter(self.pix)
qp.setRenderHint(QPainter.Antialiasing)
pen = QPen(Qt.red, 5)
brush = QBrush(Qt.red)
qp.setPen(pen)
qp.setBrush(brush)
qp.drawPoints(self.points)
self.lbl.setPixmap(self.pix)
However a better way is to use QImage in a custom widget that will act as a canvas.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class Canvas(QWidget):
def __init__(self, photo, *args, **kwargs):
super().__init__(*args, **kwargs)
self.image = QImage(photo)
self.setFixedSize(self.image.width(), self.image.height())
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
qp = QPainter(self.image)
qp.setRenderHint(QPainter.Antialiasing)
qp.setPen(QPen(Qt.red, 5))
qp.setBrush(Qt.red)
qp.drawPoint(event.pos())
self.update()
def paintEvent(self, event):
qp = QPainter(self)
rect = event.rect()
qp.drawImage(rect, self.image, rect)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
w = QWidget()
self.setCentralWidget(w)
grid = QGridLayout(w)
grid.addWidget(Canvas('photo.jpeg'))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
gui.show()
sys.exit(app.exec_())
Output:

Insert Image into QGridLayout and Draw on top of image in PyQt5

I'm pretty new to PyQt and am trying to make an application with a QPixmap on the left, which can be drawn on, and a QTextEdit on the right (for a simple OCR GUI).
I looked at:
PyQt5 Image and QGridlayout
but I couldn't connect it with the code below (I'm losing my hair with all the head scratching!!)
When I try adapting the following code, what I get is a QMainWindow with the QPixmap as the background which can be drawn on with the mouse and a second occurance of the QPixmap in it's correct position, which can not be drawn on. Can someone tell me what I'm doing wrong?
Thank you very much!
# https://stackoverflow.com/questions/51475306/
import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QMainWindow, QApplication,QGridLayout, QLabel, QWidget, QTextEdit
from PyQt5.QtGui import QPixmap, QPainter, QPen
class Menu(QMainWindow):
def __init__(self):
super().__init__()
self.drawing = False
self.lastPoint = QPoint()
self.image = QPixmap("S3.png")
self.setGeometry(100, 100, 500, 300)
self.resize(self.image.width(), self.image.height())
layout = QGridLayout()
# Add a QTextEdit box
self.edit = QTextEdit()
layout.addWidget(self.edit, 0, 0, 10, 20)
# This:
# https://stackoverflow.com/questions/52616553
# indicates that a QPixmap must be put into a label to insert into a QGridLayout
self.label = QLabel()
self.label.setPixmap(self.image)
layout.addWidget(self.label, 10, 20, 10, 20)
# https://stackoverflow.com/questions/37304684/
self.widget = QWidget()
self.widget.setLayout(layout)
self.setCentralWidget(self.widget)
self.show()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(self.rect(), self.image)
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() and Qt.LeftButton and self.drawing:
painter = QPainter(self.image)
painter.setPen(QPen(Qt.red, 3, Qt.SolidLine))
painter.drawLine(self.lastPoint, event.pos())
print(self.lastPoint,event.pos())
self.lastPoint = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if event.button == Qt.LeftButton:
self.drawing = False
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = Menu()
sys.exit(app.exec_())
Each widget must fulfill a specific task, so I have created a widget that only has the painted function, the main widget works as a container for the painting widget and the QTextEdit.
from PyQt5 import QtCore, QtGui, QtWidgets
class Label(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Label, self).__init__(parent)
self.image = QtGui.QPixmap("S3.png")
self.drawing = False
self.lastPoint = QtCore.QPoint()
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.drawPixmap(QtCore.QPoint(), self.image)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.drawing = True
self.lastPoint = event.pos()
def mouseMoveEvent(self, event):
if event.buttons() and QtCore.Qt.LeftButton and self.drawing:
painter = QtGui.QPainter(self.image)
painter.setPen(QtGui.QPen(QtCore.Qt.red, 3, QtCore.Qt.SolidLine))
painter.drawLine(self.lastPoint, event.pos())
self.lastPoint = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if event.button == QtCore.Qt.LeftButton:
self.drawing = False
def sizeHint(self):
return self.image.size()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.label = Label()
self.textedit = QtWidgets.QTextEdit()
widget = QtWidgets.QWidget()
self.setCentralWidget(widget)
lay = QtWidgets.QHBoxLayout(widget)
lay.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.textedit)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Categories