Python Qt: Interactive Re-Sizable QGraphicsItem, mouse hover area not resizing -
i trying build python class around qgraphicsrectitem
(pyside or pyqt4) provides mouse interaction through hover-overs, movable, , re-sizable. have pretty working except:
for reason, seems if mouse hover area not changing when item re-sized or moved. need solving issue.
maybe problem caused inverting y axis on qgraphicsview
:
qgraphicsview.scale(1,-1)
qgraphicsrectitem class:
class boxresizable(qtgui.qgraphicsrectitem): def __init__(self, rect, parent = none, scene = none): qtgui.qgraphicsrectitem.__init__(self, rect, parent, scene) self.setzvalue(1000) self._rect = rect self._scene = scene self.mouseover = false self.resizehandlesize = 4.0 self.mousepresspos = none self.mousemovepos = none self.mouseispressed = false self.setflags(qtgui.qgraphicsitem.itemisselectable|qtgui.qgraphicsitem.itemisfocusable) self.setacceptshoverevents(true) self.updateresizehandles() def hoverenterevent(self, event): self.updateresizehandles() self.mouseover = true self.preparegeometrychange() def hoverleaveevent(self, event): self.mouseover = false self.preparegeometrychange() def hovermoveevent(self, event): if self.topleft.contains(event.scenepos()) or self.bottomright.contains(event.scenepos()): self.setcursor(qtcore.qt.sizefdiagcursor) elif self.topright.contains(event.scenepos()) or self.bottomleft.contains(event.scenepos()): self.setcursor(qtcore.qt.sizebdiagcursor) else: self.setcursor(qtcore.qt.sizeallcursor) qtgui.qgraphicsrectitem.hovermoveevent(self, event) def mousepressevent(self, event): """ capture mouse press events , find mosue pressed on object """ self.mousepresspos = event.scenepos() self.mouseispressed = true self.rectpress = copy.deepcopy(self._rect) # top left corner if self.topleft.contains(event.scenepos()): self.mousepressarea = 'topleft' # top right corner elif self.topright.contains(event.scenepos()): self.mousepressarea = 'topright' # bottom left corner elif self.bottomleft.contains(event.scenepos()): self.mousepressarea = 'bottomleft' # bottom right corner elif self.bottomright.contains(event.scenepos()): self.mousepressarea = 'bottomright' # entire rectangle else: self.mousepressarea = none qtgui.qgraphicsrectitem.mousepressevent(self, event) def mousereleaseevent(self, event): """ capture nmouse press events. """ self.mouseispressed = false self.updateresizehandles() self.preparegeometrychange() qtgui.qgraphicsrectitem.mousereleaseevent(self, event) def mousemoveevent(self, event): """ handle mouse move events. """ self.mousemovepos = event.scenepos() if self.mouseispressed: # move top left corner if self.mousepressarea=='topleft': self._rect.settopleft(self.rectpress.topleft()-(self.mousepresspos-self.mousemovepos)) # move top right corner elif self.mousepressarea=='topright': self._rect.settopright(self.rectpress.topright()-(self.mousepresspos-self.mousemovepos)) # move bottom left corner elif self.mousepressarea=='bottomleft': self._rect.setbottomleft(self.rectpress.bottomleft()-(self.mousepresspos-self.mousemovepos)) # move bottom right corner elif self.mousepressarea=='bottomright': self._rect.setbottomright(self.rectpress.bottomright()-(self.mousepresspos-self.mousemovepos)) # move entire rectangle, don't resize else: self._rect.movecenter(self.rectpress.center()-(self.mousepresspos-self.mousemovepos)) self.updateresizehandles() self.preparegeometrychange() qtgui.qgraphicsrectitem.mousepressevent(self, event) def boundingrect(self): """ return bounding rectangle """ return self._boundingrect def updateresizehandles(self): """ update bounding rectangle , resize handles """ self.offset = self.resizehandlesize*(self._scene.graphicsview.maptoscene(1,0)-self._scene.graphicsview.maptoscene(0,1)).x() self._boundingrect = self._rect.adjusted(-self.offset, self.offset, self.offset, -self.offset) # note: draws correctly on view inverted y axes. i.e. qgraphicsview.scale(1,-1) self.topleft = qtcore.qrectf(self._boundingrect.topleft().x(), self._boundingrect.topleft().y() - 2*self.offset, 2*self.offset, 2*self.offset) self.topright = qtcore.qrectf(self._boundingrect.topright().x() - 2*self.offset, self._boundingrect.topright().y() - 2*self.offset, 2*self.offset, 2*self.offset) self.bottomleft = qtcore.qrectf(self._boundingrect.bottomleft().x(), self._boundingrect.bottomleft().y(), 2*self.offset, 2*self.offset) self.bottomright = qtcore.qrectf(self._boundingrect.bottomright().x() - 2*self.offset, self._boundingrect.bottomright().y(), 2*self.offset, 2*self.offset) def paint(self, painter, option, widget): """ paint widget """ # show boundingrect debug purposes painter.setpen(qtgui.qpen(qtcore.qt.red, 0, qtcore.qt.dashline)) painter.drawrect(self._boundingrect) # paint rectangle painter.setpen(qtgui.qpen(qtcore.qt.black, 0, qtcore.qt.solidline)) painter.drawrect(self._rect) # if mouse over, draw handles if self.mouseover: # if rect selected, fill in handles if self.isselected(): painter.setbrush(qtgui.qbrush(qtgui.qcolor(0,0,0))) painter.drawrect(self.topleft) painter.drawrect(self.topright) painter.drawrect(self.bottomleft) painter.drawrect(self.bottomright)
rest of code functioning example:
class graphicsscene(qtgui.qgraphicsscene): def __init__ (self, parent = none): qtgui.qgraphicsscene.__init__(self, parent) def setgraphicsview(self, view): self.graphicsview = view app = qtgui.qapplication(sys.argv) app.setstyle('gtk') mainwindow = qtgui.qmainwindow() scene = graphicsscene() scene.setscenerect(-100,-100, 200, 200) # set view properties view = qtgui.qgraphicsview() view.setscene(scene) view.scale(1,-1) view.setrenderhint(qtgui.qpainter.antialiasing) view.setviewportupdatemode(qtgui.qgraphicsview.boundingrectviewportupdate) view.sethorizontalscrollbarpolicy ( qtcore.qt.scrollbaralwaysoff ) view.setverticalscrollbarpolicy ( qtcore.qt.scrollbaralwaysoff ) view.setupdatesenabled(true) view.setmousetracking(true) view.setcachemode(qtgui.qgraphicsview.cachebackground) view.settransformationanchor(qtgui.qgraphicsview.anchorundermouse) scene.setgraphicsview(view) # add box boxresizable(qtcore.qrectf(-50, 50, 100.0, -100.0), parent = none, scene = scene) mainwindow.setcentralwidget(view) mainwindow.show() app.exec_() app.deletelater() sys.exit()
adding above class qgraphicsscene
, subsequent inverted y axis qgraphicsview
produce this:
any or suggestions appreciated! thanks!
found part of problem: if over-ride shape function (add function class) with:
def shape(self): path = qtgui.qpainterpath() path.addrect(self.boundingrect()) return path
the hover area changes size , position box sometimes. acoording docs qgraphicsitem.shape()
:
the default implementation calls boundingrect() return simple rectangular shape...
is bug in pyqt4?
second problem: think boundingrect , shape rectangle need have positive widths , heights? done adding:
self._rect = self._rect.normalized()
to mousereleaseevent
function.
Comments
Post a Comment