import sys
from PyQt4 import QtGui,QtCore
x=-40
y=0
z=0
class MyView(QtGui.QGraphicsView):
def __init__(self):
QtGui.QGraphicsView.__init__(self)
self.scene=QtGui.QGraphicsScene(self)
self.item=[]
self.item2=[]
myLine=QtGui.QGraphicsLineItem(-10,20,20,20)
myLine.setCursor(QtCore.Qt.CrossCursor)
self.scene.addItem(myLine)
myLine.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
self.setScene(self.scene)
def keyPressEvent(self,event):
global x
global y
global z
if event.key()==QtCore.Qt.Key_Left:
self.item.append(QtGui.QGraphicsRectItem(x,-10,40,40))
self.scene.addItem(self.item[y])
x=x+10
self.item[y].setFlag(QtGui.QGraphicsItem.ItemIsMovable)
y=y+1
elif event.key()==QtCore.Qt.Key_Right:
self.item2.append(QtGui.QGraphicsEllipseItem(x,-10,40,40))
self.scene.addItem(self.item2[z])
x=x+10
self.item2[z].setFlag(QtGui.QGraphicsItem.ItemIsMovable)
z=z+1
def mousePressEvent(self , event):
self._start=event.pos()
def mouseReleaseEvent(self,event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene.addItem(
QtGui.QGraphicsLineItem(QtCore.QLineF(start, end)))
if __name__=='__main__':
app=QtGui.QApplication(sys.argv)
view= MyView()
view.show()
sys.exit(app.exec_())
as you can see i am not able to move the rectangles and ellipses because of the mouse press event it is drawing a line
i want to be able to drag as well as draw a line
when pressed over graphics item it should drag other wise it should draw line
Use if itemAt(event.pos) is None: in mousePressEvent() to determine whether the click occurred over a QGraphicsItem. Set a state flag self.__dragging = the_item in that method, so that you can determine in the mouseMoveEvent() and the mouseReleaseEvent() whether you were dragging an object (self.__dragging is not None) or drawing a line (self.__dragging is None).
Related
My Problem is: The coordinates where my mouse is and where the painting starts is wrong.
The Canvas starts on the top left corner (0,0) but the label are on somewhere at 250,500(Because ive done this with the designer)
so if draw i have to draw outside the label to get something in the canvas :( I didnt find the problem.
Here is my Code:
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5.QtGui import QIcon, QImage, QPen, QPainter, QColor
from PyQt5.QtCore import Qt
from ui.main import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super().__init__(parent)
self.main = Ui_MainWindow()
self.main.setupUi(self)
path = "G:/SoftwareDevelopement/SignInPrototyp/signin.png"
self.main.labelSign.setPixmap(QtGui.QPixmap(path))
#self.main.labelSign.move(250,410)
self.drawing = False
self.brushSize = 2
self.brushColor = Qt.black
self.brushStyle = Qt.SolidLine
self.brushCap = Qt.RoundCap
self.brushJoin = Qt.RoundJoin
self.last_x, self.last_y = None, None
def mouseMoveEvent(self, e):
print(e.x)
print(e.y)
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.main.labelSign.pixmap())
painter.setPen(QPen(self.brushColor, self.brushSize, self.brushStyle, self.brushCap, self.brushJoin))
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
# Open and Exit main Window
if __name__ == "__main__":
global app
global window
# SCALE TO ALL RESOLUTIONS! 1
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
# AND THIS
app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
window = MainWindow()
window.raise_()
window.showMinimized()
#window.show()
window.showNormal()
window.activateWindow()
sys.exit(app.exec_())
######################!
This dont work, i have to draw on the left top corner to get inside the white
Point 0,0 of window is at top left corner of window, point 0,0 of label is at top left corner of label, you use window coordinates to draw on label (you overriden window event not label event), this two coordinate systems are not equal and to go from one to another you need to translate coordinates. For example like this:
offset = self.main.labelSign.pos()
painter.drawLine(self.last_x - offset.x(), self.last_y - offset.y(), e.x() - offset.x(), e.y() - offset.y())
You can make your drawable label self contained by creating class that inherits from QLabel and overrides mouseMoveEvent and mouseReleaseEvent, this way you dont need to translate coordinates.
so i got after long trial and error and solution:
painter = QtGui.QPainter(self.main.labelSign.pixmap())
painter_map = self.main.labelSign.geometry()
painter.setWindow(painter_map
simple remap.
I am quite new to pyqtgraph and have been learning python for some time. I am trying to get mouse click coordinates from the pyqtgraph plotitem.
Here's what I have so far.
class CrossHair():
def __init__(self, win,row=0,col=0):
self.label = pg.LabelItem(justify='right')
self.p1 = win.getItem(row=row,col=col)
self.p1.setAutoVisible(x=True,y=True)
win.addItem(self.label,row=row,col=col)
self.vLine = pg.InfiniteLine(angle=90, movable=False)
self.hLine = pg.InfiniteLine(angle=0, movable=False)
self.vb = self.p1.vb
self.p1.addItem(self.vLine, ignoreBounds=True)
self.p1.addItem(self.hLine, ignoreBounds=True)
self.proxy = pg.SignalProxy(self.p1.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
self.p1.scene().sigMouseClicked.connect(self.mouseClicked)
#self.p1.scene().sigMouseMoved.connect(self.mouseMoved)
def mouseMoved(self, evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
if self.p1.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
self.label.setText("<span style='font-size: 10pt'>x=%0.1f, <span style='color: red'>y=%0.1f</span>"%(mousePoint.x(),mousePoint.y()))
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
def mouseClicked(self,event):
global mouse_coordinates
mouse_coordinates=[]
pos = event.scenePos()
mousePoint = self.vb.mapSceneToView(pos)
mouse_coordinates = [mousePoint.x(),mousePoint.y()]
return mouse_coordinates
#self.sigMouseClicked.disconnect()
I want to define a function get_points(win) which takes the current pyqtgraph window, draws a crosshair and whenever I click, returns a list of mouse click coordinates. After a single click, I don't want it to register any more coordinates unless the I call the function again.
I wrote something like this but it did not work:
def get_points(win):
ch = CrossHair(win)
ch.p1.scene().sigMouseClicked.connect(ch.mouseClicked)
Any help or suggestions is greatly appreciated!
I'm new to Pyside and I need to compute the amount of movement in both x and y axis since the previous call to the mouseMoveEvent function
The idea is to obtain the previous position of the mouse (A) and the current one (B). The we compute the vector starting from A and ending to B
My problem is the following : QMouseEvent doesn't have a lastPos() function, but a pos() one. Thus, I can't get the previous position of the mouse (The last recorded position is the position of the previous mouse event received by the view that created the event)
In Pygame this is known as pygame.mouse.get_rel(). How can I do this
?
Here is a sample code that prints the current position of the mouse when pressed and moved
# -*- coding: utf-8 -*-
import sys
from PySide import QtGui
class Frame(QtGui.QFrame):
def __init__(self, (width, height)):
super(Frame, self).__init__()
self.setGeometry(0, 0, width, height)
self.setWindowTitle('Frame')
self.show()
self.loop()
def loop(self):
while 1:
self.update()
QtGui.QApplication.processEvents()
def mouseMoveEvent(self, event):
# Get the current position of the mouse
x, y = event.x(), event.y()
print (x, y)
def main():
app = QtGui.QApplication(sys.argv)
Frame((500, 500))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I can't test this without PySide, which I currently can't install, but I think you want something like this (read NOTE1 and NOTE2):
import sys
from PySide import QtGui
class Frame(QtGui.QFrame):
def __init__(self, (width, height)):
super(Frame, self).__init__()
# NOTE1: indicate if mouse was clicked
self.clicked= False
self.setGeometry(0, 0, width, height)
self.setWindowTitle('Frame')
self.show()
self.loop()
def loop(self):
while 1:
self.update()
QtGui.QApplication.processEvents()
def mouseMoveEvent(self, event):
# Get the current position of the mouse
x, y = event.x(), event.y()
print (x, y)
def mousePressEvent(self, event):
# NOTE 2: track clicks, not movements
if self.clicked:
# calculate vector
vector = ((self.x, self.y,), (event.x(), event.y(),))
print "vector: %s" % str(vector)
self.clicked = False
return vector
# set vector start
self.x = event.x()
self.y = event.y()
self.clicked = True
print "vector set to start from: (%d,%d)" % (self.x, self.y)
return None
def main():
app = QtGui.QApplication(sys.argv)
Frame((500, 500))
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This way you can set a vector from first click to second, vector starts on each mouse click. This probably has some errors, but the idea is clear. If you want mouse to track movement and not clicks, apply the same principles (storing last position in the subclass, set flag to see if vector should be calculated...) to the mouseMoveEvent.
I'll test it later when I'm with my pc.
I am trying to create a scenario where I need to draw line from the mousePressEvent position till the latest mouse moveposition which means i need to call paintEvent from mousePressEvent ,Is it possible ?
So scenario is this :
1) Used paintEvent to draw a 2 circles with black colour
2) Mouse press event waits for a event and press happens , I want to change the colour of the circle to green , is it possible ?
import sys, random
from PyQt4 import QtGui, QtCore
class P(QtGui.QWidget):
def __init__(self):
super(P, self).__init__()
self.initUI()
def initUI(self):
q=self.frameGeometry()
cp=QtGui.QDesktopWidget().availableGeometry().center()
q.moveCenter(cp)
self.setFixedSize(300,300)
self.setWindowTitle('Points')
self.show()
def mousePressEvent(self, QMouseEvent):
cursor =QtGui.QCursor(self)
position = QMouseEvent.pos()
xpos = QMouseEvent.x()
ypos = QMouseEvent.y()
#Trial ??????
q = QtGui.QPainter()
q.drawLine(30,30,90,90)
print QMouseEvent.pos()
def mouseReleaseEvent(self, QMouseEvent):
cursor =QtGui.QCursor()
print cursor.pos()
def paintEvent(self,e):
qp = QtGui.QPainter()
qp.begin(self)
E1 = qp.drawEllipse(30,30,20,20)
E2 = qp.drawEllipse(30,130,20,20)
def main():
app = QtGui.QApplication(sys.argv)
ex = P()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
In Simple words I need to know can we call one Event from another , i.e. Paint Event from Mouse press event ?
It is a much better idea to do all your painting in the paintEvent handler.
You should use your mouse event handlers to handle the collection of data (starting points, lengths, etc) and then do the actual repainting in the paintEvent.
Once you've collected the new data in the mouse event handlers, you can tell the QWidget that it needs to repaint by calling update function. This will schedule a paint event that will execute when the program returns to the event loop.
I'm trying to make a very basic image creator using PySide. But I'm having some troubles to draw things.
This is the portion of my script responsible for the draw area:
class Area(QWidget):
global x1
global y1
global x2
global y2
try:
x1
except NameError:
x1=0
try:
y1
except NameError:
y1=0
try:
x2
except NameError:
x2=100
try:
y2
except NameError:
y2=100
def mousePressEvent(self, me):
global x1
global y1
x1 = me.x()
y1 = me.y()
def mouseMoveEvent(self, mo):
global x2
global y2
x2 = mo.x()
y2 = mo.y()
self.update()
def paintEvent(self, pe):
global paint
paint = QPainter()
paint.begin(self)
paint.drawLine(x1,y1,x2,y2)
paint.save()
paint.restore()
blankarea = Area()
blankarea.show()
Basicaly, what the script does is just draw a line based on mouse events. However, every time the mouse click event occurs (responsible for start a line) it erases the line previously made, even after using QPainter.save() and QPainter.restore(). What could be causing this problem?
The paintEvent() method is repainting the entire widget every time it is called. The drawing from the previous calls is completely replaced with the results of each future paintEvent() call.
If you want the effect you are describing, you will need to accumulate the points and draw the entire sequence of them each time.
From the docs:
http://pyside.github.io/docs/pyside/PySide/QtGui/QWidget.html#PySide.QtGui.PySide.QtGui.QWidget.paintEvent
When the paint event occurs, the update region has normally been
erased, so you are painting on the widget's background.
Why are you painting on a QWidget when you have all the graphics view framework to play with?
Simple line-drawing example:
from PySide import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.view = View(self)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
class View(QtGui.QGraphicsView):
def __init__(self, parent):
QtGui.QGraphicsView.__init__(self, parent)
self.setScene(QtGui.QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene().addItem(
QtGui.QGraphicsLineItem(QtCore.QLineF(start, end)))
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())