3

Here is my code:

import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt

class MouseTracker(QWidget):
    distance_from_center = 0
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setMouseTracking(True)

    def initUI(self):
        self.setGeometry(200, 200, 1000, 500)
        self.setWindowTitle('Mouse Tracker')
        self.label = QLabel(self)
        self.label.resize(500, 40)
        self.show()

    def mouseMoveEvent(self, event):
        distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)
        self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()) + "Distance from center: " + str(distance_from_center))       

        q = QPainter()  #Painting the line
        q.begin(self)
        q.drawLine(event.x(), event.y(), 250, 500)
        q.end()

    def drawPoints(self, qp, x, y):
        qp.setPen(Qt.red)
        qp.drawPoint(x, y)

app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())

What I'm trying to do is paint a simple line from the position of the mouse to the middle of the widget using this:

        q = QPainter()  #Painting the line
        q.begin(self)
        q.drawLine(event.x(), event.y(), 250, 500)
        q.end()

But when I run it, no line is visible. What do I need to do?

3 Answers3

2

You must implement the function QPaintEvent, in this function you must draw the line, in addition you must call the function update() to update the drawing.

import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt

class MouseTracker(QWidget):
    distance_from_center = 0
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setMouseTracking(True)

    def initUI(self):
        self.setGeometry(200, 200, 1000, 500)
        self.setWindowTitle('Mouse Tracker')
        self.label = QLabel(self)
        self.label.resize(500, 40)
        self.show()
        self.pos = None

    def mouseMoveEvent(self, event):
        distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)
        self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()) + "Distance from center: " + str(distance_from_center))       
        self.pos = event.pos()
        self.update()

    def paintEvent(self, event):
        if self.pos:
            q = QPainter(self)
            q.drawLine(self.pos.x(), self.pos.y(), 500, 250)


app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())

Output:

enter image description here

otmane42
  • 535
  • 4
  • 11
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • It crashes when I try to do this, any ideas? –  Jan 18 '17 at 14:18
  • 1
    Moving position variable to outside the methods, next to distance_from_center makes it work for me. Thanks! –  Jan 18 '17 at 14:33
0

You can only use a QPainter inside the paintEvent method. So one way to fix is to record the x and y coordinates inside the class and update the root widget. This then calls paintEvent and you will see the line.

example

import sys
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import Qt

class MouseTracker(QWidget):
    distance_from_center = 0
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setMouseTracking(True)
        self.x = -1
        self.y = -1

    def initUI(self):
        self.setGeometry(200, 200, 1000, 500)
        self.setWindowTitle('Mouse Tracker')
        self.label = QLabel(self)
        self.label.resize(500, 40)
        self.show()

    def paintEvent(self, e):

        if not (self.x == -1 or self.y == -1):
            q = QPainter()  #Painting the line

            q.begin(self)

            q.drawLine(self.x, self.y, 250, 500)
            q.end()

    def mouseMoveEvent(self, event):
        distance_from_center = round(((event.y() - 250)**2 + (event.x() - 500)**2)**0.5)
        self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()) + "Distance from center: " + str(distance_from_center))

        self.x = event.x()
        self.y = event.y()

        self.update()

    def drawPoints(self, qp, x, y):
        qp.setPen(Qt.red)
        qp.drawPoint(x, y)

app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())

I wasn't sure about how self.x and self.y would be set initially. The -1 and the check in the paintEvent feels a bit hacky, but at least it paints.

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
0

For the previous answer, I tried it under Python3.7 and PyQt5. The result was program crash 'Process finished with exit code -1073740791 (0xC0000409)'. And in the comments, there were someone else also mentioned the crash. I find the solution to this crash: self.x and self.y must be initialized before the calling of self.show() So I simply modified the code to as follows:

def initUI(self):
    self.setGeometry(200, 200, 1000, 500)
    self.setWindowTitle('Mouse Tracker')
    self.label = QLabel(self)
    self.label.resize(500, 40)
    self.x = 100
    self.y = 100
    self.show()
csjedi
  • 3
  • 2