#!/usr/bin/env python
# The Python version of qwt-*/examples/event_filter
import sys
from PyQt4 import Qt
import PyQt4.Qwt5 as Qwt
from PyQt4.Qwt5.anynumpy import *
class ColorBar(Qt.QWidget):
def __init__(self, orientation, *args):
Qt.QWidget.__init__(self, *args)
self.__orientation = orientation
self.__light = Qt.QColor(Qt.Qt.white)
self.__dark = Qt.QColor(Qt.Qt.black)
self.setCursor(Qt.Qt.PointingHandCursor)
# __init__()
def setOrientation(self, orientation):
self.__orientation = orientation
self.update()
# setOrientation()
def orientation(self):
return self.__orientation
# orientation()
def setRange(self, light, dark):
self.__light = light
self.__dark = dark
self.update()
# setRange()
def setLight(self, color):
self.__light = color
self.update()
# setLight()
def setDark(self, color):
self.__dark = color
self.update()
# setDark()
def light(self):
return self.__light
# light()
def dark(self):
return self.__dark
# dark()
def mousePressEvent(self, event):
if event.button() == Qt.Qt.LeftButton:
pm = Qt.QPixmap.grabWidget(self)
color = Qt.QColor()
color.setRgb(pm.toImage().pixel(event.x(), event.y()))
self.emit(Qt.SIGNAL("colorSelected"), color)
event.accept()
# mousePressEvent()
def paintEvent(self, _):
painter = Qt.QPainter(self)
self.drawColorBar(painter, self.rect())
# paintEvent()
def drawColorBar(self, painter, rect):
h1, s1, v1, _ = self.__light.getHsv()
h2, s2, v2, _ = self.__dark.getHsv()
painter.save()
painter.setClipRect(rect)
painter.setClipping(True)
painter.fillRect(rect, Qt.QBrush(self.__dark))
sectionSize = 2
if (self.__orientation == Qt.Qt.Horizontal):
numIntervalls = rect.width()/sectionSize
else:
numIntervalls = rect.height()/sectionSize
section = Qt.QRect()
for i in range(numIntervalls):
if self.__orientation == Qt.Qt.Horizontal:
section.setRect(rect.x() + i*sectionSize, rect.y(),
sectionSize, rect.heigh())
else:
section.setRect(rect.x(), rect.y() + i*sectionSize,
rect.width(), sectionSize)
ratio = float(i)/float(numIntervalls)
color = Qt.QColor()
color.setHsv(h1 + int(ratio*(h2-h1) + 0.5),
s1 + int(ratio*(s2-s1) + 0.5),
v1 + int(ratio*(v2-v1) + 0.5))
painter.fillRect(section, color)
painter.restore()
# drawColorBar()
# class ColorBar
class Plot(Qwt.QwtPlot):
def __init__(self, *args):
Qwt.QwtPlot.__init__(self, *args)
self.setTitle("Interactive Plot")
self.setCanvasColor(Qt.Qt.darkCyan)
grid = Qwt.QwtPlotGrid()
grid.attach(self)
grid.setMajPen(Qt.QPen(Qt.Qt.white, 0, Qt.Qt.DotLine))
self.setAxisScale(Qwt.QwtPlot.xBottom, 0.0, 100.0)
self.setAxisScale(Qwt.QwtPlot.yLeft, 0.0, 100.0)
# Avoid jumping when label with 3 digits
# appear/disappear when scrolling vertically
scaleDraw = self.axisScaleDraw(Qwt.QwtPlot.yLeft)
scaleDraw.setMinimumExtent(scaleDraw.extent(
Qt.QPen(), self.axisWidget(Qwt.QwtPlot.yLeft).font()))
self.plotLayout().setAlignCanvasToScales(True)
self.__insertCurve(Qt.Qt.Vertical, Qt.Qt.blue, 30.0)
self.__insertCurve(Qt.Qt.Vertical, Qt.Qt.magenta, 70.0)
self.__insertCurve(Qt.Qt.Horizontal, Qt.Qt.yellow, 30.0)
self.__insertCurve(Qt.Qt.Horizontal, Qt.Qt.white, 70.0)
self.replot()
scaleWidget = self.axisWidget(Qwt.QwtPlot.yLeft)
scaleWidget.setMargin(10)
self.__colorBar = ColorBar(Qt.Qt.Vertical, scaleWidget)
self.__colorBar.setRange(
Qt.QColor(Qt.Qt.red), Qt.QColor(Qt.Qt.darkBlue))
self.__colorBar.setFocusPolicy(Qt.Qt.TabFocus)
self.connect(self.__colorBar,
Qt.SIGNAL('colorSelected'),
self.setCanvasColor)
# we need the resize events, to lay out the color bar
scaleWidget.installEventFilter(self)
self.__wheel = Qwt.QwtWheel(self.canvas())
self.__wheel.setOrientation(Qt.Qt.Vertical)
self.__wheel.setRange(-100, 100)
self.__wheel.setValue(0.0)
self.__wheel.setMass(0.2)
self.__wheel.setTotalAngle(4 * 360.0)
self.connect(self.__wheel,
Qt.SIGNAL('valueChanged(double)'),
self.scrollLeftAxis)
# we need the resize events, to lay out the wheel
self.canvas().installEventFilter(self)
scaleWidget.setWhatsThis(
'Selecting a value at the scale will insert a new curve.')
self.__colorBar.setWhatsThis(
'Selecting a color will change the background of the plot.')
self.__wheel.setWhatsThis(
'With the wheel you can move the visible area.')
self.axisWidget(Qwt.QwtPlot.xBottom).setWhatsThis(
'Selecting a value at the scale will insert a new curve.')
# __init__()
def setCanvasColor(self, color):
self.setCanvasBackground(color)
self.replot()
# setCanvasColor()
def scrollLeftAxis(self, value):
self.setAxisScale(Qwt.QwtPlot.yLeft, value, value + 100)
self.replot()
# scrollLeftAxis()
def eventFilter(self, object, event):
if event.type() == Qt.QEvent.Resize:
size = event.size()
if object == self.axisWidget(Qwt.QwtPlot.yLeft):
margin = 2
x = size.width() - object.margin() + margin
w = object.margin() - 2 * margin
y = object.startBorderDist()
h = (size.height()
- object.startBorderDist() - object.endBorderDist())
self.__colorBar.setGeometry(x, y, w, h)
elif object == self.canvas():
w, h, margin = 16, 50, 2
r = object.contentsRect();
self.__wheel.setGeometry(
r.right() - margin - w, r.center().y() - h / 2, w, h)
return Qwt.QwtPlot.eventFilter(self, object, event)
# eventFilter()
def insertCurve(self, axis, base):
if axis == Qwt.QwtPlot.yLeft or axis == Qwt.QwtPlot.yRight:
o = Qt.Qt.Horizontal
else:
o = Qt.Qt.Vertical
self.__insertCurve(o, Qt.QColor(Qt.Qt.red), base)
self.replot()
# insertCurve()
def __insertCurve(self, orientation, color, base):
curve = Qwt.QwtPlotCurve()
curve.attach(self)
curve.setPen(Qt.QPen(color))
curve.setSymbol(Qwt.QwtSymbol(Qwt.QwtSymbol.Ellipse,
Qt.QBrush(Qt.Qt.gray),
Qt.QPen(color),
Qt.QSize(8, 8)))
fixed = base*ones(10, Float)
changing = arange(0, 95.0, 10.0, Float) + 5.0
if orientation == Qt.Qt.Horizontal:
curve.setData(changing, fixed)
else:
curve.setData(fixed, changing)
# __insertCurve()
# class Plot
class CanvasPicker(Qt.QObject):
def __init__(self, plot):
Qt.QObject.__init__(self, plot)
self.__selectedCurve = None
self.__selectedPoint = -1
self.__plot = plot
canvas = plot.canvas()
canvas.installEventFilter(self)
# We want the focus, but no focus rect.
# The selected point will be highlighted instead.
canvas.setFocusPolicy(Qt.Qt.StrongFocus)
canvas.setCursor(Qt.Qt.PointingHandCursor)
canvas.setFocusIndicator(Qwt.QwtPlotCanvas.ItemFocusIndicator)
canvas.setFocus()
canvas.setWhatsThis(
'All points can be moved using the left mouse button '
'or with these keys:\n\n'
'- Up: Select next curve\n'
'- Down: Select previous curve\n'
'- Left, "-": Select next point\n'
'- Right, "+": Select previous point\n'
'- 7, 8, 9, 4, 6, 1, 2, 3: Move selected point'
)
self.__shiftCurveCursor(True)
# __init__()
def event(self, event):
if event.type() == Qt.QEvent.User:
self.__showCursor(True)
return True
return Qt.QObject.event(event)
# event()
def eventFilter(self, object, event):
if event.type() == Qt.QEvent.FocusIn:
self.__showCursor(True)
if event.type() == Qt.QEvent.FocusOut:
self.__showCursor(False)
if event.type() == Qt.QEvent.Paint:
Qt.QApplication.postEvent(
self, Qt.QEvent(Qt.QEvent.User))
elif event.type() == Qt.QEvent.MouseButtonPress:
self.__select(event.pos())
return True
elif event.type() == Qt.QEvent.MouseMove:
self.__move(event.pos())
return True
if event.type() == Qt.QEvent.KeyPress:
delta = 5
key = event.key()
if key == Qt.Qt.Key_Up:
self.__shiftCurveCursor(True)
return True
elif key == Qt.Qt.Key_Down:
self.__shiftCurveCursor(False)
return True
elif key == Qt.Qt.Key_Right or key == Qt.Qt.Key_Plus:
if self.__selectedCurve:
self.__shiftPointCursor(True)
else:
self.__shiftCurveCursor(True)
return True
elif key == Qt.Qt.Key_Left or key == Qt.Qt.Key_Minus:
if self.__selectedCurve:
self.__shiftPointCursor(False)
else:
self.__shiftCurveCursor(True)
return True
if key == Qt.Qt.Key_1:
self.__moveBy(-delta, delta)
elif key == Qt.Qt.Key_2:
self.__moveBy(0, delta)
elif key == Qt.Qt.Key_3:
self.__moveBy(delta, delta)
elif key == Qt.Qt.Key_4:
self.__moveBy(-delta, 0)
elif key == Qt.Qt.Key_6:
self.__moveBy(delta, 0)
elif key == Qt.Qt.Key_7:
self.__moveBy(-delta, -delta)
elif key == Qt.Qt.Key_8:
self.__moveBy(0, -delta)
elif key == Qt.Qt.Key_9:
self.__moveBy(delta, -delta)
return Qwt.QwtPlot.eventFilter(self, object, event)
# eventFilter()
def __select(self, pos):
found, distance, point = None, 1e100, -1
for curve in self.__plot.itemList():
if isinstance(curve, Qwt.QwtPlotCurve):
i, d = curve.closestPoint(pos)
if d < distance:
found = curve
point = i
distance = d
self.__showCursor(False)
self.__selectedCurve = None
self.__selectedPoint = -1
if found and distance < 10:
self.__selectedCurve = found
self.__selectedPoint = point
self.__showCursor(True)
# __select()
def __moveBy(self, dx, dy):
if dx == 0 and dy == 0:
return
curve = self.__selectedCurve
if not curve:
return
x = self.__plot.transform(
curve.xAxis(), curve.x(self.__selectedPoint)) + dx
y = self.__plot.transform(
curve.yAxis(), curve.y(self.__selectedPoint)) + dy
self.__move(Qt.QPoint(x, y))
# __moveBy()
def __move(self, pos):
curve = self.__selectedCurve
if not curve:
return
xData = zeros(curve.dataSize(), Float)
yData = zeros(curve.dataSize(), Float)
for i in range(curve.dataSize()):
if i == self.__selectedPoint:
xData[i] = self.__plot.invTransform(curve.xAxis(), pos.x())
yData[i] = self.__plot.invTransform(curve.yAxis(), pos.y())
else:
xData[i] = curve.x(i)
yData[i] = curve.y(i)
curve.setData(xData, yData)
self.__plot.replot()
self.__showCursor(True)
# __move()
def __showCursor(self, showIt):
curve = self.__selectedCurve
if not curve:
return
# Use copy constructors to defeat the reference semantics.
symbol = Qwt.QwtSymbol(curve.symbol())
newSymbol = Qwt.QwtSymbol(symbol)
if showIt:
newSymbol.setBrush(symbol.brush().color().dark(150))
doReplot = self.__plot.autoReplot()
self.__plot.setAutoReplot(False)
curve.setSymbol(newSymbol)
curve.draw(self.__selectedPoint, self.__selectedPoint)
curve.setSymbol(symbol)
self.__plot.setAutoReplot(doReplot)
# __showCursor()
def __shiftCurveCursor(self, up):
curves = [curve for curve in self.__plot.itemList()
if isinstance(curve, Qwt.QwtPlotCurve)]
if not curves:
return
if self.__selectedCurve in curves:
index = curves.index(self.__selectedCurve)
if up:
index += 1
else:
index -= 1
# keep index within [0, len(curves))
index += len(curves)
index %= len(curves)
else:
index = 0
self.__showCursor(False)
self.__selectedPoint = 0
self.__selectedCurve = curves[index]
self.__showCursor(True)
# __shiftCurveCursor()
def __shiftPointCursor(self, up):
curve = self.__selectedCurve
if not curve:
return
if up:
index = self.__selectedPoint + 1
else:
index = self.__selectedPoint - 1
# keep index within [0, curve.dataSize())
index += curve.dataSize()
index %= curve.dataSize()
if index != self.__selectedPoint:
self.__showCursor(False)
self.__selectedPoint = index
self.__showCursor(True)
# __shiftPointCursor()
# class CanvasPicker
class ScalePicker(Qt.QObject):
def __init__(self, plot):
Qt.QObject.__init__(self, plot)
for i in range(Qwt.QwtPlot.axisCnt):
scaleWidget = plot.axisWidget(i)
if scaleWidget:
scaleWidget.installEventFilter(self)
# __init__()
def eventFilter(self, object, event):
if (event.type() == Qt.QEvent.MouseButtonPress):
self.__mouseClicked(object, event.pos())
return True
return Qt.QObject.eventFilter(self, object, event)
# eventFilter()
def __mouseClicked(self, scale, pos):
rect = self.__scaleRect(scale)
margin = 10
rect.setRect(rect.x() - margin,
rect.y() - margin,
rect.width() + 2 * margin,
rect.height() + 2 * margin)
if rect.contains(pos):
value = 0.0
axis = -1
sd = scale.scaleDraw()
if scale.alignment() == Qwt.QwtScaleDraw.LeftScale:
value = sd.map().invTransform(pos.y())
axis = Qwt.QwtPlot.yLeft
elif scale.alignment() == Qwt.QwtScaleDraw.RightScale:
value = sd.map().invTransform(pos.y())
axis = Qwt.QwtPlot.yRight
elif scale.alignment() == Qwt.QwtScaleDraw.BottomScale:
value = sd.map().invTransform(pos.x())
axis = Qwt.QwtPlot.xBottom
elif scale.alignment() == Qwt.QwtScaleDraw.TopScale:
value = sd.map().invTransform(pos.x())
axis = Qwt.QwtPlot.xBottom
self.emit(Qt.SIGNAL("clicked"), axis, value)
# __mouseClicked()
def __scaleRect(self, scale):
bld = scale.margin()
mjt = scale.scaleDraw().majTickLength()
sbd = scale.startBorderDist()
ebd = scale.endBorderDist()
if scale.alignment() == Qwt.QwtScaleDraw.LeftScale:
return Qt.QRect(scale.width() - bld - mjt, sbd,
mjt, scale.height() - sbd - ebd)
elif scale.alignment() == Qwt.QwtScaleDraw.RightScale:
return Qt.QRect(bld, sbd,mjt, scale.height() - sbd - ebd)
elif scale.alignment() == Qwt.QwtScaleDraw.BottomScale:
return Qt.QRect(sbd, bld, scale.width() - sbd - ebd, mjt)
elif scale.alignment() == Qwt.QwtScaleDraw.TopScale:
return Qt.QRect(sbd, scale.height() - bld - mjt,
scale.width() - sbd - ebd, mjt)
else:
return Qt.QRect()
# __scaleRect
# class ScalePicker
def make():
demo = Qt.QMainWindow()
toolBar = Qt.QToolBar(demo)
toolBar.addAction(Qt.QWhatsThis.createAction(toolBar))
demo.addToolBar(toolBar)
plot = Plot(demo)
demo.setCentralWidget(plot)
plot.setWhatsThis(
'An useless plot to demonstrate how to use event filtering.\n\n'
'You can click on the color bar, the scales or move the slider.\n'
'All points can be moved using the mouse or the keyboard.'
)
CanvasPicker(plot)
scalePicker = ScalePicker(plot)
Qt.QObject.connect(scalePicker,
Qt.SIGNAL("clicked"),
plot.insertCurve)
demo.resize(540, 400)
demo.show()
return demo
# make()
def main(args):
app = Qt.QApplication(args)
demo = make()
sys.exit(app.exec_())
# main()
# Admire!
if __name__ == '__main__':
main(sys.argv)
# Local Variables: ***
# mode: python ***
# End: ***
|