I am working on a text editor. The only problem left for me is to draw a rectangle box (colored with opacity 50%) behind a text that should be able to drag and drop with text anywhere as the text is working. Moreover, the text should always fit in that rectangle box. Thanks in advance.
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PIL import Image, ImageFont, ImageDraw, ImageEnhance
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
self._zoom = 0
self._empty = True
self._scene = QtWidgets.QGraphicsScene(self)
self._photo = QtWidgets.QGraphicsPixmapItem()
self._textLayer = QtWidgets.QGraphicsSimpleTextItem ()
#self._textLayer.setFont(QFont ())
self._scene.addItem(self._photo)
self._scene.addItem(self._textLayer)
self.setScene(self._scene)
self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(80, 30, 30)))
self.setFrameShape(QtWidgets.QFrame.NoFrame)
self._textLayer.setFlags(QGraphicsItem.ItemIsMovable)
def hasPhoto(self):
return not self._empty
def fitInView(self, scale=True):
rect = QtCore.QRectF(self._photo.pixmap().rect())
if not rect.isNull():
self.setSceneRect(rect)
if self.hasPhoto():
unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def updateText(self,text,font_size=50):
# Load the font:
font_db = QFontDatabase()
font_id = font_db.addApplicationFont("fonts/Summer's Victory Over Spring - TTF.ttf")
#families = font_db.applicationFontFamilies(font_id)
#print (families)
myFont = QFont("Summers Victory Over Spring")
myFont.setPixelSize(font_size*1.5)
self._textLayer.setFont(myFont)
self._textLayer.setText(text)
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.show()
def setPhoto(self, pixmap=None):
self._zoom = 0
if not pixmap.isNull():
self._empty = False
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self._photo.setPixmap(pixmap)
else:
self._empty = True
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
self._photo.setPixmap(QPixmap())
self.fitInView()
def wheelEvent(self, event):
if self.hasPhoto():
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def toggleDragMode(self):
if self.dragMode() == QtWidgets.QGraphicsView.ScrollHandDrag:
self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
elif not self._photo.pixmap().isNull():
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
def mousePressEvent(self, event):
if self._photo.isUnderMouse():
self.photoClicked.emit(QtCore.QPoint(event.pos()))
super(PhotoViewer, self).mousePressEvent(event)
def keyReleaseEvent(self, event):
print ('Key event: %d' % event.key())
if event.key() == Qt.Key_A:
#print (dir(self._scene))
#print (dir(self._photo))
#print (dir(self._textLayer))
print ("scene Rect:",self._scene.sceneRect())
print ("scene WH:",self._scene.width(),self._scene.height())
print ("gfxPhoto pos:" ,self._photo.pos().x(),self._photo.pos().y())
print ("gfxPhoto scenepos:" ,self._photo.scenePos())
#print ("gfxPhoto Rect:",self._photo.boundingRect())
print ("gfxPhoto XY:",self._photo.x(),self._photo.y())
print ("gfxtext Rect:",self._textLayer.boundingRect())
print ("gfxtext scenepos:" ,self._textLayer.scenePos().x(),self._textLayer.scenePos().y())
print ("gfxtext pos:",self._textLayer.pos().x(),self._textLayer.pos().y())
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = PhotoViewer(self)
# 'Load image' button
self.btnLoad = QtWidgets.QToolButton(self)
self.btnLoad.setText('Load image')
self.btnLoad.clicked.connect(self.loadImage)
# Button to change from drag/pan to getting pixel info
self.btnPixInfo = QtWidgets.QToolButton(self)
self.btnPixInfo.setText('Create Text')
self.btnPixInfo.clicked.connect(self.loadText)
self.fontSize =QtWidgets.QSpinBox()
self.fontSize.valueChanged.connect(self.loadText)
self.editPixInfo = QtWidgets.QLineEdit(self)
#self.editPixInfo.setReadOnly(True)
self.viewer.photoClicked.connect(self.photoClicked)
# Arrange layout
VBlayout = QtWidgets.QVBoxLayout(self)
HBlayout = QtWidgets.QHBoxLayout()
HBlayout.setAlignment(QtCore.Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
HBlayout.addWidget(self.btnPixInfo)
HBlayout.addWidget(self.editPixInfo)
VBlayout.addLayout(HBlayout)
VBlayout.addWidget(self.viewer)
HBlayout.addWidget(self.fontSize)
self.editPixInfo.setText("Sheeda")
self.fontSize.setValue(20)
self.loadImage()
self.loadText()
self.frame = QFrame()
self.frame.setFrameStyle(QFrame.StyledPanel)
self.frame.setLineWidth(20)
def loadImage(self):
print(os.path.exists(os.path.abspath('E:\Dpinner\images\pic2.png')))
self.viewer.setPhoto(QtGui.QPixmap(os.path.abspath('E:\Dpinner\images\pic2.png')))
def loadText(self):
#self.viewer.toggleDragMode()
self.viewer.updateText(self.editPixInfo.text(),self.fontSize.value())
def photoClicked(self, pos):
if self.viewer.dragMode() == QtWidgets.QGraphicsView.NoDrag:
self.editPixInfo.setText('%d, %d' % (pos.x(), pos.y()))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
End of code. Thanks in advance
If you want a rectangle over the text you can create a custom QGraphicsSimpleTextItem
as shown below:
class GraphicsSimpleTextItem(QtWidgets.QGraphicsSimpleTextItem):
def paint(self, painter, option, widget):
super(GraphicsSimpleTextItem, self).paint(painter, option, widget)
painter.save()
color = QtGui.QColor(QtCore.Qt.red)
color.setAlpha(127)
painter.fillRect(self.boundingRect(), QtGui.QBrush(color))
painter.restore()
And then you put it in your code:
self._textLayer = GraphicsSimpleTextItem()