#!/usr/bin/env python # The Python version of qwt-*/examples/dials # for debugging, requires: python configure.py --trace ... if 0: import sip sip.settracemask(0x3f) import math import random import sys from PyQt4 import Qt import PyQt4.Qwt5 as Qwt def enumList(enum, sentinel): ''' ''' return [enum(i) for i in range(sentinel)] colorGroupList = enumList( Qt.QPalette.ColorGroup, Qt.QPalette.NColorGroups) colorRoleList = enumList( Qt.QPalette.ColorRole, Qt.QPalette.NColorRoles) handList = enumList( Qwt.QwtAnalogClock.Hand, Qwt.QwtAnalogClock.NHands) class CompassGrid(Qt.QFrame): def __init__(self, *args): Qt.QFrame.__init__(self, *args) palette = self.palette() palette.setColor(self.backgroundRole(), Qt.Qt.gray) self.setPalette(palette) layout = Qt.QGridLayout(self) for i in xrange(6): layout.addWidget(self.__createCompass(i), i / 3, i % 3) for i in xrange(layout.columnCount()): layout.setColumnStretch(i, 1) # __init__() def __createCompass(self, pos): palette = Qt.QPalette() for colorRole in colorRoleList: palette.setColor(colorRole, Qt.QColor()) palette.setColor( Qt.QPalette.Base, self.palette().color(self.backgroundRole()).light(120)) palette.setColor( Qt.QPalette.Foreground, palette.color(Qt.QPalette.Base)) compass = Qwt.QwtCompass() compass.setLineWidth(4) if pos < 3: compass.setFrameShadow(Qwt.QwtCompass.Sunken) else: compass.setFrameShadow(Qwt.QwtCompass.Raised) if pos == 0: compass.setMode(Qwt.QwtCompass.RotateScale) rose = Qwt.QwtSimpleCompassRose(16, 2) rose.setWidth(0.15) compass.setRose(rose) elif pos == 1: compass.setLabelMap({0.0: "N", 90.0: "E", 180.0: "S", 270.0: "W"}) rose = Qwt.QwtSimpleCompassRose(4, 1) compass.setRose(rose) compass.setNeedle( Qwt.QwtCompassWindArrow(Qwt.QwtCompassWindArrow.Style2)) compass.setValue(60.0) elif pos == 2: palette.setColor(Qt.QPalette.Base, Qt.Qt.darkBlue) palette.setColor(Qt.QPalette.Foreground, Qt.QColor(Qt.Qt.darkBlue).dark(120)) palette.setColor(Qt.QPalette.Text, Qt.Qt.white) compass.setScaleTicks(1, 1, 3) compass.setScale(36, 5, 0) compass.setNeedle(Qwt.QwtCompassMagnetNeedle( Qwt.QwtCompassMagnetNeedle.ThinStyle)) compass.setValue(220.0) elif pos == 3: palette.setColor(Qt.QPalette.Base, self.palette().color(self.backgroundRole())) palette.setColor(Qt.QPalette.Foreground, Qt.Qt.blue) compass.setLineWidth(0) compass.setScaleOptions(Qwt.QwtDial.ScaleBackbone | Qwt.QwtDial.ScaleTicks | Qwt.QwtDial.ScaleLabel) compass.setScaleTicks(0, 0, 3) compass.setLabelMap({ 0.0: '0', 60.0: '60', 120.0: '120', 180.0: '180', 240.0: '240', 320.0: '320'}) compass.setScale(36, 5, 0) compass.setNeedle(Qwt.QwtDialSimpleNeedle( Qwt.QwtDialSimpleNeedle.Ray, False, Qt.Qt.white)) compass.setOrigin(220.0) compass.setValue(20.0) elif pos == 4: compass.setScaleTicks(0, 0, 3) compass.setNeedle(Qwt.QwtCompassMagnetNeedle( Qwt.QwtCompassMagnetNeedle.TriangleStyle, Qt.Qt.white, Qt.Qt.red)) compass.setValue(220.0) elif pos == 5: palette.setColor(Qt.QPalette.Foreground, Qt.Qt.black) compass.setNeedle(Qwt.QwtDialSimpleNeedle( Qwt.QwtDialSimpleNeedle.Ray, False, Qt.Qt.yellow)) compass.setValue(315.0) newPalette = compass.palette() for colorRole in colorRoleList: if palette.color(colorRole).isValid(): for colorGroup in colorGroupList: newPalette.setColor( colorGroup, colorRole, palette.color(colorRole)) for colorGroup in colorGroupList: light = newPalette.color( colorGroup, Qt.QPalette.Base).light(170) dark = newPalette.color( colorGroup, Qt.QPalette.Base).dark(170) if compass.frameShadow() == Qwt.QwtDial.Raised: mid = newPalette.color( colorGroup, Qt.QPalette.Base).dark(110) else: mid = newPalette.color( colorGroup, Qt.QPalette.Base).light(110) newPalette.setColor(colorGroup, Qt.QPalette.Dark, dark) newPalette.setColor(colorGroup, Qt.QPalette.Mid, mid) newPalette.setColor(colorGroup, Qt.QPalette.Light, light) compass.setPalette(newPalette) return compass # __createCompass() # class CompassGrid class SpeedoMeter(Qwt.QwtDial): def __init__(self, *args): Qwt.QwtDial.__init__(self, *args) self.__label = 'km/h' self.setWrapping(False) self.setReadOnly(True) self.setOrigin(135.0) self.setScaleArc(0.0, 270.0) self.setNeedle(Qwt.QwtDialSimpleNeedle( Qwt.QwtDialSimpleNeedle.Arrow, True, Qt.QColor(Qt.Qt.red), Qt.QColor(Qt.Qt.gray).light(130))) self.setScaleOptions(Qwt.QwtDial.ScaleTicks | Qwt.QwtDial.ScaleLabel) self.setScaleTicks(0, 4, 8) # __init__() def setLabel(self, text): self.__label = text self.update() # setLabel() def label(self): return self.__label # label() def drawScaleContents(self, painter, center, radius): rect = Qt.QRect(0, 0, 2 * radius, 2 * radius - 10) rect.moveCenter(center) painter.setPen(self.palette().color(Qt.QPalette.Text)) painter.drawText( rect, Qt.Qt.AlignBottom | Qt.Qt.AlignHCenter, self.__label) # drawScaleContents # class SpeedoMeter class AttitudeIndicatorNeedle(Qwt.QwtDialNeedle): def __init__(self, color): Qwt.QwtDialNeedle.__init__(self) palette = Qt.QPalette() for colourGroup in colorGroupList: palette.setColor(colourGroup, Qt.QPalette.Text, color) self.setPalette(palette) # __init__() def draw(self, painter, center, length, direction, cg): direction *= math.pi / 180.0 triangleSize = int(round(length * 0.1)) painter.save() p0 = Qt.QPoint(center.x() + 1, center.y() + 1) p1 = Qwt.qwtPolar2Pos(p0, length - 2 * triangleSize - 2, direction) pa = Qt.QPolygon([ Qwt.qwtPolar2Pos(p1, 2 * triangleSize, direction), Qwt.qwtPolar2Pos(p1, triangleSize, direction + math.pi/2), Qwt.qwtPolar2Pos(p1, triangleSize, direction - math.pi/2), ]) color = self.palette().color(cg, Qt.QPalette.Text) painter.setBrush(color) painter.drawPolygon(pa) painter.setPen(Qt.QPen(color, 3)) painter.drawLine( Qwt.qwtPolar2Pos(p0, length - 2, direction + math.pi/2), Qwt.qwtPolar2Pos(p0, length - 2, direction - math.pi/2)) painter.restore() # draw() # class AttitudeIndicatorNeedle class AttitudeIndicator(Qwt.QwtDial): def __init__(self, *args): Qwt.QwtDial.__init__(self, *args) self.__gradient = 0.0 self.setMode(Qwt.QwtDial.RotateScale) self.setWrapping(True) self.setOrigin(270.0) self.setScaleOptions(Qwt.QwtDial.ScaleTicks) self.setScale(0, 0, 30.0) self.setNeedle(AttitudeIndicatorNeedle( self.palette().color(Qt.QPalette.Text))) # __init__() def angle(self): return self.value() # angle() def setAngle(self, angle): self.setValue(angle) # setAngle() def gradient(self): return self.__gradient # gradient() def setGradient(self, gradient): self.__gradient = gradient # setGradient() def keyPressEvent(self, event): if event.key() == Qt.Qt.Key_Plus: self.setGradient(self.gradient() + 0.05) elif event.key() == Qt.Qt.Key_Minus: self.setGradient(self.gradient() - 0.05) else: Qwt.QwtDial.keyPressEvent(self, event) # keyPressEvent() def drawScale(self, painter, center, radius, origin, minArc, maxArc): dir = (360.0 - origin) * math.pi / 180.0 offset = 4 p0 = Qwt.qwtPolar2Pos(center, offset, dir + math.pi) w = self.contentsRect().width() # clip region to swallow 180 - 360 degrees pa = [] pa.append(Qwt.qwtPolar2Pos(p0, w, dir - math.pi/2)) pa.append(Qwt.qwtPolar2Pos(pa[-1], 2 * w, dir + math.pi/2)) pa.append(Qwt.qwtPolar2Pos(pa[-1], w, dir)) pa.append(Qwt.qwtPolar2Pos(pa[-1], 2 * w, dir - math.pi/2)) painter.save() painter.setClipRegion(Qt.QRegion(Qt.QPolygon(pa))) Qwt.QwtDial.drawScale( self, painter, center, radius, origin, minArc, maxArc) painter.restore() # drawScale() def drawScaleContents(self, painter, center, radius): dir = 360 - int(round(self.origin() - self.value())) arc = 90 + int(round(self.gradient() * 90)) skyColor = Qt.QColor(38, 151, 221) painter.save() painter.setBrush(skyColor) painter.drawChord( self.scaleContentsRect(), (dir - arc)*16, 2*arc*16) painter.restore() # drawScaleContents() # class AttitudeIndicator class CockpitGrid(Qt.QFrame): def __init__(self, *args): Qt.QFrame.__init__(self, *args) self.setPalette( self.__colorTheme(Qt.QColor(Qt.Qt.darkGray).dark(150))) layout = Qt.QGridLayout(self) for i in xrange(3): layout.addWidget(self.__createDial(i), 0, i) for i in xrange(layout.columnCount()): layout.setColumnStretch(i, 1) self.__speed_offset = 0.8 self.__angle_offset = 0.05 self.__gradient_offset = 0.005 # __init__() def __colorTheme(self, base): background = base.dark(150) foreground = base.dark(200) mid = base.dark(110) dark = base.dark(170) light = base.light(170) text = foreground.light(800) palette = Qt.QPalette() for colorGroup in colorGroupList: palette.setColor(colorGroup, Qt.QPalette.Base, base) palette.setColor(colorGroup, Qt.QPalette.Background, background) palette.setColor(colorGroup, Qt.QPalette.Mid, mid) palette.setColor(colorGroup, Qt.QPalette.Light, light) palette.setColor(colorGroup, Qt.QPalette.Dark, dark) palette.setColor(colorGroup, Qt.QPalette.Text, text) palette.setColor(colorGroup, Qt.QPalette.Foreground, foreground) return palette # __colorTheme() def __createDial(self, pos): dial = None if pos == 0: self.__clock = Qwt.QwtAnalogClock(self) knobColor = Qt.QColor(Qt.Qt.gray).light(130) for h in handList: handColor = Qt.QColor(Qt.Qt.gray).light(150) width = 8 if h == Qwt.QwtAnalogClock.SecondHand: handColor = Qt.Qt.gray width = 5 hand = Qwt.QwtDialSimpleNeedle( Qwt.QwtDialSimpleNeedle.Arrow, True, handColor, knobColor) hand.setWidth(width) self.__clock.setHand(h, hand) timer = Qt.QTimer(self.__clock) timer.connect(timer, Qt.SIGNAL('timeout()'), self.__clock.setCurrentTime) timer.start(1000) dial = self.__clock elif pos == 1: self.__speedo = SpeedoMeter(self) self.__speedo.setRange(0.0, 240.0) self.__speedo.setScale(-1, 2, 20) timer = Qt.QTimer(self.__speedo) timer.connect(timer, Qt.SIGNAL('timeout()'), self.changeSpeed) timer.start(50) dial = self.__speedo elif pos == 2: self.__ai = AttitudeIndicator(self) gradientTimer = Qt.QTimer(self.__ai) gradientTimer.connect(gradientTimer, Qt.SIGNAL('timeout()'), self.changeGradient) gradientTimer.start(100) angleTimer = Qt.QTimer(self.__ai) angleTimer.connect( angleTimer, Qt.SIGNAL('timeout()'), self.changeAngle) angleTimer.start(100) dial = self.__ai if dial: dial.setReadOnly(True) dial.scaleDraw().setPenWidth(3) dial.setLineWidth(4) dial.setFrameShadow(Qwt.QwtDial.Sunken) return dial # __createDial() def changeSpeed(self): speed = self.__speedo.value() if ((speed < 40.0 and self.__speed_offset < 0.0) or (speed > 200.0 and self.__speed_offset > 0.0)): self.__speed_offset = -self.__speed_offset r = random.randrange(12) if r < 6: self.__speedo.setValue(speed + r*self.__speed_offset) # changeSpeed() def changeAngle(self): angle = self.__ai.angle() if angle > 180.0: angle -= 360.0 if ((angle < -7.0 and self.__angle_offset < 0.0 ) or (angle > 7.0 and self.__angle_offset > 0.0)): self.__angle_offset = -self.__angle_offset self.__ai.setAngle(angle + self.__angle_offset) # changeAngle() def changeGradient(self): gradient = self.__ai.gradient() if ((gradient < -0.05 and self.__gradient_offset < 0.0 ) or (gradient > 0.05 and self.__gradient_offset > 0.0)): self.__gradient_offset = -self.__gradient_offset self.__ai.setGradient(gradient + self.__gradient_offset) # changeGradient() # class CockpitGrid def make(): demo = Qt.QTabWidget() demo.addTab(CompassGrid(), "Compass") demo.addTab(CockpitGrid(), "Cockpit") demo.show() return demo # make() def main(args): app = Qt.QApplication(args) demo = make() sys.exit(app.exec_()) # main() # Admire! if __name__ == '__main__': if 'settracemask' in sys.argv: # for debugging, requires: python configure.py --trace ... import sip sip.settracemask(0x3f) main(sys.argv) # Local Variables: *** # mode: python *** # End: ***