Selecting several items and then taking distance between them

450 views Asked by At

I am currently having an issue with finding the distance between two items in a QGraphicsScene. I have the distance formula already down but the issue is that when I select two points or items in the graphicsScene it says they are at the same point and since they are at the same point the distance always comes out zero. To select multiple items I use ctrl + click to get two points selected at once and I know the two points are at different areas in the scene. Here is the code:

import sys
from PyQt4 import QtGui, QtCore
import math
#this sets the scene for drawing and the microscope image
class MyView(QtGui.QGraphicsView):
    def __init__(self,window):
        QtGui.QGraphicsView.__init__(self)
        self.window = window
        self.scene = QtGui.QGraphicsScene(self)
        self.item = QtGui.QGraphicsRectItem(400, 400, 400, 400)
        self.scene.addItem(self.item)
        self.setScene(self.scene)
    def paintMarkers(self,event):
        ##self.cursor = QtGui.QCursor()
        #self.cursor.setShape(2)
        p = self.mapToScene(event.x(),event.y())
        if (p.x() > 400 and p.x() < 800) and (p.y() > 400 and p.y() < 800):
            self.circleItem = QtGui.QGraphicsEllipseItem(p.x(),p.y(),5,5)
                   self.circleItem.setFlag(QtGui.QGraphicsItem.ItemIsSelectable,True)
            self.scene.addItem(self.circleItem)
            self.circleItem.setPen(QtGui.QPen(QtCore.Qt.red, 1.5))
        #self.setScene(self.scene)
    def deleteMarkers(self,event):
        p = self.mapToScene(event.x(),event.y())
        if self.scene.itemAt(p.x(),p.y()) != self.item:
            self.scene.removeItem(self.scene.itemAt(p.x(),p.y()))
        #print "Hello world"
    #def mousePressEvent(self,QMouseEvent):
        #self.paintMarkers()
    def mousePressEvent(self,event):
        if self.window.btnPaintDot.isChecked():
            self.paintMarkers(event)
        if self.window.btnDeleteMarks.isChecked():
            self.deleteMarkers(event)
        if self.window.btnPaintLength.isChecked():
            self.distanceFormula(self.scene.selectedItems())
        return QtGui.QGraphicsView.mousePressEvent(self,event)
    def distanceFormula(self,list):
        if len(list) == 2:
            """for i in list:
                p = self.mapToScene(i.x(),i.y())
                print p.x()
                print p.y()"""
            p = self.mapToScene(list[0].x(),list[0].y())
            q = self.mapToScene(list[1].x(),list[1].y())
            print p.x()
            print p.y()
            print q.x()
            print q.y()
            print list[0]
            print list[1]
            print len(list)
            length = math.sqrt((p.x() - q.x())**2 + (p.y() - q.y())**2)
            print length

class Window(QtGui.QMainWindow):
    def __init__(self):
        #This initializes the main window or form
        super(Window,self).__init__()
        self.setGeometry(50,50,1000,1000)
        self.setWindowTitle("Pre-Alignment system")

        self.view = MyView(self)
        self.setCentralWidget(self.view)

self.btnPaintLength = QtGui.QPushButton("Len",self)
        self.btnPaintLength.clicked.connect(self.paintLengthOnImage)
        self.btnPaintLength.setCheckable(True)
        self.btnPaintLength.resize(30,30)
        self.btnPaintLength.move(330,50)
#this creates the paint button allowing user to draw lines or anything on the image from the microscope
        self.btnPaintDot = QtGui.QPushButton("*",self)
        self.btnPaintDot.setCheckable(True)
        self.btnPaintDot.clicked.connect(self.paintDotOnImage)
        self.btnPaintDot.resize(30,30)
        self.btnPaintDot.move(300,50)

#creates the delete marker button
        self.btnDeleteMarks = QtGui.QPushButton("del",self)
        self.btnDeleteMarks.clicked.connect(self.paintDeleteMarks)
        self.btnDeleteMarks.setCheckable(True)
        self.btnDeleteMarks.resize(30,30)
        self.btnDeleteMarks.move(390,50)

    def paintLengthOnImage(self):
            """create length on image"""
            if self.btnPaintLength.isChecked():
                self.btnPaintDot.setChecked(False)
                self.btnPaintPolygon.setChecked(False)
                self.btnDeleteMarks.setChecked(False)
                self.view.distanceFormula(self.view.scene.selectedItems())
            else:
                self.btnPaintLength.setChecked(False)

    def paintDotOnImage(self):
            """create a dot paint button"""
            if self.btnPaintDot.isChecked():
                self.btnPaintDot.setChecked(True)
                self.btnPaintPolygon.setChecked(False)
                self.btnPaintLength.setChecked(False)
                self.btnDeleteMarks.setChecked(False)
            else:
                self.btnPaintDot.setChecked(False)
    def paintDeleteMarks(self):
            if self.btnDeleteMarks.isChecked():
                self.btnPaintDot.setChecked(False)
                self.btnPaintPolygon.setChecked(False)
                self.btnPaintPolygon.setChecked(False)
                self.btnDeleteMarks.setChecked(True)
            else:
                self.btnDeleteMarks.setChecked(False)
def run():
    app = QtGui.QApplication(sys.argv)
    GUI = Window()
    GUI.show()
    sys.exit(app.exec_())

run()

The print statements were just there for my purpose of finding where the issue was. Much thanks!

1

There are 1 answers

0
three_pineapples On BEST ANSWER

It looks like this happens because of the way the items were created. Items are always created at (0,0). When you specify the (x,y,width,height) when you construct the item, you actually create an items which extends from (0,0) to (x+width, y+height). You can verify this by looking at the size of the items boundingRect().

Instead, you should construct the object at (0,0) and move it to the correct location. With you current code, this means doing the following when you create the item:

self.circleItem = QtGui.QGraphicsEllipseItem(0,0,5,5)
self.circleItem.setPos(p.x()-self.circleItem.boundingRect().width()/2.0,p.y()-self.circleItem.boundingRect().height()/2.0)

Note, here I offset the position by half of the width/height so that the items is centred on the mouse click. You may or may not want this.