class Robot(RobotPart): def __init__(self): super(Robot, self).__init__() self.torsoItem = RobotTorso(self) self.headItem = RobotHead(self.torsoItem) self.upperLeftArmItem = RobotLimb(self.torsoItem) self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem) self.upperRightArmItem = RobotLimb(self.torsoItem) self.lowerRightArmItem = RobotLimb(self.upperRightArmItem) self.upperRightLegItem = RobotLimb(self.torsoItem) self.lowerRightLegItem = RobotLimb(self.upperRightLegItem) self.upperLeftLegItem = RobotLimb(self.torsoItem) self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem) self.timeline = QTimeLine() settings = [ # item position rotation at # x y time 0 / 1 ( self.headItem, 0, -18, 20, -20 ), ( self.upperLeftArmItem, -15, -10, 190, 180 ), ( self.lowerLeftArmItem, 30, 0, 50, 10 ), ( self.upperRightArmItem, 15, -10, 300, 310 ), ( self.lowerRightArmItem, 30, 0, 0, -70 ), ( self.upperRightLegItem, 10, 32, 40, 120 ), ( self.lowerRightLegItem, 30, 0, 10, 50 ), ( self.upperLeftLegItem, -10, 32, 150, 80 ), ( self.lowerLeftLegItem, 30, 0, 70, 10 ), ( self.torsoItem, 0, 0, 5, -20 ) ] self.animations = [] for item, pos_x, pos_y, rotation1, rotation2 in settings: item.setPos(pos_x,pos_y) animation = QGraphicsItemAnimation() animation.setItem(item) animation.setTimeLine(self.timeline) animation.setRotationAt(0, rotation1) animation.setRotationAt(1, rotation2) self.animations.append(animation) self.animations[0].setScaleAt(1, 1.1, 1.1) self.timeline.setUpdateInterval(1000 / 25) self.timeline.setCurveShape(QTimeLine.SineCurve) self.timeline.setLoopCount(0) self.timeline.setDuration(2000) self.timeline.start() def boundingRect(self): return QRectF() def paint(self, painter, option, widget=None): pass
class Robot(RobotPart): def __init__(self): super(Robot, self).__init__() self.torsoItem = RobotTorso(self) self.headItem = RobotHead(self.torsoItem) self.upperLeftArmItem = RobotLimb(self.torsoItem) self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem) self.upperRightArmItem = RobotLimb(self.torsoItem) self.lowerRightArmItem = RobotLimb(self.upperRightArmItem) self.upperRightLegItem = RobotLimb(self.torsoItem) self.lowerRightLegItem = RobotLimb(self.upperRightLegItem) self.upperLeftLegItem = RobotLimb(self.torsoItem) self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem) self.timeline = QTimeLine() settings = [ # item position rotation at # x y time 0 / 1 (self.headItem, 0, -18, 20, -20), (self.upperLeftArmItem, -15, -10, 190, 180), (self.lowerLeftArmItem, 30, 0, 50, 10), (self.upperRightArmItem, 15, -10, 300, 310), (self.lowerRightArmItem, 30, 0, 0, -70), (self.upperRightLegItem, 10, 32, 40, 120), (self.lowerRightLegItem, 30, 0, 10, 50), (self.upperLeftLegItem, -10, 32, 150, 80), (self.lowerLeftLegItem, 30, 0, 70, 10), (self.torsoItem, 0, 0, 5, -20) ] self.animations = [] for item, pos_x, pos_y, rotation1, rotation2 in settings: item.setPos(pos_x, pos_y) animation = QGraphicsItemAnimation() animation.setItem(item) animation.setTimeLine(self.timeline) animation.setRotationAt(0, rotation1) animation.setRotationAt(1, rotation2) self.animations.append(animation) self.animations[0].setScaleAt(1, 1.1, 1.1) self.timeline.setUpdateInterval(1000 / 25) self.timeline.setCurveShape(QTimeLine.SineCurve) self.timeline.setLoopCount(0) self.timeline.setDuration(2000) self.timeline.start() def boundingRect(self): return QRectF() def paint(self, painter, option, widget=None): pass
def wheelEvent(self, event): numDegrees = event.angleDelta() / 8 print("wheel: {}".format(numDegrees)) numSteps = numDegrees.y() / 15 self._numScheduledScalings += numSteps if self._numScheduledScalings * numSteps < 0: self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.ScalingTime) anim.finished.connect(self.AnimFinished) anim.start()
def wheelEvent(self, event): # Check if zooming is enabled if not self.parent.menu.options[1].isChecked(): return # Zooming event on mouse scroll numDegrees = event.angleDelta() / 8 numSteps = (numDegrees / 15).y() self._numScheduledScalings += numSteps if self._numScheduledScalings * numSteps < 0: self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.animFinished) anim.start()
def wheelEvent(self, event): numDegrees = event.angleDelta() / 8 numSteps = numDegrees / 15 self._numScheduledScalings += numSteps.y() """ if user moved the wheel in another direction, we reset previously scheduled scalings """ if self._numScheduledScalings * numSteps.y() < 0: self._numScheduledScalings = numSteps.y() anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.animFinished) anim.start()
def zoom(self, numDegrees): numSteps = numDegrees / 15 self._numScheduledScalings += numSteps if ( self._numScheduledScalings * numSteps < 0 ): # if user moved the wheel in another direction, we reset previously scheduled scalings self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.scaleAnimFinished) anim.start()
def translateVerticalEvent(self, dy): numSteps = dy * 20 self._numScheduledVTranslations += numSteps if ( self._numScheduledVTranslations * numSteps < 0 ): # if user moved the wheel in another direction, we reset previously scheduled scalings self._numScheduledVTranslations = numSteps if not self.animatingV: anim = QTimeLine(350, self) anim.setUpdateInterval(10) anim.valueChanged.connect(self.translateVTime) anim.finished.connect(self.translateVAnimFinished) anim.start()
def wheelEvent(self, event): degree = event.angleDelta().y() / 8 step = degree / 15 self.scheduledscaling = self.scheduledscaling + step animation = QTimeLine(350) animation.setUpdateInterval(20) animation.valueChanged.connect( animation.currentValue ) #Timeline does not start without this line, maybe a QT bug animation.valueChanged.connect( lambda: self.scale(1.0 + self.scheduledscaling / 300.0, 1.0 + self. scheduledscaling / 300.0)) animation.finished.connect(self.reset) animation.start()
class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle("Screen and Gaze Capture") grid = QGridLayout() layout_frame = QFrame() layout_frame.setLayout(grid) self.setCentralWidget(layout_frame) self.tracker_label = QLabel("No eye tracker connected.") grid.addWidget(self.tracker_label, 0, 0) connect_button = QPushButton("Connect to Eye Tracker") connect_button.pressed.connect(connect_to_tracker) grid.addWidget(connect_button, 1, 0) calibrate_button = QPushButton("Calibrate Eye Tracker") calibrate_button.pressed.connect(calibrate) grid.addWidget(calibrate_button, 2, 0) self.record_button = QPushButton("Record Screen and Gaze") self.record_button.pressed.connect(capture_screen) grid.addWidget(self.record_button, 3, 0) self.author_vid_button = QPushButton("Write Author Video") self.author_vid_button.pressed.connect(create_video) grid.addWidget(self.author_vid_button, 4, 0) self.author_vid_button.setEnabled(False) self.timeline = QTimeLine() self.timeline.setCurveShape(QTimeLine.LinearCurve) self.timeline.setDuration(360000) #Totsl video lengthn in milliseconds self.timeline.setFrameRange( 0, 7500) #Maximum Frames in this video as 30 fps self.timeline.frameChanged.connect(update_frame) self.timeline.setUpdateInterval(10) #Rate of Frame Capture def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: app.closeAllWindows()
def wheelEvent(self, event: QWheelEvent) -> None: if event.modifiers() & Qt.ControlModifier: num_degrees = event.angleDelta().y() / 8.0 num_steps = num_degrees / 15.0 self.num_scheduled_steps += num_steps if self.num_scheduled_steps * num_steps < 0: self.num_scheduled_steps = num_steps animation = QTimeLine(duration=350, parent=self) animation.setUpdateInterval(20) value_changed_sig: pyqtBoundSignal = animation.valueChanged value_changed_sig.connect(self.scaling_step) finished_sig: pyqtBoundSignal = animation.finished finished_sig.connect(self.animation_finished) animation.start() else: super().wheelEvent(event)
class SideSlideDecorator(QWidget): m_slidePos: QPoint m_slideWidgetPixmap: QPixmap m_timeline: QTimeLine m_backgroundPixmap: QPixmap m_decorationColor: QColor clicked = pyqtSignal() def __init__(self, *args, **kwargs): super(SideSlideDecorator, self).__init__(*args, **kwargs) self.resize(self.maximumSize()) self.m_backgroundPixmap = QPixmap() self.m_slidePos = QPoint() self.m_timeline = QTimeLine() self.m_timeline.setDuration(260) self.m_timeline.setUpdateInterval(40) self.m_timeline.setEasingCurve(QEasingCurve.OutQuad) self.m_timeline.setStartFrame(0) self.m_timeline.setEndFrame(10000) self.m_decorationColor = QColor(0, 0, 0, 0) def frameChanged(_value): self.m_decorationColor = QColor(0, 0, 0, _value / 100) self.update() self.m_timeline.frameChanged.connect(frameChanged) def grabSlideWidget(self, _slideWidget): self.m_slideWidgetPixmap = _slideWidget.grab() def grabParent(self): # self.m_backgroundPixmap = self.parentWidget().grab() pass def decorate(self, _dark): if self.m_timeline.state() == QTimeLine.Running: self.m_timeline.stop() self.m_timeline.setDirection( QTimeLine.Forward if _dark else QTimeLine.Backward) self.m_timeline.start() def slidePos(self): return self.m_slidePos def setSlidePos(self, _pos): if self.m_slidePos != _pos: self.m_slidePos = _pos self.update() def paintEvent(self, _event): painter = QPainter(self) painter.drawPixmap(0, 0, self.m_backgroundPixmap) painter.fillRect(self.rect(), self.m_decorationColor) painter.drawPixmap(self.m_slidePos, self.m_slideWidgetPixmap) super(SideSlideDecorator, self).paintEvent(_event) def mousePressEvent(self, _event): self.clicked.emit() super(SideSlideDecorator, self).mousePressEvent(_event) _slidePos = pyqtProperty(QPoint, fget=slidePos, fset=setSlidePos)
class QPageWidget(QScrollArea): """ The QPageWidget provides a stack widget with animated page transitions. """ #Emits currentChanged = pyqtSignal() def __init__(self, parent=None, direction="ltr", rtf=False): """ Creates a new QPageWidget on given parent object. parent: QWidget parent direction: "ltr" -> Left To Right "ttb" -> Top To Bottom rtf: Return to first, if its True it flips to the first page when next page requested at the last page """ # First initialize, QPageWidget is based on QScrollArea QScrollArea.__init__(self, parent) # Properties for QScrollArea self.setFrameShape(QFrame.NoFrame) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setWidgetResizable(True) # Main widget, which stores all Pages in it self.widget = QWidget(self) # Layout based on QBoxLayout which supports Vertical or Horizontal layout if direction == "ltr": self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget) self.__scrollBar = self.horizontalScrollBar() self.__base_value = self.width else: self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget) self.__scrollBar = self.verticalScrollBar() self.__base_value = self.height self.layout.setSpacing(0) #qboxlayout setmargin özelliği yok #self.layout.setMargin(0) # Return to first self.__return_to_first = rtf # TMP_PAGE, its using as last page in stack # A workaround for a QScrollArea bug self.__tmp_page = Page(QWidget(self.widget)) self.__pages = [self.__tmp_page] self.__current = 0 self.__last = 0 # Set main widget self.setWidget(self.widget) # Animation TimeLine self.__timeline = QTimeLine() self.__timeline.setUpdateInterval(2) # Updates scrollbar position when frame changed self.__timeline.frameChanged.connect( lambda x: self.__scrollBar.setValue(x)) # End of the animation self.__timeline.finished.connect(self._animateFinished) # Initialize animation self.setAnimation() self.setDuration() def _animateFinished(self): """ Its called by TimeLine when animation finished. It first runs the outMethod of last Page and then the inMethod of current Page Finally tt gives the focus to the current page and fixes the scrollBar """ # Disable other widgets for page in self.__pages: if not page == self.__pages[self.__current]: page.widget.setEnabled(False) # Run last page's outMethod if exists if self.__pages[self.__last].outMethod: self.__pages[self.__last].outMethod() # Run new page's inMethod if exists if self.__pages[self.__current].inMethod: self.__pages[self.__current].inMethod() # Give focus to the current Page self.__pages[self.__current].widget.setFocus() # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Emit currentChanged SIGNAL self.currentChanged.emit() def event(self, event): """ Overrides the main event handler to catch resize events """ # Catch Resize event if event.type() == QEvent.Resize: # Update each page size limits to mainwidget's new size for page in self.__pages: page.widget.setMinimumSize(self.size()) page.widget.setMaximumSize(self.size()) # Update viewport size limits to mainwidget's new size # It's a workaround for QScrollArea updateGeometry bug self.viewport().setMinimumSize(self.size()) self.viewport().setMaximumSize(self.size()) # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Return the Event return QScrollArea.event(self, event) def keyPressEvent(self, event): """ Overrides the keyPressEvent to ignore them """ pass def wheelEvent(self, event): """ Overrides the wheelEvent to ignore them """ pass def createPage(self, widget, inMethod=None, outMethod=None): """ Creates and adds new Page for given widget with given in/out methods. widget: A QWidget which is the mainwidget for this Page inMethod: (optional) QPageWidget triggers this method when the Page appear outMethod: (optional) QPageWidget triggers this method when the Page disappear """ self.addPage(Page(widget, inMethod, outMethod)) def addPage(self, page): """ Adds the given Page to the stack. page: A Page object """ # First remove the last page; its __tmp_page self.__pages.pop() # Add new page self.__pages.append(page) self.layout.addWidget(page.widget) # Add __tmp_page to end self.__pages.append(self.__tmp_page) self.layout.addWidget(self.__tmp_page.widget) # Create connections for page navigation signals from new page try: page.widget.pageNext.connect(self.next) page.widget.pagePrevious.connect(self.prev) page.widget.setCurrent[int].connect(self.setCurrent) except: pass def __setCurrent(self, pageNumber): """ Internal method to set current page index. """ self.__last = self.__current self.__current = min(max(0, pageNumber), len(self.__pages) - 2) if pageNumber == len(self.__pages) - 1 and self.__return_to_first: self.__current = 0 def setCurrent(self, pageNumber=0): """ Set and flip the page with given pageNumber. pageNumber: index number of Page (default is 0) """ self.__setCurrent(pageNumber) self.flipPage() def getCurrent(self): """ Returns current page index. """ return self.__current def getCurrentWidget(self): """ Returns current page widget. """ return self.getWidget(self.getCurrent()) def getWidget(self, pageNumber): """ Returns widget for given page index pageNumber: index number of Page """ try: return self.__pages[pageNumber].widget except: return None def count(self): """ Returns number of pages. """ return len(self.__pages) - 1 def setAnimation(self, animation=35): """ Set the transition animation with the given animation. animation: the number represents predefined QEasingCurves List of predefined QEasingCurves can be found from: http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum Default is QEasingCurve::InOutBack (35) """ self.__animation = animation self.__timeline.setEasingCurve(QEasingCurve(self.__animation)) def setDuration(self, duration=400): """ Set the transition duration. duration: duration time in ms """ self.__duration = duration self.__timeline.setDuration(self.__duration) def flipPage(self, direction=0): """ Flip the page with given direction. direction: can be -1, 0 or +1 -1: previous page (if exists) 0: just flip to current page +1: next page (if exists) """ # Enable all widgets for page in self.__pages: page.widget.setEnabled(True) # Check given direction direction = direction if direction == 0 else max(min(1, direction), -1) # If direction is equal to zero no need to re-set current if not direction == 0: self.__setCurrent(self.__current + direction) # If last page is different from new page, flip it ! if not self.__last == self.__current: self.__timeline.setFrameRange(self.__scrollBar.value(), self.__current * self.__base_value()) self.__timeline.start() def next(self): """ Helper method to flip next page. """ self.flipPage(1) def prev(self): """ Helper method to flip previous page. """ self.flipPage(-1)
class QPageWidget(QScrollArea): """ The QPageWidget provides a stack widget with animated page transitions. """ #Emits currentChanged = pyqtSignal() def __init__(self, parent = None, direction = "ltr", rtf = False): """ Creates a new QPageWidget on given parent object. parent: QWidget parent direction: "ltr" -> Left To Right "ttb" -> Top To Bottom rtf: Return to first, if its True it flips to the first page when next page requested at the last page """ # First initialize, QPageWidget is based on QScrollArea QScrollArea.__init__(self, parent) # Properties for QScrollArea self.setFrameShape(QFrame.NoFrame) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setWidgetResizable(True) # Main widget, which stores all Pages in it self.widget = QWidget(self) # Layout based on QBoxLayout which supports Vertical or Horizontal layout if direction == "ltr": self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget) self.__scrollBar = self.horizontalScrollBar() self.__base_value = self.width else: self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget) self.__scrollBar = self.verticalScrollBar() self.__base_value = self.height self.layout.setSpacing(0) #qboxlayout setmargin özelliği yok #self.layout.setMargin(0) # Return to first self.__return_to_first = rtf # TMP_PAGE, its using as last page in stack # A workaround for a QScrollArea bug self.__tmp_page = Page(QWidget(self.widget)) self.__pages = [self.__tmp_page] self.__current = 0 self.__last = 0 # Set main widget self.setWidget(self.widget) # Animation TimeLine self.__timeline = QTimeLine() self.__timeline.setUpdateInterval(2) # Updates scrollbar position when frame changed self.__timeline.frameChanged.connect(lambda x: self.__scrollBar.setValue(x)) # End of the animation self.__timeline.finished.connect(self._animateFinished) # Initialize animation self.setAnimation() self.setDuration() def _animateFinished(self): """ Its called by TimeLine when animation finished. It first runs the outMethod of last Page and then the inMethod of current Page Finally tt gives the focus to the current page and fixes the scrollBar """ # Disable other widgets for page in self.__pages: if not page == self.__pages[self.__current]: page.widget.setEnabled(False) # Run last page's outMethod if exists if self.__pages[self.__last].outMethod: self.__pages[self.__last].outMethod() # Run new page's inMethod if exists if self.__pages[self.__current].inMethod: self.__pages[self.__current].inMethod() # Give focus to the current Page self.__pages[self.__current].widget.setFocus() # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Emit currentChanged SIGNAL self.currentChanged.emit() def event(self, event): """ Overrides the main event handler to catch resize events """ # Catch Resize event if event.type() == QEvent.Resize: # Update each page size limits to mainwidget's new size for page in self.__pages: page.widget.setMinimumSize(self.size()) page.widget.setMaximumSize(self.size()) # Update viewport size limits to mainwidget's new size # It's a workaround for QScrollArea updateGeometry bug self.viewport().setMinimumSize(self.size()) self.viewport().setMaximumSize(self.size()) # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Return the Event return QScrollArea.event(self, event) def keyPressEvent(self, event): """ Overrides the keyPressEvent to ignore them """ pass def wheelEvent(self, event): """ Overrides the wheelEvent to ignore them """ pass def createPage(self, widget, inMethod = None, outMethod = None): """ Creates and adds new Page for given widget with given in/out methods. widget: A QWidget which is the mainwidget for this Page inMethod: (optional) QPageWidget triggers this method when the Page appear outMethod: (optional) QPageWidget triggers this method when the Page disappear """ self.addPage(Page(widget, inMethod, outMethod)) def addPage(self, page): """ Adds the given Page to the stack. page: A Page object """ # First remove the last page; its __tmp_page self.__pages.pop() # Add new page self.__pages.append(page) self.layout.addWidget(page.widget) # Add __tmp_page to end self.__pages.append(self.__tmp_page) self.layout.addWidget(self.__tmp_page.widget) # Create connections for page navigation signals from new page try: page.widget.pageNext.connect(self.next) page.widget.pagePrevious.connect(self.prev) page.widget.setCurrent[int].connect(self.setCurrent) except: pass def __setCurrent(self, pageNumber): """ Internal method to set current page index. """ self.__last = self.__current self.__current = min(max(0, pageNumber), len(self.__pages) - 2) if pageNumber == len(self.__pages) - 1 and self.__return_to_first: self.__current = 0 def setCurrent(self, pageNumber = 0): """ Set and flip the page with given pageNumber. pageNumber: index number of Page (default is 0) """ self.__setCurrent(pageNumber) self.flipPage() def getCurrent(self): """ Returns current page index. """ return self.__current def getCurrentWidget(self): """ Returns current page widget. """ return self.getWidget(self.getCurrent()) def getWidget(self, pageNumber): """ Returns widget for given page index pageNumber: index number of Page """ try: return self.__pages[pageNumber].widget except: return None def count(self): """ Returns number of pages. """ return len(self.__pages) - 1 def setAnimation(self, animation = 35): """ Set the transition animation with the given animation. animation: the number represents predefined QEasingCurves List of predefined QEasingCurves can be found from: http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum Default is QEasingCurve::InOutBack (35) """ self.__animation = animation self.__timeline.setEasingCurve(QEasingCurve(self.__animation)) def setDuration(self, duration = 400): """ Set the transition duration. duration: duration time in ms """ self.__duration = duration self.__timeline.setDuration(self.__duration) def flipPage(self, direction=0): """ Flip the page with given direction. direction: can be -1, 0 or +1 -1: previous page (if exists) 0: just flip to current page +1: next page (if exists) """ # Enable all widgets for page in self.__pages: page.widget.setEnabled(True) # Check given direction direction = direction if direction == 0 else max(min(1, direction), -1) # If direction is equal to zero no need to re-set current if not direction == 0: self.__setCurrent(self.__current + direction) # If last page is different from new page, flip it ! if not self.__last == self.__current: self.__timeline.setFrameRange(self.__scrollBar.value(), self.__current * self.__base_value()) self.__timeline.start() def next(self): """ Helper method to flip next page. """ self.flipPage(1) def prev(self): """ Helper method to flip previous page. """ self.flipPage(-1)
class TSScene(QGraphicsScene): starttimechanged = pyqtSignal(str) endtimechanged = pyqtSignal(str) def __init__(self, parent, width=14, height=12, numofchannel=6): super(TSScene, self).__init__(parent) # set waveform windows figure = Figure() figure.set_size_inches(width, height) self.graphwidth = figure.dpi * width self.canvas = FigureCanvas(figure) self.addWidget(self.canvas) self.canvas.mpl_connect('button_press_event',self.button_press_event) self.canvas.mpl_connect('button_release_event', self.button_release_event) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_event) self.canvas.mpl_connect('scroll_event', self.scroll_event) self.axesavailability = [True for i in range(numofchannel)] self.axes = [] for i in range(numofchannel): self.axes.append(figure.add_subplot(str(numofchannel)+'1'+str(i+1))) # set backend data model self.data = TSData() self.visibleWave = {} self.starttime = None self.endtime = None # prepare for user input self.downxcoord = None self.wheelactive = False self.rect = None self.installEventFilter(self) self.showgap = False self.downbutton = None self.currentxdata = None self.count = 0 self.state = 'ready' self.timeline = QTimeLine(1) self.timeline.setCurrentTime(0) self.timeline.setUpdateInterval(1) self.timeline.finished.connect(self.timeshift) self.timeline.finished.connect(self.animfinished) def animfinished(self): self.state = 'ready' self.timeline.setCurrentTime(0) def togglegap(self): self.showgap = ~self.showgap tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave,tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def applytime(self, start: str, end: str): if self.data is None: return for wave in self.visibleWave: if start<self.visibleWave[wave][3]: start = self.visibleWave[wave][3] if end>self.visibleWave[wave][4]: end = self.visibleWave[wave][4] self.starttime = UTCDateTime(start) self.endtime = UTCDateTime(end) print((self.starttime, self.endtime, '-----------------')) tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) def loadfile(self, filename: str): self.data.loadFile(filename) def getlist(self): return self.data.getlist() def getsegments(self, item: object): waves = self.data.getsegments(item.text(0)) wavelist = QListWidget() for w in waves: wavelist.addItem(w) # print(w) wavelist.itemDoubleClicked.connect(self.segmentselected) wavelistwindowlayout = QVBoxLayout() wavelistwindowlayout.addWidget(wavelist) self.wavelistwindow = QDialog(self.parent()) self.wavelistwindow.setWindowTitle('segments') self.wavelistwindow.setLayout(wavelistwindowlayout) self.wavelistwindow.resize(800,600) self.wavelistwindow.show() self.segmentsource = item.text(0) self.currentitem = item def segmentselected(self, segment: str): matches = re.match(r'[^ ]+ \| ([^ ]+) - ([^ ]+) \| .*', segment.text(), flags=0) start = UTCDateTime(matches.group(1)) end = UTCDateTime(matches.group(2)) print(start) print(end) if self.segmentsource in self.visibleWave: self.applytime(start, end) else: self.starttime = start self.endtime = end print((self.segmentsource)) self.togglewave(self.segmentsource) self.currentitem.setSelected(True) def refreshwave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) def hidewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None return True def showwave(self, wave: str, starttime=None, endtime=None): if starttime is None or endtime is None: if wave in self.visibleWave: pass else: self.togglewave(wave) else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) if wave not in self.visibleWave: self.togglewave(wave) def togglewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None else: # print(wave) waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) print((starttime, endtime)) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) #print("togglewave:", starttime, endtime) def displaywave(self, wavename: str, waveform: np.array, gaps, colorcode: int=None): if True not in self.axesavailability: return None, None else: location = self.axesavailability.index(True) axes = self.axes[location] self.axesavailability[location] = False if wavename is not None and waveform is not None: if colorcode is None: colorcode = 'C'+str(location%10) times = waveform[0,:] span = round(len(times)/4) if span<1: span = 1 axes.set_xticks(times[::span]) axes.set_xticklabels([UTCDateTime(t).strftime("%Y-%m-%d %H:%M:%S") for t in times[::span]]) lines = axes.plot(times, waveform[1,:],linestyle="-", label=wavename, color=colorcode) if self.showgap: for g in gaps: if g[4].timestamp>=times[0] and g[5].timestamp<times[-1]: axes.axvspan(g[4],g[5],facecolor='0.2',alpha=0.5) axes.legend() self.canvas.draw() if self.endtime is not None and self.starttime is not None and len(times)>0: timewindow = self.endtime-self.starttime if abs(times[0]-times[-1]-timewindow)/timewindow<0.1: self.starttime = UTCDateTime(times[0]) self.endtime = self.starttime + timewindow elif len(times)>0: self.starttime = UTCDateTime(times[0]) self.endtime = UTCDateTime(times[-1]) self.starttimechanged.emit(self.starttime.strftime("%Y-%m-%d %H:%M:%S")) self.endtimechanged.emit(self.endtime.strftime("%Y-%m-%d %H:%M:%S")) return axes, lines else: lines = None axes.legend([wavename]) return axes, lines def removewave(self, axes: Axes, lines: Line2D): if lines is not None: lines.pop(0).remove() axes.relim() axes.autoscale_view(True, True, True) axes.clear() self.canvas.draw() def timeshift(self): if self.downxcoord is None or self.currentxdata is None: return shift = self.downxcoord-self.currentxdata if shift == 0: print('skipped') return if self.starttime is None: return starttime = self.starttime + shift endtime = self.endtime + shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.visibleWave[wave][3] if endtime>self.visibleWave[wave][4]: endtime = self.visibleWave[wave][4] if starttime!=self.starttime and endtime!=self.endtime: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) return def timescale(self, delta: float): if self.starttime is None: return shift = (self.endtime - self.starttime) * -delta*0.1 starttime = self.starttime + shift endtime = self.endtime - shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.starttime if endtime>self.visibleWave[wave][4]: endtime = self.endtime if endtime-starttime<0.1: pass elif starttime==self.starttime and endtime==self.endtime: pass else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def button_press_event(self, event): if self.starttime is None: return self.downxcoord = event.xdata self.downx = event.x self.downbutton = event.button self.count = 0 def motion_notify_event(self, event): # print(event.button, self.starttime, self.downbutton, self.downxcoord, event.xdata) self.count += 1 self.currentxdata = event.xdata #print(self.currentxdata,"+" * 10) if self.starttime is None: return elif self.downxcoord is not None: if self.downbutton == 1 and self.timeline.currentTime()==0: self.state = 'busy' self.timeline.start() elif self.downbutton == 1: pass elif self.downbutton == 3: if self.rect is not None: self.removeItem(self.rect) if self.downx < event.x: self.rect = self.addRect(self.downx, 0, event.x - self.downx, self.height(), pen=QPen(Qt.red)) else: self.rect = self.addRect(event.x, 0, self.downx - event.x, self.height(), pen=QPen(Qt.red)) def button_release_event(self, event): if self.starttime is None: return if event.button == 3: left = 225 right = 1215 if self.downxcoord < event.xdata: start = self.downxcoord end = event.xdata else: start = event.xdata end = self.downxcoord start = UTCDateTime(start) end = UTCDateTime(end) print((start,end,'================')) self.applytime(start, end) # self.downx = None self.downbutton = None self.removeItem(self.rect) self.rect = None self.downxcoord = None self.currentxdata = None #print(self.count,'count!!!!!!!!') self.count=0 def scroll_event(self, event): delta = -event.step if self.wheelactive==False and event.xdata>= self.starttime and event.xdata<= self.endtime: self.wheelactive = True self.timescale(delta) self.wheelactive = False def exportmetadata(self, filename: tuple): wavelist = self.getlist() outfile = open(filename[0]+'.txt','w') for network in wavelist: for station in wavelist[network]: for wave in wavelist[network][station]: for w in wavelist[network][station][wave]: outfile.write("%s\n\n" % w) outfile.close() def exportwaveform(self, filename: tuple): traces = [] for wave in self.visibleWave: fill_value = 'last' waveform, wavename, starttime, endtime, gaps = self.data.readdisc(wave, self.starttime, self.endtime, resample=False, fill_value=fill_value) traces.append(waveform) stream = Stream(traces=traces) if 'MSEED' in filename[1]: stream.write(filename[0] + ".mseed", format='MSEED') elif 'txt' in filename[1]: stream.write(filename[0] + ".txt", format='TSPAIR') def gettimeboundary(self): return self.starttime, self.endtime return False