def setupUI(self): self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget self.openGLWidget.setGeometry(0, 0, self.sizeX, self.sizeY) self.openGLWidget.initializeGL() self.openGLWidget.resizeGL( self.sizeX, self.sizeY ) #Resize GL's knowledge of the window to match the physical size? self.openGLWidget.paintGL = self.paintGL #override the default function with my own? if self.opMode != 'show': self.filterSlider = QSlider(Qt.Vertical, self) self.filterSlider.setGeometry(self.sizeX + 10, int(self.sizeY / 2) - 100, 30, 200) self.filterSlider.valueChanged[int].connect(self.barFilter) self.limitDisplay = QLabel(self) self.limitDisplay.setGeometry(self.sizeX, int(self.sizeY / 2) - 130, 50, 30) self.limitDisplay.setAlignment(Qt.AlignCenter) self.limitDisplay.setText('-1') self.marchButton = QPushButton(self) self.marchButton.setGeometry(self.sizeX, int(self.sizeY / 2) - 160, 50, 30) self.marchButton.setText('March!') self.marchButton.clicked.connect(self.marchStep)
def __init__(self, programa): QOpenGLWidget.__init__(self) self.programa = programa self.desviacion_x = 0 self.desviacion_y = 0 self.desviacion_z = 0 self.theta = 405 self.phi = 45 self.zoom = 150 self.x = sin(radians(self.theta)) * cos(radians( self.phi)) + self.desviacion_x self.z = sin(radians(self.theta)) * sin(radians( self.phi)) + self.desviacion_z self.y = cos(radians(self.theta)) + self.desviacion_y # Vértices de los planos self.vertices_plano_vertical_arriba = ((500, 0, 500), (500, 0, 0), (-500, 0, 0), (-500, 0, 500)) self.vertices_plano_vertical_debajo = ((500, 0, 0), (-500, 0, 0), (-500, 0, -500), (500, 0, -500)) self.vertices_plano_horizontal_delante = ((500, 0, 0), (500, 500, 0), (-500, 500, 0), (-500, 0, 0)) self.vertices_plano_horizontal_detras = ((500, 0, 0), (500, -500, 0), (-500, -500, 0), (-500, 0, 0)) self.vertices_borde_plano_vertical = ((500, 0, 500), (-500, 0, 500), (-500, 0, -500), (500, 0, -500)) self.vertices_borde_plano_horizontal = ((500, 500, 0), (500, -500, 0), (-500, -500, 0), (-500, 500, 0)) self.ultima_posicion = QPoint() self.m = [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]
def resizeEvent(self, evento): # Mantiene una relación de aspecto cuadrada if self.width() > self.height(): self.resize(self.height(), self.height()) elif self.height() > self.width(): self.resize(self.width(), self.width()) QOpenGLWidget.resizeEvent(self, evento)
def __init__(self, parent, radius, quality): QOpenGLWidget.__init__(self, parent) self.__radius = radius self.__quality = quality self.__xRotation = 0 self.__yRotation = 0 self.__zRotation = 0 self.__lastPoint = QPoint()
def update(self): self._logger.debug('') self.update_model_view_projection_matrix() if IS_PYQT5: QOpenGLWidget.update(self) else: self.updateGL()
def initializeGL(self): QOpenGLWidget.makeCurrent(self.openGLWidget) gl.glEnable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthMask(1) gl.glDepthFunc(gl.GL_LEQUAL) self.object = gl.glGenLists(self.NLists) gl.glNewList(self.object, gl.GL_COMPILE) gl.glEndList()
def wheelEvent(self, evento): angulo = evento.angleDelta().y() if angulo < 0: self.zoom += 10 elif angulo > 0: self.zoom -= 10 if self.zoom < 10: self.zoom = 10 QOpenGLWidget.wheelEvent(self, evento)
def __init__(self, parent: QWidget = None): """ On initialization, we need to bind the Ctrl/command key to enable manipulation of the view. """ QGraphicsView.__init__(self, parent) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setRubberBandSelectionMode(Qt.IntersectsItemShape) self._no_drag = QGraphicsView.RubberBandDrag self._yes_drag = QGraphicsView.ScrollHandDrag # reset things that are state dependent self.clearGraphicsView() self._x0 = 0 self._y0 = 0 self._scale_size = 1.0 self._scale_limit_max = 16.0 # OLD 3.0 self._scale_limit_min = 0.21 self._scale_up_rate = 0.01 self._scale_down_rate = 0.01 self._scale_fit_factor = .5 # sets initial zoom level self._show_details = True self._last_scale_factor = 0.0 self.scene_root_item = None # the item to transform # Keyboard panning self._key_pan_delta_x = styles.PATH_BASE_WIDTH * 21 self._key_pan_delta_y = styles.PATH_HELIX_HEIGHT + styles.PATH_HELIX_PADDING / 2 # Modifier keys and buttons self._key_mod = Qt.Key_Control self._button_pan: Qt.MouseButtons = Qt.LeftButton self._button_pan_alt: Qt.MouseButtons = Qt.MidButton self._button_zoom: Qt.MouseButtons = Qt.RightButton self.toolbar = None # custom hack for the paint tool palette self._name = None # a ``SelectionItemGroup`` object when not ``None`` self._selection_lock = None self.setContextMenuPolicy(Qt.CustomContextMenu) if GL: self.is_GL = True # self.glwidget = QGLWidget(QGLFormat(QGL.SampleBuffers)) self.glwidget = QOpenGLWidget() # self.setupGL() self.gl = self.glwidget.context().versionFunctions() self.setViewport(self.glwidget) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # self.resetGL() else: self.is_GL = False self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate)
def update(self): self._logger.debug('') # if IS_QOpenGLWidget: self.makeCurrent() self.update_model_view_projection_matrix() if IS_QOpenGLWidget: QOpenGLWidget.update(self) else: self.updateGL()
def __init__(self, parent): QOpenGLWidget.__init__(self, parent) self.layers = [] self.colorpalette_regions = [(1, 1, 1), (1, 0.7, 0.7), (0.7, 1, 0.7), (0.7, 0.7, 1)] self.colorpalette_paths = [(0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)] self.dim = 2 self.zoom = 1.9 self.rotation = np.zeros(2) self.translation = np.array([-0.5, -0.5, 0])
def __init__(self, obj_path, parent=None): super().__init__(parent) surface_format = QSurfaceFormat() surface_format.setSamples(16) QOpenGLWidget.setFormat(self, surface_format) self.projection = QMatrix4x4() self.vertex_buf_offsets = [3, 3, 2] #position, normal, tex_coord self.vertex_buf_stride = sum(self.vertex_buf_offsets) self.obj_path = obj_path self.initialized = False
def __init__(self, parent, debug=False): QOpenGLWidget.__init__(self, parent) global debugger debugger = Debug(debug, 'OpenGLWidget') self.debug = debug self.viewerTab = parent self.notebook = parent.notebook self.setMinimumSize(640, 672) self.lightingOn = True self.diffuseMaterialFactor = 0.9 self.ambientMaterialFactor = 0.4 self.specularMaterialFactor = 0.7 self.glintMaterialFactor = 100.0 self.diffuseLightFactor = 0.8 self.ambientLightFactor = 0.6 self.specularLightFactor = 1.0 self.linearAttenuation = True self.image_size = 15.0 self.white = np.array([1.0, 1.0, 1.0, 1.0]) self.spheres = deque() self.cylinders = deque() self.arrows = deque() self.current_phase = 0 self.phase_direction = 1 self.number_of_phases = 1 self.sphere_slices = 20 self.sphere_stacks = 20 self.cylinder_slices = 8 self.cylinder_stacks = 2 self.timer = None self.show_arrows = True self.timer_interval = 60 self.my_width = None self.my_height = None self.background_colour = None self.show_full_screen = False self.writer = None self.rotation_centre = np.array([0.0, 0.0, 0.0]) self.matrix = np.eye(4, dtype=np.float32) self.light_switches = None d = 200.0 self.light_positions = [[-d, d, d], [d, -d, d], [-d, -d, d], [d, d, d], [-d, d, -d], [d, -d, -d], [-d, -d, -d], [d, d, -d]] self.lights = [ GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHT3, GL_LIGHT4, GL_LIGHT5, GL_LIGHT6, GL_LIGHT7 ]
def __init__(self, parent=None): super().__init__(parent) if USE_OPENGL and not isRemoteSession(): fmt = QSurfaceFormat() fmt.setSamples(4) self.setViewport(QOpenGLWidget()) self.viewport().setFormat(fmt) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) else: self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) layout = QFormLayout(self) layout.setContentsMargins(0, 0, 6, 0) layout.setFormAlignment(Qt.AlignRight | Qt.AlignBottom) self.minimap = MiniMapGraphicsView(self) layout.addWidget(self.minimap) self.setLayout(layout) self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setOptimizationFlags(QGraphicsView.DontSavePainterState | QGraphicsView.DontAdjustForAntialiasing) self.setStyleSheet( """NetworkView:focus { border: 3px solid palette(highlight); }""")
def __init__(self, camera, homography_transform, stimulus_widget, parent=None): super().__init__(parent) self._camera = camera self._homography_transform = homography_transform self.homography_points = [] self.stimulus_widget = stimulus_widget current_directory = os.path.dirname(__file__) relative_location = '../views/StimulusWindowHomographySetup.ui' path = os.path.join(current_directory, relative_location) uic.loadUi(path, self) self.exposureDoubleSpinBox.device = camera self.gainDoubleSpinBox.device = camera self.cameraFrameGraphicsView.setViewport(QOpenGLWidget()) self.camera_scene = self.cameraFrameGraphicsView.scene() self.camera_display = QGraphicsPixmapItem() self.camera_scene.addItem(self.camera_display) self.camera_display.setPos(0, 0) self.camera_scene.installEventFilter(ClickCapture(self)) self.first_shown = True
def __init__(self, parent=None): super().__init__(parent) self.setViewport(QOpenGLWidget()) scene = QGraphicsScene() scene.setBackgroundBrush(Qt.gray) self.setScene(scene) self.setMouseTracking(True)
def paintGL(self): QOpenGLWidget.makeCurrent(self.openGLWidget) ambient = [1.0, 1.0, 1.0, 0.04] lightpos = [1.0, 10.0, 100.0] gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, ambient) # Определяем текущую модель освещения gl.glEnable(gl.GL_LIGHTING) gl.glEnable(gl.GL_LIGHT0) gl.glEnable(gl.GL_DEPTH_TEST) gl.glEnable(gl.GL_COLOR_MATERIAL) gl.glLightfv(gl.GL_LIGHT0, gl.GL_POSITION, lightpos) # Определяем положение источника света try: self.prepere_scene() if self.active: self.prepare_orientation() if self.ViewAtoms: gl.glCallList(self.object) # atoms if self.CanSearch: self.get_atom_on_screen() if self.ViewBonds and (len(self.MainModel.bonds) > 0): gl.glCallList(self.object + 2) # find_bonds_exact if self.ViewVoronoi: gl.glCallList(self.object + 1) # Voronoi if self.ViewBox: gl.glCallList(self.object + 3) # lattice_parameters_abc_angles if self.ViewSurface: gl.glCallList(self.object + 4) # Surface if self.ViewContour: gl.glCallList(self.object + 5) # Contour if self.ViewContourFill: gl.glCallList(self.object + 6) # ContourFill if self.ViewAxes: gl.glCallList(self.object + 7) # Axes except Exception as exc: print(exc) pass
def __init__(self, scene): super(self.__class__, self).__init__(scene) self._scene = scene self.setViewport(QOpenGLWidget()) self.setDragMode(QGraphicsView.ScrollHandDrag) self.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio) self._scene.get_sprites().set_scale(self.transform().m11()) self.update()
def __init__(self, obj_path, parent=None): super().__init__(parent) surface_format = QSurfaceFormat() surface_format.setSamples(16) QOpenGLWidget.setFormat(self, surface_format) self.projection = QMatrix4x4() self.vertex_buf_offsets = [3, 3, 2] # position, normal, tex_coord self.vertex_buf_stride = sum(self.vertex_buf_offsets) self.obj_path = obj_path self.initialized = False if not has_libGL: get_main_window().show_status( 'OpenGL library not found. Disabling 3D view.')
def __init__(self, mode): super(mainWindow, self).__init__() self.setGeometry(0, 0, 500, 500) self.openGLWidget = QOpenGLWidget(self) self.openGLWidget.setGeometry(0, 0, 500, 500) if mode == 'unsafe': self.shader = _shader(self, self.openGLWidget) self.shader.resize(500, 500) #self.cube1 = cube((0, 0, 0)) #self.cube2 = cube((1, 0, 0)) #self.cube3 = cube((0, 0, 1)) #self.shader.addShapes(self.cube1, self.cube2, self.cube3) #self.shader.navigate(vVal = -45) #self.shader.update() else: with shaderManager(self, self.openGLWidget) as shader: self.shader = shader self.shader.resize(500, 500)
def toggleOpenGL(self): vp = QWidget() if self.openGlButton.isChecked(): fmt = QSurfaceFormat() fmt.setSamples(8) vp = QOpenGLWidget() vp.setFormat(fmt) self.graphicsView.setViewport(vp)
def __init__(self, parent: QWidget = None): """ On initialization, we need to bind the Ctrl/command key to enable manipulation of the view. """ QGraphicsView.__init__(self, parent) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setRubberBandSelectionMode(Qt.IntersectsItemShape) self._no_drag = QGraphicsView.RubberBandDrag self._yes_drag = QGraphicsView.ScrollHandDrag # reset things that are state dependent self.clearGraphicsView() self._x0 = 0 self._y0 = 0 self._scale_size = 1.0 self._scale_limit_max = 16.0 # OLD 3.0 self._scale_limit_min = 0.21 self._scale_up_rate = 0.01 self._scale_down_rate = 0.01 self._scale_fit_factor = .5 # sets initial zoom level self._show_details = True self._last_scale_factor = 0.0 self.scene_root_item = None # the item to transform # Keyboard panning self._key_pan_delta_x = styles.PATH_BASE_WIDTH * 21 self._key_pan_delta_y = styles.PATH_HELIX_HEIGHT + styles.PATH_HELIX_PADDING/2 # Modifier keys and buttons self._key_mod = Qt.Key_Control self._button_pan: Qt.MouseButtons = Qt.LeftButton self._button_pan_alt: Qt.MouseButtons = Qt.MidButton self._button_zoom: Qt.MouseButtons = Qt.RightButton self.toolbar = None # custom hack for the paint tool palette self._name = None # a ``SelectionItemGroup`` object when not ``None`` self._selection_lock = None self.setContextMenuPolicy(Qt.CustomContextMenu) if GL: self.is_GL = True # self.glwidget = QGLWidget(QGLFormat(QGL.SampleBuffers)) self.glwidget = QOpenGLWidget() # self.setupGL() self.gl = self.glwidget.context().versionFunctions() self.setViewport(self.glwidget) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # self.resetGL() else: self.is_GL = False self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate)
def __init__(self, parent): QOpenGLWidget.__init__(self, parent=parent) # Adding samples format = QSurfaceFormat() format.setSamples(8) self.setFormat(format) self.programLocations: Dict[str, GLuint] self.view: View = View() self.functionModel = FunctionModel(2) self.axesModel = AxisModel() self.evalPointsModel = EvalPointsModel() self.evalLinesModel = EvalLinesModel() self.userModels = [] self.locations = {} self.screenView = None self.mouse: List[int] = None self.setMouseTracking(True)
def Setup(self): self.setWindowTitle("Thwacker") self.setWindowIcon(QIcon()) self.setMinimumSize(QSize(750,500)) #ContentSections self.Content = QGroupBox() self.ContentLayout = QGridLayout() # ToolBar ToolsToolBar = QToolBar('Tools') self.Tools = self.addToolBar(Qt.LeftToolBarArea,ToolsToolBar) #OpenGl self.GlViewport = QOpenGLWidget() self.GlViewport.initializeGL() self.GlViewport.paintGL = self.paintGL self.GlViewport.initializeGL = self.initializeGL self._glTimer = QBasicTimer() self._glTimer.start(1000/60, self) self.VMFVerts = [] self.ReadVmf('./test.vmf') self.ContentLayout.addWidget(self.GlViewport,0,0) gluPerspective(45, self.width()/self.height(), 0.1, 50) self.Triangle = self.VMFVerts self.Indices = [] ; for i in range(len(self.VMFVerts)): self.Indices.append(i) self.Content.setLayout(self.ContentLayout) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.setCentralWidget(self.Content) self.showMaximized() self.update()
def __init__(self, parent, samplerate, duration, texsize, moreUniforms={}): QOpenGLWidget.__init__(self, parent) self.move(10000., 1000.) self.program = 0 self.iSampleRateLocation = 0 self.iBlockOffsetLocation = 0 self.hasShader = False self.duration = duration self.samplerate = samplerate self.texsize = texsize self.blocksize = self.texsize * self.texsize self.nsamples = self.duration * self.samplerate # it was *2 self.nblocks = int(ceil(float(self.nsamples) / float(self.blocksize))) self.nsamples_real = self.nblocks * self.blocksize # this too was *2 self.duration_real = float(self.nsamples_real) / float(self.samplerate) self.music = None self.floatmusic = None self.moreUniforms = moreUniforms self.sequence_texture_handle = None self.sequence_texture = None self.sequence_texture_size = None self.setTextureFormat(GL_RGBA)
def keyPressEvent(self, evento): if evento.key() == Qt.Key_W: self.theta -= 1 elif evento.key() == Qt.Key_A: self.phi -= 1 elif evento.key() == Qt.Key_S: self.theta += 1 elif evento.key() == Qt.Key_D: self.phi += 1 elif evento.key() == Qt.Key_Q: self.desviacion_z += 1 elif evento.key() == Qt.Key_E: self.desviacion_z -= 1 elif evento.key() == Qt.Key_Left: self.desviacion_x += 1 elif evento.key() == Qt.Key_Up: self.desviacion_y += 1 elif evento.key() == Qt.Key_Right: self.desviacion_x -= 1 elif evento.key() == Qt.Key_Down: self.desviacion_y -= 1 elif evento.key() == Qt.Key_1: self.ver_alzado() elif evento.key() == Qt.Key_2: self.ver_planta() elif evento.key() == Qt.Key_3: self.ver_perfil() elif evento.key() == Qt.Key_R: self.ver_reset() elif evento.key() == Qt.Key_Minus: self.zoom += 10 elif evento.key() == Qt.Key_Plus: self.zoom -= 10 self.recalcular_posicion() self.update() QOpenGLWidget.keyPressEvent(self, evento)
def __init__(self, parent=None): super(ASCGraphicsView, self).__init__(parent) self.scene = QGraphicsScene(self) self.raw_img_item = QGraphicsPixmapItem() self.raw_img_item.setZValue(0) self.anno_img_item = QGraphicsPixmapItem() self.anno_img_item.setZValue(1) self.cross_bar_v_line_item = QGraphicsLineItem() self.cross_bar_h_line_item = QGraphicsLineItem() self.cross_bar_v_line_item.setZValue(100) self.cross_bar_h_line_item.setZValue(100) self.cross_bar_v_line_item.setPen( QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.cross_bar_h_line_item.setPen( QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.paint_brush_circle_item = QGraphicsEllipseItem() self.paint_brush_rect_item = QGraphicsPolygonItem() self.paint_brush_circle_item.setZValue(10) self.paint_brush_rect_item.setZValue(11) self.paint_brush_circle_item.setVisible(False) self.paint_brush_rect_item.setVisible(False) self.paint_brush_circle_item.setPen( QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.paint_brush_rect_item.setPen( QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.scene.addItem(self.raw_img_item) self.scene.addItem(self.anno_img_item) self.scene.addItem(self.cross_bar_v_line_item) self.scene.addItem(self.cross_bar_h_line_item) self.scene.addItem(self.paint_brush_circle_item) self.scene.addItem(self.paint_brush_rect_item) self.setScene(self.scene) self.setViewport(QOpenGLWidget()) self._last_button_press = Qt.NoButton self._last_pos_middle_button = None self._last_pos_right_button = None self._brush_stats = {'type': BRUSH_TYPE_NO_BRUSH, 'size': 5} self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.slice_scroll_bar = None self.image_size = None self.is_valid = False
def setupUI(self): self.openGLWidget = QOpenGLWidget(self) #Create the GLWidget self.openGLWidget.setGeometry(0, 0, self.width, self.height) self.openGLWidget.initializeGL() self.openGLWidget.resizeGL( self.width, self.height ) #Resize GL's knowledge of the window to match the physical size? self.openGLWidget.paintGL = self.paintGL #override the default function with my own? self.marchButton = QPushButton(self) self.marchButton.setGeometry(350, self.height, 60, 25) self.marchButton.setText('Step 0') self.marchButton.clicked.connect(self.cycle) self.readout = QLabel(self) self.readout.setGeometry(240, self.height, 110, 25) self.readout.setText("[0, 0, 0, 0, 0, 0, 0, 0]") self.indicators = [] for i in range(8): indicator = QWidget(self) indicator.setGeometry(i * 30, self.height, 25, 25) indicator.setStyleSheet("background-color: blue;") self.indicators.append(indicator)
def __init__(self, args): super(TestApplication, self).__init__(args) print("EFFECTIVE QT VERSION : " + str(QT_VERSION_STR)) self.mainWin = QWidget() self.mainWin.resize(600, 600) self.mainWin.setWindowTitle('Minimal GL test') self.mainWidget = QOpenGLWidget() self.layout = QVBoxLayout(self.mainWin) self.layout.addWidget(self.mainWidget) self.mainWin.show() ctx = QOpenGLContext.currentContext() format = ctx.format() print("EFFECTIVE GL VERSION : " + str(ctx.format().version()))
def __init__(self, parent=None): super().__init__(parent=parent) # Render on OpenGL self.setViewport(QOpenGLWidget()) self.xvalues = {} self.chart = QChart() self.setChart(self.chart) self.chart.legend().setVisible(True) self.chart.legend().setAlignment(Qt.AlignTop) self.ncurves = 0 self.setRenderHint(QPainter.Antialiasing) # Cursor (with chart as parent) self.cursor = QGraphicsLineItem(self.chart) self.cursor.setZValue(100.0) # self.scene().addItem(self.cursor) # Selection features # self.setRubberBand(QChartView.HorizontalRubberBand) self.selectionBand = QRubberBand(QRubberBand.Rectangle, self) self.selecting = False self.initialClick = QPoint() # Track mouse self.setMouseTracking(True) self.labelValue = QLabel(self) self.labelValue.setStyleSheet( "background-color: rgba(255,255,255,75%); color: black;") self.labelValue.setAlignment(Qt.AlignCenter) self.labelValue.setMargin(5) self.labelValue.setVisible(False) self.build_style() self.selection_start_time = None self.selection_stop_time = None self.cursor_time = None
def __init__(self, homography_transform, intensity_mask, parent=None): super().__init__(parent) self._crosshair = False self._crosshair_thickness = 1 self._apply_intensity_mask = False self._invert = False self.setViewport(QOpenGLWidget()) self.gaussian_shader_program = QOpenGLShaderProgram() self.homography_transform = homography_transform self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.horizontalScrollBar().disconnect() self.verticalScrollBar().disconnect() self.intensity_mask = intensity_mask self.intensity_mask_renderer = GaussianIntensityMaskRenderer( parent=self) # background_brush = QBrush() # background_brush.setStyle(Qt.SolidPattern) # background_brush.setColor(Qt.black) # self.setBackgroundBrush(background_brush) self.horizontal_line = QGraphicsLineItem() self.vertical_line = QGraphicsLineItem() self.setTransformationAnchor(QGraphicsView.NoAnchor) self.horizontal_line.setLine(0, 1080 / 2, 1920, 1080 / 2) self.vertical_line.setLine(1920 / 2, 0, 1920 / 2, 1080) self.pen = QPen(Qt.white) self.horizontal_line.setPen(self.pen) self.vertical_line.setPen(self.pen) self.view_matrix = QMatrix4x4() self.dx = 0 self.dy = 0 self.angle = 0 self.scale_value = 1 self.setSceneRect(0, 0, 9000, 9000)
def show(self): self.main_view.setViewport(QOpenGLWidget()) self.main_view.setRenderHint(QPainter.Antialiasing) self.main_view.show()
class CustomQGraphicsView(QGraphicsView): """ Base class for QGraphicsViews with Mouse Zoom and Pan support via the Control/Command shortcut key. A QGraphics View stores info on the view and handles mouse events for zooming and panning Ctrl-MidMouseButton = Pan Ctrl-RightMouseButton = Dolly Zoom MouseWheel = Zoom Args: parent(QWidget): type of QWidget such as QWidget.main_splitter() for the type of View its has For details on these and other miscellaneous methods, see below. """ def __init__(self, parent=None): """ On initialization, we need to bind the Ctrl/command key to enable manipulation of the view. """ QGraphicsView.__init__(self, parent) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setRubberBandSelectionMode(Qt.IntersectsItemShape) self._no_drag = QGraphicsView.RubberBandDrag self._yes_drag = QGraphicsView.ScrollHandDrag # reset things that are state dependent self.clearGraphicsView() self._x0 = 0 self._y0 = 0 self._scale_size = 1.0 self._scale_limit_max = 24.0 # OLD 3.0 self._scale_limit_min = 0.21 self._scale_up_rate = 0.01 self._scale_down_rate = 0.01 self._scale_fit_factor = .5 # sets initial zoom level self._show_details = True self._last_scale_factor = 0.0 self.scene_root_item = None # the item to transform # Keyboard panning self._key_pan_delta_x = styles.PATH_BASE_WIDTH * 21 self._key_pan_delta_y = styles.PATH_HELIX_HEIGHT + styles.PATH_HELIX_PADDING/2 # Modifier keys and buttons self._key_mod = Qt.Key_Control self._button_pan = Qt.LeftButton self._button_pan_alt = Qt.MidButton self._button_zoom = Qt.RightButton self.toolbar = None # custom hack for the paint tool palette self._name = None self.setContextMenuPolicy(Qt.CustomContextMenu) if GL: self.is_GL = True # self.glwidget = QGLWidget(QGLFormat(QGL.SampleBuffers)) self.glwidget = QOpenGLWidget() # self.setupGL() self.gl = self.glwidget.context().versionFunctions() self.setViewport(self.glwidget) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # self.resetGL() else: self.is_GL = False self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) # self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) # self.setFocusPolicy(Qt.ClickFocus) # end def levelOfDetailChangedSignal = pyqtSignal(bool) def __repr__(self): clsName = self.__class__.__name__ objId = self._name if self._name else str(id(self))[-4:] return "<%s %s>" % (clsName, objId) def setName(self, name): self._name = name # end def def setViewportUpdateOn(self, is_enabled): if is_enabled: self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) else: self.setViewportUpdateMode(QGraphicsView.NoViewportUpdate) # end def def activateSelection(self, is_active): if self._selection_lock: self._selection_lock.clearSelection(False) self.clearSelectionLockAndCallbacks() if is_active: self._no_drag = QGraphicsView.RubberBandDrag else: self._no_drag = QGraphicsView.NoDrag if self.dragMode() != self._yes_drag: self.setDragMode(self._no_drag) # end def def clearGraphicsView(self): # Event handling self._has_focus = False # Misc self.clearSelectionLockAndCallbacks() # Pan and dolly defaults self._transform_enable = False self._dolly_zoom_enable = False self.setDragMode(self._no_drag) # end def def clearSelectionLockAndCallbacks(self): self._selection_lock = None # a selection group to limit types of items selected self._press_list = [] # bookkeeping to handle passing mouseReleaseEvents to QGraphicsItems that don't get them # end def def _setGLView(self, boolval): scene = self.scene() if boolval and self.is_GL is False: self.is_GL = True # scene.drawBackground = self._drawBackgroundGL # self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) # self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) elif not boolval and self.is_GL is True: self.is_GL = False # scene.drawBackground = self.drawBackgroundNonGL # self.setViewport(QWidget()) # self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) # end def def setupGL(self): scene = self.scene() # win = self.scene_root_item.window() self.is_GL = True self.is_GL_switch_allowed = True self.qTimer = QTimer() # self.drawBackgroundNonGL = scene.drawBackground # scene.drawBackground = self._drawBackgroundGL # format = QGLFormat(QGL.SampleBuffers) # format.setSamples(16) # print "# of samples", format.samples(), format.sampleBuffers() # self.setViewport(QGLWidget(format)) # self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # end def def _resetLOD(self): scale_factor = self.transform().m11() # print("scale_factor", scale_factor) self.scene_root_item.window().statusBar().showMessage("%0.2f" % scale_factor) if scale_factor < 0.75: self._show_details = False self.levelOfDetailChangedSignal.emit(False) # zoomed out elif scale_factor > 0.8: self._show_details = True self.levelOfDetailChangedSignal.emit(True) # zoomed in # end def def _resetGL(self): scale_factor = self.transform().m11() # print("scale_factor", scale_factor) self.scene_root_item.window().statusBar().showMessage("%0.2f" % scale_factor) if scale_factor < .15:# and self.is_GL_switch_allowed: # self.is_GL_switch_allowed = False self._setGLView(True) self._show_details = False self.levelOfDetailChangedSignal.emit(False) # zoomed out self.qTimer.singleShot(500, self._allowGLSwitch) elif scale_factor > .2:# and self.is_GL_switch_allowed: # self.is_GL_switch_allowed = False self._setGLView(False) self._show_details = True self.levelOfDetailChangedSignal.emit(True) # zoomed in self.qTimer.singleShot(500, self._allowGLSwitch) # end def def shouldShowDetails(self): return self._show_details # end def def _allowGLSwitch(self): self.is_GL_switch_allowed = True # end def def _drawBackgroundGL(self, painter, rect): """ This method is for overloading the QGraphicsScene. """ if painter.paintEngine().type() != QPaintEngine.OpenGL and \ painter.paintEngine().type() != QPaintEngine.OpenGL2: qWarning("OpenGLScene: drawBackground needs a QGLWidget to be set as viewport on the graphics view"); return # end if painter.beginNativePainting() GL.glDisable(GL.GL_DEPTH_TEST) # disable for 2D drawing GL.glClearColor(1.0, 1.0, 1.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) painter.endNativePainting() # end def def focusInEvent(self, event): self._has_focus = True def focusOutEvent(self, event): self._transform_enable = False self._dolly_zoom_enable = False self._has_focus = False self._transform_enable = False # end def def setSelectionLock(self, selection_lock): self._selection_lock = selection_lock # end def def selectionLock(self): return self._selection_lock # end def def setScaleFitFactor(self, value): """docstring for setScaleFitFactor""" self._scale_fit_factor = value # end def def setKeyPan(self, button): """Set the class pan button remotely""" self._button_pan = button # end def def addToPressList(self, item): """docstring for addToPressList""" # self._press_list[self._press_list_idx].append(item) self._press_list.append(item) # end def def keyPanDeltaX(self): """Returns the distance in scene space to move the scene_root_item when panning left or right.""" # PyQt isn't aware that QGraphicsObject isa QGraphicsItem and so # it returns a separate python object if, say, childItems() returns # a QGraphicsObject casted to a QGraphicsItem. If this is the case, # we can still find the QGraphicsObject thusly: candidateDxDeciders = list(self.scene_root_item.childItems()) candidateDxDeciders = candidateDxDeciders +\ [cd.toGraphicsObject() for cd in candidateDxDeciders] for cd in candidateDxDeciders: if cd is None: continue keyPanDXMethod = getattr(cd, 'keyPanDeltaX', None) if keyPanDXMethod is not None: return keyPanDXMethod() return 100 def keyPanDeltaY(self): """Returns the distance in scene space to move the scene_root_item when panning left or right.""" candidateDyDeciders = list(self.scene_root_item.childItems()) candidateDyDeciders = candidateDyDeciders +\ [cd.toGraphicsObject() for cd in candidateDyDeciders] for cd in candidateDyDeciders: if cd is None: continue keyPanDYMethod = getattr(cd, 'keyPanDeltaY', None) if keyPanDYMethod is not None: return keyPanDYMethod() return 100 def keyPressEvent(self, event): """ Handle key presses for mouse-drag transforms and arrow-key panning. """ if not self._has_focus: # we don't have focus -> ignore keypress return if event.key() == self._key_mod: self._transform_enable = True QGraphicsView.keyPressEvent(self, event) elif event.key() == Qt.Key_Left: transform = self.scene_root_item.transform() transform.translate(self.keyPanDeltaX(), 0) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Up: transform = self.scene_root_item.transform() transform.translate(0, self.keyPanDeltaY()) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Right: transform = self.scene_root_item.transform() transform.translate(-self.keyPanDeltaX(), 0) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Down: transform = self.scene_root_item.transform() transform.translate(0, -self.keyPanDeltaY()) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Plus: self.zoomIn(0.3) elif event.key() == Qt.Key_Minus: self.zoomIn(0.03) else: return QGraphicsView.keyPressEvent(self, event) # end else # end def def keyReleaseEvent(self, event): """docstring for keyReleaseEvent""" if event.key() == self._key_mod: self._transform_enable = False self._dolly_zoom_enable = False self._panDisable() # end if else: QGraphicsView.keyReleaseEvent(self, event) # end else # end def def enterEvent(self, event): # self.setFocus() # this call robs selection from key focus self.setDragMode(self._no_drag) QGraphicsView.enterEvent(self, event) def leaveEvent(self, event): self.clearFocus() QGraphicsView.leaveEvent(self, event) def mouseMoveEvent(self, event): """ Must reimplement mouseMoveEvent of QGraphicsView to allow ScrollHandDrag due to the fact that events are intercepted breaks this feature. """ if self._transform_enable == True: if self.dragMode() == self._yes_drag: # Add stuff to handle the pan event posf = event.localPos() xf = posf.x() yf = posf.y() factor = self.transform().m11() transform = self.scene_root_item.transform() transform.translate((xf - self._x0)/factor,\ (yf - self._y0)/factor) self.scene_root_item.setTransform(transform) self._x0 = xf self._y0 = yf elif self._dolly_zoom_enable == True: self.dollyZoom(event) # adding this allows events to be passed to items underneath QGraphicsView.mouseMoveEvent(self, event) # end def def mousePressEvent(self, event): """docstring for mousePressEvent""" if self._transform_enable == True and qApp.keyboardModifiers(): which_buttons = event.buttons() if which_buttons in [self._button_pan, self._button_pan_alt]: self._panEnable() posf = event.localPos() self._x0 = posf.x() self._y0 = posf.y() elif which_buttons == self._button_zoom: self._dolly_zoom_enable = True self._last_scale_factor = 0 # QMouseEvent.y() returns the position of the mouse cursor # relative to the widget self._y0 = event.localPos().y() else: QGraphicsView.mousePressEvent(self, event) else: QGraphicsView.mousePressEvent(self, event) # end def def mouseReleaseEvent(self, event): """If panning, stop. If handles were pressed, release them.""" if self._transform_enable == True: # QMouseEvent.button() returns the button that triggered the event which_button = event.button() if which_button in [self._button_pan, self._button_pan_alt]: self._panDisable() elif which_button == self._button_zoom: self._dolly_zoom_enable = False else: return QGraphicsView.mouseReleaseEvent(self, event) # end if else: if len(self._press_list): # Notify any pressed items to release event_pos = event.pos() for item in self._press_list: #try: # print("item release", item) item.customMouseRelease(event) #except: # item.mouseReleaseEvent(event) #end for self._press_list = [] # end if if self._selection_lock: self._selection_lock.processPendingToAddList() return QGraphicsView.mouseReleaseEvent(self, event) # end def def _panEnable(self): """Enable ScrollHandDrag Mode in QGraphicsView (displays a hand pointer)""" self.setDragMode(self._yes_drag) # end def def _panDisable(self): """Disable ScrollHandDrag Mode in QGraphicsView (displays a hand pointer)""" self.setDragMode(self._no_drag) # end def def fname(self): """docstring for fname""" pass def wheelEvent(self, event): self.safeScale(event.angleDelta().y()) # end def def safeScale(self, delta): current_scale_level = self.transform().m11() scale_factor = 1 + delta * \ (self._scale_down_rate if delta < 0 else self._scale_up_rate) * \ (app().prefs.zoom_speed/100.) new_scale_level = current_scale_level * scale_factor new_scale_level = util.clamp(current_scale_level * scale_factor,\ self._scale_limit_min,\ self._scale_limit_max) scale_change = new_scale_level / current_scale_level self.scale(scale_change, scale_change) self._resetLOD() # end def def zoomIn(self, fraction_of_max=0.5): current_scale_level = self.transform().m11() scale_change = (fraction_of_max * self._scale_limit_max) / current_scale_level self.scale(scale_change, scale_change) # end def def zoomOut(self, fraction_of_min=1): current_scale_level = self.transform().m11() scale_change = (fraction_of_min * self._scale_limit_min) / current_scale_level self.scale(scale_change, scale_change) # end def def dollyZoom(self, event): """docstring for dollyZoom""" # QMouseEvent.y() returns the position of the mouse cursor relative # to the widget yf = event.y() denom = abs(yf - self._y0) if denom > 0: scale_factor = (self.height() / 2) % denom if self._last_scale_factor != scale_factor: self._last_scale_factor = scale_factor # zoom in if mouse y position is getting bigger if yf - self._y0 > 0: self.safeScale(yf - self._y0) # end else else: # else id smaller zoom out self.safeScale(yf - self._y0) # end else # end if # end def def _resetScale(self): """reset the scale to 1""" # use the transform value if you want to get how much the view # has been scaled self._scale_size = self.transform().m11() # self._scale_limit_min = 0.41*self._scale_size # make it so fitting in view is zoomed minimum # still gives you one zoom level out before violates limit self._scale_limit_min = self._scale_size*self._scale_fit_factor # use this if you want to reset the zoom in limit # self._scale_limit_max = 3.0*self._scale_size self._last_scale_factor = 0.0 # end def def zoomToFit(self): # print("zoom to fit", self._name) # Auto zoom to center the scene thescene = self.scene_root_item.scene() # order matters? self.scene_root_item.resetTransform() # zero out translations self.resetTransform() # zero out scaling if self.toolbar: # HACK: move toolbar so it doesn't affect sceneRect self.toolbar.setPos(0, 0) thescene.setSceneRect(thescene.itemsBoundingRect()) scene_rect = thescene.sceneRect() if self.toolbar: # HACK, pt2: move toolbar back self.toolbar.setPos(self.mapToScene(0, 0)) self.fitInView(scene_rect, Qt.KeepAspectRatio) # fit in view self._resetScale() # adjust scaling so that translation works # adjust scaling so that the items don't fill 100% of the view # this is good for selection self.scale(self._scale_fit_factor, self._scale_fit_factor) self._scale_size *= self._scale_fit_factor self._resetLOD() # end def def paintEvent(self, event): if self.toolbar: self.toolbar.setPos(self.mapToScene(0, 0)) QGraphicsView.paintEvent(self, event)
def add_scene(self, scene: ModelScene, name="Scene"): view = ModelView(scene) view.setViewport(QOpenGLWidget()) self.mainpane.addTab(ViewPane(view), name)
def __init__(self, initMode: DriveMode) -> None: # Init values self.mode = initMode self.tachometerEngineRpm = 0 # 0 - 9000 self.tachometerEngineLevel = DashboardLevel.inactive self.tachometerGearboxRpm = 0 # 0 - 9000 self.tachometerGearboxLevel = DashboardLevel.inactive self.tachometerGear1Rpm = 0 # 0 - 9000 self.tachometerGear2Rpm = 0 # 0 - 9000 self.tachometerGear3Rpm = 0 # 0 - 9000 self.tachometerGear4Rpm = 0 # 0 - 9000 self.tachometerGear5Rpm = 0 # 0 - 9000 self.accelerometerAngel = 0 # -180 - +180 self.accelerometerValue = 0.0 # 0.0 - 1.0 self.accelerometerLevel = DashboardLevel.inactive self.steeringWheelEncoderAngel = 0 # -7 - +7 self.steeringWheelEncoderLevel = DashboardLevel.inactive self.turnLeftIndicatorLevel = DashboardLevel.inactive self.turnRightIndicatorLevel = DashboardLevel.inactive self.oilWarningIndicatorLevel = DashboardLevel.inactive self.watterWarningIndicatorLevel = DashboardLevel.inactive self.gearNumberValue = 0 # 0 - 5 self.speedometerValue = 0 # 0 - 999 self.speedometerLevel = DashboardLevel.inactive self.stopwatchMills = 0 # 0 - 99 self.stopwatchSeconds = 0 # 0 - 59 self.stopwatchMinutes = 0 # 0 - 59 self.stopwatchHours = 0 # 0 - 9 self.stopwatchLevel = DashboardLevel.inactive self.oilManometerValue = 0.0 # 0.0 - 9.99 self.oilManometerLevel = DashboardLevel.inactive self.oilThermometerValue = 0 # 0 - 999 self.oilThermometerLevel = DashboardLevel.inactive self.watterThermometerValue = 0 # 0 - 999 self.watterThermometerLevel = DashboardLevel.inactive self.odometerValue = 0 # 0 - 9999 self.odometerLevel = DashboardLevel.inactive # Init UI super(Dashboard, self).__init__() viewport = QOpenGLWidget() viewportFormat = QSurfaceFormat() viewportFormat.setSwapInterval(0) # disable VSync viewportFormat.setSamples(2**8) viewportFormat.setDefaultFormat(viewportFormat) viewport.setFormat(viewportFormat) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setGeometry(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setStyleSheet("border: 0px") self.setWindowTitle("Dashboard") self.setWindowFlags(Qt.FramelessWindowHint) self.scene = QGraphicsScene(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setScene(self.scene) self.setViewport(viewport) self.setInteractive(False) self.levelPens = { DashboardLevel.inactive: QPen(self.INACTIVE_COLOR, 1, Qt.SolidLine), DashboardLevel.ok: QPen(self.OK_COLOR, 1, Qt.SolidLine), DashboardLevel.warning: QPen(self.WARNING_COLOR, 1, Qt.SolidLine), DashboardLevel.dangerous: QPen(self.DANGEROUS_COLOR, 1, Qt.SolidLine) } self.levelBrushes = { DashboardLevel.inactive: QBrush(self.INACTIVE_COLOR, Qt.SolidPattern), DashboardLevel.ok: QBrush(self.OK_COLOR, Qt.SolidPattern), DashboardLevel.warning: QBrush(self.WARNING_COLOR, Qt.SolidPattern), DashboardLevel.dangerous: QBrush(self.DANGEROUS_COLOR, Qt.SolidPattern) } # Helpers dirPath = os.path.dirname(os.path.abspath(__file__)) inactivePen = self.levelPens[DashboardLevel.inactive] inactiveBrush = self.levelBrushes[DashboardLevel.inactive] def buildPolygonItem(origin: QPointF, polygon: List[QPointF]): return self.scene.addPolygon( QPolygonF([ QPointF(p.x() + origin.x(), p.y() + origin.y()) for p in polygon ]), inactivePen, inactiveBrush) def makeNumberItems(origin: QPointF, polygon: Dict[str, List[QPointF]]): return {k: buildPolygonItem(origin, p) for k, p in polygon.items()} # Add background self.backgroundPixmaps = { DriveMode.race: QPixmap(os.path.join(dirPath, "background_race.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT), DriveMode.street: QPixmap(os.path.join(dirPath, "background_street.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT) } logging.debug( f"[Dashboard.__init__] Loaded: backgroundPixmaps = {self.backgroundPixmaps}, initMode = {initMode}" ) self.backgroundItem = QGraphicsPixmapItem() self.backgroundItem.setZValue(-1) self.scene.addItem(self.backgroundItem) # Add tachometer graphics self.tachometerEngineItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_ENGINE.items()} self.tachometerGearboxItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_GEARBOX.items()} self.tachometerGearsPens = { "A": QPen(self.TACHOMETER_GEARS_ARROW_COLOR, 1, Qt.SolidLine), "N": QPen(self.TACHOMETER_GEARS_NUMBER_COLOR, 1, Qt.SolidLine) } self.tachometerGearsBrushes = { "A": QBrush(self.TACHOMETER_GEARS_ARROW_COLOR, Qt.SolidPattern), "N": QBrush(self.TACHOMETER_GEARS_NUMBER_COLOR, Qt.SolidPattern) } def makeGearsTransforms(translate: QPointF, rotate: int): arrowTrans = QTransform() arrowTrans.translate(translate.x(), translate.y()) arrowTrans.rotate(rotate) numberTrans = QTransform() numberTrans.translate(translate.x(), translate.y()) return arrowTrans, numberTrans self.tachometerGearsTransforms = \ {k: makeGearsTransforms(p[0], p[1]) for k, p in PolygonsMapping.TACHOMETER_GEARS["T"].items()} def tachometerGearsItem(gearNumber: int): (arrowTrans, numberTrans) = self.tachometerGearsTransforms[0] arrowItem = self.scene.addPolygon( PolygonsMapping.TACHOMETER_GEARS["A"], inactivePen, inactiveBrush) arrowItem.setTransform(arrowTrans) numberItem = buildPolygonItem( PolygonsMapping.TACHOMETER_GEARS["N"]["O"], PolygonsMapping.TACHOMETER_GEARS["N"]["P"][gearNumber]) numberItem.setTransform(numberTrans) return arrowItem, numberItem self.tachometerGearsItems = { 1: tachometerGearsItem(1), 2: tachometerGearsItem(2), 3: tachometerGearsItem(3), 4: tachometerGearsItem(4), 5: tachometerGearsItem(5) } # Add accelerometer graphics def makeEllipse(points: Tuple[QPointF, QPointF]): return self.scene.addEllipse(points[0].x(), points[0].y(), points[1].x() - points[0].x(), points[1].y() - points[0].y(), inactivePen, inactiveBrush) self.accelerometerCenterItem = makeEllipse( PolygonsMapping.ACCELEROMETER["C"]) self.accelerometerSectorItem = makeEllipse( PolygonsMapping.ACCELEROMETER["S"]) self.accelerometerSectorItem.setStartAngle( int((270 - (self.ACCELEROMETER_MIN_ANGEL / 2))) * 16) self.accelerometerSectorItem.setSpanAngle( self.ACCELEROMETER_MIN_ANGEL * 16) # Add steering wheel encoder graphics self.steeringWheelEncoderItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.STEERING_WHEEL_ENCODER.items()} # Add turn indicator graphics def makeTurnIndicatorItem(initCoordinates: Dict[str, Any]): return buildPolygonItem(initCoordinates["C"], initCoordinates["P"]) self.turnIndicatorLeftItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["L"]) self.turnIndicatorRightItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["R"]) # Add warning indicators graphics def makeWarningIndicatorItems(initCoordinates: Dict[str, Any]): return [ buildPolygonItem(initCoordinates["C"], p) for p in initCoordinates["P"] ] self.oilWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["OIL"]) self.watterWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["WATTER"]) # Add gear number graphics self.gearNumberPen = QPen(self.GEAR_NUMBER_COLOR, 1, Qt.SolidLine) self.gearNumberBrush = QBrush(self.GEAR_NUMBER_COLOR, Qt.SolidPattern) self.gearNumberItems = makeNumberItems( PolygonsMapping.GEAR_NUMBER["C"], PolygonsMapping.GEAR_NUMBER["P"]) # Add speedometer graphics self.speedometer001Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[1], PolygonsMapping.SPEED_NUMBERS) self.speedometer010Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[10], PolygonsMapping.SPEED_NUMBERS) self.speedometer100Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[100], PolygonsMapping.SPEED_NUMBERS) # Add stopwatch graphics self.stopwatchMS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchMS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["S01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["S10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM01Items = makeNumberItems( PolygonsMapping.STOPWATCH["M01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM10Items = makeNumberItems( PolygonsMapping.STOPWATCH["M10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchH01Items = makeNumberItems( PolygonsMapping.STOPWATCH["H01"], PolygonsMapping.STANDARD_NUMBERS) # Add oil manometer graphics self.oilManometer0d01Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.01], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer0d10Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.1], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer1d00Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[1], PolygonsMapping.STANDARD_NUMBERS) # Add oil thermometer graphics self.oilThermometer001Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer010Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer100Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add watter thermometer graphics self.watterThermometer001Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer010Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer100Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add odometer graphics self.watterOdometer0001Items = makeNumberItems( PolygonsMapping.ODOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0010Items = makeNumberItems( PolygonsMapping.ODOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0100Items = makeNumberItems( PolygonsMapping.ODOMETER[100], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer1000Items = makeNumberItems( PolygonsMapping.ODOMETER[1000], PolygonsMapping.STANDARD_NUMBERS) # Initial rendering self.renderBackground() self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) self.renderAccelerometer() self.renderSteeringWheelEncoder() self.renderTurnLeftIndicator() self.renderTurnRightIndicator() self.renderOilWarningIndicator() self.renderWatterWarningIndicator() self.renderGearNumber() self.renderSpeedometer() self.renderStopwatch() self.renderOilManometer() self.renderOilThermometer() self.renderWatterThermometer() self.renderOdometer()
class CustomQGraphicsView(QGraphicsView): """ Base class for QGraphicsViews with Mouse Zoom and Pan support via the Control/Command shortcut key. A QGraphics View stores info on the view and handles mouse events for zooming and panning Ctrl-MidMouseButton = Pan Ctrl-RightMouseButton = Dolly Zoom MouseWheel = Zoom Args: parent(QWidget): type of QWidget such as QWidget.main_splitter() for the type of View its has For details on these and other miscellaneous methods, see below. """ def __init__(self, parent=None): """ On initialization, we need to bind the Ctrl/command key to enable manipulation of the view. """ QGraphicsView.__init__(self, parent) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setRubberBandSelectionMode(Qt.IntersectsItemShape) self._no_drag = QGraphicsView.RubberBandDrag self._yes_drag = QGraphicsView.ScrollHandDrag # reset things that are state dependent self.clearGraphicsView() self._x0 = 0 self._y0 = 0 self._scale_size = 1.0 self._scale_limit_max = 16.0 # OLD 3.0 self._scale_limit_min = 0.21 self._scale_up_rate = 0.01 self._scale_down_rate = 0.01 self._scale_fit_factor = .5 # sets initial zoom level self._show_details = True self._last_scale_factor = 0.0 self.scene_root_item = None # the item to transform # Keyboard panning self._key_pan_delta_x = styles.PATH_BASE_WIDTH * 21 self._key_pan_delta_y = styles.PATH_HELIX_HEIGHT + styles.PATH_HELIX_PADDING / 2 # Modifier keys and buttons self._key_mod = Qt.Key_Control self._button_pan = Qt.LeftButton self._button_pan_alt = Qt.MidButton self._button_zoom = Qt.RightButton self.toolbar = None # custom hack for the paint tool palette self._name = None self.setContextMenuPolicy(Qt.CustomContextMenu) if GL: self.is_GL = True # self.glwidget = QGLWidget(QGLFormat(QGL.SampleBuffers)) self.glwidget = QOpenGLWidget() # self.setupGL() self.gl = self.glwidget.context().versionFunctions() self.setViewport(self.glwidget) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # self.resetGL() else: self.is_GL = False self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) # self.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) # self.setFocusPolicy(Qt.ClickFocus) # end def levelOfDetailChangedSignal = pyqtSignal(bool) def __repr__(self): clsName = self.__class__.__name__ objId = self._name if self._name else str(id(self))[-4:] return "<%s %s>" % (clsName, objId) def setName(self, name): self._name = name # end def def setViewportUpdateOn(self, is_enabled): if is_enabled: self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) else: self.setViewportUpdateMode(QGraphicsView.NoViewportUpdate) # end def def activateSelection(self, is_active): if self._selection_lock: self._selection_lock.clearSelection(False) self.clearSelectionLockAndCallbacks() if is_active: self._no_drag = QGraphicsView.RubberBandDrag else: self._no_drag = QGraphicsView.NoDrag if self.dragMode() != self._yes_drag: self.setDragMode(self._no_drag) # end def def clearGraphicsView(self): # Event handling self._has_focus = False # Misc self.clearSelectionLockAndCallbacks() # Pan and dolly defaults self._transform_enable = False self._dolly_zoom_enable = False self.setDragMode(self._no_drag) # end def def clearSelectionLockAndCallbacks(self): self._selection_lock = None # a selection group to limit types of items selected self._press_list = [ ] # bookkeeping to handle passing mouseReleaseEvents to QGraphicsItems that don't get them # end def def _setGLView(self, boolval): # scene = self.scene() if boolval and self.is_GL is False: self.is_GL = True # scene.drawBackground = self._drawBackgroundGL # self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) # self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) elif not boolval and self.is_GL is True: self.is_GL = False # scene.drawBackground = self.drawBackgroundNonGL # self.setViewport(QWidget()) # self.setViewportUpdateMode(QGraphicsView.MinimalViewportUpdate) # end def def setupGL(self): # scene = self.scene() # win = self.scene_root_item.window() self.is_GL = True self.is_GL_switch_allowed = True self.qTimer = QTimer() # self.drawBackgroundNonGL = scene.drawBackground # scene.drawBackground = self._drawBackgroundGL # format = QGLFormat(QGL.SampleBuffers) # format.setSamples(16) # print "# of samples", format.samples(), format.sampleBuffers() # self.setViewport(QGLWidget(format)) # self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) # end def def _resetLOD(self): scale_factor = self.transform().m11() # print("scale_factor", scale_factor) self.scene_root_item.window().statusBar().showMessage("%0.2f" % scale_factor) if scale_factor < 0.75: self._show_details = False self.levelOfDetailChangedSignal.emit(False) # zoomed out elif scale_factor > 0.8: self._show_details = True self.levelOfDetailChangedSignal.emit(True) # zoomed in # end def def _resetGL(self): scale_factor = self.transform().m11() # print("scale_factor", scale_factor) self.scene_root_item.window().statusBar().showMessage("%0.2f" % scale_factor) if scale_factor < .15: # and self.is_GL_switch_allowed: # self.is_GL_switch_allowed = False self._setGLView(True) self._show_details = False self.levelOfDetailChangedSignal.emit(False) # zoomed out self.qTimer.singleShot(500, self._allowGLSwitch) elif scale_factor > .2: # and self.is_GL_switch_allowed: # self.is_GL_switch_allowed = False self._setGLView(False) self._show_details = True self.levelOfDetailChangedSignal.emit(True) # zoomed in self.qTimer.singleShot(500, self._allowGLSwitch) # end def def shouldShowDetails(self): return self._show_details # end def def _allowGLSwitch(self): self.is_GL_switch_allowed = True # end def def _drawBackgroundGL(self, painter, rect): """ This method is for overloading the QGraphicsScene. """ if painter.paintEngine().type() != QPaintEngine.OpenGL and \ painter.paintEngine().type() != QPaintEngine.OpenGL2: qWarning( "OpenGLScene: drawBackground needs a QGLWidget to be set as viewport on the graphics view" ) return # end if painter.beginNativePainting() GL.glDisable(GL.GL_DEPTH_TEST) # disable for 2D drawing GL.glClearColor(1.0, 1.0, 1.0, 1.0) GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) painter.endNativePainting() # end def def focusInEvent(self, event): self._has_focus = True def focusOutEvent(self, event): self._transform_enable = False self._dolly_zoom_enable = False self._has_focus = False self._transform_enable = False # end def def setSelectionLock(self, selection_lock): self._selection_lock = selection_lock # end def def selectionLock(self): return self._selection_lock # end def def setScaleFitFactor(self, value): """docstring for setScaleFitFactor""" self._scale_fit_factor = value # end def def setKeyPan(self, button): """Set the class pan button remotely""" self._button_pan = button # end def def addToPressList(self, item): """docstring for addToPressList""" # self._press_list[self._press_list_idx].append(item) self._press_list.append(item) # end def def keyPanDeltaX(self): """Returns the distance in scene space to move the scene_root_item when panning left or right.""" # PyQt isn't aware that QGraphicsObject is a QGraphicsItem and so # it returns a separate python object if, say, childItems() returns # a QGraphicsObject cast to a QGraphicsItem. If this is the case, # we can still find the QGraphicsObject thusly: candidateDxDeciders = list(self.scene_root_item.childItems()) candidateDxDeciders = candidateDxDeciders + [ cd.toGraphicsObject() for cd in candidateDxDeciders ] for cd in candidateDxDeciders: if cd is None: continue keyPanDXMethod = getattr(cd, 'keyPanDeltaX', None) if keyPanDXMethod is not None: return keyPanDXMethod() return 100 def keyPanDeltaY(self): """Returns the distance in scene space to move the scene_root_item when panning left or right.""" candidateDyDeciders = list(self.scene_root_item.childItems()) candidateDyDeciders = candidateDyDeciders + [ cd.toGraphicsObject() for cd in candidateDyDeciders ] for cd in candidateDyDeciders: if cd is None: continue keyPanDYMethod = getattr(cd, 'keyPanDeltaY', None) if keyPanDYMethod is not None: return keyPanDYMethod() return 100 def keyPressEvent(self, event): """ Handle key presses for mouse-drag transforms and arrow-key panning. """ if not self._has_focus: # we don't have focus -> ignore keypress return if event.key() == self._key_mod: self._transform_enable = True QGraphicsView.keyPressEvent(self, event) elif event.key() == Qt.Key_Left: transform = self.scene_root_item.transform() transform.translate(self.keyPanDeltaX(), 0) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Up: transform = self.scene_root_item.transform() transform.translate(0, self.keyPanDeltaY()) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Right: transform = self.scene_root_item.transform() transform.translate(-self.keyPanDeltaX(), 0) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Down: transform = self.scene_root_item.transform() transform.translate(0, -self.keyPanDeltaY()) self.scene_root_item.setTransform(transform) elif event.key() == Qt.Key_Plus: self.zoomIn(0.3) elif event.key() == Qt.Key_Minus: self.zoomIn(0.03) else: if hasattr(self.scene_root_item, KEY_PRESS_EVENT): getattr(self.scene_root_item, KEY_PRESS_EVENT)(event) # end def def keyReleaseEvent(self, event): if event.key() == self._key_mod: self._transform_enable = False self._dolly_zoom_enable = False self._panDisable() else: if hasattr(self.scene_root_item, KEY_RELEASE_EVENT): getattr(self.scene_root_item, KEY_RELEASE_EVENT)(event) # end def def enterEvent(self, event): # self.setFocus() # this call robs selection from key focus self.setDragMode(self._no_drag) QGraphicsView.enterEvent(self, event) def leaveEvent(self, event): self.clearFocus() QGraphicsView.leaveEvent(self, event) def mouseMoveEvent(self, event): """ Must override mouseMoveEvent of QGraphicsView to allow ScrollHandDrag due to the fact that events are intercepted breaks this feature. """ if self._transform_enable: if self.dragMode() == self._yes_drag: # Add stuff to handle the pan event posf = event.localPos() xf = posf.x() yf = posf.y() factor = self.transform().m11() transform = self.scene_root_item.transform() transform.translate((xf - self._x0) / factor, (yf - self._y0) / factor) self.scene_root_item.setTransform(transform) self._x0 = xf self._y0 = yf elif self._dolly_zoom_enable: self.dollyZoom(event) # adding this allows events to be passed to items underneath QGraphicsView.mouseMoveEvent(self, event) # end def def mousePressEvent(self, event): """docstring for mousePressEvent""" if self._transform_enable and qApp.keyboardModifiers(): which_buttons = event.buttons() if which_buttons in [self._button_pan, self._button_pan_alt]: self._panEnable() posf = event.localPos() self._x0 = posf.x() self._y0 = posf.y() elif which_buttons == self._button_zoom: self._dolly_zoom_enable = True self._last_scale_factor = 0 # QMouseEvent.y() returns the position of the mouse cursor # relative to the widget self._y0 = event.localPos().y() else: QGraphicsView.mousePressEvent(self, event) else: QGraphicsView.mousePressEvent(self, event) # end def def mouseReleaseEvent(self, event): """If panning, stop. If handles were pressed, release them.""" if self._transform_enable: # QMouseEvent.button() returns the button that triggered the event which_button = event.button() if which_button in [self._button_pan, self._button_pan_alt]: self._panDisable() elif which_button == self._button_zoom: self._dolly_zoom_enable = False else: return QGraphicsView.mouseReleaseEvent(self, event) # end if else: if len(self._press_list): # Notify any pressed items to release # event_pos = event.pos() for item in self._press_list: item.customMouseRelease(event) self._press_list = [] # end if if self._selection_lock: self._selection_lock.processPendingToAddList() return QGraphicsView.mouseReleaseEvent(self, event) # end def def _panEnable(self): """Enable ScrollHandDrag Mode in QGraphicsView (displays a hand pointer)""" self.setDragMode(self._yes_drag) # end def def _panDisable(self): """Disable ScrollHandDrag Mode in QGraphicsView (displays a hand pointer)""" self.setDragMode(self._no_drag) # end def def fname(self): """docstring for fname""" def wheelEvent(self, event): self.safeScale(event.angleDelta().y()) # end def def safeScale(self, delta): current_scale_level = self.transform().m11() scale_factor = 1 + delta * (self._scale_down_rate if delta < 0 else self._scale_up_rate) * \ (app().prefs.zoom_speed/100.) new_scale_level = current_scale_level * scale_factor new_scale_level = util.clamp(current_scale_level * scale_factor, self._scale_limit_min, self._scale_limit_max) scale_change = new_scale_level / current_scale_level self.scale(scale_change, scale_change) self._resetLOD() # end def def zoomIn(self, fraction_of_max=0.5): current_scale_level = self.transform().m11() scale_change = (fraction_of_max * self._scale_limit_max) / current_scale_level self.scale(scale_change, scale_change) # end def def zoomOut(self, fraction_of_min=1): current_scale_level = self.transform().m11() scale_change = (fraction_of_min * self._scale_limit_min) / current_scale_level self.scale(scale_change, scale_change) # end def def dollyZoom(self, event): """docstring for dollyZoom""" # QMouseEvent.y() returns the position of the mouse cursor relative # to the widget yf = event.y() denom = abs(yf - self._y0) if denom > 0: scale_factor = (self.height() / 2) % denom if self._last_scale_factor != scale_factor: self._last_scale_factor = scale_factor # zoom in if mouse y position is getting bigger if yf - self._y0 > 0: self.safeScale(yf - self._y0) # end else else: # else id smaller zoom out self.safeScale(yf - self._y0) # end else # end if # end def def _resetScale(self): """reset the scale to 1""" # use the transform value if you want to get how much the view # has been scaled self._scale_size = self.transform().m11() # self._scale_limit_min = 0.41*self._scale_size # make it so fitting in view is zoomed minimum # still gives you one zoom level out before violates limit self._scale_limit_min = self._scale_size * self._scale_fit_factor # use this if you want to reset the zoom in limit # self._scale_limit_max = 3.0*self._scale_size self._last_scale_factor = 0.0 # end def def zoomToFit(self): # print("zoom to fit", self._name) # Auto zoom to center the scene thescene = self.scene_root_item.scene() # order matters? self.scene_root_item.resetTransform() # zero out translations self.resetTransform() # zero out scaling if self.toolbar: # HACK: move toolbar so it doesn't affect sceneRect self.toolbar.setPos(0, 0) thescene.setSceneRect(thescene.itemsBoundingRect()) scene_rect = thescene.sceneRect() if self.toolbar: # HACK, pt2: move toolbar back self.toolbar.setPos(self.mapToScene(0, 0)) self.fitInView(scene_rect, Qt.KeepAspectRatio) # fit in view self._resetScale() # adjust scaling so that translation works # adjust scaling so that the items don't fill 100% of the view # this is good for selection self.scale(self._scale_fit_factor, self._scale_fit_factor) self._scale_size *= self._scale_fit_factor self._resetLOD() # end def def paintEvent(self, event): if self.toolbar: self.toolbar.setPos(self.mapToScene(0, 0)) QGraphicsView.paintEvent(self, event)
def __init__(self, parent=None, **kw): # the current button self._ActiveButton = Qt.NoButton # private attributes self.__saveX = 0 self.__saveY = 0 self.__saveModifiers = Qt.NoModifier self.__saveButtons = Qt.NoButton self.__wheelDelta = 0 # do special handling of some keywords: # stereo, rw try: stereo = bool(kw['stereo']) except KeyError: stereo = False try: rw = kw['rw'] except KeyError: rw = None # create qt-level widget if QVTKRWIBase == "QWidget": if "wflags" in kw: wflags = kw['wflags'] else: wflags = Qt.WindowFlags() QWidget.__init__(self, parent, wflags | Qt.MSWindowsOwnDC) elif QVTKRWIBase == "QGLWidget": QGLWidget.__init__(self, parent) if rw: # user-supplied render window self._RenderWindow = rw else: self._RenderWindow = vtk.vtkRenderWindow() wid = self._get_win_id() self._RenderWindow.SetWindowInfo(wid) self._should_set_parent_info = (sys.platform == 'win32') if stereo: # stereo mode self._RenderWindow.StereoCapableWindowOn() self._RenderWindow.SetStereoTypeToCrystalEyes() try: self._Iren = kw['iren'] except KeyError: self._Iren = vtk.vtkGenericRenderWindowInteractor() self._Iren.SetRenderWindow(self._RenderWindow) if hasattr(self, 'devicePixelRatio'): self._pixel_ratio = self.devicePixelRatio() else: self._pixel_ratio = 1.0 # do all the necessary qt setup self.setAttribute(Qt.WA_OpaquePaintEvent) self.setAttribute(Qt.WA_PaintOnScreen) self.setMouseTracking(True) # get all mouse events self.setFocusPolicy(Qt.WheelFocus) self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self._Timer = QTimer(self) self._Timer.timeout.connect(self.TimerEvent) # add wheel timer to fix scrolling issue with trackpad self.wheel_timer = None if PyQtImpl != 'PyQt5': self.wheel_timer = QTimer() self.wheel_timer.setSingleShot(True) self.wheel_timer.setInterval(25) self.wheel_timer.timeout.connect(self._emit_wheel_event) self._saved_wheel_event_info = () self._Iren.AddObserver('CreateTimerEvent', messenger.send) messenger.connect(self._Iren, 'CreateTimerEvent', self.CreateTimer) self._Iren.AddObserver('DestroyTimerEvent', messenger.send) messenger.connect(self._Iren, 'DestroyTimerEvent', self.DestroyTimer) self._RenderWindow.AddObserver('CursorChangedEvent', messenger.send) messenger.connect(self._RenderWindow, 'CursorChangedEvent', self.CursorChangedEvent) # Create a hidden child widget and connect its destroyed signal to its # parent ``Finalize`` slot. The hidden children will be destroyed # before its parent thus allowing cleanup of VTK elements. self._hidden = QWidget(self) self._hidden.hide() self._hidden.destroyed.connect(self.Finalize)