问题描述
我的代码是使用mousepressEvent和mouseReleaseEvent在QImage上画线。它工作正常,但是当我绘制一条动态预览线(即在MouseMoveEvent上)时,我希望它会出现。现在,当我松开鼠标左键并且看不到绘图时,该行才出现。
我希望在移动鼠标时显示并更新该行的预览,并且在释放鼠标左键时仅“固定”。就像MS Paint Line工具一样:https://youtu.be/YIw9ybdoM6o?t=207
这是我的代码(它是从Scribble示例派生的):
from PyQt5.QtCore import QPoint,QRect,QSize,Qt
from PyQt5.QtGui import QImage,QPainter,QPen,QColor,qRgb
from PyQt5.QtWidgets import QApplication,QWidget,QMainWindow
import sys
class DrawingArea(QWidget):
def __init__(self,parent=None):
super(DrawingArea,self).__init__(parent)
self.setAttribute(Qt.WA_StaticContents)
self.scribbling = False
self.myPenWidth = 1
self.myPenColor = QColor('#000000')
self.image = QImage()
self.startPoint = QPoint()
def mousepressEvent(self,event):
if event.button() == Qt.LeftButton:
self.startPoint = event.pos()
self.scribbling = True
def mouseReleaseEvent(self,event):
if event.button() == Qt.LeftButton and self.scribbling:
self.drawLineto(event.pos())
self.scribbling = False
def paintEvent(self,event):
painter = QPainter(self)
dirtyRect = event.rect()
painter.drawImage(dirtyRect,self.image,dirtyRect)
def resizeEvent(self,event):
if self.width() > self.image.width() or self.height() > self.image.height():
newWidth = max(self.width() + 128,self.image.width())
newHeight = max(self.height() + 128,self.image.height())
self.resizeImage(self.image,QSize(newWidth,newHeight))
self.update()
super(DrawingArea,self).resizeEvent(event)
def drawLineto(self,endPoint):
painter = QPainter(self.image)
painter.setPen(QPen(self.myPenColor,self.myPenWidth,Qt.solidLine,Qt.RoundCap,Qt.RoundJoin))
painter.drawLine(self.startPoint,endPoint)
rad = self.myPenWidth / 2 + 2
self.update(QRect(self.startPoint,endPoint).normalized().adjusted(-rad,-rad,+rad,+rad))
def resizeImage(self,image,newSize):
if image.size() == newSize:
return
newImage = QImage(newSize,QImage.Format_RGB32)
newImage.fill(qRgb(255,255,255))
painter = QPainter(newImage)
painter.drawImage(QPoint(0,0),image)
self.image = newImage
class MainWindow(QMainWindow):
def __init__(self,parent=None):
QMainWindow.__init__(self,parent)
self.setCentralWidget(DrawingArea())
self.show()
def main():
app = QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
我不知道如何显示正在绘制的线条的预览,并且还没有找到合适的答案。我该怎么做呢?
解决方法
您可以在paintEvent()
方法内绘制线条,而不是直接在图像上绘制线条,然后在实际释放鼠标时在图像上绘制线条。
class DrawingArea(QWidget):
def __init__(self,parent=None):
super(DrawingArea,self).__init__(parent)
self.setAttribute(Qt.WA_StaticContents)
self.scribbling = False
self.myPenWidth = 1
self.myPenColor = QColor('#000000')
self.image = QImage()
self.startPoint = self.endPoint = None
def mousePressEvent(self,event):
if event.button() == Qt.LeftButton:
self.startPoint = event.pos()
def mouseMoveEvent(self,event):
if self.startPoint:
self.endPoint = event.pos()
self.update()
def mouseReleaseEvent(self,event):
if self.startPoint and self.endPoint:
self.updateImage()
def paintEvent(self,event):
painter = QPainter(self)
dirtyRect = event.rect()
painter.drawImage(dirtyRect,self.image,dirtyRect)
if self.startPoint and self.endPoint:
painter.drawLine(self.startPoint,self.endPoint)
def updateImage(self):
if self.startPoint and self.endPoint:
painter = QPainter(self.image)
painter.setPen(QPen(self.myPenColor,self.myPenWidth,Qt.SolidLine,Qt.RoundCap,Qt.RoundJoin))
painter.drawLine(self.startPoint,self.endPoint)
painter.end()
self.startPoint = self.endPoint = None
self.update()
请注意,您无需在resize事件内调用update()
,因为它会自动调用。
我还删除了不必要的update rect调用,因为在这种情况下它几乎没有用:通常在绘制非常复杂的小部件时(尤其是当许多执行计算以正确绘制所有内容,实际上只有一小部分小部件需要更新)。就您而言,计算实际的更新矩形要比绘制小部件的所有内容花费更多的时间。
,我认为this page为您的问题提供了一些非常好的解决方案。例如,它显示了如何实现实际上为您提供“绘图板”的自定义类:
class Canvas(QLabel):
def __init__(self):
super().__init__()
pixmap = QtGui.QPixmap(600,300)
self.setPixmap(pixmap)
self.last_x,self.last_y = None,None
self.pen_color = QtGui.QColor('#000000')
def set_pen_color(self,c):
self.pen_color = QtGui.QColor(c)
def mouseMoveEvent(self,e):
if self.last_x is None: # First event.
self.last_x = e.x()
self.last_y = e.y()
return # Ignore the first time.
painter = QtGui.QPainter(self.pixmap())
p = painter.pen()
p.setWidth(1)
p.setColor(self.pen_color)
painter.setPen(p)
painter.drawLine(self.last_x,self.last_y,e.x(),e.y())
painter.end()
self.update()
# Update the origin for next time.
self.last_x = e.x()
self.last_y = e.y()
def mouseReleaseEvent(self,e):
self.last_x = None
self.last_y = None
您可以在需要的任何地方使用此Canvas类(或提供的任何名称)。例如在MainWindow中:
class MainWindow(QMainWindow):
def __init__(self,parent=None):
QMainWindow.__init__(self,parent)
self.canvas = Canvas()
self.canvas.set_pen_color('#fffee5') # set the colour you want
self.setCentralWidget(self.canvas)
self.show()
希望这会有所帮助!祝您编码愉快! :)