Seems the problem is solved for now.
I searched for a couple of days and came to no conclusion. The task
crashed after having left "itemChange" in the next execution call. As
mentioned running it in the debugger inside Eclipse did not result any
error message. Running it from the terminal it gave segmentation fault.
One problem disappeared when setting the flag ItemSendsGeometryChanges
as David suggested. Then I could move the objects again. However it
crashed on another operation. Again the segmentation fault. Comparing my
rather old code with the elasticnode example code I found that I had not
set the index method (setItemIndexMethod) to NoIndex. Adding the flag,
did the trick.
Maybe this was a default before?
Heinz
PS I attach the modified code of the elasticnodes example. Not sure
anymore where I took it from, but if I am not mistaken from the
riverbankcomputing domain.
On 09/05/2010 08:32 AM, Preisig, Heinz A wrote:
Thanks for the help. I shall modify the code and look at the example
too. I also decided to re-install. Shall report on results.
Cheers,
Heinz
On 09/04/2010 03:30 PM, David Boddie wrote:
On Sat Sep 4 08:00:06 BST 2010, Preisig, Heinz A wrote:
After upgrading Ubuntu 9.10 to 10.04 I encounter some problems with
running a graphics application I built last year. It uses the mechanisms
described in the example "elasticnodes". The two application represent a
graph, which when moving the nodes also update the location of the arcs.
In both cases the arcs are not updated. In fact the example does not
show the arcs when starting it. My application does show the arcs, but
it does not update. I dug for some hours in the code, but could not find
a problem. It seems it does not get into the "itemChange" method of the
"QGraphicsItem" class. Some manipulations resulted in abortion of the
task, which when running from within Eclipse did not produce an error
message. From the terminal I got an occasional segmentation fault.
I don't know why you are getting segmentation faults, but the problem with
the itemChange method is due to a change in behaviour in Qt 4.6. You now
need to call the item's setFlag method with the ItemSendsGeometryChanges
flag to get notifications when items move.
David
_______________________________________________
PyQt mailing [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
--
Heinz A Preisig
Professor of Process Systems Engineering Private:
Øvre Bakklandet 62 B, 7013 Trondheim, Norway
Department of Chemical Engineering
Norwegian University of Science and Technology
N -- 7491 Trondheim, Norway Tel direct: +47 735 92807
Tel mob: +47 9754 1334
e-mail: [email protected]
<mailto:[email protected]>
web: www.chemeng.ntnu.no\~preisig <http://www.chemeng.ntnu.no/%7Epreisig>
_______________________________________________
PyQt mailing list [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
--
Heinz A Preisig
Professor of Process Systems Engineering Private:
Øvre Bakklandet 62 B, 7013 Trondheim, Norway
Department of Chemical Engineering
Norwegian University of Science and Technology
N -- 7491 Trondheim, Norway Tel direct: +47 735 92807
Tel mob: +47 9754 1334
e-mail: [email protected] <mailto:[email protected]>
web: www.chemeng.ntnu.no\~preisig <http://www.chemeng.ntnu.no/%7Epreisig>
#!/usr/bin/env python
#############################################################################
##
## Copyright (C) 2006-2006 Trolltech ASA. All rights reserved.
##
## This file is part of the example classes of the Qt Toolkit.
##
## Licensees holding a valid Qt License Agreement may use this file in
## accordance with the rights, responsibilities and obligations
## contained therein. Please consult your licensing agreement or
## contact [email protected] if any conditions of this licensing
## agreement are not clear to you.
##
## Further information about Qt licensing is available at:
## http://www.trolltech.com/products/qt/licensing.html or by
## contacting [email protected].
##
## This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
## WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
##
#############################################################################
import sys
import math
from PyQt4 import QtCore, QtGui
class Edge(QtGui.QGraphicsItem):
Pi = math.pi
TwoPi = 2.0 * Pi
Type = QtGui.QGraphicsItem.UserType + 2
def __init__(self, sourceNode, destNode):
QtGui.QGraphicsItem.__init__(self)
self.arrowSize = 10.0
self.sourcePoint = QtCore.QPointF()
self.destPoint = QtCore.QPointF()
self.setAcceptedMouseButtons(QtCore.Qt.NoButton)
self.source = sourceNode
self.dest = destNode
self.source.addEdge(self)
self.dest.addEdge(self)
self.adjust()
def type(self):
return Edge.Type
def sourceNode(self):
return self.source
def setSourceNode(self, node):
self.source = node
self.adjust()
def destNode(self):
return self.dest
def setDestNode(self, node):
self.dest = node
self.adjust()
def adjust(self):
if not self.source or not self.dest:
return
line = QtCore.QLineF(self.mapFromItem(self.source, 0, 0), self.mapFromItem(self.dest, 0, 0))
length = line.length()
if length == 0.0:
return
edgeOffset = QtCore.QPointF((line.dx() * 10) / length, (line.dy() * 10) / length)
self.prepareGeometryChange()
self.sourcePoint = line.p1() + edgeOffset
self.destPoint = line.p2() - edgeOffset
def boundingRect(self):
if not self.source or not self.dest:
return QtCore.QRectF()
penWidth = 1
extra = (penWidth + self.arrowSize) / 2.0
return QtCore.QRectF(self.sourcePoint,
QtCore.QSizeF(self.destPoint.x() - self.sourcePoint.x(),
self.destPoint.y() - self.sourcePoint.y())).normalized().adjusted(-extra, -extra, extra, extra)
def paint(self, painter, option, widget):
if not self.source or not self.dest:
return
# Draw the line itself.
line = QtCore.QLineF(self.sourcePoint, self.destPoint)
if line.length() == 0.0:
return
painter.setPen(QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
painter.drawLine(line)
# Draw the arrows if there's enough room.
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = Edge.TwoPi - angle
sourceArrowP1 = self.sourcePoint + QtCore.QPointF(math.sin(angle + Edge.Pi / 3) * self.arrowSize,
math.cos(angle + Edge.Pi / 3) * self.arrowSize)
sourceArrowP2 = self.sourcePoint + QtCore.QPointF(math.sin(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize,
math.cos(angle + Edge.Pi - Edge.Pi / 3) * self.arrowSize);
destArrowP1 = self.destPoint + QtCore.QPointF(math.sin(angle - Edge.Pi / 3) * self.arrowSize,
math.cos(angle - Edge.Pi / 3) * self.arrowSize)
destArrowP2 = self.destPoint + QtCore.QPointF(math.sin(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize,
math.cos(angle - Edge.Pi + Edge.Pi / 3) * self.arrowSize)
painter.setBrush(QtCore.Qt.black)
painter.drawPolygon(QtGui.QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]))
painter.drawPolygon(QtGui.QPolygonF([line.p2(), destArrowP1, destArrowP2]))
class Node(QtGui.QGraphicsItem):
Type = QtGui.QGraphicsItem.UserType + 1
def __init__(self, graphWidget):
QtGui.QGraphicsItem.__init__(self)
self.graph = graphWidget
self.edgeList = []
self.newPos = QtCore.QPointF()
self.setFlag(QtGui.QGraphicsItem.ItemIsMovable)
self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges) # required > version 4.6
self.setZValue(1)
def type(self):
return Node.Type
def addEdge(self, edge):
self.edgeList.append(edge)
edge.adjust()
def edges(self):
return self.edgeList
def calculateForces(self):
if not self.scene() or self.scene().mouseGrabberItem() is self:
self.newPos = self.pos()
return
# Sum up all forces pushing this item away.
xvel = 0.0
yvel = 0.0
for item in self.scene().items():
if not isinstance(item, Node):
continue
line = QtCore.QLineF(self.mapFromItem(item, 0, 0), QtCore.QPointF(0, 0))
dx = line.dx()
dy = line.dy()
l = 2.0 * (dx * dx + dy * dy)
if l > 0:
xvel += (dx * 150.0) / l
yvel += (dy * 150.0) / l
# Now subtract all forces pulling items together.
weight = (len(self.edgeList) + 1) * 10.0
for edge in self.edgeList:
if edge.sourceNode() is self:
pos = self.mapFromItem(edge.destNode(), 0, 0)
else:
pos = self.mapFromItem(edge.sourceNode(), 0, 0)
xvel += pos.x() / weight
yvel += pos.y() / weight
if QtCore.qAbs(xvel) < 0.1 and QtCore.qAbs(yvel) < 0.1:
xvel = yvel = 0.0
sceneRect = self.scene().sceneRect()
self.newPos = self.pos() + QtCore.QPointF(xvel, yvel)
self.newPos.setX(min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10))
self.newPos.setY(min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10))
def advance(self):
if self.newPos == self.pos():
return False
self.setPos(self.newPos)
return True
def boundingRect(self):
adjust = 2.0
return QtCore.QRectF(-10 - adjust, -10 - adjust,
23 + adjust, 23 + adjust)
def shape(self):
path = QtGui.QPainterPath()
path.addEllipse(-10, -10, 20, 20)
return path
def paint(self, painter, option, widget):
painter.setPen(QtCore.Qt.NoPen)
painter.setBrush(QtCore.Qt.darkGray)
painter.drawEllipse(-7, -7, 20, 20)
gradient = QtGui.QRadialGradient(-3, -3, 10)
if option.state & QtGui.QStyle.State_Sunken:
gradient.setCenter(3, 3)
gradient.setFocalPoint(3, 3)
gradient.setColorAt(1, QtGui.QColor(QtCore.Qt.yellow).light(120))
gradient.setColorAt(0, QtGui.QColor(QtCore.Qt.darkYellow).light(120))
else:
gradient.setColorAt(0, QtCore.Qt.yellow)
gradient.setColorAt(1, QtCore.Qt.darkYellow)
painter.setBrush(QtGui.QBrush(gradient))
painter.setPen(QtGui.QPen(QtCore.Qt.black, 0))
painter.drawEllipse(-10, -10, 20, 20)
def itemChange(self, change, value):
if change == QtGui.QGraphicsItem.ItemPositionChange:
for edge in self.edgeList:
edge.adjust()
self.graph.itemMoved()
return QtGui.QGraphicsItem.itemChange(self, change, value)
def mousePressEvent(self, event):
self.update()
QtGui.QGraphicsItem.mousePressEvent(self, event)
def mouseReleaseEvent(self, event):
self.update()
QtGui.QGraphicsItem.mouseReleaseEvent(self, event)
class GraphWidget(QtGui.QGraphicsView):
def __init__(self):
QtGui.QGraphicsView.__init__(self)
self.timerId = 0
scene = QtGui.QGraphicsScene(self)
scene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
scene.setSceneRect(-200, -200, 400, 400)
self.setScene(scene)
self.setCacheMode(QtGui.QGraphicsView.CacheBackground)
self.setRenderHint(QtGui.QPainter.Antialiasing)
self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
node1 = Node(self)
node2 = Node(self)
node3 = Node(self)
node4 = Node(self)
self.centerNode = Node(self)
node6 = Node(self)
node7 = Node(self)
node8 = Node(self)
node9 = Node(self)
scene.addItem(node1)
scene.addItem(node2)
scene.addItem(node3)
scene.addItem(node4)
scene.addItem(self.centerNode)
scene.addItem(node6)
scene.addItem(node7)
scene.addItem(node8)
scene.addItem(node9)
scene.addItem(Edge(node1, node2))
scene.addItem(Edge(node2, node3))
scene.addItem(Edge(node2, self.centerNode))
scene.addItem(Edge(node3, node6))
scene.addItem(Edge(node4, node1))
scene.addItem(Edge(node4, self.centerNode))
scene.addItem(Edge(self.centerNode, node6))
scene.addItem(Edge(self.centerNode, node8))
scene.addItem(Edge(node6, node9))
scene.addItem(Edge(node7, node4))
scene.addItem(Edge(node8, node7))
scene.addItem(Edge(node9, node8))
node1.setPos(-50, -50)
node2.setPos(0, -50)
node3.setPos(50, -50)
node4.setPos(-50, 0)
self.centerNode.setPos(0, 0)
node6.setPos(50, 0)
node7.setPos(-50, 50)
node8.setPos(0, 50)
node9.setPos(50, 50)
self.scale(0.8, 0.8)
self.setMinimumSize(400, 400)
self.setWindowTitle(self.tr("Elastic Nodes"))
def itemMoved(self):
if not self.timerId:
self.timerId = self.startTimer(1000 / 25)
def keyPressEvent(self, event):
key = event.key()
if key == QtCore.Qt.Key_Up:
self.centerNode.moveBy(0, -20)
elif key == QtCore.Qt.Key_Down:
self.centerNode.moveBy(0, 20)
elif key == QtCore.Qt.Key_Left:
self.centerNode.moveBy(-20, 0)
elif key == QtCore.Qt.Key_Right:
self.centerNode.moveBy(20, 0)
elif key == QtCore.Qt.Key_Plus:
self.scaleView(1.2)
elif key == QtCore.Qt.Key_Minus:
self.scaleView(1 / 1.2)
elif key == QtCore.Qt.Key_Space or key == QtCore.Qt.Key_Enter:
for item in self.scene().items():
if isinstance(item, Node):
item.setPos(-150 + QtCore.qrand() % 300, -150 + QtCore.qrand() % 300)
else:
QtGui.QGraphicsView.keyPressEvent(self, event)
def timerEvent(self, event):
nodes = [item for item in self.scene().items() if isinstance(item, Node)]
for node in nodes:
node.calculateForces()
itemsMoved = False
for node in nodes:
if node.advance():
itemsMoved = True
if not itemsMoved:
self.killTimer(self.timerId)
self.timerId = 0
def wheelEvent(self, event):
self.scaleView(math.pow(2.0, -event.delta() / 240.0))
def drawBackground(self, painter, rect):
# Shadow.
sceneRect = self.sceneRect()
rightShadow = QtCore.QRectF(sceneRect.right(), sceneRect.top() + 5, 5, sceneRect.height())
bottomShadow = QtCore.QRectF(sceneRect.left() + 5, sceneRect.bottom(), sceneRect.width(), 5)
if rightShadow.intersects(rect) or rightShadow.contains(rect):
painter.fillRect(rightShadow, QtCore.Qt.darkGray)
if bottomShadow.intersects(rect) or bottomShadow.contains(rect):
painter.fillRect(bottomShadow, QtCore.Qt.darkGray)
# Fill.
gradient = QtGui.QLinearGradient(sceneRect.topLeft(), sceneRect.bottomRight())
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, QtCore.Qt.lightGray)
painter.fillRect(rect.intersect(sceneRect), QtGui.QBrush(gradient))
painter.setBrush(QtCore.Qt.NoBrush)
painter.drawRect(sceneRect)
# Text.
textRect = QtCore.QRectF(sceneRect.left() + 4, sceneRect.top() + 4,
sceneRect.width() - 4, sceneRect.height() - 4)
message = self.tr("Click and drag the nodes around, and zoom with the "
"mouse wheel or the '+' and '-' keys")
font = painter.font()
font.setBold(True)
font.setPointSize(14)
painter.setFont(font)
painter.setPen(QtCore.Qt.lightGray)
painter.drawText(textRect.translated(2, 2), message)
painter.setPen(QtCore.Qt.black)
painter.drawText(textRect, message)
def scaleView(self, scaleFactor):
factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()
if factor < 0.07 or factor > 100:
return
self.scale(scaleFactor, scaleFactor)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
QtCore.qsrand(QtCore.QTime(0,0,0).secsTo(QtCore.QTime.currentTime()))
widget = GraphWidget()
widget.show()
sys.exit(app.exec_())
_______________________________________________
PyQt mailing list [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt