class AsyncCaller(object): """Call a Python function after a delay.""" def __init__(self, delay=10): self._delay = delay self._timer = None def _create_timer(self, f): self._timer = QTimer() self._timer.timeout.connect(f) self._timer.setSingleShot(True) def set(self, f): """Call a function after a delay, unless another function is set in the meantime.""" self.stop() self._create_timer(f) self.start() def start(self): """Start the timer and call the function after a delay.""" if self._timer: self._timer.start(self._delay) def stop(self): """Stop the current timer if there is one and cancel the async call.""" if self._timer: self._timer.stop() self._timer.deleteLater()
class DelayWidget(WebWidget): def __init__(self, name, cfg, parent = None): WebWidget.__init__(self, name, parent) self.config = cfg self.url.setUrl(self.config.loadLinks()[str(self.objectName())]['data']) self.timer = QTimer(self) self.timer.setInterval(1000) self.timer.setSingleShot(1) self.timeoutTimer = QTimer(self) self.timeoutTimer.setInterval(10000) self.timeoutTimer.setSingleShot(1) self.connect(self.timeoutTimer , SIGNAL('timeout()') , self.clear) self.connect(self.timer , SIGNAL('timeout()') , self.reload_) self.connect(self , SIGNAL('done()') , self.clear) def clear(self): self.config.saveDelayWidgetBusy(False) def reload_(self): if not self.isVisible(): return if not self.timeoutTimer.isActive(): self.timeoutTimer.start() if self.config.loadDelayWidgetBusy(): self.timer.start() else: self.timeoutTimer.stop() self.config.saveDelayWidgetBusy(True) WebWidget.reload_(self)
class _StatusBar(QStatusBar): """Extended status bar. Supports HTML messages """ def __init__(self, *args): QStatusBar.__init__(self, *args) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setSizeGripEnabled(False) self.setStyleSheet("QStatusBar {border: 0} QStatusBar::item {border: 0}") self._label = QLabel(self) self._label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self._label.setStyleSheet("color: red") self.addWidget(self._label) self._timer = QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self.clearMessage) def showMessage(self, text, timeout=0): """QStatusBar.showMessage() """ self._label.setText(text) self._timer.stop() if timeout > 0: self._timer.start(timeout) def clearMessage(self): """QStatusBar.clearMessage() """ self._label.clear()
class Holter(QMainWindow, Ui_Holter): """ Class documentation goes here. """ count=0 #用于计数realFHR的绘画次数,即timer的计数次数 #baseCount=0 def __init__(self,parent = None): """ Constructor """ QMainWindow.__init__(self, parent) self.setupUi(self) self.timer = QTimer() self.timerSound=QTimer() global soundfile soundfile = "F:/work in 2015 winter/5-HOLTER/FHR/_eric4project/rawHR.wav" self.timer.start(1) QtCore.QObject.connect(self.timer, SIGNAL("timeout()"),self.update) def paintEvent(self, event): qp = QtGui.QPainter() qp.begin(self) drawBackground(self, qp) drawScales(self, qp) realFHR(self, qp, FHR, Holter.count) realBaseline(self, qp, Baseline, Holter.count) Holter.count+=1 if Holter.count%1000==0: print time.strftime('%H:%M:%S',time.localtime(time.time())) print Holter.count def sound(self): winsound.PlaySound(soundfile, winsound.SND_ASYNC) #立即返回,支持异步播放
class MyWindowClass(QtGui.QMainWindow, form_class): connected = bool(False) windfreak = None time = 0 def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.ButtonUpdate_freq.clicked.connect(self.ButtonUpdate_freq_clicked)# Bind the event handlers self.ButtonUpdate_power.clicked.connect(self.ButtonUpdate_power_clicked) self.ButtonUpdate_channel.clicked.connect(self.ButtonUpdate_channel_clicked) self.ButtonConnect.clicked.connect(self.ButtonConnect_clicked) self.comboSerialBox.addItems(serial_ports()) #Gets a list of avaliable serial ports to connect to and adds to combo box def ButtonConnect_clicked(self,connection): if not self.connected: self.windfreak = wc.windfreakusb2(str(self.comboSerialBox.currentText())) self.timer = QTimer() self.connected = True self.timer.timeout.connect(self.update) self.timer.start(1000) self.control_label.setText('connected to ' + str(self.comboSerialBox.currentText())) self.freq = float(self.windfreak.get_freq())/1000 self.power = self.windfreak.get_power() self.label_freq.setText(str(self.freq)+"MHz") self.label_power.setText(str(self.power)) self.windfreak.set_clock(str(1)) #sets internal clock so that is locks self.windfreak.set_freq(str(self.freq)) def ButtonUpdate_freq_clicked(self,value): self.windfreak.set_freq(self.freq_box.text()) self.freq = float(self.windfreak.get_freq())/1000 self.label_freq.setText(str(self.freq)+"MHz") print 'freq updated' def ButtonUpdate_power_clicked(self,value): self.windfreak.set_power(self.power_box.text()) self.power = self.windfreak.get_power() self.label_power.setText(self.power) print 'power updated' def ButtonUpdate_channel_clicked(self,value): url = "http://charsiew.qoptics.quantum.nus.edu.sg:8080" try: urllib2.urlopen(url+"/switch_"+str(self.channel_box.text())) except: pass print 'channel updated' def update(self): url = "http://charsiew.qoptics.quantum.nus.edu.sg:8080" self.data = json.load(urllib2.urlopen(url+"/data")) self.label_wavelength.setText(self.data['wavelength']) self.label_optical_freq.setText(self.data['freq']) self.label_channel.setText(self.data['channel'])
class VUMeter(QObject): KITCHEN_SINK = 'alsa_output.pci-0000_00_1b.0.analog-stereo' def __init__(self, parent, sink_name=None): super(VUMeter, self).__init__(parent) if sink_name == None: self.sink_name = self.KITCHEN_SINK else: self.sink_name = sink_name self.meter_rate = 344 self.display_scale = 8 self.monitor = PAPeakMonitor(self.sink_name, self.meter_rate) self.timer = QTimer() self.timer.timeout.connect(self.update) self.timer.start(100) self.view = VUWidgetView(parent) self.view.setGeometry(0, 0, 20, parent.height() ) def update(self): for sample in self.monitor: sample = sample * self.display_scale self.view.update(sample)
def wait(self, time_ms, callback, onredirect=None, onerror=None): """ Wait for time_ms, then run callback. If onredirect is True then the timer is cancelled if redirect happens. If onredirect is callable then in case of redirect the timer is cancelled and this callable is called. If onerror is True then the timer is cancelled if a render error happens. If onerror is callable then in case of a render error the timer is cancelled and this callable is called. """ timer = QTimer() timer.setSingleShot(True) timer_callback = functools.partial(self._on_wait_timeout, timer=timer, callback=callback, ) timer.timeout.connect(timer_callback) self.logger.log("waiting %sms; timer %s" % (time_ms, id(timer)), min_level=2) timer.start(time_ms) self._active_timers.add(timer) if onredirect: self._timers_to_cancel_on_redirect[timer] = onredirect if onerror: self._timers_to_cancel_on_error[timer] = onerror
def private_call_later(self, callback, delay=None): if delay is None: delay = 0 if not isinstance(delay, (float, int)): raise ScriptError({ "argument": "delay", "message": "splash:call_later delay must be a number", "splash_method": "call_later", }) delay = int(float(delay)*1000) if delay < 0: raise ScriptError({ "argument": "delay", "message": "splash:call_later delay must be >= 0", "splash_method": "call_later", }) if lupa.lua_type(callback) != 'function': raise ScriptError({ "argument": "callback", "message": "splash:call_later callback is not a function", "splash_method": "call_later", }) qtimer = QTimer(self.tab) qtimer.setSingleShot(True) timer = _ExposedTimer(self, qtimer) run_coro = self.get_coroutine_run_func( "splash:call_later", callback, return_error=timer.store_error ) qtimer.timeout.connect(run_coro) qtimer.start(delay) return timer
class CalendarWidget(QFrame): def __init__(self, parent = None): QFrame.__init__(self, parent) self.timer = QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self.updateCurrentDateTime) self.timer.start() def paintEvent(self, event): QFrame.paintEvent(self, event) text = QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) logicalRect = QRectF(QPointF(0, 0), QSizeF(QFontMetrics(self.font()).size(Qt.TextSingleLine, text))) physicalRect, frameWidth = QRectF(self.rect()), self.frameWidth() physicalRect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth) scaleForWidth = physicalRect.width() / logicalRect.width() scaleForHeight = physicalRect.height() / logicalRect.height() logicalRect.moveTo(frameWidth / scaleForWidth , frameWidth / scaleForHeight) painter = QStylePainter(self) painter.scale(scaleForWidth, scaleForHeight) painter.drawText(logicalRect, Qt.AlignCenter, text) def updateCurrentDateTime(self): if self.isVisible(): self.update()
class IntegrationTest(QWidget): """ Test the controller and view """ def __init__(self, model): super(IntegrationTest, self).__init__() self.model = model model.current_time = parse(u'2014-05-29T17:54:55+01:00').\ replace(tzinfo=pytz.utc) model.start_time = parse(u'2014-05-29T17:00:00+01:00').\ replace(tzinfo=pytz.utc) model.end_time = parse(u'2014-05-29T18:00:00+01:00').\ replace(tzinfo=pytz.utc) view = AutoStopDialog(self) self.auto_stop = AutoStopController(model, view, parent=self) self.setWindowModality(Qt.WindowModal) self.setWindowTitle('Example') self.timer = QTimer() self.timer.timeout.connect(self.inc_time) self.timer.start(1000) self.show() def inc_time(self): """ Increment the mock timer """ self.model.current_time = self.model.current_time + timedelta(0, 1)
class _GlobalUpdateWordSetTimer: """Timer updates word set, when editor is idle. (5 sec. after last change) Timer is global, for avoid situation, when all instances update set simultaneously """ _IDLE_TIMEOUT_MS = 1000 def __init__(self): self._timer = QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._onTimer) self._scheduledMethods = [] def schedule(self, method): if not method in self._scheduledMethods: self._scheduledMethods.append(method) self._timer.start(self._IDLE_TIMEOUT_MS) def cancel(self, method): """Cancel scheduled method Safe method, may be called with not-scheduled method""" if method in self._scheduledMethods: self._scheduledMethods.remove(method) if not self._scheduledMethods: self._timer.stop() def _onTimer(self): method = self._scheduledMethods.pop() method() if self._scheduledMethods: self._timer.start(self._IDLE_TIMEOUT_MS)
class UptimeDisplayApplet(plasmascript.Applet): def __init__(self,parent,args=None): plasmascript.Applet.__init__(self,parent) def init(self): self.setHasConfigurationInterface(True) self.setAspectRatioMode(Plasma.Square) self.uptime = '' self.update_timer = QTimer() self.update_timer.start(60000) #60s QObject.connect(self.update_timer, SIGNAL("timeout()"), self.constantUpdate) self.readUptime() def sizeHint(self): return QSize(400, 400) def readUptime(self): with open('/proc/uptime', 'r') as f: uptime_seconds = float(f.readline().split()[0]) uptime_hours = int(uptime_seconds / 3600) uptime_minutes = int((uptime_seconds - (uptime_hours * 3600)) / 60) self.uptime = "%dh\n%dm" % (uptime_hours, uptime_minutes) def constantUpdate(self): self.readUptime() self.update() def paintInterface(self, painter, option, rect): painter.save() painter.setPen(Qt.black) painter.setFont(QFont('Decorative', 8)) painter.drawText(rect, Qt.AlignVCenter | Qt.AlignHCenter, str(self.uptime)) painter.restore()
class ErrorMessageFilter(QObject): """ In a parallel program, the same error may occur in several threads in close succession. For example, all slice views will notice a "filter too large" error simultaneously. This class collects error messages for a certain time (currently: 1000ms) and then displays each unique message only once. """ def __init__(self, parent): super(QObject, self).__init__(parent) self.messages = {} self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.setInterval(1000) self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeout) def showErrorMessage(self, caption, text): if not self.timer.isActive(): self.timer.start() self.messages[caption] = text def timeout(self): # Must copy now because the eventloop is allowed to run during QMessageBox.critical, below. # That is, self.messages might change while the loop is executing (not allowed). messages = copy.copy(self.messages) for caption, text in messages.iteritems(): QMessageBox.critical(self.parent(), caption, text) self.messages = {}
def run(self): app = QApplication(sys.argv) imageProvider = ImageProvider() # Create the QML user interface. view = QDeclarativeView() view.setResizeMode(QDeclarativeView.SizeRootObjectToView) engine = view.engine() engine.addImageProvider("mazakodron", imageProvider) view.setSource(QUrl('symulator/mazakodron.qml')) rootObject = view.rootObject() if not rootObject: view.setSource(QUrl('mazakodron.qml')) rootObject = view.rootObject() rootObject.requestDraw.connect(imageProvider.draw) self.rootObject = rootObject view.setGeometry(0, 0, 800, 600) view.show() timer = QTimer() timer.start(1000/60) # 60FPS timer.timeout.connect(self.process) sys.exit(app.exec_());
class MyForm(QtGui.QMainWindow): def __init__(self, parent=None): self.ticketNumber = '' ticketStatus() QtGui.QWidget.__init__(self, parent) self.ui = Ui_ticketReaderView() self.ui.setupUi(self) self.timer = QTimer() self.timer.timeout.connect(self.setDefault) self.statusBar = QtGui.QStatusBar() self.setStatusBar(self.statusBar) self.statusBar.hide() self.menuBar = QtGui.QMenuBar() self.setMenuBar(self.menuBar) self.menuBar.hide() self.ui.mainToolBar.hide() #self.showFullScreen() def keyPressEvent(self, event): key = event.key() if key != QtCore.Qt.Key_Return: self.ticketNumber+=chr(key) print('pressed: ', chr(key)) if key == QtCore.Qt.Key_Return: print('Ticket:', self.ticketNumber) if(len(self.ticketNumber)>0): self.checkIsTicketValid() self.timer.start(3000) self.ticketNumber = '' def setDefault(self): self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">Molimo nanesite <br /> Vaš tiket<br /> </span></p></body></html>", None)) def checkIsTicketValid(self): self.status = ticketStatus.checkTicketNumber(self.ticketNumber) if self.status['validationSuccess'] == 'ok': self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">"+self.status['validationMessage']+"<br /> </span></p></body></html>", None)) print (self.status) else: self.ui.textEdit.setHtml(_translate("ticketReaderView", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n" "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n" "p, li { white-space: pre-wrap; }\n" "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n" "<p align=\"center\" style=\" margin-top:0px; margin-bottom:15px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#00A3E8;\"><span style=\" font-family:\'Calibri\'; font-size:28pt; font-weight:600; color:#ffffff; background-color:#00A3E8;\">"+self.status['validationMessage']+"<br /> </span></p></body></html>", None)) print (self.status)
class DeviceReader(QThread): """Used for polling data from the Input layer during configuration""" raw_axis_data_signal = pyqtSignal(object) raw_button_data_signal = pyqtSignal(object) mapped_values_signal = pyqtSignal(object) def __init__(self, input): QThread.__init__(self) self._input = input self._read_timer = QTimer() self._read_timer.setInterval(25) self.connect(self._read_timer, SIGNAL("timeout()"), self._read_input) def stop_reading(self): """Stop polling data""" self._read_timer.stop() def start_reading(self): """Start polling data""" self._read_timer.start() def _read_input(self): [rawaxis, rawbuttons, mapped_values] = self._input.read_raw_values() self.raw_axis_data_signal.emit(rawaxis) self.raw_button_data_signal.emit(rawbuttons) self.mapped_values_signal.emit(mapped_values)
class StartPage(QWidget): """ Interfáz QML """ def __init__(self): QWidget.__init__(self) box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) view = QDeclarativeView() view.setMinimumSize(400, 400) qml = os.path.join(paths.PATH, "ui", "StartPage.qml") path = QDir.fromNativeSeparators(qml) view.setSource(QUrl.fromLocalFile(path)) view.setResizeMode(QDeclarativeView.SizeRootObjectToView) self._root = view.rootObject() box.addWidget(view) self._current_text = "" # Timer self.timer = QTimer(self) self.timer.setInterval(3000) self._show_welcome_text() self.timer.timeout.connect(self._show_text) self.timer.start() def _show_welcome_text(self): self._root.show_text(WELCOME) def _show_text(self): if not self._current_text: self.timer.setInterval(7000) result = random.choice(TEXTS) # Para evitar que se repita if result != self._current_text: self._root.show_text(result) self._current_text = result
def ask_password_dialog(parent, title, prompt, timeout = None): if parent is None: app = qt4tools.create_qapplication() translator = qt4tools.get_translator() app.installTranslator(translator) import icon dialog = QInputDialog() timer = QTimer() if not timeout is None: dialog.connect(timer, SIGNAL("timeout()"), dialog.reject) timer.setInterval(timeout * 1000) timer.start() dialog.setWindowIcon(icon.BIT_LOGO) dialog.setWindowTitle(title) dialog.setLabelText(prompt) dialog.setTextEchoMode(QLineEdit.Password) QApplication.processEvents() ret = dialog.exec_() timer.stop() if ret: password = dialog.textValue() else: password = '' del(dialog) return(password)
class PregSim(QDialog, Ui_PregSim): """ Class documentation goes here. """ def __init__(self, parent = None): """ Constructor """ QDialog.__init__(self, parent) self.setupUi(self) def switch2_simple(self, an24Dict_chosen): self.an24 = an24Dict_chosen self.timerUpdate = QTimer() QtCore.QObject.connect(self.timerUpdate, SIGNAL("timeout()"),self.update) self.timerUpdate.start(1000) self.exec_() @pyqtSignature("bool") def on_pushButton_clicked(self, checked): """ Slot documentation goes here. """ # TODO: not implemented yet self.is_hiden = True self.accept() def is_simple_hidden(self): try: is_hiden = self.is_hiden except Exception, reason: is_hiden = False return is_hiden
def __init__(self): super(QtGlWindow, self).__init__() # self.data = np.array(.2*np.random.randn(100000, 2), dtype=np.float32) self.data = np.array([ -0.5, 0.0, 0.5, 0.5, 0.0, 0.5, 0.5, 0.0, -0.5, -0.5, 0.0, -0.5, 0.0, 0.5, 0.0 ], dtype=np.float32) self.index = np.array([ 1, 2, 5, 2, 3, 5, 3, 4, 5, 4, 1, 5, 1, 2, 3, 2, 3, 4 ], dtype=np.uint32) self.widget = GlPlotWidget() self.widget.set_data(self.data, self.index) self.setGeometry(100, 100, self.widget.width, self.widget.height) self.setCentralWidget(self.widget) # automatically update window timer = QTimer(self) timer.timeout.connect(self.widget.updateGL) timer.start(1)
def highlight(self, format, cursors, priority=0, msec=0): """Highlights the selection of an arbitrary list of QTextCursors. format can be a name for a predefined text format or a QTextCharFormat; in the first case the textFormat() method should return a qtextformat to use. priority determines the order of drawing, highlighting with higher priority is drawn over highlighting with lower priority. msec, if > 0, removes the highlighting after that many milliseconds. """ if isinstance(format, QTextFormat): fmt = format key = id(format) self._formats[key] = format else: fmt = self.textFormat(format) key = format selections = [] for cursor in cursors: es = QTextEdit.ExtraSelection() es.cursor = cursor es.format = fmt selections.append(es) if msec: def clear(selfref=weakref.ref(self)): self = selfref() if self: self.clear(format) timer = QTimer(timeout=clear, singleShot=True) timer.start(msec) self._selections[key] = (priority, selections, timer) else: self._selections[key] = (priority, selections) self.update()
class LabelableSegmentationEdgesLayer( SegmentationEdgesLayer ): """ Shows a set of user-labeled edges. """ labelsChanged = pyqtSignal( dict ) # { id_pair, label_class } def __init__(self, datasource, label_class_pens, initial_labels={}, delay_ms=1000): # Class 0 (no label) is the default pen super(LabelableSegmentationEdgesLayer, self).__init__( datasource, default_pen=label_class_pens[0] ) self._delay_ms = delay_ms self._label_class_pens = label_class_pens # Initialize the labels and pens self.overwrite_edge_labels(initial_labels) self._buffered_updates = {} # To avoid sending lots of single updates if the user is clicking quickly, # we buffer the updates into a dict that is only sent after a brief delay. self._timer = QTimer(self) self._timer.setInterval(self._delay_ms) self._timer.setSingleShot(True) self._timer.timeout.connect( self._signal_buffered_updates ) def overwrite_edge_labels(self, new_edge_labels): self._edge_labels = defaultdict(lambda: 0, new_edge_labels) # Change the pens accordingly pen_table = {} for id_pair, label_class in self._edge_labels.items(): pen_table[id_pair] = self._label_class_pens[label_class] self.pen_table.overwrite(pen_table) def handle_edge_clicked(self, id_pair): """ Overridden from SegmentationEdgesLayer """ num_classes = len(self._label_class_pens) old_class = self._edge_labels[id_pair] new_class = (old_class+1) % num_classes # Update the display self.pen_table[id_pair] = self._label_class_pens[new_class] # For now, edge_labels dictionary will still contain 0-labeled edges. # We could delete them, but why bother? self._edge_labels[id_pair] = new_class # Buffer the update for listeners self._buffered_updates[id_pair] = new_class # Reset the timer self._timer.start() def _signal_buffered_updates(self): updates = self._buffered_updates self._buffered_updates = {} self.labelsChanged.emit( updates )
class VideoWidget(QWidget): """ A class for rendering video coming from OpenCV """ def __init__(self, parent=None): QWidget.__init__(self) self._capture = cv.CreateCameraCapture(0) # Take one frame to query height frame = cv.QueryFrame(self._capture) self.setMinimumSize(frame.width, frame.height) self.setMaximumSize(self.minimumSize()) self._frame = None self._image = self._build_image(frame) # Paint every 50 ms self._timer = QTimer(self) self._timer.timeout.connect(self.queryFrame) self._timer.start(50) def _build_image(self, frame): if not self._frame: self._frame = cv.CreateImage((frame.width, frame.height), cv.IPL_DEPTH_8U, frame.nChannels) if frame.origin == cv.IPL_ORIGIN_TL: cv.Copy(frame, self._frame) else: cv.Flip(frame, self._frame, 0) return IplQImage(self._frame) def paintEvent(self, event): painter = QPainter(self) painter.drawImage(QPoint(0, 0), self._image) def queryFrame(self): frame = cv.QueryFrame(self._capture) self._image = self._build_image(frame) self.update()
def main(): signal.signal(signal.SIGINT, lambda *args: QtGui.QApplication.quit()) app = QtGui.QApplication(sys.argv) w = QtGui.QWidget() trayIcon = SystemTrayIcon(myicon("stop.svg"), w) def show_icon(icon): trayIcon.setToolTip("<i>unko!</i>") trayIcon.setIcon(icon) trayIcon.show() def callback(state): show_icon(myicon("%s.svg"%state)) def check_status(): status = subprocess.Popen("ti status --no-gui-notification".split(), stdout=subprocess.PIPE).communicate()[0] if status.find("Not working on any task.") != -1: state = "stop" elif status.find("Working on ") != -1: state = "start" else: raise Exception() callback(state) check_status() timer = QTimer() timer.start(1000) # You may change this if you wish. timer.timeout.connect(check_status) # Let the interpreter run each 500 ms. # ti_server.CALLBACK = callback # ti_server.main() app.exec_() sys.exit()
class ErrorMessageFilter(QObject): """ In a parallel program, the same error may occur in several threads in close succession. For example, all slice views will notice a "filter too large" error simultaneously. This class collects error messages for a certain time (currently: 200ms) and then displays each unique message only once. """ def __init__(self, parent): super(QObject, self).__init__(parent) self.messages = {} self.timer = QTimer(self) self.timer.setSingleShot(True) self.timer.setInterval(200) self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.timeout) def showErrorMessage(self, caption, text): if not self.timer.isActive(): self.timer.start() self.messages[text] = caption def timeout(self): for text, caption in self.messages.iteritems(): QMessageBox.critical(self.parent(), caption, text) self.messages = {}
def register_timer(self, time_delta, callback): """Registers a callback function to be run after time_delta ms.""" timer = QTimer(self.window) timer.setSingleShot(True) timer.timeout.connect(callback) timer.setInterval(time_delta) timer.start()
class Player(QThread, midifile.player.Player): """An implementation of midifile.player.Player using a QThread and QTimer. emit signals: stateChanged(playing): True or False if playing state changes time(msec): The playing time, emit by default every 1000ms beat(measnum, beat, num, den): the measure number, beat number, time signature numerator and denom., where 0 = whole note, 1 = half note, 2 = quarter note, etc. """ stateChanged = pyqtSignal(bool) time = pyqtSignal(int) beat = pyqtSignal(int, int, int, int) def __init__(self, parent=None): QThread.__init__(self, parent) midifile.player.Player.__init__(self) self._timer = None def run(self): self._timer = QTimer(singleShot=True) self._timer.timeout.connect(self.timer_timeout, Qt.DirectConnection) self.timer_start_playing() self.stateChanged.emit(True) if self.exec_(): self.timer_stop_playing() self._timer = None self.stateChanged.emit(False) def start(self): if self.has_events(): QThread.start(self) def stop(self): if self.isRunning(): self.exit(1) self.wait() def timer_start(self, msec): """Starts the timer to fire once, the specified msec from now.""" self._timer.start(int(msec)) def timer_stop(self): self._timer.stop() def finish_event(self): midifile.player.Player.finish_event(self) self.exit(0) def time_event(self, time): self.time.emit(time) def beat_event(self, measnum, beat, num, den): self.beat.emit(measnum, beat, num, den)
class Plugin: def __init__(self): self.timer = QTimer(None) self.timer.setInterval(10000) self.timer.timeout.connect(self.Timeout) self.timer.setSingleShot(True) self.action = QAction("Preview mode", None) self.action.setCheckable(True) self.action.triggered.connect(self.Enabled) clementine.ui.AddAction("playlist_menu", self.action) clementine.player.Playing.connect(self.Playing) clementine.player.Paused.connect(self.Stopped) clementine.player.Stopped.connect(self.Stopped) self.enabled = False def Enabled(self, enabled): self.enabled = enabled if enabled: if clementine.player.GetState() == 2: # Playing self.timer.start() else: self.timer.stop() def Playing(self): if self.enabled: self.timer.start() def Stopped(self): self.timer.stop() def Timeout(self): if clementine.player.GetState() == 2: clementine.player.Next()
def get(self, url=None, script=None, key=None): """Load given url in webkit and return html when loaded """ self.base_url = self.base_url or url # set base URL if not set html = self.cache.get(key) if html: if self.debug: print 'load cache', key self.setHtml(html, QUrl(self.base_url)) elif url: self.load(QUrl(url)) elif script: self.js(script) loop = QEventLoop() timer = QTimer() timer.setSingleShot(True) timer.timeout.connect(loop.quit) self.loadFinished.connect(loop.quit) timer.start(self.timeout * 1000) loop.exec_() # delay here until download finished or timeout if timer.isActive(): # downloaded successfully timer.stop() html = self.current_html() if key: self.cache[key] = html self.inject_jquery() else: # didn't download in time print 'Download timeout' html = '' return html
def __init__(self): super().__init__() self.cap = None self.snapshot_flash = 0 self.IMAGE_DIR = tempfile.mkdtemp(prefix='Orange-WebcamCapture-') self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) box = self.controlArea image = self.imageLabel = QLabel( margin=0, alignment=Qt.AlignCenter, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)) box.layout().addWidget(image, 100) self.name_edit = line_edit = gui.lineEdit( box, self, 'image_title', 'Title:', orientation=Qt.Horizontal) line_edit.setPlaceholderText(self.DEFAULT_TITLE) hbox = gui.hBox(box) gui.checkBox(hbox, self, 'avatar_filter', 'Avatar filter') button = self.capture_button = QPushButton('Capture', self, clicked=self.capture_image) hbox.layout().addWidget(button, 1000) box.layout().addWidget(hbox) timer = QTimer(self, interval=40) timer.timeout.connect(self.update_webcam_image) timer.start()
class QuickHelp(QTextBrowser): #: Emitted when the shown text changes. textChanged = Signal() def __init__(self, *args, **kwargs): QTextBrowser.__init__(self, *args, **kwargs) self.setOpenExternalLinks(False) self.setOpenLinks(False) self.__text = "" self.__permanentText = "" self.__timer = QTimer(self, timeout=self.__on_timeout, singleShot=True) self.anchorClicked.connect(self.__on_anchorClicked) def showHelp(self, text, timeout=0): """ Show help for `timeout` milliseconds. if timeout is 0 then show the text until it is cleared with clearHelp or showHelp is called with an empty string. """ if self.__text != text: self.__text = str(text) self.__update() self.textChanged.emit() if timeout > 0: self.__timer.start(timeout) def clearHelp(self): """ Clear help text previously set with `showHelp`. """ self.__timer.stop() self.showHelp("") def showPermanentHelp(self, text): """ Set permanent help text. The text may be temporarily overridden by showHelp but will be shown again when that is cleared. """ if self.__permanentText != text: self.__permanentText = text self.__update() self.textChanged.emit() def currentText(self): """ Return the current shown text. """ return self.__text or self.__permanentText def __update(self): if self.__text: self.setHtml(self.__text) else: self.setHtml(self.__permanentText) def __on_timeout(self): if self.__text: self.__text = "" self.__update() self.textChanged.emit() def __on_anchorClicked(self, anchor): ev = QuickHelpDetailRequestEvent(anchor.toString(), anchor) QCoreApplication.postEvent(self, ev)
class DynamicPlotter(pg.PlotWidget): def __init__(self, sample_interval=0.01, time_window=20., parent=None): super(DynamicPlotter, self).__init__(parent) self.sample_interval = sample_interval self.time_window = time_window self.showGrid(x=True, y=True) self.setLabel('top', 'Input Real Time') self.setLabel('left', 'Amplitude', 'V') self.setLabel('bottom', 'Time', 's') self.curve = None global global_buffer def initData(self): self._interval = int(self.sample_interval * 1000) self._bufsize = int(self.time_window / self.sample_interval) self.databuffer = collections.deque([0.0] * self._bufsize, self._bufsize) self.x = np.linspace(-self.time_window, 0.0, self._bufsize) self.y = np.zeros(self._bufsize, dtype=np.float) self.audio = AudioRecord("output.wav", 1000, 1) self.audio.begin_audio() self.timer = QTimer() self.timer.timeout.connect(self.updateplot) self.timer.start(self._interval) self.curve = self.plot(self.x, self.y, pen=(0, 255, 255), antialias=True) self.curve.clear() def setSampleInterval(self, sample_interval): self.sample_interval = sample_interval self.curve.clear() self.initData() def setTimeWindow(self, time_window): self.time_window = time_window self.curve.clear() self.initData() def getdata(self): # frequency = 0.5 # noise = random.normalvariate(0., 1.) # new = 10. * math.sin(time.time() * frequency * 2 * math.pi) + noise a, b = self.audio.get_data_from_audio() new = b[0] if global_buffer.recording is True: global_buffer.counter += 1 if global_buffer.counter >= global_buffer.buffer_size: global_buffer.data[global_buffer.counter] = new return new def updateplot(self): stp = self.getdata() self.databuffer.append(stp) self.y[:] = self.databuffer self.curve.setData(self.x, self.y) def setCurveColor(self, r, g, b): self.curve.setPen(pg.mkPen(color=(r, g, b))) class MainWindow(QMainWindow): """Main window class.""" def __init__(self, parent=None): """Constructor of the class :param parent: parent :type param: QWidget() """ super(MainWindow, self).__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowTitle(__app_name__ + ' ' + __version__) self.ui.labelAbout.setText(self.tr(about)) # Connecting actions # File actions self.ui.actionNew.triggered.connect(self.newFile) # For now it cannot open a file # self.ui.actionOpen.triggered.connect(self.openFile) self.ui.actionSave.triggered.connect(self.saveFile) self.ui.actionSave_As.triggered.connect(self.saveFileAs) # Acquire actions self.ui.actionRecord.triggered.connect(self.record) self.ui.actionRecord.setCheckable(True) self.ui.actionPause.triggered.connect(self.pause) self.ui.actionPause.setCheckable(True) self.ui.actionPause.setEnabled(False) self.ui.actionStop.triggered.connect(self.stop) self.ui.actionStop.setEnabled(False) # Tools actions self.ui.actionConvert_Wav_to_Dat.triggered.connect(self.callTools) # Program actions self.ui.actionQuit.triggered.connect(self.close) self.ui.actionAbout_Wavy.triggered.connect(self.about) # Plot widget self.plot_widget = DynamicPlotter(sample_interval=0.01, time_window=20.) self.plot_widget.initData() self.ui.gridLayout_2.addWidget(self.plot_widget, 0, 1) self.plot_widget_rec = Plotter(sample_interval=0.01, time_window=5.) self.ui.gridLayout_2.addWidget(self.plot_widget_rec, 1, 1) # Inputs self.ui.doubleSpinBoxSampleInterval.valueChanged.connect(self.plot_widget.setSampleInterval) self.ui.doubleSpinBoxSampleInterval.valueChanged.connect(self.setSampleRate) self.ui.doubleSpinBoxSampleRate.valueChanged.connect(self.setSampleInterval) self.ui.spinBoxWindowTime.valueChanged.connect(self.plot_widget.setTimeWindow) self.setSampleRate(self.ui.doubleSpinBoxSampleInterval.value()) global global_buffer def setSampleRate(self, sample_interval): """Sets sample rate. """ self.ui.doubleSpinBoxSampleRate.setValue(1. / sample_interval) def setSampleInterval(self, sample_rate): """Sets sample interval. """ self.ui.doubleSpinBoxSampleInterval.setValue(1. / sample_rate) def callTools(self): dlg = ConvertWave2Data() dlg.exec_() def record(self): """Starts acquiring. """ if self.plot_widget_rec.curve is not None: self.plot_widget_rec.curve.clear() self.plot_widget_rec.initData() self.plot_widget_rec.setCurveColor(255, 0, 0) self.plot_widget_rec.setLabel('top', 'Recording ...') # Set enabled buttons self.ui.actionPause.setEnabled(True) self.ui.actionStop.setEnabled(True) self.ui.actionRecord.setEnabled(False) # Set enabled inputs self.ui.spinBoxWindowTime.setEnabled(False) self.ui.doubleSpinBoxSampleInterval.setEnabled(False) self.ui.doubleSpinBoxSampleRate.setEnabled(False) self.ui.spinBoxStopRecordingAfter.setEnabled(False) # Set enabled tool bar and menu self.ui.toolBarFile.setEnabled(False) self.ui.menuFile.setEnabled(False) self.ui.menuTools.setEnabled(False) global_buffer.recording = True def pause(self): """Pauses acquiring. """ if self.ui.actionPause.isChecked(): # Stopping changing color and label self.plot_widget_rec.timer.stop() self.plot_widget_rec.setCurveColor(255, 153, 0) self.plot_widget_rec.setLabel('top', 'Paused ...') global_buffer.recording = False else: # Starting changing color and label self.plot_widget_rec.timer.start() self.plot_widget_rec.setCurveColor(255, 0, 0) self.plot_widget_rec.setLabel('top', 'Recording ...') global_buffer.recording = True # Set enabled tool bar self.ui.toolBarFile.setEnabled(False) self.ui.menuFile.setEnabled(False) self.ui.menuTools.setEnabled(False) def stop(self): """Stops acquiring. """ # Stopping changing color and label self.plot_widget_rec.timer.stop() self.plot_widget_rec.setCurveColor(0, 255, 0) self.plot_widget_rec.setLabel('top', 'Stoped ...') # Set checked self.ui.actionRecord.setChecked(False) self.ui.actionPause.setChecked(False) # Set enabled buttons self.ui.actionPause.setEnabled(False) self.ui.actionStop.setEnabled(False) self.ui.actionRecord.setEnabled(True) # Set enabled inputs self.ui.doubleSpinBoxSampleInterval.setEnabled(True) self.ui.doubleSpinBoxSampleRate.setEnabled(True) self.ui.spinBoxWindowTime.setEnabled(True) self.ui.spinBoxStopRecordingAfter.setEnabled(True) # Set enabled tool bar self.ui.toolBarFile.setEnabled(True) self.ui.menuFile.setEnabled(True) self.ui.menuTools.setEnabled(True) global_buffer.recording = False def newFile(self): """Creates a new file.""" def saveFile(self): """Saves a file.""" def saveFileAs(self, filename=''): """Saves file as new name.""" def about(self): """Show the dialog about.""" QMessageBox.about(self, self.tr('About'), self.tr(about)) def closeQuestion(self): """Asks about to close.""" answer = QMessageBox.question(self, self.tr('Close'), self.tr('Do you want to exit ?'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) return answer == QMessageBox.Yes def closeEvent(self, event): """Re implements close event.""" if self.closeQuestion(): self.stop() self.plot_widget.audio.end_audio() event.accept() else: event.ignore()
class Window(QtGui.QMainWindow, Ui_MainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) self.initUI() def initUI(self): self.w = QWidget() # a figure instance to plot on self.figure = Figure() # this is the Canvas Widget that displays the `figure` # it takes the `figure` instance as a parameter to __init__ self.canvas = FigureCanvas(self.figure) # this is the Navigation widget # it takes the Canvas widget and a parent self.toolbar = NavigationToolbar(self.canvas, self) # set the layout for the main window self.dispLayout.addWidget(self.toolbar) self.dispLayout.addWidget(self.canvas) #buttons self.nextFrame.clicked.connect(self.dispNextImg) self.prevFrame.clicked.connect(self.dispPrevImg) self.selectFileBut.clicked.connect(self.getFile) self.playVidBut.clicked.connect(self.play) self.makeTiffBut.clicked.connect(self.makeTiff2) self.displayC.clicked.connect(self.dispCDef) self.displayC.clicked.connect(self.displayTempValues) self.displayF.clicked.connect(self.dispFDef) self.displayF.clicked.connect(self.displayTempValues) self.sl.valueChanged.connect(self.slValueChange) self.saveCvImageBut.clicked.connect(self.saveCvImage) #cid = self.canvas.mpl_connect('button_press_event', self.on_press) self.saveAsVideoSS.clicked.connect(self.saveVideoSS) self.pauseVidBut.clicked.connect(self.pauseVideo) #self.startEdit.returnPressed(frame = str(self.startEdit.text())) #self.startEdit.returnPressed(frame = str(self.startEdit.text())) #self.history.verticalScrollBar().setValue(self.history.verticalScrollBar().maximum()) self.timer = QTimer(self) self.timer.setInterval(timerHz) self.timer.timeout.connect(self.playVid5) self.timer.start() def dispCDef(self): global toggleUnitState toggleUnitState = 'C' self.history.insertPlainText('Display ' + str(toggleUnitState) + '\n') self.history.moveCursor(QTextCursor.End) def dispFDef(self): global toggleUnitState toggleUnitState = 'F' self.history.insertPlainText('Display ' + str(toggleUnitState) + '\n') self.history.moveCursor(QTextCursor.End) def startTimer(self): global hz self.timer.stop() print(hz) self.timer.setInterval(timerHz) self.timer.timeout.connect(self.playVid5) self.timer.start() print('Re-Started Timer') def stopTimer(self): self.timer.stop() def speed(self): global framerate hzIndex = self.comboBoxHz.currentIndex() if hzIndex == 0: framerate = 0.5 print('Half Framerate') elif hzIndex == 1: framerate = 1 print('Normal Framerate') elif hzIndex == 2: framerate = 2 print('Double Framerate') else: hz = 111 self.startTimer() def slValueChange(self): global frame #global fileSelected #if fileSelected != "": #print('SlValueChange Def Called') frame = self.sl.value() self.dispImg() self.canvas.draw() def setSlider(self): global lastFrame #print('Set Slider Function Called') #print('Enable Slider') self.sl.setEnabled(True) #print('Set Minimum') self.sl.setMinimum(1) #print(lastFrame) #print('Set Maximum') self.sl.setMaximum(lastFrame) self.sl.setValue(1) self.sl.setTickPosition(QSlider.TicksBelow) self.sl.setTickInterval(9) self.slStartF.setText('First Frame: 1') self.slMidF.setText('Mid Frame: ' + str(lastFrame / 2)) self.slEndF.setText('Last Frame: ' + str(lastFrame)) self.slStartT.setText('0 Seconds') self.slMidT.setText(str(lastFrame / (2 * 9)) + ' Seconds') self.slEndT.setText(str(lastFrame / 9) + ' Seconds') def saveVideoSS(self): global frame global editLastFrame global videoState videoState = 'pause' if fileSelected != "": fileNameVid = "" dlgVid = QFileDialog() #dlg.setNameFilter('PNG files (*.png)') dlgVid.setDefaultSuffix('.avi') fileNameVid = dlgVid.getSaveFileName( self.w, 'Navigate to Directory and Choose a File Name to Save To', 'untitled.avi', 'AVI Video (*.avi)') #if self.startEdit.isModified(): fileNameVid = str(fileNameVid) #if fileNameVid.endswith('.avi') == False: # fileNameVid = fileNameVid + '.avi' frame = int(self.startEdit.text()) #if self.stopEdit.isModified(): editLastFrame = int(self.stopEdit.text()) fourcc = cv2.VideoWriter_fourcc(*'MJPG') if fileNameVid != "": try: out = cv2.VideoWriter(fileNameVid, fourcc, 9.0, (640, 480), True) print('past out') for i in range(frame, editLastFrame): print('frame' + str(i)) frameForVid = self.grabDataFrame() out.write(frameForVid) if frame <= editLastFrame: frame += framerate else: print('You are at Last Frame') out.release() print('out release') print('Saved Video As ' + str(fileNameVid)) self.history.insertPlainText('SUCCESS: Saved Video\n') self.history.moveCursor(QTextCursor.End) except: self.history.insertPlainText( 'No AVI Video Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No AVI Video Generated') else: self.history.insertPlainText( 'No AVI Video Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No AVI Video Generated') def saveCvImage(self): global fileSelected global videoState videoState = 'pause' if fileSelected != "": dlg = QFileDialog() #dlg.setNameFilter('PNG files (*.png)') dlg.setDefaultSuffix('.png') fileNameImage = dlg.getSaveFileName( self.w, 'Navigate to Directory and Choose a File Name to Save To', 'untitled.png', 'PNG Image (*.png)') if fileNameImage != "": try: print(fileNameImage) cv2.imwrite(str(fileNameImage), self.grabDataFrame()) print('Saved frame ' + str(frame) + ' as .png') self.history.insertPlainText('SUCCESS: Saved Frame: ' + str(frame) + ' as PNG\n') self.history.moveCursor(QTextCursor.End) except: self.history.insertPlainText( 'No PNG Image Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No PNG Image Generated') else: self.history.insertPlainText( 'No PNG Image Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No PNG Image Generated') def makeTiff2(self): global lastFrame global fileSelected global videoState videoState = 'pause' if fileSelected != "": dlgTiff = QFileDialog() #dlg.setNameFilter('PNG files (*.png)') dlgTiff.setDefaultSuffix('.tiff') fileNameTiff = dlgTiff.getSaveFileName( self.w, 'Navigate to Directory and Choose a File Name to Save To', 'untitled.tiff', 'TIFF File (*.tiff)') print(fileNameTiff) if fileNameTiff != "": self.history.insertPlainText('File Name Selected\n') self.history.moveCursor(QTextCursor.End) print('Collecting Data Frames...') for i in range(1, lastFrame): #print('Frame to Tiff: ' + str(i)) data = self.f_read[('image' + str(i))][:] if i == 1: dataCollection = data else: dataCollection = np.dstack((dataCollection, data)) i += 1 if i == lastFrame / 2: print('Half Way Through File...') print('Completed Collecting All Data Frames') try: imsave((str(fileNameTiff)), dataCollection) print('Saved Tiff As ' + str(fileNameTiff)) self.history.insertPlainText(' Saved Tiff\n') self.history.moveCursor(QTextCursor.End) except: self.history.insertPlainText( 'No Tiff File Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No Tiff File Generated') else: self.history.insertPlainText( 'No Tiff File Generated\n Did Not Specify Proper FileName\n' ) self.history.moveCursor(QTextCursor.End) print('Did Not Specify Proper FileName') print('No Tiff File Generated') def grabTempValue(self): global frame global lastFrame global fileSelected global xMouse global yMouse data = self.f_read[('image' + str(frame))][:] data = cv2.resize(data[:, :], (640, 480)) return data[yMouse, xMouse] def on_press(self, event): global xMouse global yMouse global cursorVal #print('you pressed', event.button, event.xdata, event.ydata) xMouse = event.xdata yMouse = event.ydata cursorVal = self.grabTempValue() self.cursorTempLabel.setText('Cursor Temp: ' + readTemp(toggleUnitState, 'none')) def hover(self, event): global xMouse global yMouse global cursorVal #print('you pressed', event.button, event.xdata, event.ydata) if event.xdata != None: xMouse = int(round(event.xdata)) yMouse = int(round(event.ydata)) cursorVal = int(round(self.grabTempValue())) #if xMouse > 1 and xMouse < 640 and yMouse > 0 and yMouse < 480: self.cursorTempLabel.setText('Cursor Temp: ' + readTemp(toggleUnitState, 'none')) #else: #self.cursorTempLabel.setText('Cursor Temp: MOVE CURSOR OVER IMAGE') else: #print('MOVE CURSOR OVER IMAGE') self.cursorTempLabel.setText('Cursor Temp: MOVE CURSOR OVER IMAGE') def displayTempValues(self): global fileSelected global toggleUnitState if fileSelected != "": self.maxTempLabel.setText('Current Max Temp: ' + readTemp(toggleUnitState, 'max')) self.maxTempLocLabel.setText('Max Temp Loc: ' + str(maxLoc)) self.minTempLabel.setText('Current Min Temp: ' + readTemp(toggleUnitState, 'min')) self.minTempLocLabel.setText('Min Temp Loc: ' + str(minLoc)) def grabDataFrame(self): global frame global lastFrame global fileSelected #print('Display Image at Frame: ' + str(frame)) data = self.f_read[('image' + str(frame))][:] data = cv2.resize(data[:, :], (640, 480)) img = cv2.LUT(raw_to_8bit(data), generate_colour_map()) img2 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) rgbImage = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB) return (rgbImage) def play(self): global frame global editLastFrame global fileSelected global videoState self.history.insertPlainText('Play Video\n') self.history.moveCursor(QTextCursor.End) #print(self.startEdit.text()) if self.startEdit.isModified(): frame = int(self.startEdit.text()) print('Starting at Frame: ' + self.startEdit.text()) if self.stopEdit.isModified(): editLastFrame = int(self.stopEdit.text()) if fileSelected != "": self.timer.start() videoState = 'play' def pauseVideo(self): global videoState self.history.insertPlainText('Paused Video\n') self.history.moveCursor(QTextCursor.End) videoState = 'pause' def playVid5(self): global videoState global frame global lastFrame global editLastFrame if videoState == 'play': if editLastFrame <= lastFrame: if frame <= editLastFrame: self.sl.setValue(frame) if frame != lastFrame: frame += 1 #print('playing video') else: print('You are at Stop Frame') videoState = 'pause' else: print('You are at Last Frame') videoState = 'pause' def dispNextImg(self): global frame global lastFrame global framerate global fileSelected global videoState videoState = 'pause' self.history.insertPlainText('Next Frame: ' + str(frame) + '\n') self.history.moveCursor(QTextCursor.End) if fileSelected != "": if lastFrame > frame: frame += framerate else: print('You are at Last Frame') #self.dispImg() #self.canvas.draw() self.sl.setValue(frame) def dispPrevImg(self): global frame global fileSelected global videoState self.history.insertPlainText('Previous Frame: ' + str(frame) + '\n') self.history.moveCursor(QTextCursor.End) videoState = 'pause' if fileSelected != "": if frame > 1: frame -= 1 else: print('You are at First Frame') #self.dispImg() #self.canvas.draw() self.sl.setValue(frame) def dispImg(self): global frame global lastFrame global fileSelected global maxVal global minVal global maxLoc global minLoc #if frame > 1: #self.cb.remove() #print('Display Image at Frame: ' + str(frame)) self.currentFrameDisp.setText('Current Frame: ' + str(frame)) data = self.f_read[('image' + str(frame))][:] data = cv2.resize(data[:, :], (640, 480)) minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(data) img = cv2.LUT(raw_to_8bit(data), generate_colour_map()) rgbImage = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) self.ax = self.figure.add_subplot(111) self.ax.clear() #cmap = mpl.cm.cool #norm = mpl.colors.Normalize(vmin=5, vmax=10) #print('Ran dispImg') #print(frame) if frame == 1: self.figure.tight_layout() #colorVals = cm.get_clim(rgbImage) #print(colorVals) #cax = self.figure.add_axes([0.2, 0.08, 0.6, 0.04]) #self.figure.colorbar(rgbImage, cax, orientation='horizontal') self.cax = self.ax.imshow(rgbImage) #self.cb = self.figure.colorbar(self.cax) lastFrame = len(self.f_read) self.sl.setValue(frame) self.displayTempValues() self.currentTimeLabel.setText('Current Time: ' + str(round(((frame - 1) / 9.00), 2))) cid = self.canvas.mpl_connect('motion_notify_event', self.hover) def enableThings(self): self.playVidBut.setEnabled(True) self.pauseVidBut.setEnabled(True) self.nextFrame.setEnabled(True) self.prevFrame.setEnabled(True) self.startEdit.setEnabled(True) self.stopEdit.setEnabled(True) self.saveAsVideoSS.setEnabled(True) self.saveCvImageBut.setEnabled(True) self.makeTiffBut.setEnabled(True) self.displayC.setEnabled(True) self.displayF.setEnabled(True) def getFile(self): global frame global fileSelected global editLastFrame global lastFrame #self.pauseVideo() fileSelected = "" fileSelected = QFileDialog.getOpenFileName(self.w, 'Open File', '/') print(fileSelected) #fileTypes = ['hdf5','HDF5','HD5F','hd5f'] if fileSelected != "": #if any(x in fileSelected for x in fileTypes): try: self.dispSelectedFile.setText(fileSelected) self.f_read = h5py.File(str(fileSelected), 'r') self.dispImg() self.enableThings() self.setSlider() editLastFrame = lastFrame self.startEdit.setText(str(frame)) self.stopEdit.setText(str(lastFrame)) self.history.insertPlainText( 'Selected File and Displayed First Frame\n') self.history.moveCursor(QTextCursor.End) print('Selected File and Displayed First Frame') self.canvas.draw() #else: except: self.history.insertPlainText( 'ERROR: Incorrect File Type Selected\n Please select .HDF5 File\n' ) self.history.moveCursor(QTextCursor.End) print( 'Incorrect File Type Selected. Please select .HDF5 File.') else: self.history.insertPlainText( 'ERROR: Incorrect File Type Selected\n Please select .HDF5 File\n' ) self.history.moveCursor(QTextCursor.End) print('Incorrect File Type Selected. Please select .HDF5 File.')
def multi_mode(cli_parsed): dbm = db_manager.DB_Manager(cli_parsed.d + '/ew.db') dbm.open_connection() if not cli_parsed.resume: dbm.initialize_db() dbm.save_options(cli_parsed) m = Manager() targets = m.Queue() lock = m.Lock() multi_counter = m.Value('i', 0) display = None def exitsig(*args): dbm.close() if current_process().name == 'MainProcess': print '' print 'Resume using ./EyeWitness.py --resume {0}'.format( cli_parsed.d + '/ew.db') os._exit(1) signal.signal(signal.SIGINT, exitsig) if cli_parsed.resume: pass else: url_list, rdp_list, vnc_list = target_creator(cli_parsed) if any((cli_parsed.web, cli_parsed.headless)): for url in url_list: dbm.create_http_object(url, cli_parsed) for rdp in rdp_list: dbm.create_vnc_rdp_object('rdp', rdp, cli_parsed) for vnc in vnc_list: dbm.create_vnc_rdp_object('vnc', vnc, cli_parsed) if any((cli_parsed.web, cli_parsed.headless)): if cli_parsed.web and not cli_parsed.show_selenium: display = Display(visible=0, size=(1920, 1080)) display.start() multi_total = dbm.get_incomplete_http(targets) if multi_total > 0: if cli_parsed.resume: print 'Resuming Web Scan ({0} Hosts Remaining)'.format( str(multi_total)) else: print 'Starting Web Requests ({0} Hosts)'.format( str(multi_total)) if multi_total < cli_parsed.threads: num_threads = multi_total else: num_threads = cli_parsed.threads for i in xrange(num_threads): targets.put(None) try: workers = [ Process(target=worker_thread, args=(cli_parsed, targets, lock, (multi_counter, multi_total))) for i in xrange(num_threads) ] for w in workers: w.start() for w in workers: w.join() except Exception as e: print str(e) # Set up UA table here if cli_parsed.cycle is not None: ua_dict = get_ua_values(cli_parsed.cycle) if not cli_parsed.ua_init: dbm.clear_table("ua") completed = dbm.get_complete_http() completed[:] = [x for x in completed if x.error_state is None] for item in completed: for browser, ua in ua_dict.iteritems(): dbm.create_ua_object(item, browser, ua) cli_parsed.ua_init = True dbm.clear_table("opts") dbm.save_options(cli_parsed) for browser, ua in ua_dict.iteritems(): targets = m.Queue() multi_counter.value = 0 multi_total = dbm.get_incomplete_ua(targets, browser) if multi_total > 0: print( "[*] Starting requests for User Agent {0}" " ({1} Hosts)").format(browser, str(multi_total)) if multi_total < cli_parsed.threads: num_threads = multi_total else: num_threads = cli_parsed.threads for i in xrange(num_threads): targets.put(None) workers = [ Process(target=worker_thread, args=(cli_parsed, targets, lock, (multi_counter, multi_total), (browser, ua))) for i in xrange(num_threads) ] for w in workers: w.start() for w in workers: w.join() if any((cli_parsed.vnc, cli_parsed.rdp)): log._LOG_LEVEL = log.Level.ERROR multi_total, targets = dbm.get_incomplete_vnc_rdp() if multi_total > 0: print '' print 'Starting VNC/RDP Requests ({0} Hosts)'.format( str(multi_total)) app = QtGui.QApplication(sys.argv) timer = QTimer() timer.start(10) timer.timeout.connect(lambda: None) # add qt4 reactor import qt4reactor qt4reactor.install() from twisted.internet import reactor for target in targets: if os.path.dirname(cli_parsed.d) != os.path.dirname( target.screenshot_path): target.set_paths(cli_parsed.d) tdbm = db_manager.DB_Manager(cli_parsed.d + '/ew.db') if target.proto == 'vnc': reactor.connectTCP( target.remote_system, target.port, vnc_module.RFBScreenShotFactory( target.screenshot_path, reactor, app, target, tdbm)) else: reactor.connectTCP( target.remote_system, int(target.port), rdp_module.RDPScreenShotFactory( reactor, app, 1200, 800, target.screenshot_path, cli_parsed.timeout, target, tdbm)) reactor.runReturn() app.exec_() if display is not None: display.stop() results = dbm.get_complete_http() vnc_rdp = dbm.get_complete_vnc_rdp() dbm.close() m.shutdown() write_vnc_rdp_data(cli_parsed, vnc_rdp) sort_data_and_write(cli_parsed, results)
class DualRelay(PluginBase, Ui_DualRelay): qtcb_monoflop = pyqtSignal(int, bool) def __init__(self, *args): PluginBase.__init__(self, BrickletDualRelay, *args) self.setupUi(self) self.dr = self.device self.has_monoflop = self.firmware_version >= (1, 1, 1) self.qtcb_monoflop.connect(self.cb_monoflop) self.dr.register_callback(self.dr.CALLBACK_MONOFLOP_DONE, self.qtcb_monoflop.emit) self.dr1_button.clicked.connect(self.dr1_clicked) self.dr2_button.clicked.connect(self.dr2_clicked) self.go1_button.clicked.connect(self.go1_clicked) self.go2_button.clicked.connect(self.go2_clicked) self.r1_monoflop = False self.r2_monoflop = False self.r1_timebefore = 500 self.r2_timebefore = 500 self.a1_pixmap = load_masked_pixmap( 'plugin_system/plugins/dual_relay/relay_a1.bmp') self.a2_pixmap = load_masked_pixmap( 'plugin_system/plugins/dual_relay/relay_a2.bmp') self.b1_pixmap = load_masked_pixmap( 'plugin_system/plugins/dual_relay/relay_b1.bmp') self.b2_pixmap = load_masked_pixmap( 'plugin_system/plugins/dual_relay/relay_b2.bmp') self.update_timer = QTimer() self.update_timer.timeout.connect(self.update) self.update_timer.setInterval(50) if not self.has_monoflop: self.go1_button.setText("Go (FW Versiom >= 1.1.1 required)") self.go2_button.setText("Go (FW Versiom >= 1.1.1 required)") self.go1_button.setEnabled(False) self.go2_button.setEnabled(False) def get_state_async(self, state): width = self.dr1_button.width() if self.dr1_button.minimumWidth() < width: self.dr1_button.setMinimumWidth(width) width = self.dr2_button.width() if self.dr2_button.minimumWidth() < width: self.dr2_button.setMinimumWidth(width) dr1, dr2 = state if dr1: self.dr1_button.setText('Switch Off') self.dr1_image.setPixmap(self.a1_pixmap) else: self.dr1_button.setText('Switch On') self.dr1_image.setPixmap(self.b1_pixmap) if dr2: self.dr2_button.setText('Switch Off') self.dr2_image.setPixmap(self.a2_pixmap) else: self.dr2_button.setText('Switch On') self.dr2_image.setPixmap(self.b2_pixmap) def get_monoflop_async(self, monoflop, index): state, time, time_remaining = monoflop if index == 1: if time > 0: self.r1_timebefore = time self.time1_spinbox.setValue(self.r1_timebefore) if time_remaining > 0: if not state: self.state1_combobox.setCurrentIndex(0) self.r1_monoflop = True self.time1_spinbox.setEnabled(False) self.state1_combobox.setEnabled(False) elif index == 2: state, time, time_remaining = self.dr.get_monoflop(2) if time > 0: self.r2_timebefore = time self.time2_spinbox.setValue(self.r2_timebefore) if time_remaining > 0: if not state: self.state2_combobox.setCurrentIndex(1) self.r2_monoflop = True self.time2_spinbox.setEnabled(False) self.state2_combobox.setEnabled(False) def start(self): async_call(self.dr.get_state, None, self.get_state_async, self.increase_error_count) if self.has_monoflop: async_call(self.dr.get_monoflop, 1, lambda x: self.get_monoflop_async(x, 1), self.increase_error_count) async_call(self.dr.get_monoflop, 2, lambda x: self.get_monoflop_async(x, 2), self.increase_error_count) self.update_timer.start() def stop(self): self.update_timer.stop() def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER def get_state_dr1_clicked(self, state): dr1, dr2 = state try: self.dr.set_state(not dr1, dr2) except ip_connection.Error: return self.r1_monoflop = False self.time1_spinbox.setValue(self.r1_timebefore) self.time1_spinbox.setEnabled(True) self.state1_combobox.setEnabled(True) def dr1_clicked(self): width = self.dr1_button.width() if self.dr1_button.minimumWidth() < width: self.dr1_button.setMinimumWidth(width) if 'On' in self.dr1_button.text(): self.dr1_button.setText('Switch Off') self.dr1_image.setPixmap(self.a1_pixmap) else: self.dr1_button.setText('Switch On') self.dr1_image.setPixmap(self.b1_pixmap) async_call(self.dr.get_state, None, self.get_state_dr1_clicked, self.increase_error_count) def get_state_dr2_clicked(self, state): dr1, dr2 = state try: self.dr.set_state(dr1, not dr2) except ip_connection.Error: return self.r2_monoflop = False self.time2_spinbox.setValue(self.r2_timebefore) self.time2_spinbox.setEnabled(True) self.state2_combobox.setEnabled(True) def dr2_clicked(self): width = self.dr2_button.width() if self.dr2_button.minimumWidth() < width: self.dr2_button.setMinimumWidth(width) if 'On' in self.dr2_button.text(): self.dr2_button.setText('Switch Off') self.dr2_image.setPixmap(self.a2_pixmap) else: self.dr2_button.setText('Switch On') self.dr2_image.setPixmap(self.b2_pixmap) async_call(self.dr.get_state, None, self.get_state_dr2_clicked, self.increase_error_count) def go1_clicked(self): time = self.time1_spinbox.value() state = self.state1_combobox.currentIndex() == 0 try: if self.r1_monoflop: time = self.r1_timebefore else: self.r1_timebefore = self.time1_spinbox.value() self.dr.set_monoflop(1, state, time) self.r1_monoflop = True self.time1_spinbox.setEnabled(False) self.state1_combobox.setEnabled(False) if state: self.dr1_button.setText('Switch Off') self.dr1_image.setPixmap(self.a1_pixmap) else: self.dr1_button.setText('Switch On') self.dr1_image.setPixmap(self.b1_pixmap) except ip_connection.Error: return def go2_clicked(self): time = self.time2_spinbox.value() state = self.state2_combobox.currentIndex() == 0 try: if self.r2_monoflop: time = self.r2_timebefore else: self.r2_timebefore = self.time2_spinbox.value() self.dr.set_monoflop(2, state, time) self.r2_monoflop = True self.time2_spinbox.setEnabled(False) self.state2_combobox.setEnabled(False) if state: self.dr2_button.setText('Switch Off') self.dr2_image.setPixmap(self.a2_pixmap) else: self.dr2_button.setText('Switch On') self.dr2_image.setPixmap(self.b2_pixmap) except ip_connection.Error: return def cb_monoflop(self, relay, state): if relay == 1: self.r1_monoflop = False self.time1_spinbox.setValue(self.r1_timebefore) self.time1_spinbox.setEnabled(True) self.state1_combobox.setEnabled(True) if state: self.dr1_button.setText('Switch Off') self.dr1_image.setPixmap(self.a1_pixmap) else: self.dr1_button.setText('Switch On') self.dr1_image.setPixmap(self.b1_pixmap) else: self.r2_monoflop = False self.time2_spinbox.setValue(self.r2_timebefore) self.time2_spinbox.setEnabled(True) self.state2_combobox.setEnabled(True) if state: self.dr2_button.setText('Switch Off') self.dr2_image.setPixmap(self.a2_pixmap) else: self.dr2_button.setText('Switch On') self.dr2_image.setPixmap(self.b2_pixmap) def update_time_remaining(self, relay, time_remaining): if relay == 1: if self.r1_monoflop: self.time1_spinbox.setValue(time_remaining) elif relay == 2: if self.r2_monoflop: self.time2_spinbox.setValue(time_remaining) def update(self): if self.r1_monoflop: try: async_call(self.dr.get_monoflop, 1, lambda a: self.update_time_remaining(1, a[2]), self.increase_error_count) except ip_connection.Error: pass if self.r2_monoflop: try: async_call(self.dr.get_monoflop, 2, lambda a: self.update_time_remaining(2, a[2]), self.increase_error_count) except ip_connection.Error: pass
class View(QtGui.QMainWindow, gui.Ui_Form): # Signals game = pyqtSignal() def __init__(self): super(self.__class__, self).__init__() self.setupUi(self) self.time1.setValue(1) self.time2.setValue(1) self.time1.setMaximum(1) self.time2.setMaximum(1) self.timer = QTimer(self) self.timer.timeout.connect(self.run) self.timer.start(1) # Bei Autostart wirklich 1 ms da kein System im Hintergrund ist self.logo.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/logoS.png")) self.logoR.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/logo.png")) self.hintergrund.setPixmap(QtGui.QPixmap("/home/pi/Public/bilder/bg.png")) # Slot @pyqtSlot() def run(self): global mode global videoStart global explainTextStep global startGame if mode is 0: # Savemode """ Hier werden alle Werte zurück gesetzt """ videoStart = True setInterrupt(13) explainTextStep = 0 startGame = False self.startBildschirm.setVisible(True) mode = 1 elif mode is 1: # Startbildschirm pass elif mode is 2: # Übergang Erklärphase removeInterrupt(13) setInterrupt(11) self.startBildschirm.setVisible(False) self.sensorTexte.setVisible(True) mode = 3 elif mode is 3: # Erklärphase """ Text anzeigen durch "explainTextStep" """ if explainTextStep is 5: if not startGame: startGame = True setInterrupt(13) removeInterrupt(11) self.text.setText("Start Game") # Texte Anzeigen lassen else: self.text.setText(str(explainTextStep)) pass elif mode is 4: # Übergang Spielphase removeInterrupt(11) removeInterrupt(13) self.sensorTexte.setVisible(False) self.startBildschirm.setVisible(False) mode = 5 elif mode is 5: # Spielphase if videoStart: self.player = OMXPlayer('/home/pi/Public/Videos/teil1Neu.mp4') self.time1.setMaximum(int(self.player.duration())) self.time2.setMaximum(int(self.player.duration())) self.player.set_video_pos(260, 300, 1690, 1080) videoStart = False if self.player.is_playing(): restTime = int(self.player.duration())-int(self.player.position()) self.time1.setValue(restTime) self.time2.setValue(restTime) pass # Spielläuft else: # Spielfertig self.player.quit() mode = 0 else: pass
class EventEngine(object): """事件驱动引擎 事件驱动引擎中所有的变量都设置为了私有,这是为了防止不小心 从外部修改了这些变量的值或状态,导致bug。 变量说明 __queue:私有变量,事件队列 __active:私有变量,事件引擎开关 __thread:私有变量,事件处理线程 __timer:私有变量,计时器 __handlers:私有变量,事件处理函数字典 方法说明 __run: 私有方法,事件处理线程连续运行用 __process: 私有方法,处理事件,调用注册在引擎中的监听函数 __onTimer:私有方法,计时器固定事件间隔触发后,向事件队列中存入计时器事件 start: 公共方法,启动引擎 stop:公共方法,停止引擎 register:公共方法,向引擎中注册监听函数 unregister:公共方法,向引擎中注销监听函数 put:公共方法,向事件队列中存入新的事件 事件监听函数必须定义为输入参数仅为一个event对象,即: 函数 def func(event) 对象方法 def method(self, event) """ # -------------------------------- def __init__(self): # 事件队列 self.__queue = Queue() # 事件引擎开关 self.__active = False # 事件处理线程 self.__thread = Thread(target=self.__run) # 计时器,用于触发计时器事件 self.__timer = QTimer() self.__timer.timeout.connect(self.__onTimer) # __handlers在这里是一个字典,用于保存对应的事件调用关系 # 其中每个键对应的值是一个列表,列表中保存了对该事件进行监听的函数 self.__handlers = {} # -------------------------------- def __run(self): """引擎运行""" while self.__active == True: try: event = self.__queue.get(block=True, timeout=1) # 获取事件的阻塞时间设为1秒 self.__process(event) except Empty: pass # -------------------------- def __process(self, event): """处理事件""" # 检查是否存在对该事件进行监听的处理函数 print self.__queue if event.type_ in self.__handlers: # 若存在,则按顺序将事件传递给处理函数执行 [handler(event) for handler in self.__handlers[event.type_]] # ---------------------------------- def __onTimer(self): """向事件队列中存入计时器事件""" # 创建计时器事件 event = Event(type_=EVENT_TIMER) # 向队列中存入计时器事件 self.put(event) # --------------------------------------- def start(self): """引擎启动""" # 将引擎设为启动 self.__active = True # 启动事件处理线程 self.__thread.start() # 启动计时器,计时器时间间隔默认设为0.6秒 self.__timer.start(600) # --------------------------- def stop(self): """停止引擎""" # 将引擎设为停止 self.__active = False # 停止计时器 self.__timer.stop() # 等待事件处理线程退出 self.__thread.join() # ----------------------------------------- def register(self, type_, handler): """注册事件处理函数监听""" # 尝试获取该事件类型对应的处理函数列表,若无则创建 try: handlerList = self.__handlers[type_] except KeyError: handlerList = [] self.__handlers[type_] = handlerList # 若要注册的处理器不在该事件的处理器列表中,则注册该事件 if handler not in handlerList: handlerList.append(handler) # print 'handlerList' # print handlerList # ---------------------------- def unregister(self, type_, handler): """注销事件处理函数监听""" try: handlerList = self.__handlers[type_] # 如果该函数存在于列表中,则移除 if handler in handlerList: handlerList.remove(handler) # 如果函数列表为空,则从引擎中移除该事件类型 if not handlerList: del self.__handlers[type_] except KeyError: pass # --------------------------------------- def put(self, event): """向事件队列中存入事件""" self.__queue.put(event)
def __init__(self, parent=None): """ Args: parent: """ super(AnalogGaugeWidget, self).__init__(parent) self.use_timer_event = False self.black = QColor(0, 0, 0, 255) # self.valueColor = QColor(50, 50, 50, 255) # self.set_valueColor(50, 50, 50, 255) # self.NeedleColor = QColor(50, 50, 50, 255) self.set_NeedleColor(50, 50, 50, 255) self.NeedleColorReleased = self.NeedleColor # self.NeedleColorDrag = QColor(255, 0, 00, 255) self.set_NeedleColorDrag(255, 0, 00, 255) self.set_ScaleValueColor(50, 50, 50, 255) self.set_DisplayValueColor(50, 50, 50, 255) # self.CenterPointColor = QColor(50, 50, 50, 255) self.set_CenterPointColor(50, 50, 50, 255) # self.valueColor = black # self.black = QColor(0, 0, 0, 255) self.value_needle_count = 1 self.value_needle = QObject self.change_value_needle_style([ QPolygon([ QPoint(4, 4), QPoint(-4, 4), QPoint(-3, -120), QPoint(0, -126), QPoint(3, -120) ]) ]) self.value_min = 0 self.value_max = 1000 self.value = self.value_min self.value_offset = 0 self.value_needle_snapzone = 0.05 self.last_value = 0 # self.value2 = 0 # self.value2Color = QColor(0, 0, 0, 255) self.gauge_color_outer_radius_factor = 1 self.gauge_color_inner_radius_factor = 0.95 self.center_horizontal_value = 0 self.center_vertical_value = 0 self.debug1 = None self.debug2 = None self.scale_angle_start_value = 135 self.scale_angle_size = 270 self.angle_offset = 0 # self.scala_main_count = 10 self.set_scala_main_count(10) self.scala_subdiv_count = 5 self.pen = QPen(QColor(0, 0, 0)) self.font = QFont('Decorative', 20) self.scale_polygon_colors = [] self.set_scale_polygon_colors([[.00, Qt.red], [.1, Qt.yellow], [.15, Qt.green], [1, Qt.transparent]]) # initialize Scale value text # self.enable_scale_text = True self.set_enable_ScaleText(True) self.scale_fontname = "Decorative" self.initial_scale_fontsize = 15 self.scale_fontsize = self.initial_scale_fontsize # initialize Main value text self.enable_value_text = True self.value_fontname = "Decorative" self.initial_value_fontsize = 40 self.value_fontsize = self.initial_value_fontsize self.text_radius_factor = 0.7 # En/disable scale / fill # self.enable_barGraph = True self.set_enable_barGraph(True) # self.enable_filled_Polygon = True self.set_enable_filled_Polygon(True) self.enable_CenterPoint = True self.enable_fine_scaled_marker = True self.enable_big_scaled_marker = True self.needle_scale_factor = 0.8 self.enable_Needle_Polygon = True # necessary for resize self.setMouseTracking(False) # QTimer sorgt für neu Darstellung alle X ms # evtl performance hier verbessern mit self.update() und self.use_timer_event = False # todo: self.update als default ohne ueberpruefung, ob self.use_timer_event gesetzt ist oder nicht # Timer startet alle 10ms das event paintEvent if self.use_timer_event: timer = QTimer(self) timer.timeout.connect(self.update) timer.start(10) else: self.update() self.setWindowTitle("Analog Gauge") # self.connect(self, SIGNAL("resize()"), self.rescaleMethod) # self.resize(300 , 300) self.rescale_method()
class Listener(QWidget): def __init__(self, core_file_name): super(Listener, self).__init__() self.core_file_name = core_file_name self.setup_ui() self.setup_timers() port = SERIAL_PORT self.serial = serial.Serial(port, BAUDE_RATE, timeout=0) self.incoming_data = [] self.imu = IMU(PLATFORM_SPECIFIC_QUOTIENTS['stm']) self.stroke = Stroke() self.selector = Selector(self.core_file_name) self.acceleration_filter = AperiodicFilter(ACCELERATION_TIME_CONST) self.stroke.widget = self.display self.stroke.on_done = self.get_stroke self.previous_time = None self.data_buffer = '' self.init_selector() def setup_ui(self): self.resize(500, 500) self.out = QLabel(self) self.out.setMinimumHeight(100) font = QFont() font.setPixelSize(80) self.out.setFont(font) self.grid = QGridLayout(self) self.display = StrokeWidget() self.letter_selector = QComboBox() self.grid.addWidget(self.display, 0, 0, 1, 1) self.grid.addWidget(self.letter_selector, 1, 0, 1, 1) self.grid.addWidget(self.out, 2, 0, 1, 1) def setup_timers(self): self.serial_timer = QTimer() self.serial_timer.setInterval(SERIAL_INTERVAL) self.serial_timer.timeout.connect(self.get_data) self.serial_timer.start() self.process_timer = QTimer() self.process_timer.setInterval(PROCESS_INTERVAL) self.process_timer.timeout.connect(self.process) self.process_timer.start() self.display_timer = QTimer() self.display_timer.setInterval(DISPLAY_TIMEOUT) self.display_timer.setSingleShot(True) self.display_timer.timeout.connect(self.set_background) def init_selector(self): sel_lines = self.selector.letters_dict.keys() sel_lines.insert(0, 'new strokes') sel_lines.insert(0, 'free run') self.letter_selector.addItems(sel_lines) self.letter_selector.currentIndexChanged.connect(self.set_background) def set_background(self): letter = str(self.letter_selector.currentText()) self.display.set_background(self.core_file_name, letter) def store_stroke(self, key, stroke, existing=True): file_name = '{key}{time}.txt'.format(key=key, time=int(time())) file_path = os.path.join(LEARNED_FOLDER, file_name) np.savetxt(file_path, stroke) if existing: self.display.set_background(self.core_file_name, key, color='g') self.display_timer.start() def get_stroke(self, data): stroke = data['stroke'] dimention = data['dimention'] if dimention < MIN_DIMENTION: print 'too small' return letter = str(self.letter_selector.currentText()) if letter == 'new strokes': self.store_stroke('_', stroke, existing=False) print 'recorded' try: letters = self.selector.check_stroke(stroke) except: #TODO: check unify_stroke return if letters: self.out.setText(self.out.text()+letters[0]) if letter == 'free run' and letters: self.store_stroke(letters[0], stroke) elif letter in letters: self.store_stroke(letter, stroke) def process(self): local_data_storage = deepcopy(self.incoming_data) self.incoming_data = [] for data in local_data_storage: if self.previous_time is None: self.previous_time = data[0] continue data[0], self.previous_time = data[0] - self.previous_time, data[0] if data[0] < MAX_DATA_TIMELAPSE: self.imu.calc(data) gyro = np.linalg.norm(np.array([data[7:]])) accel = self.imu.get_global_acceleration() accel = self.acceleration_filter.set_input(accel, data[0]) accel_magnitude = np.linalg.norm(accel) if accel_magnitude > ACCELERATION_RESET: self.execute_spell() Yr = self.imu.get_y_direction() self.stroke.set_data(Yr, gyro) self.stroke.process_size(data[0], accel) self.setVisible(not self.imu.in_calibration) def execute_spell(self): self.out.setText('') def get_data(self): try: self.data_buffer += self.serial.read(self.serial.inWaiting()) if self.data_buffer == '': return data_pieces = self.data_buffer.split(BUFFER_DELIMITER) # Put incomplete piece back to the buffer self.data_buffer = data_pieces.pop(-1) # If there are no complete data pieces - return from function if not data_pieces: return # Else - get the last of the pieces and discard the rest line = data_pieces[-1] result = [float(d) for d in line.split()] if len(result) != 9: raise ValueError('Nine pieces of data should be provided.') new_line = [time()] + result self.incoming_data.append(new_line) except KeyboardInterrupt: raise except Exception as e: # Something went wrong... nobody cares. print e
class RunDialog(QDialog): def __init__(self, run_model, parent): QDialog.__init__(self, parent) self.setWindowFlags(Qt.Window) self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) self.setModal(True) self.setWindowModality(Qt.WindowModal) self.setWindowTitle("Simulations") assert isinstance(run_model, BaseRunModel) self._run_model = run_model ert = None if isinstance(run_model, BaseRunModel): ert = run_model.ert() self.simulations_tracker = SimulationsTracker() states = self.simulations_tracker.getStates() self.state_colors = {state.name: state.color for state in states} self.state_colors['Success'] = self.state_colors["Finished"] self.state_colors['Failure'] = self.state_colors["Failed"] self.total_progress = SimpleProgress() status_layout = QHBoxLayout() status_layout.addStretch() self.__status_label = QLabel() status_layout.addWidget(self.__status_label) status_layout.addStretch() status_widget_container = QWidget() status_widget_container.setLayout(status_layout) self.progress = Progress() self.progress.setIndeterminateColor(self.total_progress.color) for state in states: self.progress.addState(state.state, QColor(*state.color), 100.0 * state.count / state.total_count) legend_layout = QHBoxLayout() self.legends = {} for state in states: self.legends[state] = Legend("%s (%d/%d)", QColor(*state.color)) self.legends[state].updateLegend(state.name, 0, 0) legend_layout.addWidget(self.legends[state]) legend_widget_container = QWidget() legend_widget_container.setLayout(legend_layout) self.running_time = QLabel("") self.plot_tool = PlotTool() self.plot_tool.setParent(None) self.plot_button = QPushButton(self.plot_tool.getName()) self.plot_button.clicked.connect(self.plot_tool.trigger) self.plot_button.setEnabled(ert is not None) self.kill_button = QPushButton("Kill simulations") self.done_button = QPushButton("Done") self.done_button.setHidden(True) self.restart_button = QPushButton("Restart") self.restart_button.setHidden(True) self.show_details_button = QPushButton("Details") self.show_details_button.setCheckable(True) size = 20 spin_movie = resourceMovie("ide/loading.gif") spin_movie.setSpeed(60) spin_movie.setScaledSize(QSize(size, size)) spin_movie.start() self.processing_animation = QLabel() self.processing_animation.setMaximumSize(QSize(size, size)) self.processing_animation.setMinimumSize(QSize(size, size)) self.processing_animation.setMovie(spin_movie) button_layout = QHBoxLayout() button_layout.addWidget(self.processing_animation) button_layout.addWidget(self.running_time) button_layout.addStretch() button_layout.addWidget(self.show_details_button) button_layout.addWidget(self.plot_button) button_layout.addWidget(self.kill_button) button_layout.addWidget(self.done_button) button_layout.addWidget(self.restart_button) button_widget_container = QWidget() button_widget_container.setLayout(button_layout) self.detailed_progress = DetailedProgressWidget( self, self.state_colors) self.detailed_progress.setVisible(False) self.dummy_widget_container = QWidget( ) #Used to keep the other widgets from stretching layout = QVBoxLayout() layout.addWidget(self.total_progress) layout.addWidget(status_widget_container) layout.addWidget(self.progress) layout.addWidget(legend_widget_container) layout.addWidget(self.detailed_progress) layout.addWidget(self.dummy_widget_container) layout.addWidget(button_widget_container) layout.setStretch(0, 0) layout.setStretch(1, 0) layout.setStretch(2, 0) layout.setStretch(3, 0) layout.setStretch(4, 1) layout.setStretch(5, 1) layout.setStretch(6, 0) self.setLayout(layout) self.kill_button.clicked.connect(self.killJobs) self.done_button.clicked.connect(self.accept) self.restart_button.clicked.connect(self.restart_failed_realizations) self.show_details_button.clicked.connect(self.toggle_detailed_progress) self.__updating = False self.__update_queued = False self.__simulation_started = False self.__update_timer = QTimer(self) self.__update_timer.setInterval(500) self.__update_timer.timeout.connect(self.updateRunStatus) self._simulations_argments = {} def closeEvent(self, QCloseEvent): if not self.checkIfRunFinished(): #Kill jobs if dialog is closed if self.killJobs() != QMessageBox.Yes: QCloseEvent.ignore() def startSimulation(self, arguments): self._simulations_argments = arguments if not 'prev_successful_realizations' in self._simulations_argments: self._simulations_argments['prev_successful_realizations'] = 0 self._run_model.reset() def run(): self._run_model.startSimulations(self._simulations_argments) simulation_thread = Thread(name="ert_gui_simulation_thread") simulation_thread.setDaemon(True) simulation_thread.run = run simulation_thread.start() self.__update_timer.start() def checkIfRunFinished(self): if self._run_model.isFinished(): self.hideKillAndShowDone() if self._run_model.hasRunFailed(): error = self._run_model.getFailMessage() QMessageBox.critical( self, "Simulations failed!", "The simulation failed with the following error:\n\n%s" % error) return True return False def updateProgress(self): total_count = self._run_model.getQueueSize() queue_status = self._run_model.getQueueStatus() states = self.simulations_tracker.getStates() for state in states: state.count = 0 state.total_count = total_count for state in states: for queue_state in queue_status: if queue_state in state.state: state.count += queue_status[queue_state] self.progress.updateState(state.state, 100.0 * state.count / state.total_count) self.legends[state].updateLegend(state.name, state.count, state.total_count) def updateRunStatus(self): self.__status_label.setText(self._run_model.getPhaseName()) if self.checkIfRunFinished(): self.total_progress.setProgress(self._run_model.getProgress()) self.detailed_progress.set_progress( *self._run_model.getDetailedProgress()) self.updateProgress() return self.total_progress.setProgress(self._run_model.getProgress()) if self._run_model.isIndeterminate(): self.progress.setIndeterminate(True) states = self.simulations_tracker.getStates() for state in states: self.legends[state].updateLegend(state.name, 0, 0) else: if self.detailed_progress and self.detailed_progress.isVisible(): self.detailed_progress.set_progress( *self._run_model.getDetailedProgress()) else: self._run_model.updateDetailedProgress( ) #update information without rendering self.progress.setIndeterminate(False) self.updateProgress() self.setRunningTime() def setRunningTime(self): days = 0 hours = 0 minutes = 0 seconds = self._run_model.getRunningTime() if seconds >= 60: minutes, seconds = divmod(seconds, 60) if minutes >= 60: hours, minutes = divmod(minutes, 60) if hours >= 24: days, hours = divmod(hours, 24) if days > 0: self.running_time.setText( "Running time: %d days %d hours %d minutes %d seconds" % (days, hours, minutes, seconds)) elif hours > 0: self.running_time.setText( "Running time: %d hours %d minutes %d seconds" % (hours, minutes, seconds)) elif minutes > 0: self.running_time.setText("Running time: %d minutes %d seconds" % (minutes, seconds)) else: self.running_time.setText("Running time: %d seconds" % seconds) def killJobs(self): msg = "Are you sure you want to kill the currently running simulations?" if self._run_model.getQueueStatus().get( JobStatusType.JOB_QUEUE_UNKNOWN, 0) > 0: msg += "\n\nKilling a simulation with unknown status will not kill the realizations already submitted!" kill_job = QMessageBox.question(self, "Kill simulations?", msg, QMessageBox.Yes | QMessageBox.No) if kill_job == QMessageBox.Yes: if self._run_model.killAllSimulations(): self.reject() return kill_job def hideKillAndShowDone(self): self.__update_timer.stop() self.processing_animation.hide() self.kill_button.setHidden(True) self.done_button.setHidden(False) self.detailed_progress.set_progress( *self._run_model.getDetailedProgress()) self.restart_button.setVisible(self.has_failed_realizations()) self.restart_button.setEnabled(self._run_model.support_restart) def has_failed_realizations(self): completed = self._run_model.completed_realizations_mask initial = self._run_model.initial_realizations_mask for (index, successful) in enumerate(completed): if initial[index] and not successful: return True return False def count_successful_realizations(self): """ Counts the realizations completed in the prevoius ensemble run :return: """ completed = self._run_model.completed_realizations_mask return completed.count(True) def create_mask_from_failed_realizations(self): """ Creates a BoolVector mask representing the failed realizations :return: Type BoolVector """ completed = self._run_model.completed_realizations_mask initial = self._run_model.initial_realizations_mask inverted_mask = BoolVector(default_value=False) for (index, successful) in enumerate(completed): inverted_mask[index] = initial[index] and not successful return inverted_mask def restart_failed_realizations(self): msg = QMessageBox(self) msg.setIcon(QMessageBox.Information) msg.setText( "Note that workflows will only be executed on the restarted realizations and that this might have unexpected consequences." ) msg.setWindowTitle("Restart Failed Realizations") msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) result = msg.exec_() if result == QMessageBox.Ok: self.restart_button.setVisible(False) self.kill_button.setVisible(True) self.done_button.setVisible(False) active_realizations = self.create_mask_from_failed_realizations() self._simulations_argments[ 'active_realizations'] = active_realizations self._simulations_argments[ 'prev_successful_realizations'] += self.count_successful_realizations( ) self.startSimulation(self._simulations_argments) def toggle_detailed_progress(self): self.detailed_progress.setVisible(not ( self.detailed_progress.isVisible())) self.dummy_widget_container.setVisible(not ( self.detailed_progress.isVisible())) self.adjustSize()
def fill_content(self, content_gui): """ Fill the layouts of the central widget. Arguments: content_gui - Content used to create the GUI outfit. Return: List of errors that occured. """ self.content = {} exclude_set = tu.get_exclude_set(content=content_gui) error_list = [] tab_list = [] for entry in content_gui: key = entry['name'] if key in exclude_set: continue elif entry['layout'] in exclude_set: continue elif key == 'Stretch': layout = entry['layout'] self.layout[layout].addStretch(1) continue elif key == 'Separator': layout = entry['layout'] separator = entry['separator'] self.layout[layout].addWidget(separator) continue elif key == 'Path': tu.reduce_path_widget(exclude_set=exclude_set, content=entry['content']) elif key == 'Copy': tu.reduce_copy_entries(exclude_set=exclude_set, content=entry['content']) else: pass layout = entry['layout'] plot_labels = '' plot_name = '' try: plot_name = layout.replace('Plot ', '') plot_labels = ti.get_dtype_dict()[tu.get_function_dict() [plot_name]['typ']] except KeyError: pass # Create widget self.content[key] = entry['widget']( mount_worker=self.mount_worker, process_worker=self.process_worker, plot_worker=self.plot_worker, settings_folder=self.settings_folder, plot_labels=plot_labels, plot_name=plot_name, parent=self, **entry) if isinstance(self.content[key], TabDocker): tab_list.append(key) else: pass if layout in tab_list: self.content[layout].add_tab(self.content[key], key) else: self.layout[layout].addWidget(self.content[key]) if key == 'Button': self.content[key].sig_load.connect(self.load) self.content[key].sig_save.connect(self.save) self.content[key].sig_start.connect(self.start) self.content[key].sig_stop.connect(self.stop_dialog) self.content[key].sig_check_quota.connect(self.check_quota) else: pass if key == 'Notification': self.content[key].update_telegram() self.content[key].update_email() self.content[key].update() self.content[key].sig_stop.connect(self.stop) timer = QTimer(self) timer.setInterval(20000) timer.timeout.connect(self.content[key].get_telegram_messages) timer.start() else: pass if key == 'Plot per micrograph' or key == 'Plot histogram': self.plot_worker.sig_data.connect( self.content[key].update_figure) else: pass return error_list
class Downloader(QObject): MAX_CONNECTION = 2 DEFAULT_CACHE_EXPIRATION = 24 # hours NOT_FOUND = 0 NO_ERROR = 0 TIMEOUT_ERROR = 4 UNKNOWN_ERROR = -1 def __init__(self, parent=None): QObject.__init__(self, parent) self.queue = [] self.requestingUrls = [] self.replies = [] self.eventLoop = QEventLoop() self.sync = False self.fetchedFiles = {} self.clearCounts() self.timer = QTimer() self.timer.setSingleShot(True) self.timer.timeout.connect(self.fetchTimedOut) self.userAgent = "Mozilla/5.0" self.errorStatus = Downloader.NO_ERROR def clearCounts(self): self.fetchSuccesses = 0 self.fetchErrors = 0 self.cacheHits = 0 def fetchTimedOut(self): self.log("Downloader.timeOut()") self.abort() self.errorStatus = Downloader.TIMEOUT_ERROR def abort(self): # clear queue and abort sent requests self.queue = [] self.timer.stop() for reply in self.replies: reply.abort() self.errorStatus = Downloader.UNKNOWN_ERROR def replyFinished(self): reply = self.sender() url = reply.request().url().toString() self.log("replyFinished: %s" % url) if url not in self.fetchedFiles: self.fetchedFiles[url] = None self.requestingUrls.remove(url) self.replies.remove(reply) isFromCache = 0 httpStatusCode = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) if reply.error() == QNetworkReply.NoError: self.fetchSuccesses += 1 if reply.attribute(QNetworkRequest.SourceIsFromCacheAttribute): self.cacheHits += 1 isFromCache = 1 elif not reply.hasRawHeader("Cache-Control"): cache = QgsNetworkAccessManager.instance().cache() if cache: metadata = cache.metaData(reply.request().url()) #self.log("Expiration date: " + metadata.expirationDate().toString().encode("utf-8")) if metadata.expirationDate().isNull(): metadata.setExpirationDate( QDateTime.currentDateTime().addSecs( self.DEFAULT_CACHE_EXPIRATION * 60 * 60)) cache.updateMetaData(metadata) self.log( "Default expiration date has been set: %s (%d h)" % (url, self.DEFAULT_CACHE_EXPIRATION)) if reply.isReadable(): data = reply.readAll() self.fetchedFiles[url] = data else: qDebug("http status code: " + str(httpStatusCode)) else: if self.sync and httpStatusCode == 404: self.fetchedFiles[url] = self.NOT_FOUND self.fetchErrors += 1 if self.errorStatus == self.NO_ERROR: self.errorStatus = self.UNKNOWN_ERROR self.emit(SIGNAL('replyFinished(QString, int, int)'), url, reply.error(), isFromCache) reply.deleteLater() if debug_mode: qDebug("queue: %d, requesting: %d" % (len(self.queue), len(self.requestingUrls))) if len(self.queue) + len(self.requestingUrls) == 0: # all replies have been received if self.sync: self.logT("eventLoop.quit()") self.eventLoop.quit() else: self.timer.stop() elif len(self.queue) > 0: # start fetching the next file self.fetchNext() self.log("replyFinished End: %s" % url) def fetchNext(self): if len(self.queue) == 0: return url = self.queue.pop(0) self.log("fetchNext: %s" % url) request = QNetworkRequest(QUrl(url)) request.setRawHeader("User-Agent", self.userAgent) reply = QgsNetworkAccessManager.instance().get(request) reply.finished.connect(self.replyFinished) self.requestingUrls.append(url) self.replies.append(reply) return reply def fetchFiles(self, urlList, timeoutSec=0): self.log("fetchFiles()") self.sync = True self.queue = [] self.clearCounts() self.errorStatus = Downloader.NO_ERROR self.fetchedFiles = {} if len(urlList) == 0: return self.fetchedFiles for url in urlList: self.addToQueue(url) for i in range(self.MAX_CONNECTION): self.fetchNext() if timeoutSec > 0: self.timer.setInterval(timeoutSec * 1000) self.timer.start() self.logT("eventLoop.exec_(): " + str(self.eventLoop)) self.eventLoop.exec_() self.log("fetchFiles() End: %d" % self.errorStatus) if timeoutSec > 0: self.timer.stop() return self.fetchedFiles def addToQueue(self, url): if url in self.queue: return False self.queue.append(url) return True def queueCount(self): return len(self.queue) def finishedCount(self): return len(self.fetchedFiles) def unfinishedCount(self): return len(self.queue) + len(self.requestingUrls) def log(self, msg): if debug_mode: qDebug(msg) def logT(self, msg): if debug_mode: qDebug("%s: %s" % (str(threading.current_thread()), msg)) def fetchFilesAsync(self, urlList, timeoutSec=0): self.log("fetchFilesAsync()") self.sync = False self.queue = [] self.clearCounts() self.errorStatus = Downloader.NO_ERROR self.fetchedFiles = {} if len(urlList) == 0: return self.fetchedFiles for url in urlList: self.addToQueue(url) for i in range(self.MAX_CONNECTION): self.fetchNext() if timeoutSec > 0: self.timer.setInterval(timeoutSec * 1000) self.timer.start()
class _CameraWidget(QWidget): imagecaptured = pyqtSignal(QPixmap) done = pyqtSignal() def __init__(self, parent=None): super(_CameraWidget, self).__init__(parent) self.cameralabel = QLabel() self.cameralabel.setScaledContents(True) self.setLayout(QGridLayout()) self.toolbar = QToolBar() spacer = QWidget() # spacer.setMinimumWidth(30) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.toolbar.setIconSize(QSize(48, 48)) self.toolbar.addWidget(spacer) self.swapaction = self.toolbar.addAction(QIcon(":/widgets/cameraswap"), "Swap Camera") self.swapaction.triggered.connect(self.swapcamera) self.cameralabel.mouseReleaseEvent = self.takeimage self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.toolbar) self.layout().addWidget(self.cameralabel) self.timer = QTimer() self.timer.setInterval(20) self.timer.timeout.connect(self.showimage) self.cam = None self.pixmap = None self.currentdevice = 1 def swapcamera(self): self.stop() if self.currentdevice == 0: self.start(1) else: self.start(0) def showimage(self): if self.cam is None: return img = self.cam.getImage() self.image = ImageQt(img) pixmap = QPixmap.fromImage(self.image) self.cameralabel.setPixmap(pixmap) def takeimage(self, *args): self.timer.stop() img = self.cam.getImage() self.image = ImageQt(img) self.pixmap = QPixmap.fromImage(self.image) self.cameralabel.setPixmap(self.pixmap) self.imagecaptured.emit(self.pixmap) self.done.emit() @property def camera_res(self): width, height = tuple(roam.config.settings['camera_res'].split(',')) return width, height def start(self, dev=1): try: self.cam = vc.Device(dev) try: width, height = self.camera_res self.cam.setResolution(int(width), int(height)) except KeyError: pass self.currentdevice = dev except vidcap.error: if dev == 0: utils.error("Could not start camera") raise CameraError("Could not start camera") self.start(dev=0) return roam.config.settings['camera'] = self.currentdevice self.timer.start() def stop(self): self.timer.stop() del self.cam self.cam = None
class LockinThermometerWidget(Ui.Ui_Form, QWidget): def __init__(self, parent=None): super(LockinThermometerWidget, self).__init__(parent) self.setupUi(self) self.setWindowTitle('Lockin Thermometer') self.timer = None self.Rthermometer = float('nan') ''' Not sure if DateAxisItem is available anymore ''' axis = pg.AxisItem(orientation='bottom') self.plot = pg.PlotWidget(axisItems={'bottom': axis}) self.plot.setBackground('w') self.plot.plotItem.showGrid(x=True, y=True) self.plot.addLegend() self.verticalLayout.addWidget(self.plot) self.curve = pg.PlotCurveItem(name='X', symbol='o', pen='b') self.plot.addItem(self.curve) self.clearPb.clicked.connect(self.clearData) self.clearData() self.plotYAxisCombo.currentIndexChanged.connect(self.updatePlot) self.sr830 = None self.runPb.clicked.connect(self.run) self.parameterItems = [self.attenuatorGainSb, self.sourceImpedanceSb, self.driveResistanceSb, self.leadResistanceSb, self.preampGainSb, self.sensorVoltageSb] self.savePb.clicked.connect(self.saveParameterSet) self.loadPb.clicked.connect(self.loadParameterSet) self.deletePb.clicked.connect(self.deleteParameterSet) self.attenuatorAttenuationSb.valueChanged.connect(self.updateAttenuatorGain) self.attenuatorGainSb.valueChanged.connect(self.updateAttenuatorAttenuation) self.sensorVoltageIndicator.setUnit('V') self.sensorCurrentIndicator.setUnit('A') self.sensorPowerIndicator.setUnit('W') sr830 = SR830(None) sr830.sensitivity.populateEnumComboBox(self.minSensitivityCombo) self.loadParameterSets() self.restoreSettings() self.hkSub = HousekeepingSubscriber(parent = self) self.hkSub.adrResistanceReceived.connect(self.collectAdrResistance) self.hkSub.start() self.adrResistanceIndicator.setUnit(u'Ω') self.adrResistanceIndicator.setPrecision(5) self.publisher = None combo = self.calibrationCombo combo.addItem('RuOx 600') combo.addItem('RuOx 2005') combo.addItem('RuOx Bus (Shuo)') combo.addItem('RuOx Chip (InsideBox)') combo.setItemData(0, 'Nominal sensor calibration for RuOx 600 series', Qt.ToolTipRole) combo.setItemData(1, 'Calibration for RuOx sensor #2005 series', Qt.ToolTipRole) combo.setItemData(2, 'Cross-calibration against RuOx #2005 by Shuo (not so good above ~300mK)', Qt.ToolTipRole) combo.setItemData(3, 'Cross-calibration against RuOx #2005 by Yu', Qt.ToolTipRole) self.selectCalibration() combo.currentIndexChanged.connect(self.selectCalibration) def selectCalibration(self): cal = self.calibrationCombo.currentText() if cal == 'RuOx 600': self.calibration = RuOx600() elif cal == 'RuOx 2005': self.calibration = RuOx2005() elif cal == 'RuOx Bus (Shuo)': self.calibration = RuOxBus() elif cal == 'RuOx Chip (InsideBox)': self.calibration = RuOxBox() def collectAdrResistance(self, R): self.Rthermometer = R self.adrResistanceIndicator.setValue(R) def updateAttenuatorGain(self, v): sb = self.attenuatorGainSb block = sb.blockSignals(True) sb.setValue(1./v) sb.blockSignals(block) def updateAttenuatorAttenuation(self, v): sb = self.attenuatorAttenuationSb block = sb.blockSignals(True) sb.setValue(1./v) sb.blockSignals(block) def saveParameterSet(self): s = QSettings() s.beginGroup('ParameterSets') name = self.configCombo.currentText() s.beginGroup(name) s.setValue('adjustExcitation', self.adjustExcitationCb.isChecked()) s.setValue('sensorName', self.sensorNameLe.text()) s.setValue('sr830Visa', self.visaCombo.currentText()) s.setValue('autoRanging', self.autoRangingCb.isChecked()) s.setValue('minSensitivity', self.minSensitivityCombo.currentCode()) for item in self.parameterItems: s.setValue(item.objectName(), item.value()) s.endGroup() s.endGroup() def loadParameterSet(self): s = QSettings() name = self.configCombo.currentText() s.beginGroup('ParameterSets') if not name in s.childGroups(): dlg = QErrorMessage(self) dlg.setWindowTitle('Error') dlg.showMessage('No saved parameters available for %s' % name) return s.beginGroup(name) for item in self.parameterItems: item.setValue(s.value(item.objectName(), item.value(), type=float)) self.adjustExcitationCb.setChecked(s.value('adjustExcitation', False, type=bool)) self.sensorNameLe.setText(s.value('sensorName', '', type=QString)) self.visaCombo.setCurrentIndex(self.visaCombo.findText(s.value('sr830Visa', 'GPIB0::12', type=QString))) self.autoRangingCb.setChecked(s.value('autoRanging', True, type=bool)) self.minSensitivityCombo.setCurrentCodeSilently(s.value('minSensitivity', 0, type=int)) s.endGroup() s.endGroup() def loadParameterSets(self): s = QSettings() s.beginGroup('ParameterSets') names = s.childGroups() self.configCombo.addItems(names) def deleteParameterSet(self): i = self.configCombo.currentIndex() name = self.configCombo.itemText(i) s = QSettings() s.beginGroup('ParameterSets') s.beginGroup(name) s.remove('') s.endGroup() s.endGroup() self.configCombo.removeItem(i) def closeEvent(self, event): if self.timer: self.timer.stop() self.saveSettings() self.hkSub.stop() self.hkSub.wait(1000) def restoreSettings(self): s = QSettings() #visa = s.value('visa', QString(), type=QString) #i = self.visaCombo.findText(visa) #elf.visaCombo.setCurrentIndex(i) self.configCombo.setCurrentIndex(self.configCombo.findText(s.value('parameterSet', '', type=QString))) if len(self.configCombo.currentText()): self.loadParameterSet() #self.sensorNameLe.setText(s.value('sensorName', '', type=QString)) def saveSettings(self): s = QSettings() #s.setValue('visa', self.visaCombo.currentText()) s.setValue('parameterSet', self.configCombo.currentText()) #s.setValue('sensorName', self.sensorNameLe.text()) def enableWidgets(self, enable): self.visaCombo.setEnabled(enable) self.attenuatorGroupBox.setEnabled(enable) self.seriesResistanceGroupBox.setEnabled(enable) self.preampGroupBox.setEnabled(enable) self.sensorNameLe.setEnabled(enable) self.loadPb.setEnabled(enable) self.savePb.setEnabled(enable) self.deletePb.setEnabled(enable) self.configCombo.setEnabled(enable) def run(self): if self.sr830 is not None: self.stop() else: self.start() def stop(self): self.timer.stop() self.timer = None self.sr830 = None self.runPb.setText('Start') self.enableWidgets(True) del self.publisher; self.publisher = None def sensorName(self): return str(self.sensorNameLe.text()) def start(self): sensorName = self.sensorName() self.setWindowTitle('Lock-In Thermometer %s' % sensorName ) #setAppId(sensorName) if sensorName == 'BusThermometer': icon = QIcon('Icons/LockinThermometer_Bus.ico') elif sensorName == 'RuOx2005Thermometer': icon = QIcon('Icons/LockinThermometer_BoxOutside.ico') elif sensorName == 'BoxThermometer': icon = QIcon('Icons/LockinThermometer_BoxInside2.ico') else: icon = QIcon('Icons/LockinThermometer.ico') self.setWindowIcon(icon) visa = str(self.visaCombo.currentText()) self.sr830 = SR830(visa) #self.sr830.debug = True self.sr830.readAll() self.sr830.sineOut.caching = False # Disable caching on this Sockets = {'BusThermometer':PubSub.LockinThermometerAdr, 'RuOx2005Thermometer':PubSub.LockinThermometerRuOx2005, 'BoxThermometer':PubSub.LockinThermometerBox} socket = Sockets[sensorName] self.publisher = ZmqPublisher('LockinThermometer', socket) self.runPb.setText('Stop') self.timer = QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self.snapSignal) self.timer.start() self.enableWidgets(False) self.rangeChangedTime = 0 self.exChangedTime = 0 t = time.time() timeString = time.strftime('%Y%m%d-%H%M%S', time.localtime(t)) dateString = time.strftime('%Y%m%d') sensorName = str(self.sensorNameLe.text()) s = QSettings('WiscXrayAstro', application='ADR3RunInfo') path = str(s.value('runPath', '', type=str)) fileName = os.path.join(path, '%s_%s.dat' % (sensorName, dateString)) if not os.path.isfile(fileName): # Maybe create new file with open(fileName, 'a+') as f: f.write('#LockinThermometer.py\n') f.write('#Date=%s\n' % timeString) f.write('#SensorName=%s\n' % sensorName) f.write('#SR830=%s\n' % self.sr830.visaId()) f.write('#AttenuatorGain=%f\n' % self.attenuatorGainSb.value()) f.write('#AttenuatorSourceImpedance=%f\n' % self.sourceImpedanceSb.value()) f.write('#DriveResistance=%f\n' % self.driveResistanceSb.value()) f.write('#LeadResistance=%f\n' % self.leadResistanceSb.value()) f.write('#PreampGain=%f\n' % self.preampGainSb.value()) f.write('#DesiredExcitation=%f\n' % self.sensorVoltageSb.value()) k = self.sr830.allSettingValues() for key,value in k.iteritems(): f.write('#SR830/%s=%s\n' % (key,value)) f.write('#'+'\t'.join(['time', 'VsineOut', 'X', 'Y', 'f', 'Sensitivity', 'RxCalc', 'Rtherm'])+'\n') self.fileName = fileName def snapSignal(self): t = time.time() self.sr830.snapSignal() VsineOut = self.sr830.sineOut.value X = self.sr830.X Y = self.sr830.Y f = self.sr830.f rangeChangeAge = t - self.rangeChangedTime exChangeAge = t - self.exChangedTime sensitivity = self.sr830.sensitivity.value if self.autoRangingCb.isChecked(): self.sr830.checkStatus() minCode = self.minSensitivityCombo.currentCode() currentCode = self.sr830.sensitivity.code if self.sr830.overload and rangeChangeAge > 10: self.sr830.sensitivity.code = currentCode+1 self.rangeChangeTime = t elif X > 0.9*sensitivity and rangeChangeAge > 10: self.sr830.sensitivity.code = currentCode+1 self.rangeChangedTime = t elif X < 0.3*sensitivity and rangeChangeAge > 10: if currentCode > minCode: self.sr830.sensitivity.code = currentCode - 1 self.rangeChangedTime = t elif currentCode < minCode: self.sr830.sensitivity.code = minCode self.rangeChangedTime = t G1 = self.attenuatorGainSb.value() G2 = self.preampGainSb.value() Rsource = self.sourceImpedanceSb.value() Rd = self.driveResistanceSb.value() Rl = self.leadResistanceSb.value() Rs = Rsource+Rd+Rl Vx = X / G2 Vex = VsineOut * G1 # Real excitation self.sensorVoltageIndicator.setValue(Vx) Rx = Rs / (Vex/Vx-1.) I = Vx / Rx self.sensorCurrentIndicator.setValue(I) P = Vx*I Temp = self.calibration.calculateTemperature([Rx])[0] # @todo This is really a crutch Tbase = self.calibration.correctForReadoutPower(Temp, P) if self.publisher is not None: if rangeChangeAge > 10 and exChangeAge > 10 and Temp == Temp and Temp > 0 and Temp < 10: self.publisher.publishDict(self.sensorName(), {'t': t, 'R': Rx, 'T': Temp, 'P': P, 'Tbase': Tbase}) #self.publisher.publish('ADR_Sensor_R', Rx) #self.publisher.publish('ADR_Temperature', Temp) # Log data with open(self.fileName, 'a+') as of: of.write('%.3f\t%.3f\t%.5E\t%.5E\t%.3f\t%.1E\t%.5E\t%.5E\n' % (t, VsineOut, X, Y, f, sensitivity, Rx, self.Rthermometer)) self.ts.append(t) self.xs.append(X) self.ys.append(Y) self.fs.append(f) self.VsineOuts.append(VsineOut) self.Rs.append(Rx) self.Vxs.append(Vx) self.Ps.append(P) self.Ts.append(Temp) self.Tbases.append(Tbase) self.sensorIndicator.setValue(Rx) self.temperatureIndicator.setKelvin(Temp) self.baseTempIndicator.setKelvin(Tbase) self.sensorPowerIndicator.setValue(P) self.updateLed.flashOnce() self.updatePlot() # Not sure where this code came from. Seems questionable (FJ) # if len(self.Ts) > 2 : # dTdt = abs((self.Ts[-1] - self.Ts[-2]) / (self.ts[-1] - self.ts[-2])) # if dTdt > 0.1: # self.temperatureIndicator.setKelvin('N/A') # self.stop() # Perhaps change excitation if exChangeAge < 10 or rangeChangeAge < 10 or not self.adjustExcitationCb.isChecked(): return VxDesired = self.sensorVoltageSb.value() IDesired = VxDesired / Rx VexDesired = IDesired*(Rx+Rs) change = (VexDesired-Vex)/Vex tolerance = 1E-2*self.toleranceSb.value() if abs(change) < tolerance: return VsineOutDesired = VexDesired / G1 # This is what we would like to see # What we actually get may be something different Vnew = min(5,max(VsineOutDesired,0.004)) if tolerance == 0 and abs(Vnew - VsineOut) > 0.009: # If a large step is required, do it slowly Vnew = (3.*VsineOut+1.*Vnew)/4. if abs(Vnew - VsineOut) < 0.002: return self.exChangedTime = t self.sr830.sineOut.value = Vnew def clearData(self): self.ts = [] self.xs = [] self.ys = [] self.fs = [] self.Rs = [] self.Ps = [] self.VsineOuts = [] self.Vxs = [] self.Ts = [] self.Tbases = [] self.updatePlot() def updatePlot(self): yAxis = self.plotYAxisCombo.currentText() pl = self.plot if yAxis == 'X': y = self.xs pl.setLabel('left', 'Lock-in X', 'V') elif yAxis == 'Y': y = self.ys pl.setLabel('left', 'Lock-in Y', 'V') elif yAxis == 'R': y = self.Rs pl.setLabel('left', 'R sensor', u'Ω') elif yAxis == 'V sine out': y = self.VsineOuts pl.setLabel('left', 'V sine out', 'V') elif yAxis == 'V sensor': y = self.Vxs pl.setLabel('left', 'V sensor', 'V') elif yAxis == 'P sensor': y = self.Ps pl.setLabel('left', 'P sensor', 'W') elif yAxis == 'Sensor temperature': y = self.Ts pl.setLabel('left', 'T sensor', 'K') elif yAxis == 'Base temperature': y = self.Tbases pl.setLabel('left', 'T base', 'K') elif yAxis == '': return x = self.ts self.curve.setData(x, y)
class CalibrateGyroscopeBias(QWidget, Ui_calibrate_gyroscope_bias): TYPE_GYR_BIAS = 5 NUM_AVG = 5000 qtcb_callback = pyqtSignal(int, int, int) def __init__(self, parent): QWidget.__init__(self) self.setupUi(self) self.parent = parent self.imu = parent.parent.imu self.set_default() self.start_button.clicked.connect(self.next_state) self.i = 0 self.t = 0 self.state = 0 self.temperature_raw = 0 self.t_raw_start_low = 0 self.t_raw_end_high = 0 self.gyr_sum = [0, 0, 0] self.gyr_bias_low = [0, 0, 0] self.gyr_bias_high = [0, 0, 0] self.update_timer = QTimer() self.update_timer.timeout.connect(self.update_temperature) self.update_timer.setInterval(1000) self.qtcb_callback.connect(self.callback) def start(self): self.update_temperature() self.update_timer.start() self.imu.register_callback(self.imu.CALLBACK_ANGULAR_VELOCITY, self.qtcb_callback.emit) def stop(self): self.update_timer.stop() self.imu.set_angular_velocity_period(0) def update_temperature(self): self.temperature_raw = self.imu.get_imu_temperature() t_str = "%.2f" % (self.temperature_raw / 100.0) if self.state < 2: self.t_low.setText(t_str) else: self.t_high.setText(t_str) def set_default(self): self.gyr_sum = [0, 0, 0] self.gyr_bias = [0, 0, 0] text = """For the gyroscope bias calibration the IMU Brick has \ to lie still for about 5 seconds. As soon as you press "Start Calibration" \ the calibration will begin. Make sure that the IMU Brick lies absolutely still during the calibration. \ Don't make vibrations by walking around and don't type on your keyboard \ if possible place the IMU Brick on another desk. Even small vibrations can \ deteriorate this calibration significantly. The gyroscope bias is highly dependent on the temperature, so you have to \ calibrate the bias two times with different temperatures. The first \ measurement should be with a low temperature and the second with a high one. \ The temperature difference should be at least 5%cC. If you have \ a temperature where the IMU Brick is mostly used, you should use this \ temperature for one of the sampling points. """ % 0xB0 self.text_label.setText(text) self.start_button.setText("Start Calibration Low Temperature") def calc(self): if self.state == 2: for i in range(3): self.gyr_bias_low[i] = self.gyr_sum[i] / self.NUM_AVG if i == 0: self.bias_low_x.setText(str(self.gyr_bias_low[i])) elif i == 1: self.bias_low_y.setText(str(self.gyr_bias_low[i])) elif i == 2: self.bias_low_z.setText(str(self.gyr_bias_low[i])) else: for i in range(3): self.gyr_bias_high[i] = self.gyr_sum[i] / self.NUM_AVG if i == 0: self.bias_high_x.setText(str(self.gyr_bias_high[i])) elif i == 1: self.bias_high_y.setText(str(self.gyr_bias_high[i])) elif i == 2: self.bias_high_z.setText(str(self.gyr_bias_high[i])) def next_state(self): self.state += 1 if self.state == 5: self.state = 0 if self.state == 0: self.gyr_sum = [0, 0, 0] self.update_temperature() self.imu.set_angular_velocity_period(0) bias = [ self.gyr_bias_low[0], self.gyr_bias_low[1], self.gyr_bias_low[2], (self.t_raw_start_low + self.t_raw_end_low) / 2, self.gyr_bias_high[0], self.gyr_bias_high[1], self.gyr_bias_high[2], (self.t_raw_start_high + self.t_raw_end_high) / 2, 0, 0 ] self.imu.set_calibration(self.TYPE_GYR_BIAS, bias) self.parent.refresh_values() self.bias_low_x.setText("?") self.bias_low_y.setText("?") self.bias_low_z.setText("?") self.t_low.setText("?") self.bias_high_x.setText("?") self.bias_high_y.setText("?") self.bias_high_z.setText("?") self.t_high.setText("?") self.set_default() elif self.state == 1: self.update_timer.stop() self.t_raw_start_low = self.imu.get_imu_temperature() bias = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] self.imu.set_calibration(self.TYPE_GYR_BIAS, bias) self.parent.refresh_values() self.imu.set_angular_velocity_period(1) self.text_label.setText("Waiting...") self.start_button.setEnabled(False) elif self.state == 2: self.t_raw_end_low = self.imu.get_imu_temperature() self.calc() self.update_temperature() self.update_timer.start() self.start_button.setText("Start Calibration High Temperature") self.text_label.setText("""Now wait for the temperature to rise. \ A temperature difference of at least 5%cC is recommended. The calibration will again take 5 seconds and the IMU Brick needs to lie absolutely still.""" % 0xB0) elif self.state == 3: self.update_timer.stop() self.t_raw_start_high = self.imu.get_imu_temperature() self.imu.set_angular_velocity_period(1) self.text_label.setText("Waiting...") self.start_button.setEnabled(False) elif self.state == 4: self.t_raw_end_high = self.imu.get_imu_temperature() self.calc() self.text_label.setText("""Ready. To save the calibration \ press "Save Calibration" """) self.start_button.setText("Save Calibration") def callback(self, gyr_x, gyr_y, gyr_z): if self.i == 0: self.t = time.time() self.gyr_sum = [0, 0, 0] if not self.start_button.isEnabled(): self.text_label.setText("Calibrating: " + str(self.i) + '/' + str(self.NUM_AVG)) else: return self.gyr_sum[0] -= gyr_x self.gyr_sum[1] -= gyr_y self.gyr_sum[2] -= gyr_z self.i += 1 if self.i == self.NUM_AVG: self.imu.set_angular_velocity_period(0) self.start_button.setEnabled(True) self.next_state() self.i = 0
class Transformation(visionModule): ''' classdocs ''' __imgScene = None __imgSceneTh = None __calibrated = False __calibrating = False __basisMatrix = array([[1, 0], [0, 1]]) __offset = array([0, 0]) def __init__(self, gui=None, imageGrabber=None, config=None): ''' Constructor ''' super(Transformation, self).__init__(gui=gui, imageGrabber=imageGrabber, config=config) self.__calibrated = False self.__calibrating = False self.__basisMatrix = array([[1, 0], [0, 1]]) self.__offset = array([0, 0]) if self._gui != None: self.__initGui() if self._config != None: cfgFile = self._config.getConfigValue("CONFIGURATION", "cfgTransformation") if cfgFile != None and self.__loadConfigData(cfgFile): self._gui.status("Loaded transformtaion config.") mrLogger.logInfo("Loaded transformation config file " + str(cfgFile)) def __initGui(self): ''' Initiates gui ''' # initiate scene self.__gview = self._gui.getObj("imgTransformation") self.__scene = QGraphicsScene() self.__gview.setScene(self.__scene) self.__gviewTh = self._gui.getObj("imgTransformationThreshold") self.__sceneTh = QGraphicsScene() self.__gviewTh.setScene(self.__sceneTh) # create listeners self._gui.connect("cmdCalibrateTransformation", "clicked()", self.__calibrateTransformation) self._gui.connect("cmdSaveTransformation", "clicked()", self.saveSettings) self._gui.connect("cmdLoadTransformation", "clicked()", self.loadSetting) # start timer self.__sceneImgTimer = QTimer() self.__sceneImgTimer.timeout.connect(self._showImage) self.__sceneImgTimer.start(100) def saveSettings(self): ''' Save Settings ''' # stop video active = self._imageGrabber.isActive() self._imageGrabber.stopVideo() options = copy(self._gui.dialogOptionsDef) options['type'] = self._gui.dialogTypes['FileSave'] options['title'] = "Save configuration" options['filetypes'] = "Configuration (*cfg *mr)" src = str(self._gui.dialog(options)) if len(src) > 0: # check path if not src.endswith(".cfg"): src += ".cfg" # save data to file data = { 'basismatrix': self.__basisMatrix, 'offset': self.__offset, 'calibrated': self.__calibrated } dump(data, open(src, "wb")) self._gui.status("Configuration saved to: " + src) # restore video streaming mode if active: self._imageGrabber.startVideo() def loadSetting(self): ''' Load Settings ''' # stop video active = self._imageGrabber.isActive() self._imageGrabber.stopVideo() # get path options = copy(self._gui.dialogOptionsDef) options['filetypes'] = "config file (*cfg)" src = str(self._gui.dialog(options)) if self.__loadConfigData(src): self._gui.status("Tranformation config loaded.") # restore video streaming mode if active: self._imageGrabber.startVideo() def __loadConfigData(self, src): ''' Loads config data from file ''' if len(src) > 0 and isfile(src): # load file data = load(open(src, "rb")) if 'basismatrix' in data: self.__basisMatrix = data['basismatrix'] if 'offset' in data: self.__offset = data['offset'] if 'calibrated' in data: self.__calibrated = data['calibrated'] return True return False def isCalibrated(self): ''' @return: True if image is calibrated ''' return self.__calibrated def isCalibrating(self): ''' @return: True if calibration is in progress ''' return self.__calibrating def startCalibration(self): ''' Starts calibration of transformation ''' if not self.isCalibrating(): start_new_thread(self.__calibrateTransformation, ()) def __calibrateTransformation(self): ''' Calculates transformation values ''' if self._img == None: return self._gui.status("Calibrating transformation...") self.__calibrating = True img = self._img ''' Preprocessing image: ''' try: # get data th = self._gui.getObj("sliderThesholdCircles").value() cannyUp = self._gui.getObj("sliderCirclesCannyUp").value() thCircles = self._gui.getObj("sliderThesholdCircles2").value() minRadius = ( float(str(self._gui.getObj("txtCirclesRadiusMin").text())) / 100.0) * img.shape[0] maxRadius = ( float(str(self._gui.getObj("txtCirclesRadiusMax").text())) / 100.0) * img.shape[0] minDist = ( float(str(self._gui.getObj("txtCirclesDistanceMin").text())) / 100.0) * img.shape[0] blur = 5 # blur image for better result gimg = cvtColor(img, COLOR_RGB2GRAY) gimg = medianBlur(gimg, blur) # create binary image gimg = threshold(gimg, th, 255, THRESH_BINARY)[1] self.__imgSceneTh = gimg ''' Searching for circles by using Hough-Transformation: ''' circles = HoughCircles(gimg, CV_HOUGH_GRADIENT, 1, int(minDist), param1=cannyUp, param2=thCircles, minRadius=int(minRadius), maxRadius=int(maxRadius)) circles = around(circles).astype(int16) centers = circles[0][:, :3] ''' Identifying corners of playing field by evaluating centers of circles: Existence of 4 points are mandatory! ''' vlnr = argsort(centers[:, 0], ) pts_left = centers[vlnr[:2], :] pts_right = centers[vlnr[2:], :] # defining points for coordinate system # left: p00 = pts_left[argsort(pts_left[:, 1])[0], :] p01 = pts_left[argsort(pts_left[:, 1])[1], :] # right: p10 = pts_right[argsort(pts_right[:, 0])[0], :] p11 = pts_right[argsort(pts_right[:, 0])[1], :] # correcting axes with aritmethic mean. p00 and p11 are set # vertical: a_v1 = p01 - p00 a_v2 = p11 - p10 a_v = (a_v1 + a_v2) / 2 # horizontal: a_h1 = p10 - p00 a_h2 = p11 - p01 a_h = (a_h1 + a_h2) / 2 # correcting other corners p10c = p00 + a_h p01c = p11 - a_h # paint lines and circles circle(img, (p00[0], p00[1]), p00[2], (255, 0, 0), 2) circle(img, (p11[0], p11[1]), p11[2], (255, 0, 0), 2) circle(img, (p10[0], p10[1]), p10[2], (255, 0, 0), 2) circle(img, (p01[0], p01[1]), p01[2], (255, 0, 0), 2) line(img, (p00[0], p00[1]), (p01c[0], p01c[1]), (0, 255, 0), 2) line(img, (p00[0], p00[1]), (p10c[0], p10c[1]), (0, 255, 0), 2) line(img, (p10c[0], p10c[1]), (p11[0], p11[1]), (0, 255, 0), 2) line(img, (p01c[0], p01c[1]), (p11[0], p11[1]), (0, 255, 0), 2) self.__imgScene = img ''' Setting Offset and Basismatrix ''' self.__offset = array([p00[0], p00[1]]) self.__basisMatrix = array([[a_v[0], a_h[0]], [a_v[1], a_h[1]]]) except: self._gui.status("Error while calibrating transformation") self.__calibrating = False self._gui.status("Calibration finished.") pass def transformatePoint(self, point=array([0, 0])): ''' Transformates a point into local coordinates space @param point: Tuple (x,y) of points coordinates to transform @return: Tuple (x,y) of transformed coordinates ''' A = self.__basisMatrix O = self.__offset # Creating reference to origin of coordinates space b = point - O transformation = solve(A, b) return transformation def transformObjects(self, objs=[]): ''' Transforms a list of vision objects @param objs: List of vision objects @return: List of transformed vision objects ''' for obj in objs: center = self.transformatePoint(array(obj['center'])) center = (center[1], center[0]) obj['center'] = center def _showImage(self): ''' Shows image ''' if not self.isCalibrated() or self.isCalibrating(): self._updateScene(self.__gview, self.__scene, self.__imgScene, convert=False, keepRatio=True) self._updateScene(self.__gviewTh, self.__sceneTh, self.__imgSceneTh, convert=True, keepRatio=True)
def createTimer(self): timer = QTimer() timer.start() self.timers[timer.timerId()] = timer print >> sys.stderr, 'Created new timer with ID', timer.timerId() return timer
class MainWindow(QMainWindow): def __init__(self, labeltool, parent=None): QMainWindow.__init__(self, parent) self.idletimer = QTimer() self.loader = None self.labeltool = labeltool self.setupGui() self.loadApplicationSettings() self.onAnnotationsLoaded() # Slots def onPluginLoaded(self, action): self.ui.menuPlugins.addAction(action) def onStatusMessage(self, message=''): self.statusBar().showMessage(message, 5000) def onModelDirtyChanged(self, dirty): postfix = "[+]" if dirty else "" if self.labeltool.getCurrentFilename() is not None: self.setWindowTitle("%s - %s %s" % \ (APP_NAME, QFileInfo(self.labeltool.getCurrentFilename()).fileName(), postfix)) else: self.setWindowTitle("%s - Unnamed %s" % (APP_NAME, postfix)) def onMousePositionChanged(self, x, y): self.posinfo.setText("%d, %d" % (x, y)) def startBackgroundLoading(self): self.stopBackgroundLoading(forced=True) self.loader = BackgroundLoader(self.labeltool.model(), self.statusBar(), self.sb_progress) self.idletimer.timeout.connect(self.loader.load) self.loader.finished.connect(self.stopBackgroundLoading) self.statusBar().addWidget(self.sb_progress) self.sb_progress.show() self.idletimer.start() def stopBackgroundLoading(self, forced=False): if not forced: self.statusBar().showMessage("Background loading finished", 5000) self.idletimer.stop() if self.loader is not None: self.idletimer.timeout.disconnect(self.loader.load) self.statusBar().removeWidget(self.sb_progress) self.loader = None def onAnnotationsLoaded(self): self.labeltool.model().dirtyChanged.connect(self.onModelDirtyChanged) self.onModelDirtyChanged(self.labeltool.model().dirty()) self.treeview.setModel(self.labeltool.model()) self.scene.setModel(self.labeltool.model()) self.selectionmodel = QItemSelectionModel(self.labeltool.model()) self.treeview.setSelectionModel(self.selectionmodel) self.treeview.selectionModel().currentChanged.connect( self.labeltool.setCurrentImage) self.property_editor.onModelChanged(self.labeltool.model()) self.startBackgroundLoading() def onCurrentImageChanged(self): new_image = self.labeltool.currentImage() self.scene.setCurrentImage(new_image) self.onFitToWindowModeChanged() self.treeview.scrollTo(new_image.index()) img = self.labeltool.getImage(new_image) if img == None: self.controls.setFilename("") self.selectionmodel.setCurrentIndex( new_image.index(), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) return h = img.shape[0] w = img.shape[1] self.image_resolution.setText("%dx%d" % (w, h)) # TODO: This info should be obtained from AnnotationModel or LabelTool if isinstance(new_image, FrameModelItem): self.controls.setFrameNumAndTimestamp(new_image.framenum(), new_image.timestamp()) elif isinstance(new_image, ImageFileModelItem): self.controls.setFilename(os.path.basename(new_image['filename'])) self.selectionmodel.setCurrentIndex( new_image.index(), QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows) def onFitToWindowModeChanged(self): if self.options["Fit-to-window mode"].isChecked(): self.view.fitInView() def onScaleChanged(self, scale): self.zoominfo.setText("%.2f%%" % (100 * scale, )) def initShortcuts(self, HOTKEYS): self.shortcuts = [] for hotkey in HOTKEYS: assert len(hotkey) >= 2 key = hotkey[0] fun = hotkey[1] desc = "" if len(hotkey) > 2: desc = hotkey[2] if type(fun) == str: fun = import_callable(fun) hk = QAction(desc, self) hk.setShortcut(QKeySequence(key)) hk.setEnabled(True) if hasattr(fun, '__call__'): hk.triggered.connect(bind(fun, self.labeltool)) else: hk.triggered.connect( compose_noargs([bind(f, self.labeltool) for f in fun])) self.ui.menuShortcuts.addAction(hk) self.shortcuts.append(hk) def initOptions(self): self.options = {} for o in ["Fit-to-window mode"]: action = QAction(o, self) action.setCheckable(True) self.ui.menuOptions.addAction(action) self.options[o] = action ### ### GUI/Application setup ###___________________________________________________________________________________________ def setupGui(self): self.ui = uic.loadUi(os.path.join(GUIDIR, "labeltool.ui"), self) # get inserters and items from labels # FIXME for handling the new-style config correctly inserters = dict([ (label['attributes']['class'], label['inserter']) for label in config.LABELS if 'class' in label.get('attributes', {}) and 'inserter' in label ]) items = dict([ (label['attributes']['class'], label['item']) for label in config.LABELS if 'class' in label.get('attributes', {}) and 'item' in label ]) # Property Editor self.property_editor = PropertyEditor(config.LABELS) self.ui.dockProperties.setWidget(self.property_editor) # Scene self.scene = AnnotationScene(self.labeltool, items=items, inserters=inserters) self.property_editor.insertionModeStarted.connect( self.scene.onInsertionModeStarted) self.property_editor.insertionModeEnded.connect( self.scene.onInsertionModeEnded) # SceneView self.view = GraphicsView(self) self.view.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.view.setScene(self.scene) self.central_widget = QWidget() self.central_layout = QVBoxLayout() self.controls = ControlButtonWidget() self.controls.back_button.clicked.connect(self.labeltool.gotoPrevious) self.controls.forward_button.clicked.connect(self.labeltool.gotoNext) self.central_layout.addWidget(self.controls) self.central_layout.addWidget(self.view) self.central_widget.setLayout(self.central_layout) self.setCentralWidget(self.central_widget) self.initShortcuts(config.HOTKEYS) self.initOptions() self.treeview = AnnotationTreeView() self.treeview.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) self.ui.dockAnnotations.setWidget(self.treeview) self.scene.selectionChanged.connect(self.scene.onSelectionChanged) self.treeview.selectedItemsChanged.connect( self.scene.onSelectionChangedInTreeView) self.posinfo = QLabel("-1, -1") self.posinfo.setFrameStyle(QFrame.StyledPanel) self.statusBar().addPermanentWidget(self.posinfo) self.scene.mousePositionChanged.connect(self.onMousePositionChanged) self.image_resolution = QLabel("[no image]") self.image_resolution.setFrameStyle(QFrame.StyledPanel) self.statusBar().addPermanentWidget(self.image_resolution) self.zoominfo = QLabel() self.zoominfo.setFrameStyle(QFrame.StyledPanel) self.statusBar().addPermanentWidget(self.zoominfo) self.view.scaleChanged.connect(self.onScaleChanged) self.onScaleChanged(self.view.getScale()) self.sb_progress = QProgressBar() # View menu self.ui.menu_Views.addAction(self.ui.dockProperties.toggleViewAction()) self.ui.menu_Views.addAction( self.ui.dockAnnotations.toggleViewAction()) # Show the UI. It is important that this comes *after* the above # adding of custom widgets, especially the central widget. Otherwise the # dock widgets would be far to large. self.ui.show() ## connect action signals self.connectActions() def connectActions(self): ## File menu self.ui.actionNew.triggered.connect(self.fileNew) self.ui.actionOpen.triggered.connect(self.fileOpen) self.ui.actionSave.triggered.connect(self.fileSave) self.ui.actionSave_As.triggered.connect(self.fileSaveAs) self.ui.actionExit.triggered.connect(self.close) ## View menu self.ui.actionLocked.toggled.connect(self.onViewsLockedChanged) ## Help menu self.ui.action_About.triggered.connect(self.about) ## Navigation self.ui.action_Add_Image.triggered.connect(self.addMediaFile) self.ui.actionNext.triggered.connect(self.labeltool.gotoNext) self.ui.actionPrevious.triggered.connect(self.labeltool.gotoPrevious) self.ui.actionZoom_In.triggered.connect( functools.partial(self.view.setScaleRelative, 1.2)) self.ui.actionZoom_Out.triggered.connect( functools.partial(self.view.setScaleRelative, 1 / 1.2)) ## Connections to LabelTool self.labeltool.pluginLoaded.connect(self.onPluginLoaded) self.labeltool.statusMessage.connect(self.onStatusMessage) self.labeltool.annotationsLoaded.connect(self.onAnnotationsLoaded) self.labeltool.currentImageChanged.connect(self.onCurrentImageChanged) ## options menu self.options["Fit-to-window mode"].changed.connect( self.onFitToWindowModeChanged) def loadApplicationSettings(self): settings = QSettings() size = settings.value("MainWindow/Size", QSize(800, 600)) pos = settings.value("MainWindow/Position", QPoint(10, 10)) state = settings.value("MainWindow/State") locked = settings.value("MainWindow/ViewsLocked", False) if isinstance(size, QVariant): size = size.toSize() if isinstance(pos, QVariant): pos = pos.toPoint() if isinstance(state, QVariant): state = state.toByteArray() if isinstance(locked, QVariant): locked = locked.toBool() self.resize(size) self.move(pos) self.restoreState(state) self.ui.actionLocked.setChecked(bool(locked)) def saveApplicationSettings(self): settings = QSettings() settings.setValue("MainWindow/Size", self.size()) settings.setValue("MainWindow/Position", self.pos()) settings.setValue("MainWindow/State", self.saveState()) settings.setValue("MainWindow/ViewsLocked", self.ui.actionLocked.isChecked()) if self.labeltool.getCurrentFilename() is not None: filename = self.labeltool.getCurrentFilename() else: filename = None settings.setValue("LastFile", filename) def okToContinue(self): if self.labeltool.model().dirty(): reply = QMessageBox.question( self, "%s - Unsaved Changes" % (APP_NAME), "Save unsaved changes?", QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if reply == QMessageBox.Cancel: return False elif reply == QMessageBox.Yes: return self.fileSave() return True def fileNew(self): if self.okToContinue(): self.labeltool.clearAnnotations() def fileOpen(self): if not self.okToContinue(): return path = '.' filename = self.labeltool.getCurrentFilename() if (filename is not None) and (len(filename) > 0): path = QFileInfo(filename).path() format_str = ' '.join(self.labeltool.getAnnotationFilePatterns()) fname = QFileDialog.getOpenFileName( self, "%s - Load Annotations" % APP_NAME, path, "%s annotation files (%s)" % (APP_NAME, format_str)) if len(str(fname)) > 0: self.labeltool.loadAnnotations(fname) def fileSave(self): filename = self.labeltool.getCurrentFilename() if filename is None: return self.fileSaveAs() return self.labeltool.saveAnnotations(filename) def fileSaveAs(self): fname = '.' # self.annotations.filename() or '.' format_str = ' '.join(self.labeltool.getAnnotationFilePatterns()) fname = QFileDialog.getSaveFileName( self, "%s - Save Annotations" % APP_NAME, fname, "%s annotation files (%s)" % (APP_NAME, format_str)) if len(str(fname)) > 0: return self.labeltool.saveAnnotations(str(fname)) return False def addMediaFile(self): path = '.' filename = self.labeltool.getCurrentFilename() if (filename is not None) and (len(filename) > 0): path = QFileInfo(filename).path() image_types = [ '*.jpg', '*.bmp', '*.png', '*.pgm', '*.ppm', '*.ppm', '*.tif', '*.gif' ] video_types = ['*.mp4', '*.mpg', '*.mpeg', '*.avi', '*.mov', '*.vob'] format_str = ' '.join(image_types + video_types) fnames = QFileDialog.getOpenFileNames( self, "%s - Add Media File" % APP_NAME, path, "Media files (%s)" % (format_str, )) item = None for fname in fnames: if len(str(fname)) == 0: continue fname = str(fname) if os.path.isabs(fname): fname = os.path.relpath(fname, str(path)) for pattern in image_types: if fnmatch.fnmatch(fname, pattern): item = self.labeltool.addImageFile(fname) if item is None: return self.labeltool.addVideoFile(fname) return item def onViewsLockedChanged(self, checked): features = QDockWidget.AllDockWidgetFeatures if checked: features = QDockWidget.NoDockWidgetFeatures self.ui.dockProperties.setFeatures(features) self.ui.dockAnnotations.setFeatures(features) ### ### global event handling ###______________________________________________________________________________ def closeEvent(self, event): if self.okToContinue(): self.saveApplicationSettings() else: event.ignore() def about(self): QMessageBox.about( self, "About %s" % APP_NAME, """<b>%s</b> version %s <p>This labeling application for computer vision research was developed at the CVHCI research group at KIT. <p>For more details, visit our homepage: <a href="%s">%s</a>""" % (APP_NAME, __version__, ORGANIZATION_DOMAIN, ORGANIZATION_DOMAIN))
class MainWindow(QMainWindow, Ui_MainWindow): qtcb_enumerate = pyqtSignal(str, str, 'char', type((0, )), type((0, )), int, int) qtcb_connected = pyqtSignal(int) qtcb_disconnected = pyqtSignal(int) def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setupUi(self) signal.signal(signal.SIGINT, self.exit_brickv) signal.signal(signal.SIGTERM, self.exit_brickv) self.async_thread = async_start_thread(self) self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION) self.tree_view_model_labels = ['Name', 'UID', 'Position', 'FW Version'] self.tree_view_model = QStandardItemModel(self) self.tree_view.setModel(self.tree_view_model) self.tree_view.doubleClicked.connect(self.item_double_clicked) self.set_tree_view_defaults() # Remove dummy tab self.tab_widget.removeTab(1) self.name = '<unknown>' self.uid = '<unknown>' self.version = (0, 0, 0) self.disconnect_times = [] self.qtcb_enumerate.connect(self.cb_enumerate) self.qtcb_connected.connect(self.cb_connected) self.qtcb_disconnected.connect(self.cb_disconnected) self.ipcon = IPConnection() self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, self.qtcb_enumerate.emit) self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, self.qtcb_connected.emit) self.ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED, self.qtcb_disconnected.emit) self.current_device_info = None self.flashing_window = None self.advanced_window = None self.data_logger_window = None self.delayed_refresh_updates_timer = QTimer() self.delayed_refresh_updates_timer.timeout.connect( self.delayed_refresh_updates) self.delayed_refresh_updates_timer.setInterval(500) self.reset_view() self.button_advanced.setDisabled(True) self.tab_widget.currentChanged.connect(self.tab_changed) self.tab_widget.setMovable(True) self.tab_widget.tabBar().installEventFilter(self) self.button_connect.clicked.connect(self.connect_clicked) self.button_flashing.clicked.connect(self.flashing_clicked) self.button_advanced.clicked.connect(self.advanced_clicked) self.button_data_logger.clicked.connect(self.data_logger_clicked) self.plugin_manager = PluginManager() # host info self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT) self.host_index_changing = True for host_info in self.host_infos: self.combo_host.addItem(host_info.host) self.last_host = None self.combo_host.currentIndexChanged.connect(self.host_index_changed) self.spinbox_port.setValue(self.host_infos[0].port) self.spinbox_port.valueChanged.connect(self.port_changed) self.checkbox_authentication.stateChanged.connect( self.authentication_state_changed) self.label_secret.hide() self.edit_secret.hide() self.edit_secret.setEchoMode(QLineEdit.Password) self.edit_secret.textEdited.connect(self.secret_changed) self.checkbox_secret_show.hide() self.checkbox_secret_show.stateChanged.connect( self.secret_show_state_changed) self.checkbox_remember_secret.hide() self.checkbox_remember_secret.stateChanged.connect( self.remember_secret_state_changed) self.checkbox_authentication.setChecked( self.host_infos[0].use_authentication) self.edit_secret.setText(self.host_infos[0].secret) self.checkbox_remember_secret.setChecked( self.host_infos[0].remember_secret) self.host_index_changing = False # auto-reconnect self.label_auto_reconnects.hide() self.auto_reconnects = 0 # RED Session losts self.label_red_session_losts.hide() self.red_session_losts = 0 # override QMainWindow.closeEvent def closeEvent(self, event): if not self.exit_logger(): event.ignore() return self.exit_brickv() def exit_brickv(self, signl=None, frme=None): if self.current_device_info is not None: self.current_device_info.plugin.stop_plugin() self.current_device_info.plugin.destroy_plugin() self.update_current_host_info() config.set_host_infos(self.host_infos) self.do_disconnect() if signl != None and frme != None: print("Received SIGINT or SIGTERM, shutting down.") sys.exit() def exit_logger(self): exitBrickv = True if (self.data_logger_window is not None) and ( self.data_logger_window.data_logger_thread is not None) and ( not self.data_logger_window.data_logger_thread.stopped): quit_msg = "The Data Logger is running. Are you sure you want to exit the program?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: self.data_logger_window.data_logger_thread.stop() else: exitBrickv = False return exitBrickv def host_index_changed(self, i): if i < 0: return self.host_index_changing = True self.spinbox_port.setValue(self.host_infos[i].port) self.checkbox_authentication.setChecked( self.host_infos[i].use_authentication) self.edit_secret.setText(self.host_infos[i].secret) self.checkbox_remember_secret.setChecked( self.host_infos[i].remember_secret) self.host_index_changing = False def port_changed(self, value): self.update_current_host_info() def authentication_state_changed(self, state): visible = state == Qt.Checked self.label_secret.setVisible(visible) self.edit_secret.setVisible(visible) self.checkbox_secret_show.setVisible(visible) self.checkbox_remember_secret.setVisible(visible) self.update_current_host_info() def secret_changed(self): self.update_current_host_info() def secret_show_state_changed(self, state): if state == Qt.Checked: self.edit_secret.setEchoMode(QLineEdit.Normal) else: self.edit_secret.setEchoMode(QLineEdit.Password) self.update_current_host_info() def remember_secret_state_changed(self, state): self.update_current_host_info() def tab_changed(self, i): if not hasattr(self.tab_widget.widget(i), '_info'): new_current_device_info = None else: new_current_device_info = self.tab_widget.widget(i)._info new_current_device_info.plugin.start_plugin() # stop the now deselected plugin, if there is one that's running if self.current_device_info is not None: self.current_device_info.plugin.stop_plugin() self.current_device_info = new_current_device_info def update_current_host_info(self): if self.host_index_changing: return i = self.combo_host.currentIndex() if i < 0: return #self.host_infos[i].host = self.combo_host.currentText() self.host_infos[i].port = self.spinbox_port.value() self.host_infos[ i].use_authentication = self.checkbox_authentication.isChecked() self.host_infos[i].secret = self.edit_secret.text() self.host_infos[ i].remember_secret = self.checkbox_remember_secret.isChecked() def remove_all_device_infos(self): for device_info in infos.get_device_infos(): self.remove_device_info(device_info.uid) def remove_device_info(self, uid): tab_id = self.tab_for_uid(uid) device_info = infos.get_info(uid) device_info.plugin.stop_plugin() device_info.plugin.destroy_plugin() if tab_id >= 0: self.tab_widget.removeTab(tab_id) # ensure that the widget gets correctly destroyed. otherwise QWidgets # tend to leak as Python is not able to collect their PyQt object tab_window = device_info.tab_window device_info.tab_window = None # If we reboot the RED Brick, the tab_window sometimes is # already None here if tab_window != None: tab_window.hide() tab_window.setParent(None) plugin = device_info.plugin device_info.plugin = None if plugin != None: plugin.hide() plugin.setParent(None) infos.remove_info(uid) def reset_view(self): self.tab_widget.setCurrentIndex(0) self.remove_all_device_infos() self.update_tree_view() def do_disconnect(self): self.auto_reconnects = 0 self.label_auto_reconnects.hide() self.red_session_losts = 0 self.label_red_session_losts.hide() self.reset_view() async_next_session() # force garbage collection, to ensure that all plugin related objects # got destroyed before disconnect is called. this is especially # important for the RED Brick plugin because its relies on releasing # the the RED Brick API objects in the __del__ method as a last resort # to avoid leaking object references. but this only works if garbage # collection is done before disconnect is called gc.collect() try: self.ipcon.disconnect() except: pass def do_authenticate(self, is_auto_reconnect): if not self.checkbox_authentication.isChecked(): return True try: secret = self.edit_secret.text().encode('ascii') except: self.do_disconnect() QMessageBox.critical( self, 'Connection', 'Authentication secret cannot contain non-ASCII characters.', QMessageBox.Ok) return False self.ipcon.set_auto_reconnect( False) # don't auto-reconnect on authentication error try: self.ipcon.authenticate(secret) except: self.do_disconnect() if is_auto_reconnect: extra = ' after auto-reconnect' else: extra = '' QMessageBox.critical( self, 'Connection', 'Could not authenticate' + extra + '. Check secret and ensure ' + 'authentication for Brick Daemon is enabled.', QMessageBox.Ok) return False self.ipcon.set_auto_reconnect(True) return True def flashing_clicked(self): if self.flashing_window is None: self.flashing_window = FlashingWindow(self) self.flashing_window.show() self.flashing_window.refresh_updates_clicked() def advanced_clicked(self): if self.advanced_window is None: self.advanced_window = AdvancedWindow(self) self.advanced_window.show() def data_logger_clicked(self): if self.data_logger_window is None: self.data_logger_window = DataLoggerWindow(self) self.data_logger_window.show() def connect_clicked(self): if self.ipcon.get_connection_state( ) == IPConnection.CONNECTION_STATE_DISCONNECTED: try: self.last_host = self.combo_host.currentText() self.button_connect.setDisabled(True) self.button_connect.setText("Connecting ...") self.button_connect.repaint() QApplication.processEvents() self.ipcon.connect(self.last_host, self.spinbox_port.value()) except: self.button_connect.setDisabled(False) self.button_connect.setText("Connect") QMessageBox.critical( self, 'Connection', 'Could not connect. Please check host, check ' + 'port and ensure that Brick Daemon is running.') else: self.do_disconnect() def item_double_clicked(self, index): position_index = index.sibling(index.row(), 2) if position_index.isValid() and position_index.data().startswith( 'Ext'): index = index.parent() uid_index = index.sibling(index.row(), 1) if uid_index.isValid(): self.show_plugin(uid_index.data()) def create_tab_window(self, device_info): tab_window = TabWindow(self.tab_widget, device_info.name, self.untab) tab_window._info = device_info tab_window.set_callback_on_tab(lambda index: self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_PENDING and \ self.tab_widget.setTabEnabled(index, False)) layout = QVBoxLayout(tab_window) info_bar = QHBoxLayout() # uid info_bar.addWidget(QLabel('UID:')) label = QLabel('{0}'.format(device_info.uid)) label.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextSelectableByKeyboard) info_bar.addWidget(label) info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding)) # connected uid if device_info.connected_uid != '0': info_bar.addWidget(QLabel('Connected to:')) button = QToolButton() button.setText(device_info.connected_uid) button.clicked.connect( lambda: self.show_plugin(device_info.connected_uid)) info_bar.addWidget(button) info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding)) # position info_bar.addWidget(QLabel('Position:')) info_bar.addWidget(QLabel('{0}'.format(device_info.position.upper()))) info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding)) # firmware version label_version_name = QLabel('Version:') label_version = QLabel('...') if not device_info.plugin.has_custom_version(label_version_name, label_version): label_version_name.setText('FW Version:') label_version.setText( infos.get_version_string(device_info.plugin.firmware_version)) info_bar.addWidget(label_version_name) info_bar.addWidget(label_version) info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding)) # timeouts info_bar.addWidget(QLabel('Timeouts:')) label_timeouts = QLabel('0') info_bar.addWidget(label_timeouts) layout.addLayout(info_bar) # actions actions = device_info.plugin.get_actions() if actions != None: if type(actions) == QAction: button = QPushButton(actions.text()) button.clicked.connect(actions.trigger) else: button = QToolButton() button.setText(actions[0]) button.setPopupMode(QToolButton.InstantPopup) button.setToolButtonStyle(Qt.ToolButtonTextOnly) button.setArrowType(Qt.DownArrow) button.setAutoRaise(True) menu = QMenu(actions[0]) button.setMenu(menu) for action in actions[1]: menu.addAction(action) info_bar.addSpacerItem(QSpacerItem(40, 20, QSizePolicy.Expanding)) info_bar.addWidget(button) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) device_info.plugin.label_timeouts = label_timeouts device_info.plugin.layout().setContentsMargins(0, 0, 0, 0) layout.addWidget(line) layout.addWidget(device_info.plugin) return tab_window def tab_move(self, event): # visualize rearranging of tabs (if allowed by tab_widget) if self.tab_widget.isMovable(): if event.type( ) == QEvent.MouseButtonPress and event.button() & Qt.LeftButton: QApplication.setOverrideCursor(QCursor(Qt.SizeHorCursor)) elif event.type( ) == QEvent.MouseButtonRelease and event.button() & Qt.LeftButton: QApplication.restoreOverrideCursor() return False def untab(self, tab_index): tab = self.tab_widget.widget(tab_index) tab.untab() tab._info.plugin.start_plugin() self.tab_widget.setCurrentIndex(0) def eventFilter(self, source, event): if source is self.tab_widget.tabBar(): return self.tab_move(event) return False def tab_for_uid(self, uid): for i in range(1, self.tab_widget.count()): try: if self.tab_widget.widget(i)._info.uid == uid: return i except: pass return -1 def show_plugin(self, uid): i = self.tab_for_uid(uid) tab_window = infos.get_info(uid).tab_window if i > 0 and self.tab_widget.isTabEnabled(i): self.tab_widget.setCurrentIndex(i) QApplication.setActiveWindow(tab_window) tab_window.show() tab_window.activateWindow() tab_window.raise_() def cb_enumerate(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type): if self.ipcon.get_connection_state( ) != IPConnection.CONNECTION_STATE_CONNECTED: # ignore enumerate callbacks that arrived after the connection got closed return if enumeration_type in [ IPConnection.ENUMERATION_TYPE_AVAILABLE, IPConnection.ENUMERATION_TYPE_CONNECTED ]: device_info = infos.get_info(uid) something_changed_ref = [False] if device_info == None: if device_identifier == BrickMaster.DEVICE_IDENTIFIER: device_info = infos.BrickMasterInfo() elif device_identifier == BrickRED.DEVICE_IDENTIFIER: device_info = infos.BrickREDInfo() elif position in ('a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'): position = position.lower() device_info = infos.BrickletInfo() else: device_info = infos.BrickInfo() something_changed_ref[0] = True def set_device_info_value(name, value): if getattr(device_info, name) != value: setattr(device_info, name, value) something_changed_ref[0] = True set_device_info_value('uid', uid) set_device_info_value('connected_uid', connected_uid) set_device_info_value('position', position) set_device_info_value('hardware_version', hardware_version) set_device_info_value('firmware_version_installed', firmware_version) set_device_info_value('device_identifier', device_identifier) set_device_info_value('protocol_version', 2) set_device_info_value('enumeration_type', enumeration_type) if device_info.type == 'bricklet': for brick_info in infos.get_brick_infos(): if brick_info.uid == device_info.connected_uid: if brick_info.bricklets[position] != device_info: brick_info.bricklets[position] = device_info something_changed_ref[0] = True elif device_info.type == 'brick': for bricklet_info in infos.get_bricklet_infos(): if bricklet_info.connected_uid == device_info.uid: if device_info.bricklets[ bricklet_info.position] != bricklet_info: device_info.bricklets[ bricklet_info.position] = bricklet_info something_changed_ref[0] = True if device_info.plugin == None: self.plugin_manager.create_plugin_instance( device_identifier, self.ipcon, device_info) device_info.tab_window = self.create_tab_window(device_info) device_info.tab_window.setWindowFlags(Qt.Widget) device_info.tab_window.tab() infos.add_info(device_info) something_changed_ref[0] = True if something_changed_ref[0]: self.update_tree_view() elif enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED: for device_info in infos.get_device_infos(): if device_info.uid == uid: self.tab_widget.setCurrentIndex(0) self.remove_device_info(device_info.uid) if device_info.type == 'brick': for port in device_info.bricklets: if device_info.bricklets[ port] and device_info.bricklets[ port].uid == uid: device_info.bricklets[port] = None self.update_tree_view() def hack_to_remove_red_brick_tab(self, red_brick_uid): for device_info in infos.get_device_infos(): if device_info.uid == red_brick_uid: self.tab_widget.setCurrentIndex(0) self.remove_device_info(device_info.uid) self.red_session_losts += 1 self.label_red_session_losts.setText( 'RED Brick Session Loss Count: {0}'.format( self.red_session_losts)) self.label_red_session_losts.show() break self.update_tree_view() def cb_connected(self, connect_reason): self.disconnect_times = [] self.update_ui_state() if connect_reason == IPConnection.CONNECT_REASON_REQUEST: self.auto_reconnects = 0 self.label_auto_reconnects.hide() self.red_session_losts = 0 self.label_red_session_losts.hide() self.ipcon.set_auto_reconnect(True) index = self.combo_host.findText(self.last_host) if index >= 0: self.combo_host.removeItem(index) host_info = self.host_infos[index] del self.host_infos[index] self.host_infos.insert(0, host_info) else: index = self.combo_host.currentIndex() host_info = self.host_infos[index].duplicate() host_info.host = self.last_host self.host_infos.insert(0, host_info) self.combo_host.insertItem(-1, self.last_host) self.combo_host.setCurrentIndex(0) while self.combo_host.count() > config.HOST_INFO_COUNT: self.combo_host.removeItem(self.combo_host.count() - 1) if not self.do_authenticate(False): return try: self.ipcon.enumerate() except: self.update_ui_state() elif connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT: self.auto_reconnects += 1 self.label_auto_reconnects.setText( 'Auto-Reconnect Count: {0}'.format(self.auto_reconnects)) self.label_auto_reconnects.show() if not self.do_authenticate(True): return try: self.ipcon.enumerate() except: self.update_ui_state() else: try: self.ipcon.enumerate() except: self.update_ui_state() def cb_disconnected(self, disconnect_reason): if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST: self.auto_reconnects = 0 self.label_auto_reconnects.hide() self.red_session_losts = 0 self.label_red_session_losts.hide() if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST or not self.ipcon.get_auto_reconnect( ): self.update_ui_state() elif len(self.disconnect_times ) >= 3 and self.disconnect_times[-3] < time.time() + 1: self.disconnect_times = [] self.ipcon.set_auto_reconnect(False) self.update_ui_state() self.reset_view() QMessageBox.critical( self, 'Connection', 'Stopped automatic reconnecting due to multiple connection errors in a row.' ) else: self.disconnect_times.append(time.time()) self.update_ui_state(IPConnection.CONNECTION_STATE_PENDING) def set_tree_view_defaults(self): self.tree_view_model.setHorizontalHeaderLabels( self.tree_view_model_labels) self.tree_view.expandAll() self.tree_view.setColumnWidth(0, 250) self.tree_view.setColumnWidth(1, 85) self.tree_view.setColumnWidth(2, 85) self.tree_view.setColumnWidth(3, 90) self.tree_view.setExpandsOnDoubleClick(False) self.tree_view.setSortingEnabled(True) self.tree_view.header().setSortIndicator(2, Qt.AscendingOrder) def update_ui_state(self, connection_state=None): # FIXME: need to call processEvents() otherwise get_connection_state() # might return the wrong value QApplication.processEvents() if connection_state is None: connection_state = self.ipcon.get_connection_state() self.button_connect.setDisabled(False) self.button_flashing.setDisabled(False) if connection_state == IPConnection.CONNECTION_STATE_DISCONNECTED: self.button_connect.setText('Connect') self.combo_host.setDisabled(False) self.spinbox_port.setDisabled(False) self.checkbox_authentication.setDisabled(False) self.edit_secret.setDisabled(False) self.button_advanced.setDisabled(True) elif connection_state == IPConnection.CONNECTION_STATE_CONNECTED: self.button_connect.setText("Disconnect") self.combo_host.setDisabled(True) self.spinbox_port.setDisabled(True) self.checkbox_authentication.setDisabled(True) self.edit_secret.setDisabled(True) self.update_advanced_window() # restart all pause plugins for info in infos.get_device_infos(): info.plugin.resume_plugin() elif connection_state == IPConnection.CONNECTION_STATE_PENDING: self.button_connect.setText('Abort Pending Automatic Reconnect') self.combo_host.setDisabled(True) self.spinbox_port.setDisabled(True) self.checkbox_authentication.setDisabled(True) self.edit_secret.setDisabled(True) self.button_advanced.setDisabled(True) self.button_flashing.setDisabled(True) # pause all running plugins for info in infos.get_device_infos(): info.plugin.pause_plugin() enable = connection_state == IPConnection.CONNECTION_STATE_CONNECTED for i in range(1, self.tab_widget.count()): self.tab_widget.setTabEnabled(i, enable) for device_info in infos.get_device_infos(): device_info.tab_window.setEnabled(enable) QApplication.processEvents() def update_tree_view(self): sis = self.tree_view.header().sortIndicatorSection() sio = self.tree_view.header().sortIndicatorOrder() self.tree_view_model.clear() for info in infos.get_brick_infos(): parent = [ QStandardItem(info.name), QStandardItem(info.uid), QStandardItem(info.position.upper()), QStandardItem('.'.join( map(str, info.firmware_version_installed))) ] for item in parent: item.setFlags(item.flags() & ~Qt.ItemIsEditable) self.tree_view_model.appendRow(parent) for port in sorted(info.bricklets): if info.bricklets[port] and info.bricklets[ port].protocol_version == 2: child = [ QStandardItem(info.bricklets[port].name), QStandardItem(info.bricklets[port].uid), QStandardItem(info.bricklets[port].position.upper()), QStandardItem('.'.join( map( str, info.bricklets[port]. firmware_version_installed))) ] for item in child: item.setFlags(item.flags() & ~Qt.ItemIsEditable) parent[0].appendRow(child) if info.can_have_extension: extensions = [] if info.extensions['ext0'] != None: extensions.append((info.extensions['ext0'], 'Ext0')) if info.extensions['ext1'] != None: extensions.append((info.extensions['ext1'], 'Ext1')) for extension in extensions: child = [ QStandardItem(extension[0].name), QStandardItem(''), QStandardItem(extension[1]), QStandardItem('') ] for item in child: item.setFlags(item.flags() & ~Qt.ItemIsEditable) parent[0].appendRow(child) self.set_tree_view_defaults() self.tree_view.header().setSortIndicator(sis, sio) self.update_advanced_window() self.delayed_refresh_updates_timer.start() def update_advanced_window(self): self.button_advanced.setEnabled(len(infos.get_brick_infos()) > 0) def delayed_refresh_updates(self): self.delayed_refresh_updates_timer.stop() if self.flashing_window is not None and self.flashing_window.isVisible( ): self.flashing_window.refresh_updates_clicked()
class Barometer(PluginBase): def __init__(self, *args): PluginBase.__init__(self, BrickletBarometer, *args) self.barometer = self.device has_calibrate = self.firmware_version == (1, 0, 0) has_averaging = self.firmware_version >= (2, 0, 1) self.moving_average_pressure = 25 self.average_pressure = 10 self.average_temperature = 10 self.cbe_air_pressure = CallbackEmulator( self.barometer.get_air_pressure, self.cb_air_pressure, self.increase_error_count) self.cbe_altitude = CallbackEmulator(self.barometer.get_altitude, self.cb_altitude, self.increase_error_count) self.air_pressure_label = AirPressureLabel() self.altitude_label = AltitudeLabel() self.chip_temperature_label = ChipTemperatureLabel() if has_calibrate: self.chip_temperature_label.setAlignment(Qt.AlignCenter) self.current_air_pressure = None self.current_altitude = None plot_list = [['', Qt.red, self.get_current_air_pressure]] self.air_pressure_plot_widget = PlotWidget('Air Pressure [mbar]', plot_list) plot_list = [['', Qt.darkGreen, self.get_current_altitude]] self.altitude_plot_widget = PlotWidget('Altitude [m]', plot_list) if has_calibrate: self.calibrate_button = QPushButton('Calibrate Altitude') self.calibrate_button.clicked.connect(self.calibrate_clicked) else: self.get_reference_button = QPushButton('Get') self.get_reference_button.clicked.connect( self.get_reference_clicked) self.set_reference_button = QPushButton('Set') self.set_reference_button.clicked.connect( self.set_reference_clicked) self.reference_label = QLabel('Reference Air Pressure [mbar]:') self.reference_edit = QLineEdit() self.get_reference_clicked() if has_averaging: self.avg_pressure_box = QSpinBox() self.avg_pressure_box.setMinimum(0) self.avg_pressure_box.setMaximum(10) self.avg_pressure_box.setSingleStep(1) self.avg_pressure_box.setValue(10) self.avg_temperature_box = QSpinBox() self.avg_temperature_box.setMinimum(0) self.avg_temperature_box.setMaximum(255) self.avg_temperature_box.setSingleStep(1) self.avg_temperature_box.setValue(10) self.avg_moving_pressure_box = QSpinBox() self.avg_moving_pressure_box.setMinimum(0) self.avg_moving_pressure_box.setMaximum(25) self.avg_moving_pressure_box.setSingleStep(1) self.avg_moving_pressure_box.setValue(25) self.avg_pressure_box.editingFinished.connect( self.avg_pressure_box_finished) self.avg_temperature_box.editingFinished.connect( self.avg_temperature_box_finished) self.avg_moving_pressure_box.editingFinished.connect( self.avg_moving_pressure_box_finished) layout_h1 = QHBoxLayout() layout_h1.addStretch() layout_h1.addWidget(self.air_pressure_label) layout_h1.addStretch() layout_v1 = QVBoxLayout() layout_v1.addLayout(layout_h1) layout_v1.addWidget(self.air_pressure_plot_widget) layout_h2 = QHBoxLayout() layout_h2.addStretch() layout_h2.addWidget(self.altitude_label) layout_h2.addStretch() layout_v2 = QVBoxLayout() layout_v2.addLayout(layout_h2) layout_v2.addWidget(self.altitude_plot_widget) if has_calibrate: layout_h3 = QHBoxLayout() layout_h3.addWidget(self.chip_temperature_label) layout_h3.addWidget(self.calibrate_button) else: layout_h3 = QHBoxLayout() layout_h3.addWidget(self.reference_label) layout_h3.addWidget(self.reference_edit) layout_h3.addWidget(self.get_reference_button) layout_h3.addWidget(self.set_reference_button) layout_v3 = QVBoxLayout() layout_v3.addWidget(self.chip_temperature_label) layout_v3.addLayout(layout_h3) if has_averaging: line1 = QFrame() line1.setFrameShape(QFrame.VLine) line1.setFrameShadow(QFrame.Sunken) line2 = QFrame() line2.setFrameShape(QFrame.VLine) line2.setFrameShadow(QFrame.Sunken) layout_h4 = QHBoxLayout() layout_h4.addWidget(QLabel('Air Pressure Moving Average Length:')) layout_h4.addWidget(self.avg_moving_pressure_box) layout_h4.addWidget(line1) layout_h4.addWidget(QLabel('Air Pressure Average Length:')) layout_h4.addWidget(self.avg_pressure_box) layout_h4.addWidget(line2) layout_h4.addWidget(QLabel('Temperate Average Length:')) layout_h4.addWidget(self.avg_temperature_box) layout_h1 = QHBoxLayout() layout_h1.addLayout(layout_v1) layout_h1.addLayout(layout_v2) layout = QVBoxLayout(self) layout.addLayout(layout_h1) if has_calibrate: layout.addLayout(layout_h3) else: layout.addLayout(layout_v3) if has_averaging: lineh = QFrame() lineh.setFrameShape(QFrame.HLine) lineh.setFrameShadow(QFrame.Sunken) layout.addWidget(lineh) layout.addLayout(layout_h4) self.chip_temp_timer = QTimer() self.chip_temp_timer.timeout.connect(self.update_chip_temp) self.chip_temp_timer.setInterval(100) def start(self): async_call(self.barometer.get_air_pressure, None, self.cb_air_pressure, self.increase_error_count) async_call(self.barometer.get_altitude, None, self.cb_altitude, self.increase_error_count) self.cbe_air_pressure.set_period(100) self.cbe_altitude.set_period(100) async_call(self.barometer.get_averaging, None, self.cb_averaging, self.increase_error_count) self.air_pressure_plot_widget.stop = False self.altitude_plot_widget.stop = False self.update_chip_temp() self.chip_temp_timer.start() def stop(self): self.cbe_air_pressure.set_period(0) self.cbe_altitude.set_period(0) self.air_pressure_plot_widget.stop = True self.altitude_plot_widget.stop = True self.chip_temp_timer.stop() def destroy(self): pass def get_url_part(self): return 'barometer' @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletBarometer.DEVICE_IDENTIFIER def cb_averaging(self, avg): moving_average_pressure, average_pressure, average_temperature = avg self.moving_average_pressure = moving_average_pressure self.average_pressure = average_pressure self.average_temperature = average_temperature self.avg_moving_pressure_box.setValue(moving_average_pressure) self.avg_pressure_box.setValue(average_pressure) self.avg_temperature_box.setValue(average_temperature) def avg_pressure_box_finished(self): self.average_pressure = self.avg_pressure_box.value() self.save_new_averaging() def avg_temperature_box_finished(self): self.average_temperature = self.avg_temperature_box.value() self.save_new_averaging() def avg_moving_pressure_box_finished(self): self.moving_average_pressure = self.avg_moving_pressure_box.value() self.save_new_averaging() def save_new_averaging(self): self.barometer.set_averaging(self.moving_average_pressure, self.average_pressure, self.average_temperature) def calibrate_clicked(self): try: # Call set_reference_air_pressure that has the same function ID as # calibrate_altitude the extra parameter will just be ignored self.barometer.set_reference_air_pressure(0) except ip_connection.Error: pass def get_reference_clicked_async(self, reference): r = str(reference / 1000.0) self.reference_edit.setText(r) def get_reference_clicked(self): async_call(self.barometer.get_reference_air_pressure, None, self.get_reference_clicked_async, self.increase_error_count) def set_reference_clicked(self): try: r = round(float(self.reference_edit.text()) * 1000) except: self.reference_edit.setText('Invalid input') return try: self.barometer.set_reference_air_pressure(r) except ip_connection.Error: self.reference_edit.setText( 'Error while setting reference air pressure') return def get_current_air_pressure(self): return self.current_air_pressure def get_current_altitude(self): return self.current_altitude def update_chip_temp_async(self, temp): t = temp / 100.0 self.chip_temperature_label.setText('%.2f' % t) def update_chip_temp(self): async_call(self.barometer.get_chip_temperature, None, self.update_chip_temp_async, self.increase_error_count) def cb_air_pressure(self, air_pressure): self.current_air_pressure = air_pressure / 1000.0 self.air_pressure_label.setText('%.3f' % self.current_air_pressure) def cb_altitude(self, altitude): self.current_altitude = altitude / 100.0 self.altitude_label.setText('%.2f' % self.current_altitude, '%.2f' % (self.current_altitude / 0.3048))
class LI3DSPlugin_Arduino(ILI3DSPlugin_Tabs): # Qt Signals signal_arduino_state_start_on = pyqtSignal() signal_arduino_state_start_off = pyqtSignal() def __init__(self, *args, **kwargs): """ :param args: :param kwargs: """ super(LI3DSPlugin_Arduino, self).__init__(*args, **kwargs) # tab: Arduino self.states.set_state('arduino', 'flash') self.states.set_state('arduino', 'start') self.states.set_state('arduino', 'pause') self.gui.widget.pushButton_arduino_start.clicked[bool].connect(self.on_pushButton_arduino_start_clicked) self.gui.widget.pushButton_arduino_flash.clicked[bool].connect(self.on_pushButton_arduino_flash_clicked) self.gui.widget.pushButton_arduino_pause.clicked[bool].connect(self.on_pushButton_arduino_pause_clicked) # self._update_arduino_states_pixmaps() # Arduino - States self._update_gui_arduino_states_timer = QTimer() self._update_gui_arduino_states_timer.timeout.connect(self._on_update_gui_arduino_states_timer) self._update_gui_arduino_states_timer.setInterval(500) # Arduino - Diagnostics self._update_gui_arduino_diags_timer = QTimer() self._update_gui_arduino_diags_timer.timeout.connect(self._on_update_gui_arduino_diagnostics_timer) self._update_gui_arduino_diags_timer.setInterval(500) self._update_gui_arduino_states_timer.start() self._update_gui_arduino_diags_timer.start() # url: # ps: le tableau t2_t3_t4[3] est converti par rosmsg comme un chr()*3 (par soucy d'optimisation j'imagine). # Du coup, on ne recupere pas directement la valeur de l'entier mais la correspondance char. self.map_arduino_to_qt_ros_msg = { '/GPS/Clock/t2': lambda msg: ord(msg.t2_t3_t4[0]), '/GPS/Clock/t3': lambda msg: ord(msg.t2_t3_t4[1]), '/GPS/Clock/t4': lambda msg: ord(msg.t2_t3_t4[2]), '/GPS/PPS': lambda msg: 0, '/CamLight/nb_trigs': lambda msg: msg.num_trigs_for_pics, '/CamLight/states/boot': lambda msg: msg.state_boot } # '/CamLight/time_between_pics': lambda msg: msg.time_between_pics, # --------------------------------- # PUBLISHERS # --------------------------------- self._pub_arduino_commands, self._msg_arduino_commands = self.ros.find_publisher('/Arduino/sub/cmds') # --------------------------------- # --------------------------------- # SUBSCRIBERS # --------------------------------- # Arduino States self._sub_arduino_states = self.ros.subscribe_to_topic( '/Arduino/pub/states', self._cb_arduino_states, queue_size=10 ) self._msg_arduino_states = None self._play_sound = True rp = rospkg.RosPack() self.path_to_sound = path_to_sound = os.path.join(rp.get_path('rqt_li3ds'), 'resource', 'Click2-Sebastian-759472264.wav') # urls: # - https://github.com/Katee/quietnet/issues/18 # - http://stackoverflow.com/questions/17657103/how-to-play-wav-file-in-python # - http://soundbible.com/1705-Click2.html self._sounds = { 'click': AudioFile(path_to_sound) } self.li3ds_plugin.loginfo('arduino', 'path_to_sound: %s' % path_to_sound) def _update_arduino_states_pixmaps(self): """ """ self.gui.update_label_pixmap_onoff('arduino', 'flash') self.gui.update_label_pixmap_onoff('arduino', 'start') self.gui.update_label_pixmap_onoff('arduino', 'pause') @pyqtSlot(bool) def on_pushButton_arduino_start_clicked(self, checked): rospy.loginfo("[Arduino][Commands] - 'Start' button pushed!") # state = self.states.switch_state('arduino', 'start', update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True) # self.gui.widget.pushButton_arduino_start.setText(str(('Disable' if state else 'Enable') + ' Start')) @pyqtSlot(bool) def on_pushButton_arduino_flash_clicked(self, checked): rospy.loginfo("[Arduino][Commands] - 'Flash' button pushed!") state = self.states.switch_state('arduino', 'flash', update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True) self.gui.widget.pushButton_arduino_flash.setText(str(('Disable' if state else 'Enable') + ' Flash')) @pyqtSlot(bool) def on_pushButton_arduino_pause_clicked(self, checked): rospy.loginfo("[Arduino][Commands] - 'Pause' button pushed!") state = self.states.switch_state('arduino', 'pause', update_label_pixmap=self.gui.update_label_pixmap_onoff, update_ros=True) self.gui.widget.pushButton_arduino_pause.setText(str(('Disable' if state else 'Enable') + ' Pause')) def _on_update_gui_arduino_states_timer(self): """ """ # Synch _msg_arduino_states = self._msg_arduino_states # if _msg_arduino_states: self.gui.widget.textEdit_arduino_flash.setText(str(_msg_arduino_states.state_flash)) self.gui.widget.textEdit_arduino_pause.setText(str(_msg_arduino_states.state_pause)) self.gui.widget.textEdit_arduino_start.setText(str(_msg_arduino_states.state_start)) def _on_update_gui_arduino_diagnostics_timer(self): """ Synchronisation du QTreeWidget 'self.gui.widget.treeWidget_arduino_diag' avec les valeurs dans le message ROS 'self._msg_arduino_states' contenant les etats de l'Arduino. """ if self._msg_arduino_states: root_path = '' for qt_item, path_to_qt_item in iternodes( self.gui.widget.treeWidget_arduino_diag, lambda t: zip([t.topLevelItem(topLevel) for topLevel in range(t.topLevelItemCount())], [root_path] * t.topLevelItemCount()), lambda t: [t.child(id_child) for id_child in range(t.childCount())] ): # print('%s' % path_to_node) lambda_get_value_from_msg = self.map_arduino_to_qt_ros_msg.get(path_to_qt_item, lambda msg: None) value_in_ros_msg = lambda_get_value_from_msg(self._msg_arduino_states) if value_in_ros_msg is not None: qt_item.setText(1, str(value_in_ros_msg)) def _cb_arduino_states(self, msg): """ :param msg: :type msg: arduino_msgs.msg.states """ # rospy.loginfo("_cb_arduino_states - type(msg): %s" % type(msg)) self._msg_arduino_states = msg if msg.state_start: self.signal_arduino_state_start_on.emit() else: self.signal_arduino_state_start_off.emit() if self._play_sound & msg.state_start & (not msg.state_pause): self._sounds['click'].play() def connect_signal(self, signal, cb): """ :param signal: :param cb: :return: """ # self.__class__.__dict__.get(signal).connect(cb) # self.__class__.__dict__.get('signal_arduino_state_start_on').connect(cb) self.signal_arduino_state_start_on.connect(cb) def _publish_arduino_states(self): """ """ msg = self._msg_arduino_commands() # msg.update_clock = False msg.t2_t3_t4 = [0] * 3 # msg.state_flash = self.states.get_state('arduino', 'flash') msg.state_start = self.states.get_state('arduino', 'start') msg.state_pause = self.states.get_state('arduino', 'pause') # msg.state_boot = self.states.get_state('camlight', 'boot') # self._pub_arduino_commands.publish(msg) def state_updated(self): """ :return: """ try: if self._pub_arduino_commands: self._publish_arduino_states() except AttributeError as e: rospy.logwarn('_state_updated()')
class PolarConnect: def __init__(self): self.server = WebServer(self.handler) self.log = None if API_LOG_PATH is not None: self.log = open(API_LOG_PATH, 'w') try: self.server.listen() self.timer = QTimer() self.timer.timeout.connect(self.advance) self.timer.start(TICK_INTERVAL) except: QMessageBox.critical( self.window(), 'PolarConnect', 'Failed to listen on port {}.\nMake sure it is available and is not in use.' .format(NET_PORT)) def advance(self): self.server.advance() def handler(self, request): if self.log is not None: self.log.write('[request]\n') json.dump(request, self.log, indent=4, sort_keys=True) self.log.write('\n\n') name = request.get('action', '') version = request.get('version', 4) params = request.get('params', {}) reply = {'result': None, 'error': None} try: method = None for methodName, methodInst in inspect.getmembers( self, predicate=inspect.ismethod): apiVersionLast = 0 apiNameLast = None if getattr(methodInst, 'api', False): for apiVersion, apiName in getattr(methodInst, 'versions', []): if apiVersionLast < apiVersion <= version: apiVersionLast = apiVersion apiNameLast = apiName if apiNameLast is None and apiVersionLast == 0: apiNameLast = methodName if apiNameLast is not None and apiNameLast == name: method = methodInst break if method is None: raise Exception('unsupported action') else: reply['result'] = methodInst(**params) except Exception as e: reply['error'] = str(e) if version <= 4: reply = reply['result'] if self.log is not None: self.log.write('[reply]\n') json.dump(reply, self.log, indent=4, sort_keys=True) self.log.write('\n\n') return reply def download(self, url): try: (code, contents) = download(url) except Exception as e: raise Exception('{} download failed with error {}'.format( url, str(e))) if code == 200: return contents else: raise Exception('{} download failed with return code {}'.format( url, code)) def window(self): return aqt.mw def reviewer(self): reviewer = self.window().reviewer if reviewer is None: raise Exception('reviewer is not available') else: return reviewer def collection(self): collection = self.window().col if collection is None: raise Exception('collection is not available') else: return collection def decks(self): decks = self.collection().decks if decks is None: raise Exception('decks are not available') else: return decks def scheduler(self): scheduler = self.collection().sched if scheduler is None: raise Exception('scheduler is not available') else: return scheduler def database(self): database = self.collection().db if database is None: raise Exception('database is not available') else: return database def media(self): media = self.collection().media if media is None: raise Exception('media is not available') else: return media def startEditing(self): self.window().requireReset() def stopEditing(self): if self.collection() is not None: self.window().maybeReset() def createNote(self, note): collection = self.collection() model = collection.models.byName(note['modelName']) if model is None: raise Exception('model was not found: {}'.format( note['modelName'])) deck = collection.decks.byName(note['deckName']) if deck is None: raise Exception('deck was not found: {}'.format(note['deckName'])) ankiNote = anki.notes.Note(collection, model) ankiNote.model()['did'] = deck['id'] ankiNote.tags = note['tags'] for name, value in note['fields'].items(): if name in ankiNote: ankiNote[name] = value allowDuplicate = False if 'options' in note: if 'allowDuplicate' in note['options']: allowDuplicate = note['options']['allowDuplicate'] if type(allowDuplicate) is not bool: raise Exception( 'option parameter \'allowDuplicate\' must be boolean') duplicateOrEmpty = ankiNote.dupeOrEmpty() if duplicateOrEmpty == 1: raise Exception('cannot create note because it is empty') elif duplicateOrEmpty == 2: if not allowDuplicate: raise Exception('cannot create note because it is a duplicate') else: return ankiNote elif duplicateOrEmpty == False: return ankiNote else: raise Exception('cannot create note for unknown reason') # # Miscellaneous # @api() def version(self): return API_VERSION @api() def upgrade(self): response = QMessageBox.question(self.window(), 'PolarConnect', 'Upgrade to the latest version?', QMessageBox.Yes | QMessageBox.No) if response == QMessageBox.Yes: try: data = self.download(URL_UPGRADE) path = os.path.splitext(__file__)[0] + '.py' with open(path, 'w') as fp: fp.write(makeStr(data)) QMessageBox.information( self.window(), 'PolarConnect', 'Upgraded to the latest version, please restart Anki.') return True except Exception as e: QMessageBox.critical(self.window(), 'PolarConnect', 'Failed to download latest version.') raise e return False @api() def sync(self): self.window().onSync() @api() def multi(self, actions): return list(map(self.handler, actions)) # # Decks # @api() def deckNames(self): return self.decks().allNames() @api() def deckNamesAndIds(self): decks = {} for deck in self.deckNames(): decks[deck] = self.decks().id(deck) return decks @api() def getDecks(self, cards): decks = {} for card in cards: did = self.database().scalar('select did from cards where id=?', card) deck = self.decks().get(did)['name'] if deck in decks: decks[deck].append(card) else: decks[deck] = [card] return decks @api() def createDeck(self, deck): try: self.startEditing() did = self.decks().id(deck) finally: self.stopEditing() return did @api() def changeDeck(self, cards, deck): self.startEditing() did = self.collection().decks.id(deck) mod = anki.utils.intTime() usn = self.collection().usn() # normal cards scids = anki.utils.ids2str(cards) # remove any cards from filtered deck first self.collection().sched.remFromDyn(cards) # then move into new deck self.collection().db.execute( 'update cards set usn=?, mod=?, did=? where id in ' + scids, usn, mod, did) self.stopEditing() @api() def deleteDecks(self, decks, cardsToo=False): try: self.startEditing() decks = filter(lambda d: d in self.deckNames(), decks) for deck in decks: did = self.decks().id(deck) self.decks().rem(did, cardsToo) finally: self.stopEditing() @api() def getDeckConfig(self, deck): if not deck in self.deckNames(): return False collection = self.collection() did = collection.decks.id(deck) return collection.decks.confForDid(did) @api() def saveDeckConfig(self, config): collection = self.collection() config['id'] = str(config['id']) config['mod'] = anki.utils.intTime() config['usn'] = collection.usn() if not config['id'] in collection.decks.dconf: return False collection.decks.dconf[config['id']] = config collection.decks.changed = True return True @api() def setDeckConfigId(self, decks, configId): configId = str(configId) for deck in decks: if not deck in self.deckNames(): return False collection = self.collection() if not configId in collection.decks.dconf: return False for deck in decks: did = str(collection.decks.id(deck)) aqt.mw.col.decks.decks[did]['conf'] = configId return True @api() def cloneDeckConfigId(self, name, cloneFrom='1'): configId = str(cloneFrom) if not configId in self.collection().decks.dconf: return False config = self.collection().decks.getConf(configId) return self.collection().decks.confId(name, config) @api() def removeDeckConfigId(self, configId): configId = str(configId) collection = self.collection() if configId == 1 or not configId in collection.decks.dconf: return False collection.decks.remConf(configId) return True @api() def storeMediaFile(self, filename, data): self.deleteMediaFile(filename) self.media().writeData(filename, base64.b64decode(data)) @api() def retrieveMediaFile(self, filename): filename = os.path.basename(filename) filename = normalize('NFC', filename) filename = self.media().stripIllegal(filename) path = os.path.join(self.media().dir(), filename) if os.path.exists(path): with open(path, 'rb') as file: return base64.b64encode(file.read()).decode('ascii') return False @api() def deleteMediaFile(self, filename): self.media().syncDelete(filename) @api() def addNote(self, note): ankiNote = self.createNote(note) audio = note.get('audio') if audio is not None and len(audio['fields']) > 0: try: data = self.download(audio['url']) skipHash = audio.get('skipHash') if skipHash is None: skip = False else: m = hashlib.md5() m.update(data) skip = skipHash == m.hexdigest() if not skip: for field in audio['fields']: if field in ankiNote: ankiNote[field] += u'[sound:{}]'.format( audio['filename']) self.media().writeData(audio['filename'], data) except Exception as e: errorMessage = str(e).replace("&", "&").replace( "<", "<").replace(">", ">") for field in audio['fields']: if field in ankiNote: ankiNote[field] += errorMessage collection = self.collection() self.startEditing() collection.addNote(ankiNote) collection.autosave() self.stopEditing() return ankiNote.id @api() def canAddNote(self, note): try: return bool(self.createNote(note)) except: return False @api() def updateNoteFields(self, note): ankiNote = self.collection().getNote(note['id']) if ankiNote is None: raise Exception('note was not found: {}'.format(note['id'])) for name, value in note['fields'].items(): if name in ankiNote: ankiNote[name] = value ankiNote.flush() @api() def addTags(self, notes, tags, add=True): self.startEditing() self.collection().tags.bulkAdd(notes, tags, add) self.stopEditing() @api() def removeTags(self, notes, tags): return self.addTags(notes, tags, False) @api() def getTags(self): return self.collection().tags.all() @api() def suspend(self, cards, suspend=True): for card in cards: if self.suspended(card) == suspend: cards.remove(card) if len(cards) == 0: return False scheduler = self.scheduler() self.startEditing() if suspend: scheduler.suspendCards(cards) else: scheduler.unsuspendCards(cards) self.stopEditing() return True @api() def unsuspend(self, cards): self.suspend(cards, False) @api() def suspended(self, card): card = self.collection().getCard(card) return card.queue == -1 @api() def areSuspended(self, cards): suspended = [] for card in cards: suspended.append(self.suspended(card)) return suspended @api() def areDue(self, cards): due = [] for card in cards: if self.findCards('cid:{} is:new'.format(card)): due.append(True) else: date, ivl = self.collection().db.all( 'select id/1000.0, ivl from revlog where cid = ?', card)[-1] if ivl >= -1200: due.append( bool(self.findCards('cid:{} is:due'.format(card)))) else: due.append(date - ivl <= time()) return due @api() def getIntervals(self, cards, complete=False): intervals = [] for card in cards: if self.findCards('cid:{} is:new'.format(card)): intervals.append(0) else: interval = self.collection().db.list( 'select ivl from revlog where cid = ?', card) if not complete: interval = interval[-1] intervals.append(interval) return intervals @api() def modelNames(self): return self.collection().models.allNames() @api() def modelNamesAndIds(self): models = {} for model in self.modelNames(): models[model] = int(self.collection().models.byName(model)['id']) return models @api() def modelNameFromId(self, modelId): model = self.collection().models.get(modelId) if model is None: raise Exception('model was not found: {}'.format(modelId)) else: return model['name'] @api() def modelFieldNames(self, modelName): model = self.collection().models.byName(modelName) if model is None: raise Exception('model was not found: {}'.format(modelName)) else: return [field['name'] for field in model['flds']] @api() def modelFieldsOnTemplates(self, modelName): model = self.collection().models.byName(modelName) if model is None: raise Exception('model was not found: {}'.format(modelName)) templates = {} for template in model['tmpls']: fields = [] for side in ['qfmt', 'afmt']: fieldsForSide = [] # based on _fieldsOnTemplate from aqt/clayout.py matches = re.findall('{{[^#/}]+?}}', template[side]) for match in matches: # remove braces and modifiers match = re.sub(r'[{}]', '', match) match = match.split(':')[-1] # for the answer side, ignore fields present on the question side + the FrontSide field if match == 'FrontSide' or side == 'afmt' and match in fields[ 0]: continue fieldsForSide.append(match) fields.append(fieldsForSide) templates[template['name']] = fields return templates @api() def deckNameFromId(self, deckId): deck = self.collection().decks.get(deckId) if deck is None: raise Exception('deck was not found: {}'.format(deckId)) else: return deck['name'] @api() def findNotes(self, query=None): if query is None: return [] else: return list(map(int, self.collection().findNotes(query))) @api() def findCards(self, query=None): if query is None: return [] else: return list(map(int, self.collection().findCards(query))) @api() def cardsInfo(self, cards): result = [] for cid in cards: try: card = self.collection().getCard(cid) model = card.model() note = card.note() fields = {} for info in model['flds']: order = info['ord'] name = info['name'] fields[name] = { 'value': note.fields[order], 'order': order } result.append({ 'cardId': card.id, 'fields': fields, 'fieldOrder': card.ord, 'question': card._getQA()['q'], 'answer': card._getQA()['a'], 'modelName': model['name'], 'deckName': self.deckNameFromId(card.did), 'css': model['css'], 'factor': card.factor, #This factor is 10 times the ease percentage, # so an ease of 310% would be reported as 3100 'interval': card.ivl, 'note': card.nid }) except TypeError as e: # Anki will give a TypeError if the card ID does not exist. # Best behavior is probably to add an 'empty card' to the # returned result, so that the items of the input and return # lists correspond. result.append({}) return result @api() def notesInfo(self, notes): result = [] for nid in notes: try: note = self.collection().getNote(nid) model = note.model() fields = {} for info in model['flds']: order = info['ord'] name = info['name'] fields[name] = { 'value': note.fields[order], 'order': order } result.append({ 'noteId': note.id, 'tags': note.tags, 'fields': fields, 'modelName': model['name'], 'cards': self.collection().db.list( 'select id from cards where nid = ? order by ord', note.id) }) except TypeError as e: # Anki will give a TypeError if the note ID does not exist. # Best behavior is probably to add an 'empty card' to the # returned result, so that the items of the input and return # lists correspond. result.append({}) return result @api() def cardsToNotes(self, cards): return self.collection().db.list( 'select distinct nid from cards where id in ' + anki.utils.ids2str(cards)) @api() def guiBrowse(self, query=None): browser = aqt.dialogs.open('Browser', self.window()) browser.activateWindow() if query is not None: browser.form.searchEdit.lineEdit().setText(query) if hasattr(browser, 'onSearch'): browser.onSearch() else: browser.onSearchActivated() return list(map(int, browser.model.cards)) @api() def guiAddCards(self): addCards = aqt.dialogs.open('AddCards', self.window()) addCards.activateWindow() @api() def guiReviewActive(self): return self.reviewer().card is not None and self.window( ).state == 'review' @api() def guiCurrentCard(self): if not self.guiReviewActive(): raise Exception('Gui review is not currently active.') reviewer = self.reviewer() card = reviewer.card model = card.model() note = card.note() fields = {} for info in model['flds']: order = info['ord'] name = info['name'] fields[name] = {'value': note.fields[order], 'order': order} if card is not None: return { 'cardId': card.id, 'fields': fields, 'fieldOrder': card.ord, 'question': card._getQA()['q'], 'answer': card._getQA()['a'], 'buttons': [b[0] for b in reviewer._answerButtonList()], 'modelName': model['name'], 'deckName': self.deckNameFromId(card.did), 'css': model['css'], 'template': card.template()['name'] } @api() def guiStartCardTimer(self): if not self.guiReviewActive(): return False card = self.reviewer().card if card is not None: card.startTimer() return True else: return False @api() def guiShowQuestion(self): if self.guiReviewActive(): self.reviewer()._showQuestion() return True else: return False @api() def guiShowAnswer(self): if self.guiReviewActive(): self.window().reviewer._showAnswer() return True else: return False @api() def guiAnswerCard(self, ease): if not self.guiReviewActive(): return False reviewer = self.reviewer() if reviewer.state != 'answer': return False if ease <= 0 or ease > self.scheduler().answerButtons(reviewer.card): return False reviewer._answerCard(ease) return True @api() def guiDeckOverview(self, name): collection = self.collection() if collection is not None: deck = collection.decks.byName(name) if deck is not None: collection.decks.select(deck['id']) self.window().onOverview() return True return False @api() def guiDeckBrowser(self): self.window().moveToState('deckBrowser') @api() def guiDeckReview(self, name): if self.guiDeckOverview(name): self.window().moveToState('review') return True else: return False @api() def guiExitAnki(self): timer = QTimer() def exitAnki(): timer.stop() self.window().close() timer.timeout.connect(exitAnki) timer.start( 1000) # 1s should be enough to allow the response to be sent. @api() def addNotes(self, notes): results = [] for note in notes: try: results.append(self.addNote(note)) except Exception: results.append(None) return results @api() def canAddNotes(self, notes): results = [] for note in notes: results.append(self.canAddNote(note)) return results
class RestDialog(QDialog): def __init__(self, parent): super(RestDialog, self).__init__(parent) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Window) self.setAttribute(Qt.WA_TranslucentBackground) self.secs = 0 self.pr = RoundProgress(self) self.pr.setObjectName("rest_progress") self.pr.setFixedSize(QSize(200, 200)) self.btn_continue = QPushButton(_("IGNORE REST"), self) self.btn_continue.setFixedSize(QSize(100, 30)) self.btn_continue.setObjectName("btn_ignore_rest") if not ProfileConfig.donate_alerted: self.btn_continue.setIcon(QIcon( QPixmap(":/Icon/icons/dollar.png"))) self.btn_continue.clicked.connect(self.on_btn_ignore_rest) self.a = 0 self.total_secs = 0 self.timer = QTimer() self.timer.setInterval(1000) self.timer.timeout.connect(self.to) self.l = QVBoxLayout(self) self.l.addWidget(self.pr, 0, Qt.AlignCenter) self.l.addWidget(self.btn_continue, 0, Qt.AlignCenter) def to(self): self.a += 1 self.total_secs -= 1 self.pr.setValue(self.a) min = self.total_secs // MIN_SECS secs = self.total_secs - min * MIN_SECS self.pr.label.setText( u"<center>" + _("REST") + u"<br>" + u"{}:{}".format(str(min).zfill(2), str(secs).zfill(2)) + u"</center>") if self.total_secs <= 0: self.timer.stop() self.accept() def start(self, secs): self.total_secs = secs self.a = 0 self.pr.setRange(0, self.total_secs) self.timer.start() # noinspection PyMethodOverriding def exec_(self, tomato_min): self.start( UserConfig.BREAK_MINUTES.get(str(tomato_min) + "MIN", 5) * MIN_SECS) return super(RestDialog, self).exec_() def reject(self): if self.timer.isActive(): self.timer.stop() super(RestDialog, self).reject() def on_btn_ignore_rest(self, ): if not ProfileConfig.donate_alerted: DialogDonate(mw).exec_() ProfileConfig.donate_alerted = True self.btn_continue.setIcon(QIcon()) if askUser( u""" <p>""" + _("IGNORE REST QUESTION") + u"""</p> """, self): self.reject()
class _FileWatcher(QObject): """File watcher. QFileSystemWatcher notifies client about any change (file access mode, modification date, etc.) But, we need signal, only after file contents had been changed """ modified = pyqtSignal(bool) removed = pyqtSignal(bool) def __init__(self, path): QObject.__init__(self) self._contents = None self._watcher = QFileSystemWatcher() self._timer = None self._path = path self.setPath(path) self.enable() def __del__(self): self._stopTimer() def enable(self): """Enable signals from the watcher """ self._watcher.fileChanged.connect(self._onFileChanged) def disable(self): """Disable signals from the watcher """ self._watcher.fileChanged.disconnect(self._onFileChanged) self._stopTimer() def setContents(self, contents): """Set file contents. Watcher uses it to compare old and new contents of the file. """ self._contents = contents # Qt File watcher may work incorrectly, if file was not existing, when it started self.setPath(self._path) def setPath(self, path): """Path had been changed or file had been created. Set new path """ if self._watcher.files(): self._watcher.removePaths(self._watcher.files()) if path is not None and os.path.isfile(path): self._watcher.addPath(path) self._path = path def _emitModifiedStatus(self): """Emit self.modified signal with right status """ isModified = self._contents != self._safeRead(self._path) self.modified.emit(isModified) def _onFileChanged(self): """File changed. Emit own signal, if contents changed """ if os.path.exists(self._path): self._emitModifiedStatus() else: self.removed.emit(True) self._startTimer() def _startTimer(self): """Init a timer. It is used for monitoring file after deletion. Git removes file, than restores it. """ if self._timer is None: self._timer = QTimer() self._timer.setInterval(500) self._timer.timeout.connect(self._onCheckIfDeletedTimer) self._timer.start() def _stopTimer(self): """Stop timer, if exists """ if self._timer is not None: self._timer.stop() def _onCheckIfDeletedTimer(self): """Check, if file has been restored """ if os.path.exists(self._path): self.removed.emit(False) self._emitModifiedStatus() self.setPath( self._path ) # restart Qt file watcher after file has been restored self._stopTimer() def _safeRead(self, path): """Read file. Ignore exceptions """ try: with open(path, 'rb') as file: return file.read() except (OSError, IOError): return None
class Principal(QMainWindow, ui_principal.Ui_Principal): def __init__(self, parent=None): QMainWindow.__init__(self) self.setupUi(self) print(pg.__version__) self.sb = SerialDAQ() #'/dev/pts/6') while not self.sb.connected: msg = QMessageBox.critical(None, "Advertencia", u"La interfaz no está conectada", QMessageBox.Retry | QMessageBox.Abort) if msg == QMessageBox.Retry: self.sb.open() else: sys.exit(1) self.updateTimer = QTimer() self.updateTimer.timeout.connect(self.update) # Asigna valores iniciales por defecto a los parámetros de cada canal for i in range(NUM_CANALES): str_pendiente = 'pendiente_' + str(i + 1) pendiente = getattr(self, str_pendiente) str_ordenada = 'ordenada_' + str(i + 1) ordenada = getattr(self, str_ordenada) str_nombre = 'nombre_' + str(i + 1) nombre = getattr(self, str_nombre) str_unidad = 'unidad_' + str(i + 1) unidad = getattr(self, str_unidad) pendiente.setText(str(PENDIENTE_DEF)) ordenada.setText(str(0.0)) nombre.setText('Canal ' + str(i + 1)) unidad.setText('Volt') self.sb.config_analog(i + 1, name=nombre.text(), activate=False, calib=(float(ordenada.text()), float(pendiente.text()))) self.sb.activate_analog(1) self.midiendo = False self.guardado = True self.vent_grafico = [] self.grafico = [] self.actionMedir.triggered.connect(self.medir) self.actionGuardar.triggered.connect(self.guardar) self.actionSalir.triggered.connect(self.close) pg.setConfigOption('background', 'w') pg.setConfigOption('foreground', 'k') def guardar(self): self.guardado = True def medir(self): if not self.midiendo: if not self.guardado: msg = QMessageBox.critical(None, "Advertencia", u"Se perderán los datos actuales", QMessageBox.Ok | QMessageBox.Cancel) if msg == QMessageBox.Cancel: return self.guardado = False self.midiendo = True self.vent_grafico = [] self.grafico = [] self.sb.clear_analog() print(u'Iniciando medición') self.actionMedir.setIconText('Detener') self.frecuencia = self.frecuenciaSpinBox.value() self.num_ventana = 0 self.cur_range = 0 print "Frecuencia deseada =", 1. / self.frecuencia print "Frecuencia deseada =", int( 10000. / self.frecuencia) * 0.0001 self.timestamp = 1.065 * 0.0001 * int( 10000. / self.frecuencia) * np.arange(0, self.sb.bufsize) for i in range(NUM_CANALES): gb = getattr(self, 'groupBox_' + str(i + 1)) nombre = getattr(self, 'nombre_' + str(i + 1)) str_pendiente = 'pendiente_' + str(i + 1) pendiente = getattr(self, str_pendiente) str_ordenada = 'ordenada_' + str(i + 1) ordenada = getattr(self, str_ordenada) self.sb.config_analog(i + 1, name=nombre.text(), activate=gb.isChecked(), calib=(float(ordenada.text()), float(pendiente.text()))) if self.sb.channel_active[i]: print('Canal {0} activo.'.format(str(i + 1), )) self.vent_grafico.append(Grafico(self, self.num_ventana)) self.num_ventana += 1 self.grafico.append(self.vent_grafico[i].graphicsView.plot( autoDownsample=False, clipToView=True, antialias=True, pen=pg.mkPen('r', width=1.), symbol='o', symbolSize=4, symbolPen=pg.mkPen('r', width=1), symbolBrush=pg.mkBrush('r'))) title = 'Canal {0}: '.format(str(i + 1)) + \ self.sb.channel_name[i] self.vent_grafico[i].setWindowTitle(title) self.vent_grafico[i].graphicsView.setYRange( 0., self.sb.channel_calib[i][1] * 2**ADC_BITS) # self.vent_grafico[i].graphicsView.setXRange(0., TIME_RANGE ) #.setLimits(maxXRange=100, minXRange=50) #self.grafico[i].setDownsampling(auto=True) # self.vent_grafico[i].graphicsView.setXRange(0., 50.) self.vent_grafico[i].show() else: print('Canal {0} inactivo.'.format(str(i + 1), )) self.grafico.append(None) self.vent_grafico.append(None) self.sb.start_continuous(self.frecuencia) self.updateTimer.start(50) #1./self.frecuencia*1000) else: self.midiendo = False print(u'Deteniendo medición') self.actionMedir.setIconText('Medir') self.updateTimer.stop() self.sb.update_analog() self.sb.stop() # self.vent_grafico = [] # def update(self): self.sb.update_analog() new_range = False if (self.sb.channel_pointer / self.frecuencia) / TIME_RANGE > self.cur_range: self.cur_range += 1 new_range = True # print self.cur_range for i in range(NUM_CANALES): if self.sb.channel_active[i]: # if new_range: # self.vent_grafico[i].graphicsView.setXRange((self.cur_range - 1) * TIME_RANGE, self.cur_range * TIME_RANGE ) self.grafico[i].setData( self.timestamp[0:self.sb.channel_pointer], self.sb.channel_data[i][0:self.sb.channel_pointer]) def closeEvent(self, event): if not self.guardado: msg = QMessageBox.critical(None, "Salir", u"Se perderán los datos actuales", QMessageBox.Ok | QMessageBox.Cancel) if msg == QMessageBox.Cancel: event.ignore() return for ventana in self.vent_grafico: if ventana is not None: ventana.destroy() event.accept()
class CustomCodeFrame(QFrame): poke_code = pyqtSignal(str, int, QByteArray) # code_set_label, code_id, new_bytes log = pyqtSignal(str, str) # msg, color def __init__(self, code_set, parent=None): super(CustomCodeFrame, self).__init__(parent) self.cs = code_set self.tmr_reset_bg_clr = QTimer(self) self.tmr_reset_bg_clr.setInterval(500) # ms self.tmr_reset_bg_clr.timeout.connect(self.resetBGColor) self.txt_label = QLineEdit(self) self.txt_label.setMaximumWidth(160) self.txt_label.setPlaceholderText('Label') self.txt_codes = QPlainTextEdit(self) self.txt_codes.setMaximumHeight(66) font = QFont('Monospace') font.setStyleHint(QFont.TypeWriter) self.txt_codes.setFont(font) self.txt_codes.cursorPositionChanged.connect(self.resetBGColor) icon_height = self.txt_label.height() * 8 / 15 self.btn_poke = QPushButton(self) self.btn_poke.setIcon(QIcon('img/flaticon/draw39.png')) self.btn_poke.setIconSize(QSize(icon_height, icon_height)) self.btn_poke.setFixedSize(QSize(icon_height * 1.5, icon_height * 1.5)) self.btn_poke.setAutoFillBackground(True) self.btn_poke.setStyleSheet('background-color: white') self.btn_poke.setToolTip('Poke memory') self.btn_poke.clicked.connect(self.onPoke) self.layout = QHBoxLayout(self) self.layout.addWidget(self.txt_label) self.layout.setAlignment(self.txt_label, Qt.AlignTop) self.layout.addWidget(self.txt_codes) self.layout.setAlignment(self.txt_codes, Qt.AlignTop) self.layout.addWidget(self.btn_poke) self.layout.setAlignment(self.btn_poke, Qt.AlignTop) self.layout.setContentsMargins(0, 2, 0, 2) def setAlternateBGColor(self): self.setStyleSheet( 'CustomCodeFrame { background-color:rgb(248,248,248) }') def setErrorBGColor(self): self.txt_codes.setStyleSheet('background-color: rgb(255,128,128)') self.tmr_reset_bg_clr.start() def resetBGColor(self): if self.tmr_reset_bg_clr.isActive(): self.tmr_reset_bg_clr.stop() self.txt_codes.setStyleSheet('background-color: white') @pyqtSlot() def onPoke(self): try: parse_custom_codes(self.cs, str(self.txt_codes.toPlainText())) except SyntaxError, e: self.log.emit(str(e), 'red') self.setErrorBGColor() return if len(self.cs.c) <= 0: self.log.emit('POKE failed: no codes found', 'red') self.setErrorBGColor() return # Sequentially poke codes for code in self.cs.c: raw_bytes = struct.pack('>Q', code.dft_value)[-code.num_bytes:] self.poke_code.emit(code.label, code.id, QByteArray(raw_bytes))
class Plugin: """Plugin interface """ def __init__(self): core.restoreSession.connect(self._onRestoreSession) core.aboutToTerminate.connect(self._saveSession) self._timer = QTimer(core) self._timer.timeout.connect(self._autoSaveSession) self._timer.setInterval(_AUTO_SAVE_INTERVAL_MS) self._timer.start() def del_(self): """Explicitly called destructor """ core.restoreSession.disconnect(self._onRestoreSession) core.aboutToTerminate.disconnect(self._saveSession) def _onRestoreSession(self): """Enki initialisation finished. Now restore session """ # if have documents except 'untitled' new doc, don't restore session if core.workspace().currentDocument() is not None: return if not os.path.exists(_SESSION_FILE_PATH): return session = enki.core.json_wrapper.load(_SESSION_FILE_PATH, 'session', None) if session is not None: for filePath in session['opened']: if os.path.exists(filePath): core.workspace().openFile(filePath) if session['current'] is not None: document = self._documentForPath(session['current']) if document is not None: # document might be already deleted core.workspace().setCurrentDocument(document) if 'project' in session: path = session['project'] if path is not None and os.path.isdir(path): core.project().open(path) def _documentForPath(self, filePath): """Find document by it's file path. Raises ValueError, if document hasn't been found """ for document in core.workspace().documents(): if document.filePath() is not None and \ document.filePath() == filePath: return document return None def _saveSession(self, showWarnings=True): """Enki is going to be terminated. Save session """ fileList = [ document.filePath() for document in core.workspace().documents() if document.filePath() is not None and os.path.exists( document.filePath()) and not '/.git/' in document.filePath() and not (document.fileName().startswith('svn-commit') and document.fileName().endswith('.tmp')) ] if not fileList: return currentPath = None if core.workspace().currentDocument() is not None: currentPath = core.workspace().currentDocument().filePath() session = { 'current': currentPath, 'opened': fileList, 'project': core.project().path() } enki.core.json_wrapper.dump(_SESSION_FILE_PATH, 'session', session, showWarnings) def _autoSaveSession(self): self._saveSession(showWarnings=False)
class Plot2DDataWidget(QWidget): def __init__(self, parent=None, measdata=[[1, 3, 2], [3, 5, 7]], header=["index", "prime numbers"], SymbolSize=10, linecolor='y', pointcolor='b', title='Plot Window'): # This class derivates from a Qt MainWindow so we have to call # the class builder ".__init__()" #QMainWindow.__init__(self) QWidget.__init__(self) # "self" is now a Qt Mainwindow, then we load the user interface # generated with QtDesigner and call it self.ui self.ui = Plot2DDataWidget_Ui.Ui_Plot2DData() # Now we have to feed the GUI building method of this object (self.ui) # with a Qt Mainwindow, but the widgets will actually be built as children # of this object (self.ui) self.ui.setupUi(self) self.setWindowTitle(title) self.x_index = 0 self.y_index = 0 self.curve = self.ui.plot_area.plot(pen=linecolor) self.curve.setSymbolBrush(pointcolor) self.curve.setSymbol('o') self.curve.setSymbolSize(SymbolSize) self.parent = parent self.measdata = measdata self.header = header self.update_dropdown_boxes(header) self.update_plot_timer = QTimer() self.update_plot_timer.setSingleShot( True ) #The timer would not wait for the completion of the task otherwise self.update_plot_timer.timeout.connect(self.autoupdate) if self.ui.auto_upd.isChecked(): self.autoupdate() def update_timer_timeout(self, msec): self.update_plot_timer.setInterval(msec) def updateX(self, value): self.x_index = value #self.update_plot() #that was the bug #This created a loop because update_plot called check_connection #which called update_dropdown_boxes, which cleared the x_axis_box #which triggered a call to updateX def updateY(self, value): self.y_index = value #self.update_plot() def change_line_color(self, color=None): #yellow 4294967040 if color == None: color = QColorDialog.getColor(QColor(4294967040), None, 'Line color', QColorDialog.ShowAlphaChannel) if color.isValid(): self.curve.setPen(color) def change_point_color(self, color=None): #blue 4279259391 if color == None: color = QColorDialog.getColor(QColor(4279259391), None, 'Point color', QColorDialog.ShowAlphaChannel) if color.isValid(): self.curve.setSymbolBrush(color) def change_symbol_size(self, value): self.curve.setSymbolSize(value) def check_connection(self, state=1): """check if the pointer to the Master dataset to display (self.measdata in Main.py) has changed""" if state and hasattr(self.parent, "measdata"): if self.parent.measdata != self.measdata: self.measdata = self.parent.measdata if self.parent.current_header != self.header: self.update_dropdown_boxes(self.parent.current_header) #print "Reestablishing connection" def autoupdate(self, state=1): if state: self.update_plot() self.update_plot_timer.start( self.ui.refresh_rate.value() * 1000) #The value must be converted to milliseconds else: self.update_plot_timer.stop() def update_plot(self): """plot the data columns selected in the drop-down menu boxes""" if self.ui.autoconnect.isChecked(): self.check_connection() if self.x_index != -1 and self.y_index != -1 and self.measdata[ self.x_index] != [] and self.measdata[self.y_index] != []: self.curve.setData(self.measdata[self.x_index], self.measdata[self.y_index]) def update_dropdown_boxes(self, header): """Update the drop-down boxes that select the content of the plot""" self.ui.x_axis_box.clear() self.ui.x_axis_box.addItems(header) self.ui.y_axis_box.clear() self.ui.y_axis_box.addItems(header) self.header = header
from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * from qgis.utils import iface from PyQt4.QtCore import QTimer timer = QTimer() timer.setInterval(10000) QObject.connect(timer, SIGNAL("timeout()"), qgis.utils.iface.mapCanvas().refreshAllLayers) timer.start()
class Pager(QObject): """Provides an interface for paging in a View by page number. Pages are numbered starting with 1 in this api! """ currentPageChanged = pyqtSignal(int) pageCountChanged = pyqtSignal(int) def __init__(self, view): """Initializes the Pager with the View. Also connects with the Surface of the View and its Layout, so don't interchange them after initializing the Pager. """ super(Pager, self).__init__(view) self._currentPage = 0 self._pageCount = 0 self._blockLevel = 0 self._pageNumSet = False self._updateTimer = QTimer( singleShot=True, interval=100, timeout=self._updatePageNumber) # connect view.installEventFilter(self) view.surface().installEventFilter(self) view.surface().pageLayout().changed.connect(self._layoutChanged) # Connect to the kineticScrollingEnabled signal to avoid unneeded updates. view.kineticScrollingActive.connect(self.blockListening) def currentPage(self): """Returns the current page number (0 if there are no pages).""" return self._currentPage def setCurrentPage(self, num): """Shows the specified page number.""" changed, self._currentPage = self._currentPage != num, num self._pageNumSet = True self.blockListening(True) self.view().gotoPageNumber(num - 1) self.blockListening(False) if changed: self.currentPageChanged.emit(self._currentPage) def pageCount(self): """Returns the number of pages.""" return self._pageCount def view(self): return self.parent() def _layoutChanged(self): """Called internally whenever the layout is updated.""" layout = self.view().surface().pageLayout() self._pageCount, old = len(layout), self._pageCount if old != self._pageCount: self.pageCountChanged.emit(self._pageCount) self._updatePageNumber() def _updatePageNumber(self): """Called internally on layout change or view resize or surface move.""" self._currentPage, old = self.view().currentPageNumber() + 1, self._currentPage if self._currentPage == 0 and self._pageCount > 0: # the view may not be initialized self._currentPage = 1 if old != self._currentPage: self.currentPageChanged.emit(self._currentPage) def blockListening(self, block): """Block/unblock listening to event, used to avoid multiple updates when we know lots of events are going to be sent to the pager. Blocking can be nested, only the outermost unblock will really unblock the event processing.""" if block: self._blockLevel += 1 else: self._blockLevel -= 1 if self._blockLevel == 0: if self._pageNumSet: self._pageNumSet = False else: self._updatePageNumber() def eventFilter(self, obj, ev): if (self._blockLevel == 0 and ((ev.type() == QEvent.Resize and obj is self.view()) or (ev.type() == QEvent.Move and obj is self.view().surface())) and not self._updateTimer.isActive()): self._updateTimer.start() return False