def __init__(self, tabWidget, helper, *args): super(HTTYD, self).__init__(*args) self.setupUi(self) self._machine = QStateMachine() self._setup_states() self._event = threading.Event() self.tabName = "HTTYD" self.menuName = "HTTYD Tab" self.tabWidget = tabWidget # the above helper cf instances are only assigned to _cf_L and _cf_R after they start logging self._helper = helper self._cf = None self.last_time = 0 # assign the label to the _cf_status_ string self._cf_status = self.cfStatusLabel.text() self._status = self.statusLabel.text() # initial flight mode self.flying_enabled = False self.switch_flight_mode(FlightModeStates.DISCONNECTED) self.path_pos_threshold = 0.2 # The position and rotation of the cf and wand obtained by the # lighthouse tracking, if it cant be tracked the position becomes Nan self.cf_pos = Position(0, 0, 0) self.wand_pos = Position(0, 0, 0) # The regular cf_pos can a times due to lost tracing become Nan, # this the latest known valid cf position self.valid_cf_pos = Position(0, 0, 0) # Always wrap callbacks from Crazyflie API though QT Signal/Slots # to avoid manipulating the UI when rendering it self._connected_signal.connect(self._connected) self._disconnected_signal.connect(self._disconnected) self._log_data_signal.connect(self._log_data_received) self._param_updated_signal.connect(self._param_updated) # connect the status change signal to the update status # funciton self.statusChanged.connect(self._update_status) self.cfStatusChanged.connect(self._update_cf_status) # Connect the Crazyflie API callbacks to the signals self._helper.cf.connected.add_callback(self._connected_signal.emit) self._helper.cf.disconnected.add_callback(self._disconnected_signal.emit) # Connect the UI elements self.liftButton.clicked.connect(self.set_lift_mode) self.landButton.clicked.connect(self.set_land_mode) self.followButton.clicked.connect(self.set_follow_mode) self.emergencyButton.clicked.connect(self.set_kill_engine)
def __init__(self, stickMan, keyReceiver): self.m_stickMan = stickMan self.m_keyReceiver = keyReceiver # Create animation group to be used for all transitions. self.m_animationGroup = QParallelAnimationGroup() stickManNodeCount = self.m_stickMan.nodeCount() self._pas = [] for i in range(stickManNodeCount): pa = QPropertyAnimation(self.m_stickMan.node(i), 'pos') self._pas.append(pa) self.m_animationGroup.addAnimation(pa) # Set up intial state graph. self.m_machine = QStateMachine() self.m_machine.addDefaultAnimation(self.m_animationGroup) self.m_alive = QState(self.m_machine) self.m_alive.setObjectName('alive') # Make it blink when lightning strikes before entering dead animation. lightningBlink = QState(self.m_machine) lightningBlink.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'penColor', Qt.black) lightningBlink.assignProperty(self.m_stickMan, 'fillColor', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'isDead', True) timer = QTimer(lightningBlink) timer.setSingleShot(True) timer.setInterval(100) lightningBlink.entered.connect(timer.start) lightningBlink.exited.connect(timer.stop) self.m_dead = QState(self.m_machine) self.m_dead.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.black) self.m_dead.assignProperty(self.m_stickMan, 'penColor', Qt.white) self.m_dead.assignProperty(self.m_stickMan, 'fillColor', Qt.black) self.m_dead.setObjectName('dead') # Idle state (sets no properties). self.m_idle = QState(self.m_alive) self.m_idle.setObjectName('idle') self.m_alive.setInitialState(self.m_idle) # Lightning strikes at random. self.m_alive.addTransition(LightningStrikesTransition(lightningBlink)) lightningBlink.addTransition(timer.timeout, self.m_dead) self.m_machine.setInitialState(self.m_alive)
def __init__(self, form) -> None: self._form = form self._machine = machine = QStateMachine() init = self._make_initial_state(form) dev_fetched = self._make_dev_fetched_state(form) save = self._make_save_state(form) machine.addState(init) machine.addState(dev_fetched) machine.addState(save) machine.setInitialState(init) init.addTransition(form.gotDevices, dev_fetched) unselected_tr = self.CheckedTranstion( form.deviceList.itemChanged, target=dev_fetched, testFn=lambda: not self._hasSelectedItems()) save.addTransition(unselected_tr) save.addTransition(form.editBtn.clicked, init) selected_tr = self.CheckedTranstion(form.deviceList.itemChanged, target=save, testFn=self._hasSelectedItems) entered_dev_feched = self.CheckedTranstion( dev_fetched.entered, target=save, testFn=self._hasSelectedItems) dev_fetched.addTransition(selected_tr) dev_fetched.addTransition(entered_dev_feched) dev_fetched.addTransition(form.editBtn.clicked, init) machine.start()
def my_ui(self): v_box = QVBoxLayout() config_box = QGroupBox('配置') grid = QGridLayout() label_one = QLabel('当前状态') self.choose_button = QPushButton() self.machine = QStateMachine() zoom_state = QState(self.machine) shrink_state = QState(self.machine) self.machine.setInitialState(zoom_state) zoom_state.assignProperty(self.choose_button, 'text', '放大') shrink_state.assignProperty(self.choose_button, 'text', '缩小') shrink_state.addTransition(self.choose_button.clicked, zoom_state) zoom_state.addTransition(self.choose_button.clicked, shrink_state) self.machine.start() grid.addWidget(label_one, 0, 0) grid.addWidget(self.choose_button, 0, 1) grid.addWidget(QLabel('倍数'), 1, 0) slider = QSlider(Qt.Horizontal) slider.setMaximum(5) slider.setMinimum(1) slider.setTickInterval(1) slider.setTickPosition(QSlider.TicksBothSides) slider.setSingleStep(1) slider.valueChanged.connect(self.value_deal) grid.addWidget(slider, 1, 1) kind = QComboBox() for v in self.kinds: kind.addItem(v) kind.activated.connect(self.choosed) grid.addWidget(QLabel('类别:'), 2, 0) grid.addWidget(kind, 2, 1) button_show = QPushButton('显示') button_show.clicked.connect(self.show_image) config_box.setLayout(grid) v_box.addWidget(config_box) v_box.addWidget(button_show) self.setLayout(v_box) self.resize(10, 300) self.show()
def init_ui(self): vbox = QVBoxLayout() button1 = QPushButton('fuck1') vbox.addWidget(button1) button1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) vbox.setContentsMargins(80, 80, 80, 80) self.setLayout(vbox) machine = QStateMachine(self) s1 = QState() s1.assignProperty(button1, "text", "Outside") s2 = QState() s2.assignProperty(button1, "text", "Inside") enter_transition = QEventTransition(button1, QEvent.Enter) enter_transition.setTargetState(s2) s1.addTransition(enter_transition) leave_transition = QEventTransition(button1, QEvent.Leave) leave_transition.setTargetState(s1) s2.addTransition(leave_transition) s3 = QState() s3.assignProperty(button1, 'text', 'Pressing...') press_transition = QEventTransition(button1, QEvent.MouseButtonPress) press_transition.setTargetState(s3) s2.addTransition(press_transition) release_transition = QEventTransition(button1, QEvent.MouseButtonRelease) release_transition.setTargetState(s2) s3.addTransition(release_transition) machine.addState(s1) machine.addState(s2) machine.addState(s3) machine.setInitialState(s1) machine.start()
def __init__(self, secret_key, access_key, server_url, external_wallet_amount): super().__init__() self.fsm = QStateMachine() self.timerRequestOrderbook = QTimer() self.timerRequestAccountInfo = QTimer() self.currentTime = datetime.datetime.now() self.init() self.createState() self.upbitIf = UpbitWrapper.UpbitWrapper(secret_key, access_key, server_url, 'KRW-XRP') self.current_price = 0 self.current_ask_price = 0 self.current_bid_price = 0 self.external_wallet_amount = external_wallet_amount self.current_account_info = 0
def __init__(self): print('Стенд А3135') print('(c) ПКБ ЦТ, 2020') self.server = Server() self.form = MainForm(self.server) self.stm = QStateMachine() self.controller = Controller(server=self.server, form=self.form, stm=self.stm) self.controller.show_panel('меню') self.controller.text.setText('Hello') self.controller.show_menu('Главное меню') self.form.showMaximized() self.menu_state = MenuState(self.controller) self.stm.setInitialState(self.menu_state) self.stm.start()
def Home(self): self.items = [] for i in range(len(self.names['home'])): item = QPushButton(self) item.setText(self.names['home'][i]) item.setGeometry(395, 350, 120, 80) item.setStyleSheet( "QPushButton:hover{background-color:rgb(241, 90, 36);border:5px solid rgb(0, 97, 157);}\n" "QPushButton{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}QPushButton:pressed{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}\n" "") self.font.setPointSize(15) item.setFont(self.font) self.items.append(item) exec("""item.clicked.connect(partial(self.IND,i=%i))""" % (i)) self.rootState = QState() self.tiledState = QState(self.rootState) self.centeredState = QState(self.rootState) for i, item in enumerate(self.items): self.tiledState.assignProperty( item, 'pos', QPointF(((i % 6) * 5.3) * 30, ((i // 6) * 5.3) * 30)) self.centeredState.assignProperty(item, 'pos', QPointF()) self.states = QStateMachine() self.states.addState(self.rootState) self.states.setInitialState(self.rootState) self.rootState.setInitialState(self.centeredState) self.group = QParallelAnimationGroup() for i, item in enumerate(self.items): anim = QPropertyAnimation(item, b'pos') anim.setStartValue(QPoint(400, 300)) anim.setDuration(750 + i * 25) anim.setEasingCurve(QEasingCurve.InOutBack) self.group.addAnimation(anim) for u in self.items: trans = self.rootState.addTransition(u.clicked, self.tiledState) trans.addAnimation(self.group) self.states.start()
def init_log_sm(self): self.log_state = QStateMachine() pre_system = QState() pre_event = QState() post_event = QState() self.log_state.addState(pre_system) self.log_state.addState(pre_event) self.log_state.addState(post_event) self.log_state.setInitialState(pre_system) pre_system.assignProperty(self.events, "enabled", False) pre_system.assignProperty(self.compass, "enabled", False) pre_system.assignProperty(self.exact_angle, "enabled", False) pre_event.assignProperty(self.events, "enabled", True) pre_event.assignProperty(self.compass, "enabled", False) pre_event.assignProperty(self.exact_angle, "enabled", False) post_event.assignProperty(self.compass, "enabled", True) post_event.assignProperty(self.exact_angle, "enabled", True) pre_system.addTransition( self.systems.acted, pre_event ) pre_system.addTransition(self.timeout_timer.timeout, pre_system) pre_event.addTransition(self.timeout_timer.timeout, pre_system) post_event.addTransition(self.timeout_timer.timeout, pre_system) pre_event.addTransition( self.systems.acted, pre_event ) post_event.addTransition( self.systems.acted, pre_event ) post_event.addTransition( self.events.acted, post_event ) pre_event.addTransition( self.events.acted, post_event ) pre_system.entered.connect(self.events.switch_active) pre_system.entered.connect(self.systems.switch_active) pre_event.entered.connect(self.events.switch_active) post_event.exited.connect(self.compass.clear_state) post_event.exited.connect(lambda: self.exact_angle.log_angle(False)) self.log_state.setRunning(True)
def __init__(self, stickMan, keyReceiver): self.m_stickMan = stickMan self.m_keyReceiver = keyReceiver # Create animation group to be used for all transitions. self.m_animationGroup = QParallelAnimationGroup() stickManNodeCount = self.m_stickMan.nodeCount() self._pas = [] for i in range(stickManNodeCount): pa = QPropertyAnimation(self.m_stickMan.node(i), b'pos') self._pas.append(pa) self.m_animationGroup.addAnimation(pa) # Set up intial state graph. self.m_machine = QStateMachine() self.m_machine.addDefaultAnimation(self.m_animationGroup) self.m_alive = QState(self.m_machine) self.m_alive.setObjectName('alive') # Make it blink when lightning strikes before entering dead animation. lightningBlink = QState(self.m_machine) lightningBlink.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'penColor', Qt.black) lightningBlink.assignProperty(self.m_stickMan, 'fillColor', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'isDead', True) timer = QTimer(lightningBlink) timer.setSingleShot(True) timer.setInterval(100) lightningBlink.entered.connect(timer.start) lightningBlink.exited.connect(timer.stop) self.m_dead = QState(self.m_machine) self.m_dead.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.black) self.m_dead.assignProperty(self.m_stickMan, 'penColor', Qt.white) self.m_dead.assignProperty(self.m_stickMan, 'fillColor', Qt.black) self.m_dead.setObjectName('dead') # Idle state (sets no properties). self.m_idle = QState(self.m_alive) self.m_idle.setObjectName('idle') self.m_alive.setInitialState(self.m_idle) # Lightning strikes at random. self.m_alive.addTransition(LightningStrikesTransition(lightningBlink)) lightningBlink.addTransition(timer.timeout, self.m_dead) self.m_machine.setInitialState(self.m_alive)
def __init__(self): QWidget.__init__(self) style1 = "background-color: red" style2 = "background-color: black" animation = QPropertyAnimation(self, b'styleSheet') animation.setDuration(5) state1 = QState() state2 = QState() state1.assignProperty(self, 'styleSheet', style1) state2.assignProperty(self, 'styleSheet', style2) state1.addTransition(state1.propertiesAssigned, state2) state2.addTransition(state2.propertiesAssigned, state1) self.machine = QStateMachine() self.machine.addDefaultAnimation(animation) self.machine.addState(state1) self.machine.addState(state2) self.machine.setInitialState(state1) self.machine.start()
def __init__(self, parent=None): super().__init__(parent) self.setAttribute(Qt.WA_QuitOnClose) self.setAttribute(Qt.WA_DeleteOnClose) # create instance variables self._ui = uic.loadUi('mainwindow.ui', self) # create models self.measureModels = { 1: MeasureModel(self), 2: MeasureModel(self), } self._instrumentManager = InstrumentManager(self, self.measureModels) self.machine = QStateMachine() self.stateInitial = QState() self.stateReadyToCheck = QState() self.stateReadyToMeasure = QState() self.stateAfterMeasure = QState() self.initDialog()
def __init__(self): super().__init__() self.fsm = QStateMachine() self.qmlEngine = QQmlApplicationEngine() self.qmlEngine.addImportPath("qml") self.qmlEngine.addImportPath("lib") self.qmlEngine.load(QUrl('qrc:/qml/main.qml')) self.rootObject = self.qmlEngine.rootObjects()[0] self.rootObject.comPortOpened.connect(self.sigComPortOpened) self.rootObject.comPortClosed.connect(self.sigComPortClosed) self.rootObject.powerOn.connect(self.sigPowerOn) self.rootObject.powerOff.connect(self.sigPowerOff) self.createState() pass
def twoStateButton(name,stateMachine,action,*states): st = QStateMachine() a1,a2 = states s1,s2 = QState(),QState() icon1 = QIcon(Icons + a1[1]) icon2 = QIcon(Icons + a2[1]) s1.setObjectName(a1[0]) s2.setObjectName(a2[0]) s1.assignProperty(action, "icon", icon1) s2.assignProperty(action, "icon", icon2) s1.assignProperty(action, "text", a1[0]) s2.assignProperty(action, "text", a2[0]) s1.addTransition(action.triggered, s2) s2.addTransition(action.triggered, s1) st.addState(s1) st.addState(s2) st.setInitialState(s1) stateMachine[name] = st st.start()
def gen_output_widget(self): if self._name != "__none__": # Each output is a tuple [QPushButton, QStateMachine] self.output_widget = (QPushButton(), QStateMachine()) self.output_widget[0].setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create output states output_off = QState() output_on = QState() # Attach states to output button and define state transitions output_off.assignProperty(self.output_widget[0], 'text', "%s Output On" % self._name.split()[1]) output_off.addTransition(self.output_widget[0].clicked, output_on) output_off.entered.connect(self.exec_output_off) output_on.assignProperty(self.output_widget[0], 'text', '%s Output Off' % self._name.split()[1]) output_on.addTransition(self.output_widget[0].clicked, output_off) output_on.entered.connect(self.exec_output_on) # Add states, set initial state, and start machine self.output_widget[1].addState(output_off) self.output_widget[1].addState(output_on) self.output_widget[1].setInitialState(output_off) self.output_widget[1].start() else: self.output_widget = (QPushButton(), False) self.output_widget[0].setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) self.output_widget[0].setEnabled(False) self.output_widget[0].setText("Keithley not Initialized")
def __init__(self, parent): super(DrawLotteryView, self).__init__() self.pwindow = parent #获取父窗口指针 self.states = QStateMachine() sinitinfo = QState() sltypeinfo = QState() sprizeinfo = QState() svnumberwindow = QState() sdrawlottery = QState() sfinal = QState() sinitinfo.addTransition(self.on_nextstep_event, sltypeinfo) sltypeinfo.addTransition(self.on_nextstep_event, sprizeinfo) sprizeinfo.addTransition(self.on_nextstep_event, svnumberwindow) svnumberwindow.addTransition(self.on_nextstep_event, sdrawlottery) sdrawlottery.addTransition(self.on_nextstep_event, sfinal) sfinal.addTransition(self.on_final_event, sinitinfo) sinitinfo.entered.connect(self.initinfo) sltypeinfo.entered.connect(self.viewltypeinfo) sprizeinfo.entered.connect(self.viewprizeinfo) svnumberwindow.entered.connect(self.viewnumberwindow) sdrawlottery.entered.connect(self.drawlottery) sfinal.entered.connect(self.final) self.states.addState(sinitinfo) self.states.addState(sltypeinfo) self.states.addState(sprizeinfo) self.states.addState(svnumberwindow) self.states.addState(sdrawlottery) self.states.addState(sfinal) self.states.setInitialState(sinitinfo) self.states.start()
window.raise_() #tr = QScxmlSignalTransition(pb.clicked) scxml_machine = QScxml() scxml_machine.registerObject(pb, "pb") scxml_machine.registerObject(cb, "cb") scxml_machine.load("test144.scxml") #scxml_machine = QScxml.load("ExifMediaRename.scxml", ) scxml_machine.start() if 0: sm = QStateMachine() s1 = QState() s2 = QState() s2.entered.connect(toto) st = QSignalTransition(pb.clicked) st.setTargetState(s2) s1.addTransition(st) sm.addState(s1) sm.addState(s2) sm.setInitialState(s1) sm.start() sys.exit(app.exec_())
p4 = Pixmap(QPixmap(':/k3b.png')) p5 = Pixmap(QPixmap(':/help-browser.png')) p6 = Pixmap(QPixmap(':/kchart.png')) scene = QGraphicsScene(0, 0, 400, 300) scene.setBackgroundBrush(scene.palette().window()) scene.addItem(widget) scene.addItem(boxProxy) scene.addItem(p1) scene.addItem(p2) scene.addItem(p3) scene.addItem(p4) scene.addItem(p5) scene.addItem(p6) machine = QStateMachine() state1 = QState(machine) state2 = QState(machine) state3 = QState(machine) machine.setInitialState(state1) # State 1. state1.assignProperty(button, 'text', "Switch to state 2") state1.assignProperty(widget, 'geometry', QRectF(0, 0, 400, 150)) state1.assignProperty(box, 'geometry', QRect(-200, 150, 200, 150)) state1.assignProperty(p1, 'pos', QPointF(68, 185)) state1.assignProperty(p2, 'pos', QPointF(168, 185)) state1.assignProperty(p3, 'pos', QPointF(268, 185)) state1.assignProperty(p4, 'pos', QPointF(68 - 150, 48 - 150)) state1.assignProperty(p5, 'pos', QPointF(168, 48 - 150)) state1.assignProperty(p6, 'pos', QPointF(268 + 150, 48 - 150))
p4.setGeometry(QRectF(0.0, 236.0, 64.0, 64.0)) scene = QGraphicsScene(0, 0, 300, 300) scene.setBackgroundBrush(Qt.white) scene.addItem(p1) scene.addItem(p2) scene.addItem(p3) scene.addItem(p4) window = QGraphicsView(scene) window.setFrameStyle(0) window.setAlignment(Qt.AlignLeft | Qt.AlignTop) window.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) window.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) machine = QStateMachine() machine.setGlobalRestorePolicy(QStateMachine.RestoreProperties) group = QState(machine) selectedRect = QRect(86, 86, 128, 128) idleState = QState(group) group.setInitialState(idleState) objects = [p1, p2, p3, p4] createStates(objects, selectedRect, group) createAnimations(objects, machine) machine.setInitialState(group) machine.start()
class MissionPage(QWidget): mission_ended = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.record = -1 self.inspected = None self.oob_update = False prefs = QSettings() prefs.beginGroup("/General") timeout = prefs.value("/Timeout") dark_mode = prefs.value("/DarkMode") prefs.endGroup() # Instantiate core objects self.timeout_timer = QTimer() self.timeout_timer.setTimerType(Qt.VeryCoarseTimer) self.timeout_timer.setInterval(timeout * 1000) self.timeout_timer.setSingleShot(True) self.timeout_timer.timeout.connect(self.update_temp_log) self.systems = ActionsWidget(LogSource.SYSTEM) self.systems.acted.connect(self.log_item) self.events = ActionsWidget(LogSource.EVENT) self.events.acted.connect(self.log_item) self.compass = Compass() self.compass_widget = QWidget() compass_layout = QHBoxLayout() self.compass_widget.setLayout(compass_layout) compass_layout.addWidget(self.compass) self.compass.angle_event.connect(self.log_item) self.exact_angle = ExactAngle() self.exact_angle_widget = QWidget() exact_angle_layout = QHBoxLayout() self.exact_angle_widget.setLayout(exact_angle_layout) exact_angle_layout.addWidget(self.exact_angle) self.exact_angle.btn_event.connect(self.reset_timer) self.exact_angle.angle_event.connect(self.log_item) tab_widget = QTabWidget() tab_bar = tab_widget.tabBar() tab_bar.setFont(QFont('Consolas', 12, 3)) tab_widget.addTab(self.compass_widget, "Compass") tab_widget.addTab(self.exact_angle_widget, "Precise Angle") tab_widget.setStyleSheet(""" QTabWidget::pane { border-top: 2px solid #C2C7CB; } /* Style the tab using the tab sub-control. Note that it reads QTabBar _not_ QTabWidget */ QTabBar::tab { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E1E1E1, stop: 0.4 #DDDDDD, stop: 0.5 #D8D8D8, stop: 1.0 #D3D3D3); border: 2px solid #C4C4C3; border-bottom-color: #C2C7CB; /* same as the pane color */ border-top-left-radius: 4px; border-top-right-radius: 4px; min-width: 8ex; padding: 2px; color: black; } QTabBar::tab:selected, QTabBar::tab:hover { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #fafafa, stop: 0.4 #f4f4f4, stop: 0.5 #e7e7e7, stop: 1.0 #fafafa); } QTabBar::tab:selected { border-color: #ff0000; border-bottom-color: #C2C7CB; /* same as pane color */ } QTabBar::tab:!selected { margin-top: 2px; /* make non-selected tabs look smaller */ } """) header_layout = QHBoxLayout() self.zulu_time_label = QLabel() self.assessor_label = QLabel() self.date_label = QLabel() self.dl_label = QLabel() self.mnemonic_label = QLabel() header_layout.addWidget(self.zulu_time_label) header_layout.addWidget(self.assessor_label) header_layout.addWidget(self.date_label) header_layout.addWidget(self.dl_label) header_layout.addWidget(self.mnemonic_label) res = QApplication.primaryScreen().size() w, h = res.width(), res.height() if w > 1920 or h > 1080: hdr_font = QFont("Consolas", 16, 2) end_font = QFont("Consolas", 32, 5) else: hdr_font = QFont("Consolas", 14, 2) end_font = QFont("Consolas", 28, 5) for index in range(header_layout.count()): widget = header_layout.itemAt(index).widget() widget.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Maximum ) widget.setFont(hdr_font) widget.setAlignment(Qt.AlignCenter) # Setup logging state machine self.init_log_sm() # Setup splitters actions_splitter = QSplitter( Qt.Horizontal, frameShape=QFrame.StyledPanel, frameShadow=QFrame.Plain ) actions_splitter.addWidget(self.systems) actions_splitter.addWidget(self.events) actions_splitter.addWidget(tab_widget) actions_splitter.setChildrenCollapsible(False) main_splitter = QSplitter( Qt.Vertical, frameShape=QFrame.StyledPanel, frameShadow=QFrame.Plain ) self.log_area = QTableWidget(0, 3) self.log_area.cellDoubleClicked.connect(self.entry_inspected) self.log_area.cellChanged.connect(self.entry_changed) self.log_area.setHorizontalHeaderLabels( ["Time", "System", "Events"] ) self.log_area.horizontalHeader().setStretchLastSection(True) self.set_dark_mode(dark_mode) end_msn_btn = QPushButton("END\r\nMISSION") end_msn_btn.clicked.connect(self.end_mission) end_msn_btn.setFont(end_font) end_msn_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) end_msn_btn.setStyleSheet("background-color: red; color: white") bottom_layout = QGridLayout() bottom_widget = QWidget() bottom_widget.setLayout(bottom_layout) bottom_layout.addWidget(self.log_area, 0, 0, 1, 7) bottom_layout.addWidget(end_msn_btn, 0, 8, 1, 1) main_splitter.addWidget(actions_splitter) main_splitter.addWidget(bottom_widget) main_splitter.setChildrenCollapsible(False) handle_css = """ QSplitter::handle { background-image: url(:/imgs/dot_pattern.png); background-repeat: repeat-xy; background-color: none; border: 1px solid gray; } QSplitter::handle:pressed { background-image: url(:/imgs/pressed.png); } """ actions_splitter.setStyleSheet(handle_css) main_splitter.setStyleSheet(handle_css) # Finalize layout main_layout = QVBoxLayout() main_layout.addLayout(header_layout) main_layout.addWidget(main_splitter) self.setLayout(main_layout) def load_mission(self, config, timer, time, recovered=None): cfg_systems = [] cfg_events = [] for system in config['systems']: cfg_systems.append(system) for event in config['events']: cfg_events.append(event) self.systems.add_actions(cfg_systems) self.events.add_actions(cfg_events) self.timer = timer self.timer.timeout.connect(self.inc_time) self.time = time self.assessor = config['assessor'] self.assessor_label.setText("Assessor: " + self.assessor) self.date = config['date'] self.date_label.setText("Date: " + self.date) self.dl = config['dl'] self.dl_label.setText("Mission: DL-" + self.dl) self.mnemonic = config['mnemonic'] self.mnemonic_label.setText("Mnemonic: " + self.mnemonic) date = QDate.fromString(self.date, "dd/MM/yyyy").toString("yyyyMMdd") self.file_name = f"DL-{self.dl} {self.mnemonic} {date}" temp_path = Path(__file__).parents[1] / "temp" temp_cfg = temp_path / f"{self.file_name}.cfg" os.makedirs(os.path.dirname(temp_cfg), exist_ok=True) self.temp_log = temp_path / f"{self.file_name}.csv" os.makedirs(os.path.dirname(self.temp_log), exist_ok=True) if temp_cfg: with open(temp_cfg, 'w') as save_cfg_file: save_cfg_file.write(json.dumps(config)) else: QMessageBox.critical( self, "Error", f"Unable to load recovered config file: {temp_cfg}" ) return if recovered: self.recover_log(recovered) def recover_log(self, log): with open(log, 'r', newline='') as infile: reader = csv.reader(infile, delimiter=',') for row in reader: self.record = self.record + 1 self.log_area.insertRow(self.record) self.log_area.setItem( self.record, 0, QTableWidgetItem(row[0]) ) self.log_area.setItem( self.record, 1, QTableWidgetItem(row[1]) ) self.log_area.setItem( self.record, 2, QTableWidgetItem(row[2]) ) # TODO: This isn't working... self.log_area.scrollToBottom() @pyqtSlot() def inc_time(self): self.time = self.time.addSecs(1) self.zulu_time_label.setText( "Time: {} ZULU".format(self.time.toString("HH:mm:ss")) ) def init_log_sm(self): self.log_state = QStateMachine() pre_system = QState() pre_event = QState() post_event = QState() self.log_state.addState(pre_system) self.log_state.addState(pre_event) self.log_state.addState(post_event) self.log_state.setInitialState(pre_system) pre_system.assignProperty(self.events, "enabled", False) pre_system.assignProperty(self.compass, "enabled", False) pre_system.assignProperty(self.exact_angle, "enabled", False) pre_event.assignProperty(self.events, "enabled", True) pre_event.assignProperty(self.compass, "enabled", False) pre_event.assignProperty(self.exact_angle, "enabled", False) post_event.assignProperty(self.compass, "enabled", True) post_event.assignProperty(self.exact_angle, "enabled", True) pre_system.addTransition( self.systems.acted, pre_event ) pre_system.addTransition(self.timeout_timer.timeout, pre_system) pre_event.addTransition(self.timeout_timer.timeout, pre_system) post_event.addTransition(self.timeout_timer.timeout, pre_system) pre_event.addTransition( self.systems.acted, pre_event ) post_event.addTransition( self.systems.acted, pre_event ) post_event.addTransition( self.events.acted, post_event ) pre_event.addTransition( self.events.acted, post_event ) pre_system.entered.connect(self.events.switch_active) pre_system.entered.connect(self.systems.switch_active) pre_event.entered.connect(self.events.switch_active) post_event.exited.connect(self.compass.clear_state) post_event.exited.connect(lambda: self.exact_angle.log_angle(False)) self.log_state.setRunning(True) def log_system(self, system): self.record = self.record + 1 event_time = self.time.toString("HH:mm:ss") self.log_area.insertRow(self.record) self.log_area.setItem( self.record, 0, QTableWidgetItem(event_time) ) self.log_area.setItem( self.record, 1, QTableWidgetItem(system) ) self.log_area.setItem( self.record, 2, QTableWidgetItem("") ) self.log_area.scrollToBottom() def log_event(self, event): current = self.log_area.item(self.record, 2).text() if len(current) > 0: current = current + "; " current = current + event self.log_area.setItem( self.record, 2, QTableWidgetItem(current) ) def log_compass(self, range): current = self.log_area.item(self.record, 2).text() current = current + range self.log_area.setItem( self.record, 2, QTableWidgetItem(current) ) def log_angle(self, angle): current = self.log_area.item(self.record, 2).text() current = f"{current} at {angle}°" self.log_area.setItem( self.record, 2, QTableWidgetItem(current) ) @pyqtSlot(Angle) @pyqtSlot(int) def log_item(self, data): last_unlogged = self.timeout_timer.isActive() self.timeout_timer.start() src = self.sender() if type(src) is ActionsWidget: if self.exact_angle.has_valid(): if self.exact_angle.is_valid(): self.log_angle(self.exact_angle.calc_angle()) self.exact_angle.clear_state() if src.source is LogSource.SYSTEM: self.log_system(src.get_action(data)) if last_unlogged: self.update_temp_log() elif src.source is LogSource.EVENT: self.log_event(src.get_action(data)) elif type(src) is Compass: self.log_compass(Angle.to_string(data)) elif type(src) is ExactAngle: self.log_angle(str(data)) @pyqtSlot(int, int) def entry_inspected(self, row, col): self.inspected = row, col @pyqtSlot(int, int) def entry_changed(self, row, col): if (row, col) == self.inspected: if not self.timeout_timer.isActive(): self.update_temp_log(False) elif row == self.record - 1: self.oob_update = True def update_temp_log(self, append=True): if self.oob_update: append = False self.oob_update = False if self.temp_log: if append: with open(self.temp_log, 'a', newline='') as outfile: writer = csv.writer(outfile) rowdata = [] row = self.log_area.rowCount() - 1 for column in range(self.log_area.columnCount()): item = self.log_area.item(row, column) if item is not None: rowdata.append( item.text() ) else: rowdata.append('') writer.writerow(rowdata) else: with open(self.temp_log, 'w', newline='') as outfile: writer = csv.writer(outfile) for row in range(self.log_area.rowCount()): rowdata = [] for column in range(self.log_area.columnCount()): item = self.log_area.item(row, column) if item is not None: rowdata.append( item.text() ) else: rowdata.append('') writer.writerow(rowdata) def save_log(self): path, _ = QFileDialog.getSaveFileName( self, 'Save File', self.file_name, 'CSV(*.csv)' ) if path: with open(path, 'w', newline='') as outfile: writer = csv.writer(outfile) for row in range(self.log_area.rowCount()): rowdata = [] for column in range(self.log_area.columnCount()): item = self.log_area.item(row, column) if item is not None: rowdata.append( item.text() ) else: rowdata.append('') writer.writerow(rowdata) return True return False @pyqtSlot() def end_mission(self): quit_prompt = QMessageBox.question( self, "End mission?", "If you choose to end this mission, the time hack will end and logging will stop. Really end?" # noqa: E501 ) if quit_prompt == QMessageBox.Yes: if self.save_log(): QMessageBox.information( self, "Mission Ended", "Mission has been ended and your logs have been saved." ) temp_path = Path(__file__).parents[1] / "temp" log_files = [ file for file in temp_path.rglob("*.csv") if file.is_file() ] cfg_files = [ file for file in temp_path.rglob("*.cfg") if file.is_file() ] if log_files and cfg_files: try: for file in log_files + cfg_files: file.unlink() except OSError as e: QMessageBox.critical( self, "Error", f"Error encountered attempting to delete temp files: { e.strerror }" # noqa: E501 ) self.mission_ended.emit() @pyqtSlot() def reset_timer(self): self.timeout_timer.start() @pyqtSlot(int) def set_timeout(self, timeout): self.timeout_timer.setInterval(timeout * 1000) @pyqtSlot(QSize) def window_resized(self, size): self.events.resize(size.height()) self.systems.resize(size.height()) @pyqtSlot(int) def set_dark_mode(self, enable): if enable: self.log_area.setStyleSheet("QTableWidget::item { color: white }") else: self.log_area.setStyleSheet("QTableWidget::item { color: none }")
def __init__(self): super().__init__() self.ocx = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1") self.fsm = QStateMachine() self.createState()
class LifeCycle(object): def __init__(self, stickMan, keyReceiver): self.m_stickMan = stickMan self.m_keyReceiver = keyReceiver # Create animation group to be used for all transitions. self.m_animationGroup = QParallelAnimationGroup() stickManNodeCount = self.m_stickMan.nodeCount() self._pas = [] for i in range(stickManNodeCount): pa = QPropertyAnimation(self.m_stickMan.node(i), 'pos') self._pas.append(pa) self.m_animationGroup.addAnimation(pa) # Set up intial state graph. self.m_machine = QStateMachine() self.m_machine.addDefaultAnimation(self.m_animationGroup) self.m_alive = QState(self.m_machine) self.m_alive.setObjectName('alive') # Make it blink when lightning strikes before entering dead animation. lightningBlink = QState(self.m_machine) lightningBlink.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'penColor', Qt.black) lightningBlink.assignProperty(self.m_stickMan, 'fillColor', Qt.white) lightningBlink.assignProperty(self.m_stickMan, 'isDead', True) timer = QTimer(lightningBlink) timer.setSingleShot(True) timer.setInterval(100) lightningBlink.entered.connect(timer.start) lightningBlink.exited.connect(timer.stop) self.m_dead = QState(self.m_machine) self.m_dead.assignProperty(self.m_stickMan.scene(), 'backgroundBrush', Qt.black) self.m_dead.assignProperty(self.m_stickMan, 'penColor', Qt.white) self.m_dead.assignProperty(self.m_stickMan, 'fillColor', Qt.black) self.m_dead.setObjectName('dead') # Idle state (sets no properties). self.m_idle = QState(self.m_alive) self.m_idle.setObjectName('idle') self.m_alive.setInitialState(self.m_idle) # Lightning strikes at random. self.m_alive.addTransition(LightningStrikesTransition(lightningBlink)) lightningBlink.addTransition(timer.timeout, self.m_dead) self.m_machine.setInitialState(self.m_alive) def setDeathAnimation(self, fileName): deathAnimation = self.makeState(self.m_dead, fileName) self.m_dead.setInitialState(deathAnimation) def start(self): self.m_machine.start() def addActivity(self, fileName, key): state = self.makeState(self.m_alive, fileName) self.m_alive.addTransition( KeyPressTransition(self.m_keyReceiver, key, state)) def makeState(self, parentState, animationFileName): topLevel = QState(parentState) animation = Animation() file = QFile(animationFileName) if file.open(QIODevice.ReadOnly): animation.load(file) frameCount = animation.totalFrames() previousState = None for i in range(frameCount): animation.setCurrentFrame(i) frameState = QState(topLevel) nodeCount = animation.nodeCount() for j in range(nodeCount): frameState.assignProperty(self.m_stickMan.node(j), 'pos', animation.nodePos(j)) frameState.setObjectName('frame %d' % i) if previousState is None: topLevel.setInitialState(frameState) else: previousState.addTransition(previousState.propertiesAssigned, frameState) previousState = frameState previousState.addTransition(previousState.propertiesAssigned, topLevel.initialState()) return topLevel
button4.setZValue(3) scene = QGraphicsScene(0, 0, 300, 300) scene.setBackgroundBrush(Qt.black) scene.addItem(button1) scene.addItem(button2) scene.addItem(button3) scene.addItem(button4) window = QGraphicsView(scene) window.setFrameStyle(0) window.setAlignment(Qt.AlignLeft | Qt.AlignTop) window.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) window.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) machine = QStateMachine() group = QState() timer = QTimer() timer.setInterval(1250) timer.setSingleShot(True) group.entered.connect(timer.start) state1 = createGeometryState(button1, QRect(100, 0, 50, 50), button2, QRect(150, 0, 50, 50), button3, QRect(200, 0, 50, 50), button4, QRect(250, 0, 50, 50), group) state2 = createGeometryState(button1, QRect(250, 100, 50, 50), button2, QRect(250, 150, 50, 50), button3, QRect(250, 200, 50, 50), button4, QRect(250, 250, 50, 50), group)
class StartTuto(QDialog): def __init__(self): super(StartTuto, self).__init__() QDialog.__init__(self) self.Next = 0 self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground, True) self.setWindowTitle("لنتعلم معا") self.font = QFont('abdo salem') self.font.setPointSize(20) self.font.setBold(True) self.ex = QPushButton(self) self.ex.setFont(self.font) self.ex.setGeometry(400 + 80, 450, 150, 50) self.ex.setText('خروج') self.ex.setStyleSheet( "QPushButton:hover{background-color:rgb(241, 90, 36);border:5px solid rgb(0, 97, 157);}\n" "QPushButton{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}QPushButton:pressed{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}\n" "") self.ex.clicked.connect(self.Exit) self.hm = QPushButton(self) self.hm.setFont(self.font) self.hm.setGeometry(200 + 80, 450, 150, 50) self.hm.setText('الرئيسية') self.hm.setStyleSheet( "QPushButton:hover{background-color:rgb(241, 90, 36);border:5px solid rgb(0, 97, 157);}\n" "QPushButton{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}QPushButton:pressed{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}\n" "") self.hm.clicked.connect(self.home) self.resize(925, 500) self.Ind = [ 'data', 'if', 'for', 'while', 'def', 'class', 'oop', 'exp', 'prj2', 'prj3', 'st' ] self.names = { 'home': [ 'المتغير و\n أنواع البيانات', 'الجملة الشرطية\nIF', 'حلقة التقسيم\nFOR', 'حلقة مادام\nWHILE', 'الدالة\nDEF', 'الفئة\nClass', 'البرمجة كائنية\nالتوجه OOP', 'العبارات', 'المشروع الاول\nRANGE', 'المشروع الثاني\nStr', 'ابدء' ], 'data': [ 'المتغير', 'الأحرف ', 'الأرقام ', 'القائمة', 'القاموس', 'الخطأ\nالصحيح', 'دوال \nانواع البيانات', 'الأمثلة' ], 'if': [ 'الجملة الشرطية\nIF', 'ادوات المقارنة', 'استعمالات\n ELIF و ELSE' ], 'for': ['فكرة \nFOR', 'استعمالات \nFOR', 'امثلة'], 'while': ['فكرة \nWHILE', 'استعمالات \nWHILE', 'امثلة'], 'def': [ 'دالة بسيطة', 'arg\nدالة مع', '*arg\nدالة مع', 'دالة مع\n**kwargs' ], 'class': ['فئة بسيطة\n مع متغير', 'فئة بسيطة\n مع دالة'], 'oop': ['البناء\n__init__', 'خاصية الاراثة', 'دالة\nsuper()'], 'exp': ['عبارة\nreturn', 'عبارة\nassert', 'عبارة\nyield'], 'prj2': ['المشروع'], 'prj3': ['محاكات\nCount', 'محاكات\nFind', 'تطوير\nFind'], 'st': 'exit' } self.Home() def Home(self): self.items = [] for i in range(len(self.names['home'])): item = QPushButton(self) item.setText(self.names['home'][i]) item.setGeometry(395, 350, 120, 80) item.setStyleSheet( "QPushButton:hover{background-color:rgb(241, 90, 36);border:5px solid rgb(0, 97, 157);}\n" "QPushButton{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}QPushButton:pressed{color:white;background-color: rgb(50, 50, 50);border:5px solid rgb(255, 255, 255);}\n" "") self.font.setPointSize(15) item.setFont(self.font) self.items.append(item) exec("""item.clicked.connect(partial(self.IND,i=%i))""" % (i)) self.rootState = QState() self.tiledState = QState(self.rootState) self.centeredState = QState(self.rootState) for i, item in enumerate(self.items): self.tiledState.assignProperty( item, 'pos', QPointF(((i % 6) * 5.3) * 30, ((i // 6) * 5.3) * 30)) self.centeredState.assignProperty(item, 'pos', QPointF()) self.states = QStateMachine() self.states.addState(self.rootState) self.states.setInitialState(self.rootState) self.rootState.setInitialState(self.centeredState) self.group = QParallelAnimationGroup() for i, item in enumerate(self.items): anim = QPropertyAnimation(item, b'pos') anim.setStartValue(QPoint(400, 300)) anim.setDuration(750 + i * 25) anim.setEasingCurve(QEasingCurve.InOutBack) self.group.addAnimation(anim) for u in self.items: trans = self.rootState.addTransition(u.clicked, self.tiledState) trans.addAnimation(self.group) self.states.start() def Exit(self): open('Files/choice', 'w').write('exit') self.close() def home(self): open('Files/choice', 'w').write('home') self.close() def IND(self, i): open('Files/choice', 'a').write(str(i)) if self.Next != 2: self.Next += 1 if self.names[self.Ind[i]] != 'exit': a = self.names[self.Ind[i]] k = 0 for i in self.items[0:len(a)]: i.setText(a[k]) k += 1 for i in self.items[len(a):]: i.hide() else: self.items[-1].hide() else: self.close()
class UiState(QObject): sigComPortOpened = pyqtSignal() sigComPortClosed = pyqtSignal() sigPowerOn = pyqtSignal() sigPowerOff = pyqtSignal() def __init__(self): super().__init__() self.fsm = QStateMachine() self.qmlEngine = QQmlApplicationEngine() self.qmlEngine.addImportPath("qml") self.qmlEngine.addImportPath("lib") self.qmlEngine.load(QUrl('qrc:/qml/main.qml')) self.rootObject = self.qmlEngine.rootObjects()[0] self.rootObject.comPortOpened.connect(self.sigComPortOpened) self.rootObject.comPortClosed.connect(self.sigComPortClosed) self.rootObject.powerOn.connect(self.sigPowerOn) self.rootObject.powerOff.connect(self.sigPowerOff) self.createState() pass def createState(self): # state defintion mainState = QState(self.fsm) finalState = QFinalState(self.fsm) self.fsm.setInitialState(mainState) initState = QState(mainState) openState = QState(mainState) mainState.setInitialState(initState) standbyState = QState(openState) processingState = QState(openState) openState.setInitialState(standbyState) # transition defition initState.addTransition(self.sigComPortOpened, openState) openState.addTransition(self.sigComPortClosed, initState) standbyState.addTransition(self.sigPowerOn, processingState) processingState.addTransition(self.sigPowerOff, standbyState) initState.entered.connect(self.initStateEntered) openState.entered.connect(self.openStateEntered) standbyState.entered.connect(self.standbyStateEntered) processingState.entered.connect(self.processingStateEntered) # fsm start self.fsm.start() pass @pyqtSlot() def initStateEntered(self): print("init") QMetaObject.invokeMethod(self.rootObject, "setPathViewIndex", QtCore.Q_ARG("QVariant", 0)) pass @pyqtSlot() def openStateEntered(self): print("open") pass @pyqtSlot() def standbyStateEntered(self): print("standby") QMetaObject.invokeMethod(self.rootObject, "setPathViewIndex", QtCore.Q_ARG("QVariant", 1)) pass @pyqtSlot() def processingStateEntered(self): print("processing") QMetaObject.invokeMethod(self.rootObject, "setPathViewIndex",QtCore.Q_ARG("QVariant", 2)) pass
class DrawLotteryView(QObject): def __init__(self, parent): super(DrawLotteryView, self).__init__() self.pwindow = parent #获取父窗口指针 self.states = QStateMachine() sinitinfo = QState() sltypeinfo = QState() sprizeinfo = QState() svnumberwindow = QState() sdrawlottery = QState() sfinal = QState() sinitinfo.addTransition(self.on_nextstep_event, sltypeinfo) sltypeinfo.addTransition(self.on_nextstep_event, sprizeinfo) sprizeinfo.addTransition(self.on_nextstep_event, svnumberwindow) svnumberwindow.addTransition(self.on_nextstep_event, sdrawlottery) sdrawlottery.addTransition(self.on_nextstep_event, sfinal) sfinal.addTransition(self.on_final_event, sinitinfo) sinitinfo.entered.connect(self.initinfo) sltypeinfo.entered.connect(self.viewltypeinfo) sprizeinfo.entered.connect(self.viewprizeinfo) svnumberwindow.entered.connect(self.viewnumberwindow) sdrawlottery.entered.connect(self.drawlottery) sfinal.entered.connect(self.final) self.states.addState(sinitinfo) self.states.addState(sltypeinfo) self.states.addState(sprizeinfo) self.states.addState(svnumberwindow) self.states.addState(sdrawlottery) self.states.addState(sfinal) self.states.setInitialState(sinitinfo) self.states.start() def show(self): #It is IMPERATIVE that all forward slashes are scrubbed out, otherwise QTWebKit seems to be # easily confused # kickOffHTML = 'file:///' + join(dirname(__file__).replace('\\', '/'), "www/test02.html").replace('\\', '/') # kickOffHTML = 'file:///' + join(dirname(__file__).replace('\\', '/'), "www/test02.html").replace('\\', '/') kickOffHTML = 'file:///' + QDir().absolutePath() + SysConfig().getlotterywindowspath() + 'index.html' # kickOffHTML = 'http://get.webgl.org/' # kickOffHTML = 'http://www.airtightinteractive.com/demos/js/nebula/' #This is basically a browser instance # self.gweb = QGraphicsWebView() self.web = QWebView() self.web.setMinimumSize(1024,680) self.web.setWindowFlags(Qt.FramelessWindowHint) #无边框 self.web.setContextMenuPolicy(0) #关闭右键 #Unlikely to matter but prefer to be waiting for callback then try to catch # it in time. self.web.loadFinished.connect(self.onLoad) self.web.load(QUrl(kickOffHTML)) self.web.show() # self.scene = QGraphicsScene() # self.scene.addItem(self.gweb) # self.view = QGraphicsView() # self.view.setScene(self.scene) # self.view.show() def onLoad(self): #如果mywebinterface未初始化,则初始化mywebinterface # if getattr(self, "mywebinterface", False) == False: # self.mywebinterface = WebInterface() #This is the body of a web browser tab self.myPage = self.web.page() self.myPage.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True) self.myPage.settings().setAttribute(QWebSettings.JavascriptEnabled, True) self.myPage.settings().setAttribute(QWebSettings.WebGLEnabled, True) self.myPage.settings().setAttribute(QWebSettings.AcceleratedCompositingEnabled, True) #This is the actual context/frame a webpage is running in. # Other frames could include iframes or such. self.myFrame = self.myPage.mainFrame() # ATTENTION here's the magic that sets a bridge between Python to HTML self.myFrame.addToJavaScriptWindowObject("mywebinterface", self) #Tell the HTML side, we are open for business self.myFrame.evaluateJavaScript("ApplicationIsReady()") def initinfo(self): # print('initinfo') cltypes = self.pwindow.getcurrentqueue() if cltypes == None: self.isfinished = True else: self.isfinished = False self.currentltype = cltypes['ltype'] self.currentnumber = cltypes['number'] #当前奖项需要抽取的数量 self.drawcount = int(self.currentnumber) #当前抽奖序列的人数,需要重复抽奖的次数 self.isdrawing = False #当前是否为抽奖状态 @pyqtSlot() def nextstep(self): if self.isfinished: # print('close this window') self.on_message_event.emit('当前抽奖序列已抽取完毕!<br>按退出按钮退出!') else: if self.isdrawing and self.drawcount > 0: self.drawlottery() else: # print('nextstep') self.on_nextstep_event.emit() @pyqtSlot() def exitwindow(self): # print('exit window') self.web.close() def viewltypeinfo(self): # print('viewltypeinfo') self.on_viewltypeinfo_event.emit(self.currentltype, int(self.currentnumber)) def viewprizeinfo(self): # print('return prizeinfo') ls = SysConfig().getprizeitempicandnote(self.currentltype) icon = ls[0] notes = ls[1] self.on_viewprizeinfo_event.emit(icon, notes) def viewnumberwindow(self): # print('return viewnumberwindow') self.on_viewnumberwindow_event.emit() def drawlottery(self): # print('return drawlottery') progress = str(int(self.currentnumber)-self.drawcount+1) + '/' + self.currentnumber self.on_viewprogress_event.emit(progress) try: dl = DAllList().getwininfo() sid = dl[0][2] + dl[0][5] + dl[0][6] + dl[0][7] name = dl[1] DAllList().setwininfo(self.currentltype,dl[0]) except: sid = '0000' name = 'error, retry' self.drawcount = 0 self.isdrawing = False self.on_drawlottery_event.emit(sid, name) pass self.on_drawlottery_event.emit(sid, name) self.drawcount -= 1 if self.drawcount == 0: self.isdrawing = False else: self.isdrawing = True def final(self): print('final') self.on_final_event.emit() @pyqtSlot() def changesize(self): # print('changesize') if self.web.isFullScreen(): self.web.showNormal() else: self.web.showFullScreen() on_nextstep_event = pyqtSignal() on_viewltypeinfo_event = pyqtSignal(str, int) on_viewprizeinfo_event = pyqtSignal(str, str) on_viewluckguyinfo_event = pyqtSignal(str, str) on_viewnumberwindow_event = pyqtSignal() on_drawlottery_event = pyqtSignal(str, str) on_final_event = pyqtSignal() on_message_event = pyqtSignal(str) on_viewprogress_event = pyqtSignal(str) # app = QApplication(sys.argv) # # myWebApp = DrawLotteryView() # myWebApp.show() # # exit(app.exec_())
def __init__(self, earth, desk_geo, screen_geo, *args, **kwargs): """ Please see help(MainWindow) for more info. """ super(MainWindow, self).__init__(*args, **kwargs) # Instantiate KeyboardCommands class self.commands = KeyboardCommands() # Will hold hand_recognition QtCapture class self.capture = None # Will hold camera object for OpenCV self.camera = None # Will hold thread for issuing GE commands self.command_thread = None # Make Qt gesture icon window frameless self.setWindowFlags(QtCore.Qt.FramelessWindowHint) # Get resolution, window size, and offsets for positioning self.google_earth = earth # Variables for popup windows self.popup_window = None self.popup_title = "" self.popup_text = "" # Available screen geometry self.desktop = desk_geo # Total screen geometry self.screen = screen_geo # Sets gesture icon window to be 1/4 of available screen space self.qt_window_height = int(self.desktop.height() * 1 / 4) # Set geometry of Qt gesture icon window self.setGeometry( QtWidgets.QStyle.alignedRect( QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, QtCore.QSize(self.desktop.width(), self.qt_window_height), self.desktop)) # Create layouts for organizing Qt gesture icon window self.layout = QVBoxLayout() self.layout1 = QHBoxLayout() self.layout2 = QHBoxLayout() self.layout3 = QHBoxLayout() # Dictionary to hold labels once they are created self.label_dict = dict() # Lists hold gesture icon file names and gesture icon titles self.image_list = [ 'images/index_up.png', 'images/v_sign.png', 'images/thumb_left.png', 'images/thumb_right.png', 'images/fist.png', 'images/five_wide.png', 'images/palm.png', 'images/shaka.png' ] self.title_list = [ 'Move Up', 'Move Down', 'Move Left', 'Move Right', 'Zoom In', 'Zoom Out', 'Tilt Up', 'Tilt Down' ] # Create and add 6 labels containing hand gesture image to layout2 and 6 # labels with the gesture descriptions to layout1 for num in range(0, 8): # Each label is created to hold gesture icon image self.label = QLabel(self) # Pixmap is created with the current gesture icon image self.pixmap = QPixmap(self.image_list[num]) # Breakpoints to scale size of gesture icons for different resolutions if self.screen.width() >= 2560: self.pixmap = self.pixmap.scaledToWidth(225) elif self.screen.width() >= 1920: self.pixmap = self.pixmap.scaledToWidth(185) elif self.screen.width() > 1280 and self.screen.height() >= 1200: self.pixmap = self.pixmap.scaledToWidth(175) elif self.screen.width() > 800 and self.screen.height() >= 1024: self.pixmap = self.pixmap.scaledToWidth(125) elif self.screen.width() > 800: self.pixmap = self.pixmap.scaledToWidth(100) else: self.pixmap = self.pixmap.scaledToWidth(50) # Assigns gesture icon image to the current label self.label.setPixmap(self.pixmap) # Create gesture title label for the image self.label_title = QLabel(self.title_list[num]) # Store current icon image label in dictionary self.label_dict[num] = self.label # Place current icon image label in layout self.layout2.addWidget(self.label_dict[num], alignment=QtCore.Qt.AlignCenter) # Place current icon image title label in layout self.layout1.addWidget(self.label_title, alignment=QtCore.Qt.AlignCenter) # Create state machine to reliably handle state changes during threading self.state_machine = QStateMachine() # Create button to handle state changes when pressed self.state_button = QPushButton(self) self.state_button.setStyleSheet("background-color: silver") # Connect button released signal to check_state slot self.state_button.released.connect(self.check_state) # Create on state for state machine self.on = QState() # Create off state for state machine self.off = QState() # Add transition for on state to off state when offSignal is emitted self.on.addTransition(self.offSignal, self.off) # Add transition for on state to on state when state_button clicked signal emitted self.on.addTransition(self.state_button.clicked, self.on) # Add transition for off state to on state when onSignal is emitted self.off.addTransition(self.onSignal, self.on) # Assign text property to state_button in on state self.on.assignProperty(self.state_button, "text", "Start Gesture Navigation") # Assign text property to state_button in off state self.off.assignProperty(self.state_button, "text", "Stop Gesture Navigation") # Add off state to state machine self.state_machine.addState(self.off) # Add on state to state machine self.state_machine.addState(self.on) # Set state machine initial state to on self.state_machine.setInitialState(self.on) # State state machine self.state_machine.start() # Create gesture tips button and connect it to start_gesture_tips slot self.tips_button = QPushButton("Gesture Navigation Tips") self.tips_button.setStyleSheet("background-color: silver") self.tips_button.pressed.connect(self.start_gesture_tips) # Create exit button and connect it to exit slot self.exit_button = QPushButton("Exit Program") self.exit_button.setStyleSheet("background-color: silver") self.exit_button.pressed.connect(self.exit) # Add tips, state, and exit button to layout 3 self.layout3.addWidget(self.tips_button) self.layout3.addWidget(self.state_button) self.layout3.addWidget(self.exit_button) # Add layout 1, 2, and 3 to layout self.layout.addLayout(self.layout1) self.layout.addLayout(self.layout2) self.layout.addLayout(self.layout3) # Create widget to hold layout, add layout to widget self.widget = QWidget() self.widget.setLayout(self.layout) # Set widget with layouts as central widget self.setCentralWidget(self.widget)
class MainWindow(QMainWindow): """ This is a class that creates a PyQt5 window containing start, stop, and exit buttons as well as gesture icons. The window is the main window for our program. Attributes: commands: KeyboardCommand class object capture: QtCapture class object camera: OpenCV camera object command_thread: CommandThread class object google_earth: GoogleEarth class object popup_window: QMessageBox object popup_title (string) : Pop up window title popup_text (string) : Pop up window body text desktop : Available screen geometry based on current screen resolution screen : Total screen geometry based on current screen resolution qt_window_height (int) : Calculated value for gesture icon window size layout : Instantiate QVBoxLayout or QHBoxLayout classes, used for aligning images and buttons label_dict (dict) : Contains labels that are used to display gesture icon images image_list (list) : Contains names of image files for gesture icon images title_list (list) : Contains names of titles for corresponding gesture images state_machine: Instantiate QStateMachine class, used to control state of program buttons label : Instantiate QLabel class, labels used to hold gesture icon images and text button : Instantiate QPushButton class, buttons used to start, stop, and exit program widget : Insantiate QWidget class, contains and displays labels and buttons Args: earth : GoogleEarth class object desk_geo: Available screen geometry screen_geo: Total screen geometry """ # Signals for updating state of state machine onSignal = pyqtSignal() offSignal = pyqtSignal() def __init__(self, earth, desk_geo, screen_geo, *args, **kwargs): """ Please see help(MainWindow) for more info. """ super(MainWindow, self).__init__(*args, **kwargs) # Instantiate KeyboardCommands class self.commands = KeyboardCommands() # Will hold hand_recognition QtCapture class self.capture = None # Will hold camera object for OpenCV self.camera = None # Will hold thread for issuing GE commands self.command_thread = None # Make Qt gesture icon window frameless self.setWindowFlags(QtCore.Qt.FramelessWindowHint) # Get resolution, window size, and offsets for positioning self.google_earth = earth # Variables for popup windows self.popup_window = None self.popup_title = "" self.popup_text = "" # Available screen geometry self.desktop = desk_geo # Total screen geometry self.screen = screen_geo # Sets gesture icon window to be 1/4 of available screen space self.qt_window_height = int(self.desktop.height() * 1 / 4) # Set geometry of Qt gesture icon window self.setGeometry( QtWidgets.QStyle.alignedRect( QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter, QtCore.QSize(self.desktop.width(), self.qt_window_height), self.desktop)) # Create layouts for organizing Qt gesture icon window self.layout = QVBoxLayout() self.layout1 = QHBoxLayout() self.layout2 = QHBoxLayout() self.layout3 = QHBoxLayout() # Dictionary to hold labels once they are created self.label_dict = dict() # Lists hold gesture icon file names and gesture icon titles self.image_list = [ 'images/index_up.png', 'images/v_sign.png', 'images/thumb_left.png', 'images/thumb_right.png', 'images/fist.png', 'images/five_wide.png', 'images/palm.png', 'images/shaka.png' ] self.title_list = [ 'Move Up', 'Move Down', 'Move Left', 'Move Right', 'Zoom In', 'Zoom Out', 'Tilt Up', 'Tilt Down' ] # Create and add 6 labels containing hand gesture image to layout2 and 6 # labels with the gesture descriptions to layout1 for num in range(0, 8): # Each label is created to hold gesture icon image self.label = QLabel(self) # Pixmap is created with the current gesture icon image self.pixmap = QPixmap(self.image_list[num]) # Breakpoints to scale size of gesture icons for different resolutions if self.screen.width() >= 2560: self.pixmap = self.pixmap.scaledToWidth(225) elif self.screen.width() >= 1920: self.pixmap = self.pixmap.scaledToWidth(185) elif self.screen.width() > 1280 and self.screen.height() >= 1200: self.pixmap = self.pixmap.scaledToWidth(175) elif self.screen.width() > 800 and self.screen.height() >= 1024: self.pixmap = self.pixmap.scaledToWidth(125) elif self.screen.width() > 800: self.pixmap = self.pixmap.scaledToWidth(100) else: self.pixmap = self.pixmap.scaledToWidth(50) # Assigns gesture icon image to the current label self.label.setPixmap(self.pixmap) # Create gesture title label for the image self.label_title = QLabel(self.title_list[num]) # Store current icon image label in dictionary self.label_dict[num] = self.label # Place current icon image label in layout self.layout2.addWidget(self.label_dict[num], alignment=QtCore.Qt.AlignCenter) # Place current icon image title label in layout self.layout1.addWidget(self.label_title, alignment=QtCore.Qt.AlignCenter) # Create state machine to reliably handle state changes during threading self.state_machine = QStateMachine() # Create button to handle state changes when pressed self.state_button = QPushButton(self) self.state_button.setStyleSheet("background-color: silver") # Connect button released signal to check_state slot self.state_button.released.connect(self.check_state) # Create on state for state machine self.on = QState() # Create off state for state machine self.off = QState() # Add transition for on state to off state when offSignal is emitted self.on.addTransition(self.offSignal, self.off) # Add transition for on state to on state when state_button clicked signal emitted self.on.addTransition(self.state_button.clicked, self.on) # Add transition for off state to on state when onSignal is emitted self.off.addTransition(self.onSignal, self.on) # Assign text property to state_button in on state self.on.assignProperty(self.state_button, "text", "Start Gesture Navigation") # Assign text property to state_button in off state self.off.assignProperty(self.state_button, "text", "Stop Gesture Navigation") # Add off state to state machine self.state_machine.addState(self.off) # Add on state to state machine self.state_machine.addState(self.on) # Set state machine initial state to on self.state_machine.setInitialState(self.on) # State state machine self.state_machine.start() # Create gesture tips button and connect it to start_gesture_tips slot self.tips_button = QPushButton("Gesture Navigation Tips") self.tips_button.setStyleSheet("background-color: silver") self.tips_button.pressed.connect(self.start_gesture_tips) # Create exit button and connect it to exit slot self.exit_button = QPushButton("Exit Program") self.exit_button.setStyleSheet("background-color: silver") self.exit_button.pressed.connect(self.exit) # Add tips, state, and exit button to layout 3 self.layout3.addWidget(self.tips_button) self.layout3.addWidget(self.state_button) self.layout3.addWidget(self.exit_button) # Add layout 1, 2, and 3 to layout self.layout.addLayout(self.layout1) self.layout.addLayout(self.layout2) self.layout.addLayout(self.layout3) # Create widget to hold layout, add layout to widget self.widget = QWidget() self.widget.setLayout(self.layout) # Set widget with layouts as central widget self.setCentralWidget(self.widget) # Function to display pop up windows and block GUI loop until closed def show_popup(self, title, message, icon): """ Function to create a pop up window that blocks the event loop until it is closed. Used to send info or warning messages. Parameters: title (string) : Title of pop up window message (string) : Body text of pop up window icon : QMessageBox icon to be displayed """ # Create QMessageBox for pop up message self.popup_window = QMessageBox() # Set pop up title to passed in title self.popup_window.setWindowTitle(title) # Set pop up body text to passed in message self.popup_window.setText(message) # Set pop up icon to passed in icon self.popup_window.setIcon(icon) # Set pop up window to use Ok close button self.popup_window.setStandardButtons(QMessageBox.Ok) # Execute pop up window so that it blocks GUI loop until closed self.popup_window.exec() # Check state of state machine, take actions based on current state def check_state(self): """ Function to check the current state of the state machine. Calls check_earth_tips if in on state, calls stop_opencv if in off state. """ current_state = self.state_machine.configuration() if self.on in current_state: self.check_earth_tips() elif self.off in current_state: self.stop_opencv() def start_gesture_tips(self): """ Function to create PyHand Earth gesture navigation tips window. """ # Sets title of pop up window self.popup_title = "Welcome to PyHand Earth!" # Sets body text of pop up window self.popup_text = """\nThis program allows you to navigate the Google Earth Pro desktop application using only your Webcam and eight hand gestures. \n\t Instructions and Tips \n\nFor the best experience, please read the instructions below and then close this window: \n\n1. Position your webcam so that you have a blank, light-colored background behind you. \n\n2. Position your right hand and desired gesture in front of the webcam so that it fills a good portion of the orange bounding rectangle in the live video window once it opens. \n\n3. If the prediction is stuck on the wrong gesture, just shake your hand a little and let it reset. \n\n4. If you remove your hand completely and have a blank background, navigation should halt. \n\n5. Happy navigating! """ # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Information) def check_earth_tips(self): """ Called by check_state when state machine is in on state. Checks to see if Google Earth Start-up Tips window is open, and asks user to close the window with a pop up window message. If Google Earth Start-up Tips window is closed, calls open_camera. """ # Checks if Google Earth start-up tips window is open if self.google_earth.start_up_tips(): # Sets title of pop up window self.popup_title = "Gesture Navigation Warning Message" # Sets body text of pop up window self.popup_text = "Please make sure the Start-up Tips window is closed before " + \ "starting gesture navigation" # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Warning) else: # If Google Earth start-up tips window now open, calls open_camera self.open_camera() def open_camera(self): """ Function to create OpenCV VideoCapture object. If camera is not found, creates pop up window message to warn user and ask them to connect a camera. If camera is found, calls start_opencv. """ # Creates cv2 VideoCapture object, passing in -1 to find first active camera self.camera = cv2.VideoCapture(-1) # If camera is not found, create pop up window to warn the user if self.camera is None or not self.camera.isOpened(): # Sets title of pop up window self.popup_title = "No Camera Found Warning Message" # Sets body text of pop up window self.popup_text = "No camera has been detected. \n\nPlease connect a camera before " + \ "starting gesture navigation.\n" # Calls show_popup to create pop up window self.show_popup(self.popup_title, self.popup_text, QMessageBox.Warning) else: # If camera is found, calls start_opencv self.start_opencv() def start_opencv(self): """ Function to start the OpenCV gesture navigation window. Repositions the Google Earth window to take up half of the screen, then calls create_opencv to instantiate QtCapture window. The CommandThread class object is then instantiated to begin sending commands generated in the CaptureThread class to Google Earth. The QtCapture window is then displayed. Finally, the offSignal is emitted to change the state machine to the off state and the tips_button is disabled to prevent tips from being shown while gesture navigation is active. """ # Repositions Google Earth to take up one half of the available screen size self.google_earth.reposition_earth_small() # If opencv window not created, create it if not self.capture: self.create_opencv() else: self.capture = None self.create_opencv() # If command thread exists, remove it if self.command_thread: self.command_thread = None # Start command thread for sending commands to GE self.command_thread = CommandThread(self.capture, self.commands) self.command_thread.start() # Show opencv window self.capture.show() # Emits offSignal to ensure button in correct state self.offSignal.emit() # Disable tips button while gesture navigation is active self.tips_button.setEnabled(False) def create_opencv(self): """ Creates QtCapture window to display the OpenCV window frames. Resizes and repositions the QtCapture window based on current monitor resolution. """ # Create QtCapture window for rendering opencv window self.capture = QtCapture(self.desktop, self.screen, self.camera) self.capture.setParent(self.widget) self.capture.setWindowFlags(QtCore.Qt.Tool) self.capture.setWindowTitle("OpenCV Recording Window") # Get new height based on available screen space minus an offset for the window title new_height = int((self.desktop.height() * 3 / 4) - 35) # Get width that is half of the available screen space half_width = int(self.desktop.width() / 2) # Breakpoints to resize and reposition QtCapture window based on current monitor resolution if self.screen.width() > 1280: window_x = int(self.desktop.width() / 2) + (self.screen.width() - self.desktop.width()) self.capture.setGeometry(window_x, 0, half_width, new_height) elif self.screen.width() > 1152: new_width = int((self.desktop.width() * 29 / 64) + 3) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) elif self.screen.width() > 1024: new_width = int((self.desktop.width() * 25 / 64)) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) else: new_width = int((self.desktop.width() * 20 / 64) - 3) window_x = int(half_width + (half_width - new_width) + (self.screen.width() - self.desktop.width())) self.capture.setGeometry(window_x, 0, new_width, new_height) def stop_opencv(self): """ Function to close the QtCapture OpenCV window and stop commands being sent to Google Earth. """ # Sends request to end the Google Earth command thread self.command_thread.end_thread() time.sleep(1) # If capture object exists, end thread, release camera, and close window if self.capture: self.capture.stop_thread() time.sleep(1) self.capture.delete() self.capture.setParent(None) # Repositions Google Earth to take up full width of available screen space self.google_earth.reposition_earth_large() # Emits onSignal to ensure button in correct state self.onSignal.emit() # Enable tips when gesture navigation is not active self.tips_button.setEnabled(True) def exit(self): """ Slot function for exit button signal. Stops commands being sent to Google Earth, ends the OpenCV window thread if running, closes Google Earth, and exits the Qt application. """ # If the command thread is running, request thread end if self.command_thread: self.command_thread.end_thread() time.sleep(1) # If the capture thread is running, request thread end if self.capture: self.capture.stop_thread() time.sleep(1) # Close the Google Earth window self.google_earth.close_earth() # Quit the Qt application, returning to main QtCore.QCoreApplication.instance().quit()
def gen_mpp_ctrl(self): ################################# # mpp tracking controls # self.mpp_ctrl = QWidget() self.mpp_ctrl_layout = QVBoxLayout() # Create QStateMachine for output state self.mpp_state = QStateMachine() self.mpp_meas_button = QPushButton() self.mpp_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create output states self.mpp_meas_off = QState() self.mpp_meas_on = QState() # Attach states to output button and define state transitions self.mpp_meas_off.assignProperty(self.mpp_meas_button, 'text', 'MPP Monitor Off') self.mpp_meas_off.addTransition(self.mpp_meas_button.clicked, self.mpp_meas_on) self.mpp_meas_off.entered.connect(self.exec_mpp_stop) self.mpp_meas_on.assignProperty(self.mpp_meas_button, 'text', 'MPP Monitor On') self.mpp_meas_on.addTransition(self.mpp_meas_button.clicked, self.mpp_meas_off) self.mpp_meas_on.entered.connect(self.exec_mpp_run) # Add states, set initial state, and start machine self.mpp_state.addState(self.mpp_meas_off) self.mpp_state.addState(self.mpp_meas_on) self.mpp_state.setInitialState(self.mpp_meas_off) self.mpp_state.start() # Tracking mode initialization # Note this example of passing arguments to a callback self.mpp_bias_config = { "unit": "V", "min": "m", "max": "", "label": "MPP Initialization (V)", "limit": 2.0, "signed": True, "default": [0.30, ""] } self.mpp_bias = QVisaUnitSelector.QVisaUnitSelector( self.mpp_bias_config) self.mpp_bias.unit_value.valueChanged.connect( lambda arg=self.mpp_bias.value(): self.update_bias(arg)) # Compliance Spinbox self.mpp_cmpl_config = { "unit": "A", "min": "u", "max": "", "label": "Compliance (A)", "limit": 1.0, "signed": False, "default": [100, "m"] } self.mpp_cmpl = QVisaUnitSelector.QVisaUnitSelector( self.mpp_cmpl_config) # Tracking mode convergence self.mpp_ampl_config = { "unit": "V", "min": "u", "max": "m", "label": "Sense amplitude (mV)", "limit": 100, "signed": False, "default": [20.0, "m"] } self.mpp_ampl = QVisaUnitSelector.QVisaUnitSelector( self.mpp_ampl_config) # Delay self.mpp_gain_config = { "unit": "__DOUBLE__", "label": html.unescape("Proportional Gain (‰)"), "limit": 1000, "signed": False, "default": [30.0] } self.mpp_gain = QVisaUnitSelector.QVisaUnitSelector( self.mpp_gain_config) # Delay self.mpp_delay_config = { "unit": "__DOUBLE__", "label": "Measurement Interval (s)", "limit": 60.0, "signed": False, "default": [0.1] } self.mpp_delay = QVisaUnitSelector.QVisaUnitSelector( self.mpp_delay_config) # Add mpp widgets to layout self.mpp_ctrl_layout.addWidget(self.mpp_meas_button) self.mpp_ctrl_layout.addWidget(self.mpp_bias) self.mpp_ctrl_layout.addWidget(self.mpp_cmpl) self.mpp_ctrl_layout.addWidget(self.mpp_ampl) self.mpp_ctrl_layout.addWidget(self.mpp_gain) self.mpp_ctrl_layout.addWidget(self.mpp_delay) self.mpp_ctrl_layout.setContentsMargins(0, 0, 0, 0) # Set widget layout self.mpp_ctrl.setLayout(self.mpp_ctrl_layout)
class Me(QWidget): def __init__(self, path): super().__init__() self.kinds = [ 'INTER_NEAREST', 'INTER_LINEAR', 'INTER_CUBIC', 'INTER_AREA', 'INTER_LANCZOS4', 'INTER_LINEAR_EXACT', 'INTER_MAX', 'WARP_FILL_OUTLIERS', 'WARP_INVERSE_MAP' ] self.kinds_value = [] self.path = path self.h_x = 1 self.v_y = 1 self.kind = 0 self.my_ui() def my_ui(self): v_box = QVBoxLayout() config_box = QGroupBox('配置') grid = QGridLayout() label_one = QLabel('当前状态') self.choose_button = QPushButton() self.machine = QStateMachine() zoom_state = QState(self.machine) shrink_state = QState(self.machine) self.machine.setInitialState(zoom_state) zoom_state.assignProperty(self.choose_button, 'text', '放大') shrink_state.assignProperty(self.choose_button, 'text', '缩小') shrink_state.addTransition(self.choose_button.clicked, zoom_state) zoom_state.addTransition(self.choose_button.clicked, shrink_state) self.machine.start() grid.addWidget(label_one, 0, 0) grid.addWidget(self.choose_button, 0, 1) grid.addWidget(QLabel('倍数'), 1, 0) slider = QSlider(Qt.Horizontal) slider.setMaximum(5) slider.setMinimum(1) slider.setTickInterval(1) slider.setTickPosition(QSlider.TicksBothSides) slider.setSingleStep(1) slider.valueChanged.connect(self.value_deal) grid.addWidget(slider, 1, 1) kind = QComboBox() for v in self.kinds: kind.addItem(v) kind.activated.connect(self.choosed) grid.addWidget(QLabel('类别:'), 2, 0) grid.addWidget(kind, 2, 1) button_show = QPushButton('显示') button_show.clicked.connect(self.show_image) config_box.setLayout(grid) v_box.addWidget(config_box) v_box.addWidget(button_show) self.setLayout(v_box) self.resize(10, 300) self.show() def choosed(self, x): self.kind = x pass def value_deal(self, x): self.h_x = x self.v_y = x print(self.choose_button.text()) text = self.choose_button.text() pass def show_image(self): if text == '放大': pass else: self.h_x = 1 / self.h_x self.v_y = 1 / self.v_y origin_img = cv.imread(self.path, cv.IMREAD_COLOR) res_img = cv.resize(origin_img, None, fx=self.h_x, fy=self.v_y, interpolation=self.kind) # my_utility.custom_show(origin_img, [1,2,1]) # my_utility.custom_show(res_img, [1,2,2]) # my_utility.plt.show() names = ['origin_image.png', 'res_image.png'] images = [origin_img, res_img] my_utility.custom_show_opencv(names, images) print('origin shape', origin_img.shape) print('res shape', res_img.shape) pass
def __init__(self, size, parent=None): super(PadNavigator, self).__init__(parent) self.form = Ui_Form() splash = SplashItem() splash.setZValue(1) pad = FlippablePad(size) flipRotation = QGraphicsRotation(pad) xRotation = QGraphicsRotation(pad) yRotation = QGraphicsRotation(pad) flipRotation.setAxis(Qt.YAxis) xRotation.setAxis(Qt.YAxis) yRotation.setAxis(Qt.XAxis) pad.setTransformations([flipRotation, xRotation, yRotation]) backItem = QGraphicsProxyWidget(pad) widget = QWidget() self.form.setupUi(widget) self.form.hostName.setFocus() backItem.setWidget(widget) backItem.setVisible(False) backItem.setFocus() backItem.setCacheMode(QGraphicsItem.ItemCoordinateCache) r = backItem.rect() backItem.setTransform(QTransform().rotate(180, Qt.YAxis).translate( -r.width() / 2, -r.height() / 2)) selectionItem = RoundRectItem(QRectF(-60, -60, 120, 120), QColor(Qt.gray), pad) selectionItem.setZValue(0.5) smoothSplashMove = QPropertyAnimation(splash) smoothSplashOpacity = QPropertyAnimation(splash) smoothSplashMove.setEasingCurve(QEasingCurve.InQuad) smoothSplashMove.setDuration(250) smoothSplashOpacity.setDuration(250) smoothXSelection = QPropertyAnimation(selectionItem) smoothYSelection = QPropertyAnimation(selectionItem) smoothXRotation = QPropertyAnimation(xRotation) smoothYRotation = QPropertyAnimation(yRotation) smoothXSelection.setDuration(125) smoothYSelection.setDuration(125) smoothXRotation.setDuration(125) smoothYRotation.setDuration(125) smoothXSelection.setEasingCurve(QEasingCurve.InOutQuad) smoothYSelection.setEasingCurve(QEasingCurve.InOutQuad) smoothXRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothYRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipRotation = QPropertyAnimation(flipRotation) smoothFlipScale = QPropertyAnimation(pad) smoothFlipXRotation = QPropertyAnimation(xRotation) smoothFlipYRotation = QPropertyAnimation(yRotation) flipAnimation = QParallelAnimationGroup(self) smoothFlipScale.setDuration(500) smoothFlipRotation.setDuration(500) smoothFlipXRotation.setDuration(500) smoothFlipYRotation.setDuration(500) smoothFlipScale.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipXRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipYRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipScale.setKeyValueAt(0, 1.0) smoothFlipScale.setKeyValueAt(0.5, 0.7) smoothFlipScale.setKeyValueAt(1, 1.0) flipAnimation.addAnimation(smoothFlipRotation) flipAnimation.addAnimation(smoothFlipScale) flipAnimation.addAnimation(smoothFlipXRotation) flipAnimation.addAnimation(smoothFlipYRotation) setVariablesSequence = QSequentialAnimationGroup() setFillAnimation = QPropertyAnimation(pad) setBackItemVisibleAnimation = QPropertyAnimation(backItem) setSelectionItemVisibleAnimation = QPropertyAnimation(selectionItem) setFillAnimation.setDuration(0) setBackItemVisibleAnimation.setDuration(0) setSelectionItemVisibleAnimation.setDuration(0) setVariablesSequence.addPause(250) setVariablesSequence.addAnimation(setBackItemVisibleAnimation) setVariablesSequence.addAnimation(setSelectionItemVisibleAnimation) setVariablesSequence.addAnimation(setFillAnimation) flipAnimation.addAnimation(setVariablesSequence) stateMachine = QStateMachine(self) splashState = QState(stateMachine) frontState = QState(stateMachine) historyState = QHistoryState(frontState) backState = QState(stateMachine) frontState.assignProperty(pad, "fill", False) frontState.assignProperty(splash, "opacity", 0.0) frontState.assignProperty(backItem, "visible", False) frontState.assignProperty(flipRotation, "angle", 0.0) frontState.assignProperty(selectionItem, "visible", True) backState.assignProperty(pad, "fill", True) backState.assignProperty(backItem, "visible", True) backState.assignProperty(xRotation, "angle", 0.0) backState.assignProperty(yRotation, "angle", 0.0) backState.assignProperty(flipRotation, "angle", 180.0) backState.assignProperty(selectionItem, "visible", False) stateMachine.addDefaultAnimation(smoothXRotation) stateMachine.addDefaultAnimation(smoothYRotation) stateMachine.addDefaultAnimation(smoothXSelection) stateMachine.addDefaultAnimation(smoothYSelection) stateMachine.setInitialState(splashState) anyKeyTransition = QEventTransition(self, QEvent.KeyPress, splashState) anyKeyTransition.setTargetState(frontState) anyKeyTransition.addAnimation(smoothSplashMove) anyKeyTransition.addAnimation(smoothSplashOpacity) enterTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Enter, backState) returnTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Return, backState) backEnterTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Enter, frontState) backReturnTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Return, frontState) enterTransition.setTargetState(historyState) returnTransition.setTargetState(historyState) backEnterTransition.setTargetState(backState) backReturnTransition.setTargetState(backState) enterTransition.addAnimation(flipAnimation) returnTransition.addAnimation(flipAnimation) backEnterTransition.addAnimation(flipAnimation) backReturnTransition.addAnimation(flipAnimation) columns = size.width() rows = size.height() stateGrid = [] for y in range(rows): stateGrid.append([QState(frontState) for _ in range(columns)]) frontState.setInitialState(stateGrid[0][0]) selectionItem.setPos(pad.iconAt(0, 0).pos()) for y in range(rows): for x in range(columns): state = stateGrid[y][x] rightTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Right, state) leftTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Left, state) downTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Down, state) upTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Up, state) rightTransition.setTargetState(stateGrid[y][(x + 1) % columns]) leftTransition.setTargetState( stateGrid[y][((x - 1) + columns) % columns]) downTransition.setTargetState(stateGrid[(y + 1) % rows][x]) upTransition.setTargetState(stateGrid[((y - 1) + rows) % rows][x]) icon = pad.iconAt(x, y) state.assignProperty(xRotation, "angle", -icon.x() / 6.0) state.assignProperty(yRotation, "angle", icon.y() / 6.0) state.assignProperty(selectionItem, "x", icon.x()) state.assignProperty(selectionItem, "y", icon.y()) frontState.assignProperty(icon, "visible", True) backState.assignProperty(icon, "visible", False) setIconVisibleAnimation = QPropertyAnimation(icon) setIconVisibleAnimation.setDuration(0) setVariablesSequence.addAnimation(setIconVisibleAnimation) scene = QGraphicsScene(self) scene.setBackgroundBrush( QBrush(QPixmap(":/images/blue_angle_swirl.jpg"))) scene.setItemIndexMethod(QGraphicsScene.NoIndex) scene.addItem(pad) scene.setSceneRect(scene.itemsBoundingRect()) self.setScene(scene) sbr = splash.boundingRect() splash.setPos(-sbr.width() / 2, scene.sceneRect().top() - 2) frontState.assignProperty(splash, "y", splash.y() - 100.0) scene.addItem(splash) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setMinimumSize(50, 50) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) if QGLFormat.hasOpenGL(): self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) stateMachine.start()
class QKeithleySolar(QVisaApplication.QVisaApplication): def __init__(self, _config): # Inherits QVisaApplication -> QWidget super(QKeithleySolar, self).__init__(_config) # Generate Main Layout self.gen_main_layout() ##################################### # APPLICATION HELPER METHODS # # Wrapper method to get keitley write handle # Returns the pyVisaDevice object def keithley(self): return self.get_device_by_name(self.device_select.currentText()) # Update bias on keithley def update_bias(self, _value): if self.keithley() is not None: self.keithley().set_voltage(_value) # Method to refresh the widget def refresh(self): # If add insturments have been initialized if self.get_devices() is not None: # Reset the widget and add insturments self.device_select.refresh(self) # Enable measurement buttons self.iv_meas_button.setEnabled(True) self.voc_meas_button.setEnabled(True) self.mpp_meas_button.setEnabled(True) else: # Disable measurement buttons self.iv_meas_button.setEnabled(False) self.voc_meas_button.setEnabled(False) self.mpp_meas_button.setEnabled(False) ##################################### # SOLAR APP MAIN LAYOUTS # # *) gen_main_layout() # 1) gen_solar_ctrl() # a) gen_sweep_ctrl() # b) gen_voc_ctrl() # c) gen_mpp_crtl() # 2) gen_solar_plot() # def gen_main_layout(self): # Create Icon for QMessageBox self._set_icon( QIcon( os.path.join(os.path.dirname(os.path.realpath(__file__)), "python.ico"))) # Create layout objects and set layout self.layout = QHBoxLayout() self.layout.addLayout(self.gen_solar_ctrl(), 1) self.layout.addWidget(self.gen_solar_plot(), 3) self.setLayout(self.layout) # Method to generate solar characterization controls def gen_solar_ctrl(self): # Solar mode layout self.ctl_layout = QVBoxLayout() # Add insturement selector self.device_select_label = QLabel("Select Device") self.device_select = self._gen_device_select() self.device_select.setFixedWidth(200) # Generate (IV, Voc, MPP) container widgets # These methods will pack self.inst_select self.gen_iv_ctrl() # self.iv_ctrl self.gen_voc_ctrl() # self.voc_ctrl self.gen_mpp_ctrl() # self.mpp_ctrl # Add measurement widgets to QStackedWidget self.meas_pages = QStackedWidget() self.meas_pages.addWidget(self.iv_ctrl) self.meas_pages.addWidget(self.voc_ctrl) self.meas_pages.addWidget(self.mpp_ctrl) self.meas_pages.setCurrentIndex(0) # Measurement select QComboBox self.meas_select_label = QLabel("Measurement Mode") self.meas_select = QComboBox() self.meas_select.setFixedWidth(200) self.meas_select.addItems(["IV", "Voc", "MPP"]) self.meas_select.currentTextChanged.connect(self.update_meas_pages) # Meta widget for trace description self.meta_widget_label = QLabel("<b>Trace Description</b>") self.meta_widget = self._gen_meta_widget() self.meta_widget.set_meta_subkey("__desc__") self.save_widget = self._gen_save_widget() ##################################### # ADD CONTROLS # # Add measurement select and measurement pages self.ctl_layout.addWidget(self.meas_pages) self.ctl_layout.addWidget( self._gen_hbox_widget([self.meas_select, self.meas_select_label])) self.ctl_layout.addWidget( self._gen_hbox_widget( [self.device_select, self.device_select_label])) # Pack the standard save widget self.ctl_layout.addStretch(1) self.ctl_layout.addWidget(self.meta_widget_label) self.ctl_layout.addWidget(self.meta_widget) self.ctl_layout.addWidget(self.save_widget) # Positioning self.ctl_layout.setContentsMargins(0, 15, 0, 20) return self.ctl_layout ##################################### # MEASUREMENT MODE CONTROLS # # Method to generate sweep controls def gen_iv_ctrl(self): # Sweep control layout self.iv_ctrl = QWidget() self.iv_ctrl_layout = QVBoxLayout() # Sweep measurement Button. This will be a state machine which # alternates between 'measure' and 'abort' states self.iv_meas_state = QStateMachine() self.iv_meas_button = QPushButton() self.iv_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create measurement states self.iv_meas_run = QState() self.iv_meas_stop = QState() # Assign state properties and transitions self.iv_meas_run.assignProperty(self.iv_meas_button, 'text', 'Abort Sweep') self.iv_meas_run.addTransition(self.iv_meas_button.clicked, self.iv_meas_stop) self.iv_meas_run.entered.connect(self.exec_iv_run) self.iv_meas_stop.assignProperty(self.iv_meas_button, 'text', 'Measure Sweep') self.iv_meas_stop.addTransition(self.iv_meas_button.clicked, self.iv_meas_run) self.iv_meas_stop.entered.connect(self.exec_iv_stop) # Add states, set initial state, and state machine self.iv_meas_state.addState(self.iv_meas_run) self.iv_meas_state.addState(self.iv_meas_stop) self.iv_meas_state.setInitialState(self.iv_meas_stop) self.iv_meas_state.start() # Sweep start self.iv_start_config = { "unit": "V", "min": "m", "max": "", "label": "Sweep Start (V)", "limit": 2.0, "signed": True, "default": [-0.5, ""] } self.iv_start = QVisaUnitSelector.QVisaUnitSelector( self.iv_start_config) # Sweep stop self.iv_stop_config = { "unit": "V", "min": "m", "max": "", "label": "Sweep Stop (V)", "limit": 2.0, "signed": True, "default": [0.5, ""] } self.iv_stop = QVisaUnitSelector.QVisaUnitSelector(self.iv_stop_config) # Compliance Spinbox self.iv_cmpl_config = { "unit": "A", "min": "u", "max": "", "label": "Compliance (A)", "limit": 1.0, "signed": False, "default": [100, "m"] } self.iv_cmpl = QVisaUnitSelector.QVisaUnitSelector(self.iv_cmpl_config) # Compliance self.iv_npts_config = { "unit": "__INT__", "label": "Number of Points", "limit": 256.0, "signed": False, "default": [51.0] } self.iv_npts = QVisaUnitSelector.QVisaUnitSelector(self.iv_npts_config) # Add sweep widgets to layout self.iv_ctrl_layout.addWidget(self.iv_meas_button) self.iv_ctrl_layout.addWidget(self.iv_start) self.iv_ctrl_layout.addWidget(self.iv_stop) self.iv_ctrl_layout.addWidget(self.iv_cmpl) self.iv_ctrl_layout.addWidget(self.iv_npts) self.iv_ctrl_layout.setContentsMargins(0, 0, 0, 0) # Set widget layout self.iv_ctrl.setLayout(self.iv_ctrl_layout) # Method to generate Voc controls def gen_voc_ctrl(self): # Voc control layout self.voc_ctrl = QWidget() self.voc_ctrl_layout = QVBoxLayout() # Create QStateMachine for output state self.voc_state = QStateMachine() self.voc_meas_button = QPushButton() self.voc_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create output states self.voc_meas_off = QState() self.voc_meas_on = QState() # Attach states to output button and define state transitions self.voc_meas_off.assignProperty(self.voc_meas_button, 'text', 'Voc Monitor Off') self.voc_meas_off.addTransition(self.voc_meas_button.clicked, self.voc_meas_on) self.voc_meas_off.entered.connect(self.exec_voc_stop) self.voc_meas_on.assignProperty(self.voc_meas_button, 'text', 'Voc Monitor On') self.voc_meas_on.addTransition(self.voc_meas_button.clicked, self.voc_meas_off) self.voc_meas_on.entered.connect(self.exec_voc_run) # Add states, set initial state, and start machine self.voc_state.addState(self.voc_meas_off) self.voc_state.addState(self.voc_meas_on) self.voc_state.setInitialState(self.voc_meas_off) self.voc_state.start() # Tracking mode initialization # Note this example of passing arguments to a callback self.voc_bias_config = { "unit": "V", "min": "m", "max": "", "label": "Voc Initialization (V)", "limit": 2.0, "signed": True, "default": [0.3, ""] } self.voc_bias = QVisaUnitSelector.QVisaUnitSelector( self.voc_bias_config) self.voc_bias.unit_value.valueChanged.connect( lambda arg=self.voc_bias.value(): self.update_bias(arg)) # Compliance Spinbox self.voc_cmpl_config = { "unit": "A", "min": "u", "max": "", "label": "Compliance (A)", "limit": 1.0, "signed": False, "default": [100, "m"] } self.voc_cmpl = QVisaUnitSelector.QVisaUnitSelector( self.voc_cmpl_config) # Tracking mode convergence self.voc_conv_config = { "unit": "A", "min": "n", "max": "m", "label": "Voc Convergence (A)", "limit": 0.05, "signed": False, "default": [0.05, "u"] } self.voc_conv = QVisaUnitSelector.QVisaUnitSelector( self.voc_conv_config) # Delay self.voc_gain_config = { "unit": "__DOUBLE__", "label": html.unescape("Proportional Gain (‰)"), "limit": 1000, "signed": False, "default": [30.0] } self.voc_gain = QVisaUnitSelector.QVisaUnitSelector( self.voc_gain_config) # Delay self.voc_delay_config = { "unit": "__DOUBLE__", "label": "Measurement Interval (s)", "limit": 60.0, "signed": False, "default": [1.0] } self.voc_delay = QVisaUnitSelector.QVisaUnitSelector( self.voc_delay_config) # Add voc widgets to layout self.voc_ctrl_layout.addWidget(self.voc_meas_button) self.voc_ctrl_layout.addWidget(self.voc_bias) self.voc_ctrl_layout.addWidget(self.voc_cmpl) self.voc_ctrl_layout.addWidget(self.voc_conv) self.voc_ctrl_layout.addWidget(self.voc_gain) self.voc_ctrl_layout.addWidget(self.voc_delay) self.voc_ctrl_layout.setContentsMargins(0, 0, 0, 0) # Set widget layout self.voc_ctrl.setLayout(self.voc_ctrl_layout) # Method to generate MPP controls def gen_mpp_ctrl(self): ################################# # mpp tracking controls # self.mpp_ctrl = QWidget() self.mpp_ctrl_layout = QVBoxLayout() # Create QStateMachine for output state self.mpp_state = QStateMachine() self.mpp_meas_button = QPushButton() self.mpp_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create output states self.mpp_meas_off = QState() self.mpp_meas_on = QState() # Attach states to output button and define state transitions self.mpp_meas_off.assignProperty(self.mpp_meas_button, 'text', 'MPP Monitor Off') self.mpp_meas_off.addTransition(self.mpp_meas_button.clicked, self.mpp_meas_on) self.mpp_meas_off.entered.connect(self.exec_mpp_stop) self.mpp_meas_on.assignProperty(self.mpp_meas_button, 'text', 'MPP Monitor On') self.mpp_meas_on.addTransition(self.mpp_meas_button.clicked, self.mpp_meas_off) self.mpp_meas_on.entered.connect(self.exec_mpp_run) # Add states, set initial state, and start machine self.mpp_state.addState(self.mpp_meas_off) self.mpp_state.addState(self.mpp_meas_on) self.mpp_state.setInitialState(self.mpp_meas_off) self.mpp_state.start() # Tracking mode initialization # Note this example of passing arguments to a callback self.mpp_bias_config = { "unit": "V", "min": "m", "max": "", "label": "MPP Initialization (V)", "limit": 2.0, "signed": True, "default": [0.30, ""] } self.mpp_bias = QVisaUnitSelector.QVisaUnitSelector( self.mpp_bias_config) self.mpp_bias.unit_value.valueChanged.connect( lambda arg=self.mpp_bias.value(): self.update_bias(arg)) # Compliance Spinbox self.mpp_cmpl_config = { "unit": "A", "min": "u", "max": "", "label": "Compliance (A)", "limit": 1.0, "signed": False, "default": [100, "m"] } self.mpp_cmpl = QVisaUnitSelector.QVisaUnitSelector( self.mpp_cmpl_config) # Tracking mode convergence self.mpp_ampl_config = { "unit": "V", "min": "u", "max": "m", "label": "Sense amplitude (mV)", "limit": 100, "signed": False, "default": [20.0, "m"] } self.mpp_ampl = QVisaUnitSelector.QVisaUnitSelector( self.mpp_ampl_config) # Delay self.mpp_gain_config = { "unit": "__DOUBLE__", "label": html.unescape("Proportional Gain (‰)"), "limit": 1000, "signed": False, "default": [30.0] } self.mpp_gain = QVisaUnitSelector.QVisaUnitSelector( self.mpp_gain_config) # Delay self.mpp_delay_config = { "unit": "__DOUBLE__", "label": "Measurement Interval (s)", "limit": 60.0, "signed": False, "default": [0.1] } self.mpp_delay = QVisaUnitSelector.QVisaUnitSelector( self.mpp_delay_config) # Add mpp widgets to layout self.mpp_ctrl_layout.addWidget(self.mpp_meas_button) self.mpp_ctrl_layout.addWidget(self.mpp_bias) self.mpp_ctrl_layout.addWidget(self.mpp_cmpl) self.mpp_ctrl_layout.addWidget(self.mpp_ampl) self.mpp_ctrl_layout.addWidget(self.mpp_gain) self.mpp_ctrl_layout.addWidget(self.mpp_delay) self.mpp_ctrl_layout.setContentsMargins(0, 0, 0, 0) # Set widget layout self.mpp_ctrl.setLayout(self.mpp_ctrl_layout) # Method to generate solar cell plots. This will be implemented # as three QVisaDynamicPlots packed into a QStackedWidget def gen_solar_plot(self): # Call QStackedWidget constructor self.plot_stack = QStackedWidget() # Plot IV-Sweep mode self.iv_plot = QVisaDynamicPlot.QVisaDynamicPlot(self) self.iv_plot.add_subplot(111, twinx=True) self.iv_plot.set_axes_labels("111", "Voltage (V)", "Current (mA)") self.iv_plot.set_axes_labels("111t", "Voltage (V)", "Power (mW)") self.iv_plot.set_axes_adjust(_left=0.15, _right=0.85, _top=0.9, _bottom=0.1) self.iv_plot.refresh_canvas(supress_warning=True) self.voc_plot = QVisaDynamicPlot.QVisaDynamicPlot(self) self.voc_plot.add_subplot(111, twinx=True) self.voc_plot.set_axes_labels("111", "Time (s)", "Voc (V)") self.voc_plot.set_axes_labels("111t", "Time (s)", "Ioc (V)") self.voc_plot.set_axes_adjust(_left=0.15, _right=0.85, _top=0.9, _bottom=0.1) self.voc_plot.refresh_canvas(supress_warning=True) self.mpp_plot = QVisaDynamicPlot.QVisaDynamicPlot(self) self.mpp_plot.add_subplot(111, twinx=True) self.mpp_plot.set_axes_labels("111", "Time (s)", "Vmpp (V)") self.mpp_plot.set_axes_labels("111t", "Time (s)", "Pmpp (mW)") self.mpp_plot.set_axes_adjust(_left=0.15, _right=0.85, _top=0.9, _bottom=0.1) self.mpp_plot.refresh_canvas(supress_warning=True) # Sync plot clear data buttons with application data self.iv_plot.sync_application_data(True) self.voc_plot.sync_application_data(True) self.mpp_plot.sync_application_data(True) # Sync meta widget when clearing data from plots self.iv_plot.set_mpl_refresh_callback( "_sync_meta_widget_to_data_object") self.voc_plot.set_mpl_refresh_callback( "_sync_meta_widget_to_data_object") self.mpp_plot.set_mpl_refresh_callback( "_sync_meta_widget_to_data_object") # Add QVisaDynamicPlots to QStackedWidget self.plot_stack.addWidget(self.iv_plot) self.plot_stack.addWidget(self.voc_plot) self.plot_stack.addWidget(self.mpp_plot) # Return the stacked widget self.plot_stack.setCurrentIndex(0) return self.plot_stack # Sync meta widget to data object def _sync_meta_widget_to_data_object(self): # Application keys _data_keys = self._get_data_object().keys() _widget_keys = self.meta_widget.get_meta_keys() # Check if widget keys are not in data keys for _key in _widget_keys: # If not then delete the key from meta_widget if _key not in _data_keys: self.meta_widget.del_meta_key(_key) # Flip between controls when measurement mode selector is updated def update_meas_pages(self): if self.meas_select.currentText() == "IV": self.meas_pages.setCurrentIndex(0) self.plot_stack.setCurrentIndex(0) if self.meas_select.currentText() == "Voc": self.meas_pages.setCurrentIndex(1) self.plot_stack.setCurrentIndex(1) if self.meas_select.currentText() == "MPP": self.meas_pages.setCurrentIndex(2) self.plot_stack.setCurrentIndex(2) # Callback method to delete data when traces are cleared def sync_mpl_clear(self): # Extract plot and data object _plot = self.plot_stack.currentWidget() _data = self._get_data_object() # Note that plot subkeys map to data keys for _subkey in _plot.get_axes_handles().subkeys("111"): _data.del_key(_subkey) ##################################### # IV-SWEEP MEASUREMENT MODE # # Sweep measurement EXECUTION def exec_iv_thread(self): # Set sweep parameters as simple linspace _params = np.linspace(float(self.iv_start.value()), float(self.iv_stop.value()), int(self.iv_npts.value())) # Get QVisaDataObject data = self._get_data_object() key = data.add_hash_key("pv-bias") # Add data fields to key data.set_subkeys(key, ["t", "V", "I", "P"]) data.set_metadata(key, "__type__", "pv-bias") # Add key to meta widget self.meta_widget.add_meta_key(key) # Generate colors _c0 = self.iv_plot.gen_next_color() _c1 = self.iv_plot.gen_next_color() # Clear plot and zero arrays self.iv_plot.add_axes_handle('111', key, _color=_c0) self.iv_plot.add_axes_handle('111t', key, _color=_c1) # Thread start time start = float(time.time()) # Output on self.keithley().voltage_src() self.keithley().current_cmp(self.iv_cmpl.value()) self.keithley().output_on() # Loop through sweep parameters for _bias in _params: # If thread is running if self.iv_thread_running: # Set bias self.keithley().set_voltage(_bias) # Get data from buffer _buffer = self.keithley().meas().split(",") # Extract data from buffer _now = float(time.time() - start) # Append measured values to data arrays data.append_subkey_data(key, "t", _now) data.append_subkey_data(key, "V", float(_buffer[0])) data.append_subkey_data(key, "I", -1.0 * float(_buffer[1])) data.append_subkey_data( key, "P", -1.0 * float(_buffer[1]) * float(_buffer[0])) self.iv_plot.append_handle_data("111", key, float(_buffer[0]), -1.0 * float(_buffer[1])) self.iv_plot.append_handle_data( "111t", key, float(_buffer[0]), -1.0 * float(_buffer[0]) * float(_buffer[1])) self.iv_plot.update_canvas() self.keithley().set_voltage(0.0) self.keithley().output_off() # Reset sweep control and update measurement state to stop. # Post a button click event to the QStateMachine to trigger # a state transition if thread is still running (not aborted) if self.iv_thread_running: self.iv_meas_button.click() # Sweep measurement ON def exec_iv_run(self): if self.keithley() is not None: # Put measurement button in abort state self.iv_meas_button.setStyleSheet( "background-color: #ffcccc; border-style: solid; border-width: 1px; border-color: #800000; padding: 7px;" ) # Disable controls self.save_widget.setEnabled(False) self.device_select.setEnabled(False) self.meas_select.setEnabled(False) self.iv_plot.mpl_refresh_setEnabled(False) self.voc_plot.mpl_refresh_setEnabled(False) self.mpp_plot.mpl_refresh_setEnabled(False) # Run the measurement thread function self.iv_thread = threading.Thread(target=self.exec_iv_thread, args=()) self.iv_thread.daemon = True # Daemonize thread self.iv_thread.start() # Start the execution self.iv_thread_running = True # Sweep measurement OFF def exec_iv_stop(self): if self.keithley() is not None: # Put measurement button in measure state self.iv_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Enable controls self.save_widget.setEnabled(True) self.device_select.setEnabled(True) self.meas_select.setEnabled(True) self.iv_plot.mpl_refresh_setEnabled(True) self.voc_plot.mpl_refresh_setEnabled(True) self.mpp_plot.mpl_refresh_setEnabled(True) # Set thread running to False. This will break the sweep measurements # execution loop on next iteration. self.iv_thread_running = False self.iv_thread.join() # Waits for thread to complete ##################################### # VOC-MONITOR MEASUREMENT MODE # def exec_voc_thread(self): # Get QVisaDataObject data = self._get_data_object() key = data.add_hash_key("pv-voc") # Add data fields to key data.set_subkeys(key, ["t", "Voc", "Ioc"]) data.set_metadata(key, "__type__", "pv-voc") # Add key to meta widget self.meta_widget.add_meta_key(key) # Generate colors _c0 = self.voc_plot.gen_next_color() _c1 = self.voc_plot.gen_next_color() # Clear plot and zero arrays self.voc_plot.add_axes_handle('111', key, _color=_c0) self.voc_plot.add_axes_handle('111t', key, _color=_c1) # Thread start time start = float(time.time()) # Set bias to initial value in voltas and turn output ON self.keithley().set_voltage(self.voc_bias.value()) self.keithley().current_cmp(self.voc_cmpl.value()) self.keithley().output_on() # Thread loop while self.voc_thread_running is True: # Iteration timer _iter_start = float(time.time()) # Covvergence loop while True: # Get data from buffer _buffer = self.keithley().meas().split(",") # Check if current is below convergence value # note that convergence is specified in mA if (abs(float(_buffer[1]))) <= float(self.voc_conv.value()): break # If convergence takes too long paint a value (10s) elif float(time.time() - _iter_start) >= 3.0: break # Otherwise, adjust the voltage proportionally else: # Create 1mV sense amplitude _v, _i = np.add(float(_buffer[0]), np.linspace(-0.0005, 0.0005, 3)), [] # Measure current over sense amplitude array for _ in _v: self.keithley().set_voltage(_) _b = self.keithley().meas().split(",") _i.append(-1.0 * float(_b[1])) # Reset the voltage self.keithley().set_voltage(float(_buffer[0])) # Adjust bias in direction of lower current # If current is positive (photo-current) increase voltage if np.mean(_i) >= 0.0: self.update_bias( float(_buffer[0]) * float(1.0 + self.voc_gain.value() / 1000.)) else: self.update_bias( float(_buffer[0]) * float(1.0 - self.voc_gain.value() / 1000.)) # Extract data from buffer _now = float(time.time() - start) data.append_subkey_data(key, "t", _now) data.append_subkey_data(key, "Voc", 1.0 * float(_buffer[0])) data.append_subkey_data(key, "Ioc", -1.0 * float(_buffer[1])) # Sanity check # Append handle data and update canvas self.voc_plot.append_handle_data("111", key, _now, 1.0 * float(_buffer[0])) self.voc_plot.append_handle_data("111t", key, _now, -1.0 * float(_buffer[1])) self.voc_plot.update_canvas() # Measurement delay if self.voc_delay.value() != 0: time.sleep(self.voc_delay.value()) # Cleanup after thread termination self.keithley().set_voltage(0.0) self.keithley().output_off() # Tracking measurement ON def exec_voc_run(self): if self.keithley() is not None: # Update UI for ON state self.voc_meas_button.setStyleSheet( "background-color: #cce6ff; border-style: solid; border-width: 1px; border-color: #1a75ff; padding: 7px;" ) # Disable controls self.save_widget.setEnabled(False) self.device_select.setEnabled(False) self.meas_select.setEnabled(False) self.voc_bias.setEnabled(False) self.voc_cmpl.setEnabled(False) self.iv_plot.mpl_refresh_setEnabled(False) self.voc_plot.mpl_refresh_setEnabled(False) self.mpp_plot.mpl_refresh_setEnabled(False) # Run the measurement thread function self.voc_thread = threading.Thread(target=self.exec_voc_thread, args=()) self.voc_thread.daemon = True # Daemonize thread self.voc_thread.start() # Start the execution self.voc_thread_running = True # Set execution flag # Tracking measurement OFF def exec_voc_stop(self): if self.keithley() is not None: # Put measurement button in measure state self.voc_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Enable controls self.save_widget.setEnabled(True) self.meas_select.setEnabled(True) self.device_select.setEnabled(True) self.voc_bias.setEnabled(True) self.voc_cmpl.setEnabled(True) self.iv_plot.mpl_refresh_setEnabled(True) self.voc_plot.mpl_refresh_setEnabled(True) self.mpp_plot.mpl_refresh_setEnabled(True) # Set thread running to False. This will break the sweep measurements # execution loop on next iteration. self.voc_thread_running = False self.voc_thread.join() # Waits for thread to complete ##################################### # MPP-MONITOR MEASUREMENT MODE # def exec_mpp_thread(self): # Get QVisaDataObject data = self._get_data_object() key = data.add_hash_key("pv-mpp") # Add data fields to key data.set_subkeys(key, ["t", "Vmpp", "Impp", "Pmpp"]) data.set_metadata(key, "__type__", "pv-mpp") # Add key to meta widget self.meta_widget.add_meta_key(key) # Generate colors _c0 = self.mpp_plot.gen_next_color() _c1 = self.mpp_plot.gen_next_color() # Clear plot and zero arrays self.mpp_plot.add_axes_handle('111', key, _color=_c0) self.mpp_plot.add_axes_handle('111t', key, _color=_c1) # Thread start time start = float(time.time()) # Set bias to initial value in voltas and turn output ON self.keithley().set_voltage(self.mpp_bias.value()) self.keithley().current_cmp(self.mpp_cmpl.value()) self.keithley().output_on() # Thread loop while self.mpp_thread_running is True: # Iteration timer _iter_start = float(time.time()) # Covvergence loop _d = [] while True: # Get data from buffer _buffer = self.keithley().meas().split(",") # If convergence takes too long paint a value (10s) if float(time.time() - _iter_start) >= 3.0: break # Otherwise, adjust the voltage proportionally else: # Create 1mV sense amplitude _amplitude = self.mpp_ampl.value() _v, _i = np.add( float(_buffer[0]), np.linspace(-1.0 * _amplitude, _amplitude, 5)), [] # Measure current over sense amplitude array for _ in _v: self.keithley().set_voltage(_) _b = self.keithley().meas().split(",") _i.append(-1.0 * float(_b[1])) # Reset the voltage self.keithley().set_voltage(float(_buffer[0])) # Calculate derivative _p = np.multiply(_i, _v) _d = np.gradient(np.multiply(_i, _v)) _d = np.divide(_d, _amplitude) # Differntial gain controller if np.mean(_d) <= 0.0: self.update_bias( float(_buffer[0]) * float(1.0 - self.mpp_gain.value() / 1000.)) else: self.update_bias( float(_buffer[0]) * float(1.0 + self.mpp_gain.value() / 1000.)) # Extract data from buffer _now = float(time.time() - start) data.append_subkey_data(key, "t", _now) data.append_subkey_data(key, "Vmpp", 1.0 * float(_buffer[0])) data.append_subkey_data(key, "Impp", -1.0 * float(_buffer[1])) data.append_subkey_data( key, "Pmpp", -1.0 * float(_buffer[1]) * float(_buffer[0])) # Append handle data and update canvas self.mpp_plot.append_handle_data("111", key, _now, float(_buffer[0])) self.mpp_plot.append_handle_data( "111t", key, _now, float(_buffer[0]) * -1.0 * float(_buffer[1]) * 1000.) self.mpp_plot.update_canvas() # Measurement delay if self.mpp_delay.value() != 0: time.sleep(self.mpp_delay.value()) # Cleanup after thread termination self.keithley().set_voltage(0.0) self.keithley().output_off() # Tracking measurement ON def exec_mpp_run(self): if self.keithley() is not None: # Update UI for ON state self.mpp_meas_button.setStyleSheet( "background-color: #cce6ff; border-style: solid; border-width: 1px; border-color: #1a75ff; padding: 7px;" ) # Disable widgets self.save_widget.setEnabled(False) self.meas_select.setEnabled(False) self.device_select.setEnabled(False) self.mpp_bias.setEnabled(False) self.mpp_cmpl.setEnabled(False) self.iv_plot.mpl_refresh_setEnabled(False) self.voc_plot.mpl_refresh_setEnabled(False) self.mpp_plot.mpl_refresh_setEnabled(False) # Run the measurement thread function self.mpp_thread = threading.Thread(target=self.exec_mpp_thread, args=()) self.mpp_thread.daemon = True # Daemonize thread self.mpp_thread.start() # Start the execution self.mpp_thread_running = True # Set execution flag # Tracking measurement OFF def exec_mpp_stop(self): if self.keithley() is not None: # Put measurement button in measure state self.mpp_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Enable widgets self.save_widget.setEnabled(True) self.meas_select.setEnabled(True) self.device_select.setEnabled(True) self.mpp_bias.setEnabled(True) self.mpp_cmpl.setEnabled(True) self.iv_plot.mpl_refresh_setEnabled(True) self.voc_plot.mpl_refresh_setEnabled(True) self.mpp_plot.mpl_refresh_setEnabled(True) # Set thread running to False. This will break the sweep measurements # execution loop on next iteration. self.mpp_thread_running = False self.mpp_thread.join() # Waits for thread to complete
def gen_iv_ctrl(self): # Sweep control layout self.iv_ctrl = QWidget() self.iv_ctrl_layout = QVBoxLayout() # Sweep measurement Button. This will be a state machine which # alternates between 'measure' and 'abort' states self.iv_meas_state = QStateMachine() self.iv_meas_button = QPushButton() self.iv_meas_button.setStyleSheet( "background-color: #dddddd; border-style: solid; border-width: 1px; border-color: #aaaaaa; padding: 7px;" ) # Create measurement states self.iv_meas_run = QState() self.iv_meas_stop = QState() # Assign state properties and transitions self.iv_meas_run.assignProperty(self.iv_meas_button, 'text', 'Abort Sweep') self.iv_meas_run.addTransition(self.iv_meas_button.clicked, self.iv_meas_stop) self.iv_meas_run.entered.connect(self.exec_iv_run) self.iv_meas_stop.assignProperty(self.iv_meas_button, 'text', 'Measure Sweep') self.iv_meas_stop.addTransition(self.iv_meas_button.clicked, self.iv_meas_run) self.iv_meas_stop.entered.connect(self.exec_iv_stop) # Add states, set initial state, and state machine self.iv_meas_state.addState(self.iv_meas_run) self.iv_meas_state.addState(self.iv_meas_stop) self.iv_meas_state.setInitialState(self.iv_meas_stop) self.iv_meas_state.start() # Sweep start self.iv_start_config = { "unit": "V", "min": "m", "max": "", "label": "Sweep Start (V)", "limit": 2.0, "signed": True, "default": [-0.5, ""] } self.iv_start = QVisaUnitSelector.QVisaUnitSelector( self.iv_start_config) # Sweep stop self.iv_stop_config = { "unit": "V", "min": "m", "max": "", "label": "Sweep Stop (V)", "limit": 2.0, "signed": True, "default": [0.5, ""] } self.iv_stop = QVisaUnitSelector.QVisaUnitSelector(self.iv_stop_config) # Compliance Spinbox self.iv_cmpl_config = { "unit": "A", "min": "u", "max": "", "label": "Compliance (A)", "limit": 1.0, "signed": False, "default": [100, "m"] } self.iv_cmpl = QVisaUnitSelector.QVisaUnitSelector(self.iv_cmpl_config) # Compliance self.iv_npts_config = { "unit": "__INT__", "label": "Number of Points", "limit": 256.0, "signed": False, "default": [51.0] } self.iv_npts = QVisaUnitSelector.QVisaUnitSelector(self.iv_npts_config) # Add sweep widgets to layout self.iv_ctrl_layout.addWidget(self.iv_meas_button) self.iv_ctrl_layout.addWidget(self.iv_start) self.iv_ctrl_layout.addWidget(self.iv_stop) self.iv_ctrl_layout.addWidget(self.iv_cmpl) self.iv_ctrl_layout.addWidget(self.iv_npts) self.iv_ctrl_layout.setContentsMargins(0, 0, 0, 0) # Set widget layout self.iv_ctrl.setLayout(self.iv_ctrl_layout)
((i // 8) - 4) * kineticPix.height() + kineticPix.height() / 2)) # Centered. centeredState.assignProperty(item, 'pos', QPointF()) # Ui. view = View(scene) view.setWindowTitle("Animated Tiles") view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) view.setBackgroundBrush(QBrush(bgPix)) view.setCacheMode(QGraphicsView.CacheBackground) view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) view.show() states = QStateMachine() states.addState(rootState) states.setInitialState(rootState) rootState.setInitialState(centeredState) group = QParallelAnimationGroup() for i, item in enumerate(items): anim = QPropertyAnimation(item, b'pos') anim.setDuration(750 + i * 25) anim.setEasingCurve(QEasingCurve.InOutBack) group.addAnimation(anim) trans = rootState.addTransition(ellipseButton.pressed, ellipseState) trans.addAnimation(group) trans = rootState.addTransition(figure8Button.pressed, figure8State)
def __init__(self, size, parent=None): super(PadNavigator, self).__init__(parent) self.form = Ui_Form() splash = SplashItem() splash.setZValue(1) pad = FlippablePad(size) flipRotation = QGraphicsRotation(pad) xRotation = QGraphicsRotation(pad) yRotation = QGraphicsRotation(pad) flipRotation.setAxis(Qt.YAxis) xRotation.setAxis(Qt.YAxis) yRotation.setAxis(Qt.XAxis) pad.setTransformations([flipRotation, xRotation, yRotation]) backItem = QGraphicsProxyWidget(pad) widget = QWidget() self.form.setupUi(widget) self.form.hostName.setFocus() backItem.setWidget(widget) backItem.setVisible(False) backItem.setFocus() backItem.setCacheMode(QGraphicsItem.ItemCoordinateCache) r = backItem.rect() backItem.setTransform(QTransform().rotate(180, Qt.YAxis).translate(-r.width()/2, -r.height()/2)) selectionItem = RoundRectItem(QRectF(-60, -60, 120, 120), QColor(Qt.gray), pad) selectionItem.setZValue(0.5) smoothSplashMove = QPropertyAnimation(splash, b'y') smoothSplashOpacity = QPropertyAnimation(splash, b'opacity') smoothSplashMove.setEasingCurve(QEasingCurve.InQuad) smoothSplashMove.setDuration(250) smoothSplashOpacity.setDuration(250) smoothXSelection = QPropertyAnimation(selectionItem, b'x') smoothYSelection = QPropertyAnimation(selectionItem, b'y') smoothXRotation = QPropertyAnimation(xRotation, b'angle') smoothYRotation = QPropertyAnimation(yRotation, b'angle') smoothXSelection.setDuration(125) smoothYSelection.setDuration(125) smoothXRotation.setDuration(125) smoothYRotation.setDuration(125) smoothXSelection.setEasingCurve(QEasingCurve.InOutQuad) smoothYSelection.setEasingCurve(QEasingCurve.InOutQuad) smoothXRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothYRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipRotation = QPropertyAnimation(flipRotation, b'angle') smoothFlipScale = QPropertyAnimation(pad, b'scale') smoothFlipXRotation = QPropertyAnimation(xRotation, b'angle') smoothFlipYRotation = QPropertyAnimation(yRotation, b'angle') flipAnimation = QParallelAnimationGroup(self) smoothFlipScale.setDuration(500) smoothFlipRotation.setDuration(500) smoothFlipXRotation.setDuration(500) smoothFlipYRotation.setDuration(500) smoothFlipScale.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipXRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipYRotation.setEasingCurve(QEasingCurve.InOutQuad) smoothFlipScale.setKeyValueAt(0, 1.0) smoothFlipScale.setKeyValueAt(0.5, 0.7) smoothFlipScale.setKeyValueAt(1, 1.0) flipAnimation.addAnimation(smoothFlipRotation) flipAnimation.addAnimation(smoothFlipScale) flipAnimation.addAnimation(smoothFlipXRotation) flipAnimation.addAnimation(smoothFlipYRotation) setVariablesSequence = QSequentialAnimationGroup() setFillAnimation = QPropertyAnimation(pad, b'fill') setBackItemVisibleAnimation = QPropertyAnimation(backItem, b'visible') setSelectionItemVisibleAnimation = QPropertyAnimation(selectionItem, b'visible') setFillAnimation.setDuration(0) setBackItemVisibleAnimation.setDuration(0) setSelectionItemVisibleAnimation.setDuration(0) setVariablesSequence.addPause(250) setVariablesSequence.addAnimation(setBackItemVisibleAnimation) setVariablesSequence.addAnimation(setSelectionItemVisibleAnimation) setVariablesSequence.addAnimation(setFillAnimation) flipAnimation.addAnimation(setVariablesSequence) stateMachine = QStateMachine(self) splashState = QState(stateMachine) frontState = QState(stateMachine) historyState = QHistoryState(frontState) backState = QState(stateMachine) frontState.assignProperty(pad, "fill", False) frontState.assignProperty(splash, "opacity", 0.0) frontState.assignProperty(backItem, "visible", False) frontState.assignProperty(flipRotation, "angle", 0.0) frontState.assignProperty(selectionItem, "visible", True) backState.assignProperty(pad, "fill", True) backState.assignProperty(backItem, "visible", True) backState.assignProperty(xRotation, "angle", 0.0) backState.assignProperty(yRotation, "angle", 0.0) backState.assignProperty(flipRotation, "angle", 180.0) backState.assignProperty(selectionItem, "visible", False) stateMachine.addDefaultAnimation(smoothXRotation) stateMachine.addDefaultAnimation(smoothYRotation) stateMachine.addDefaultAnimation(smoothXSelection) stateMachine.addDefaultAnimation(smoothYSelection) stateMachine.setInitialState(splashState) anyKeyTransition = QEventTransition(self, QEvent.KeyPress, splashState) anyKeyTransition.setTargetState(frontState) anyKeyTransition.addAnimation(smoothSplashMove) anyKeyTransition.addAnimation(smoothSplashOpacity) enterTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Enter, backState) returnTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Return, backState) backEnterTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Enter, frontState) backReturnTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Return, frontState) enterTransition.setTargetState(historyState) returnTransition.setTargetState(historyState) backEnterTransition.setTargetState(backState) backReturnTransition.setTargetState(backState) enterTransition.addAnimation(flipAnimation) returnTransition.addAnimation(flipAnimation) backEnterTransition.addAnimation(flipAnimation) backReturnTransition.addAnimation(flipAnimation) columns = size.width() rows = size.height() stateGrid = [] for y in range(rows): stateGrid.append([QState(frontState) for _ in range(columns)]) frontState.setInitialState(stateGrid[0][0]) selectionItem.setPos(pad.iconAt(0, 0).pos()) for y in range(rows): for x in range(columns): state = stateGrid[y][x] rightTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Right, state) leftTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Left, state) downTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Down, state) upTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Up, state) rightTransition.setTargetState(stateGrid[y][(x + 1) % columns]) leftTransition.setTargetState(stateGrid[y][((x - 1) + columns) % columns]) downTransition.setTargetState(stateGrid[(y + 1) % rows][x]) upTransition.setTargetState(stateGrid[((y - 1) + rows) % rows][x]) icon = pad.iconAt(x, y) state.assignProperty(xRotation, "angle", -icon.x() / 6.0) state.assignProperty(yRotation, "angle", icon.y() / 6.0) state.assignProperty(selectionItem, "x", icon.x()) state.assignProperty(selectionItem, "y", icon.y()) frontState.assignProperty(icon, "visible", True) backState.assignProperty(icon, "visible", False) setIconVisibleAnimation = QPropertyAnimation(icon, b'visible') setIconVisibleAnimation.setDuration(0) setVariablesSequence.addAnimation(setIconVisibleAnimation) scene = QGraphicsScene(self) scene.setBackgroundBrush(QBrush(QPixmap(":/images/blue_angle_swirl.jpg"))) scene.setItemIndexMethod(QGraphicsScene.NoIndex) scene.addItem(pad) scene.setSceneRect(scene.itemsBoundingRect()) self.setScene(scene) sbr = splash.boundingRect() splash.setPos(-sbr.width() / 2, scene.sceneRect().top() - 2) frontState.assignProperty(splash, "y", splash.y() - 100.0) scene.addItem(splash) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setMinimumSize(50, 50) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) if QGLFormat.hasOpenGL(): self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers))) stateMachine.start()
button4.setZValue(3) scene = QGraphicsScene(0, 0, 300, 300) scene.setBackgroundBrush(Qt.black) scene.addItem(button1) scene.addItem(button2) scene.addItem(button3) scene.addItem(button4) window = QGraphicsView(scene) window.setFrameStyle(0) window.setAlignment(Qt.AlignLeft | Qt.AlignTop) window.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) window.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) machine = QStateMachine() group = QState() timer = QTimer() timer.setInterval(1250) timer.setSingleShot(True) group.entered.connect(timer.start) state1 = createGeometryState(button1, QRect(100, 0, 50, 50), button2, QRect(150, 0, 50, 50), button3, QRect(200, 0, 50, 50), button4, QRect(250, 0, 50, 50), group) state2 = createGeometryState(button1, QRect(250, 100, 50, 50), button2, QRect(250, 150, 50, 50), button3, QRect(250, 200, 50, 50), button4,
def __init__(self, scene, x_max, y_max, back_color): scene = QGraphicsScene(0, 0, x_max, y_max) scene.setBackgroundBrush(back_color) color = [Qt.green, Qt.lightGray, Qt.darkYellow, QtGui.QColor.fromRgb(255, 85, 0)] self.anim_butt = [ QGraphicsRectWidget(color[j]) for j in range(4) ] for j in range(4): scene.addItem(self.anim_butt[j]) self.window = QGraphicsView(scene) self.window.setFrameStyle(0) self.window.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.window.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.window.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.machine = QStateMachine() self.group = QState() self.timer = QTimer() self.timer.setInterval(1250) self.timer.setSingleShot(True) self.group.entered.connect(self.timer.start) # set states positions anim_state_rects = [ [QRect(x_max*xp/6, y_max*yp/4, 8, 8) for xp in range(4)] for yp in range(4) ] self.states = [ self.createGeometryState( self.anim_butt[0], anim_state_rects[0][j], self.anim_butt[1], anim_state_rects[1][j], self.anim_butt[2], anim_state_rects[2][j], self.anim_butt[3], anim_state_rects[3][j], self.group ) for j in range(4) ] self.group.setInitialState(self.states[0]) self.animationGroup = QParallelAnimationGroup() self.anim = QPropertyAnimation(self.anim_butt[3], 'geometry') self.anim.setDuration(1250) self.anim.setEasingCurve(QEasingCurve.InBack) self.animationGroup.addAnimation(self.anim) self.subGroup = QSequentialAnimationGroup(self.animationGroup) self.subGroup.addPause(100) self.anim = QPropertyAnimation(self.anim_butt[2], 'geometry') self.anim.setDuration(1000) self.anim.setEasingCurve(QEasingCurve.OutElastic) self.subGroup.addAnimation(self.anim) self.subGroup = QSequentialAnimationGroup(self.animationGroup) self.subGroup.addPause(500) self.anim = QPropertyAnimation(self.anim_butt[1], 'geometry') self.anim.setDuration(500) self.anim.setEasingCurve(QEasingCurve.OutElastic) self.subGroup.addAnimation(self.anim) self.subGroup = QSequentialAnimationGroup(self.animationGroup) self.subGroup.addPause(750) self.anim = QPropertyAnimation(self.anim_butt[0], 'geometry') self.anim.setDuration(250) self.anim.setEasingCurve(QEasingCurve.OutElastic) self.subGroup.addAnimation(self.anim) self.stateSwitcher = StateSwitcher(self.machine) self.group.addTransition(self.timer.timeout, self.stateSwitcher) for j in range(4): self.stateSwitcher.addState(self.states[j], self.animationGroup) self.machine.addState(self.group) self.machine.setInitialState(self.group) self.machine.start()
class MainWindow(QMainWindow): instrumentsFound = pyqtSignal() sampleFound = pyqtSignal() measurementFinished = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.setAttribute(Qt.WA_QuitOnClose) self.setAttribute(Qt.WA_DeleteOnClose) # create instance variables self._ui = uic.loadUi('mainwindow.ui', self) # create models self.measureModels = { 1: MeasureModel(self), 2: MeasureModel(self), } self._instrumentManager = InstrumentManager(self, self.measureModels) self.machine = QStateMachine() self.stateInitial = QState() self.stateReadyToCheck = QState() self.stateReadyToMeasure = QState() self.stateAfterMeasure = QState() self.initDialog() def setupStateMachine(self): self.machine.addState(self.stateInitial) self.machine.addState(self.stateReadyToCheck) self.machine.addState(self.stateReadyToMeasure) self.machine.addState(self.stateAfterMeasure) self.stateInitial.addTransition(self.instrumentsFound, self.stateReadyToCheck) self.stateInitial.assignProperty(self._ui.btnSearchInstruments, 'enabled', 'True') self.stateInitial.assignProperty(self._ui.btnCheckSample, 'enabled', 'False') self.stateInitial.assignProperty(self._ui.btnMeasureStart, 'visible', 'True') self.stateInitial.assignProperty(self._ui.btnMeasureStart, 'enabled', 'False') self.stateInitial.assignProperty(self._ui.btnMeasureStop, 'visible', 'False') self.stateInitial.assignProperty(self._ui.btnMeasureStop, 'enabled', 'False') self.stateInitial.assignProperty(self._ui.radioLetter1, 'checked', 'True') self.stateInitial.assignProperty(self._ui.radioLetter1, 'enabled', 'True') self.stateInitial.assignProperty(self._ui.radioLetter2, 'enabled', 'True') self.stateReadyToCheck.addTransition(self.sampleFound, self.stateReadyToMeasure) self.stateReadyToCheck.assignProperty(self._ui.btnSearchInstruments, 'enabled', 'True') self.stateReadyToCheck.assignProperty(self._ui.btnCheckSample, 'enabled', 'True') self.stateReadyToCheck.assignProperty(self._ui.btnMeasureStart, 'visible', 'True') self.stateReadyToCheck.assignProperty(self._ui.btnMeasureStart, 'enabled', 'False') self.stateReadyToCheck.assignProperty(self._ui.btnMeasureStop, 'visible', 'False') self.stateReadyToCheck.assignProperty(self._ui.btnMeasureStop, 'enabled', 'False') self.stateReadyToCheck.assignProperty(self._ui.radioLetter1, 'enabled', 'True') self.stateReadyToCheck.assignProperty(self._ui.radioLetter2, 'enabled', 'True') self.stateReadyToMeasure.addTransition(self.measurementFinished, self.stateAfterMeasure) self.stateReadyToMeasure.addTransition(self.instrumentsFound, self.stateReadyToCheck) self.stateReadyToMeasure.assignProperty(self._ui.btnSearchInstruments, 'enabled', 'True') self.stateReadyToMeasure.assignProperty(self._ui.btnCheckSample, 'enabled', 'False') self.stateReadyToMeasure.assignProperty(self._ui.btnMeasureStart, 'visible', 'True') self.stateReadyToMeasure.assignProperty(self._ui.btnMeasureStart, 'enabled', 'True') self.stateReadyToMeasure.assignProperty(self._ui.btnMeasureStop, 'visible', 'False') self.stateReadyToMeasure.assignProperty(self._ui.btnMeasureStop, 'enabled', 'False') self.stateReadyToMeasure.assignProperty(self._ui.radioLetter1, 'enabled', 'False') self.stateReadyToMeasure.assignProperty(self._ui.radioLetter2, 'enabled', 'False') self.stateAfterMeasure.addTransition(self._ui.btnMeasureStop.clicked, self.stateReadyToCheck) self.stateAfterMeasure.addTransition(self.instrumentsFound, self.stateReadyToCheck) self.stateAfterMeasure.assignProperty(self._ui.btnSearchInstruments, 'enabled', 'True') self.stateAfterMeasure.assignProperty(self._ui.btnCheckSample, 'enabled', 'False') self.stateAfterMeasure.assignProperty(self._ui.btnMeasureStart, 'visible', 'False') self.stateAfterMeasure.assignProperty(self._ui.btnMeasureStart, 'enabled', 'False') self.stateAfterMeasure.assignProperty(self._ui.btnMeasureStop, 'visible', 'True') self.stateAfterMeasure.assignProperty(self._ui.btnMeasureStop, 'enabled', 'True') self.stateAfterMeasure.assignProperty(self._ui.radioLetter1, 'enabled', 'False') self.stateAfterMeasure.assignProperty(self._ui.radioLetter2, 'enabled', 'False') self.machine.setInitialState(self.stateInitial) self.machine.start() def setupUiSignals(self): self._ui.btnSearchInstruments.clicked.connect( self.onBtnSearchInstrumentsClicked) self._ui.btnCheckSample.clicked.connect(self.onBtnCheckSample) self._ui.btnMeasureStart.clicked.connect(self.onBtnMeasureStart) self._ui.btnMeasureStop.clicked.connect(self.onBtnMeasureStop) self._ui.radioLetter1.toggled.connect(self.onRadioToggled) self._ui.radioLetter2.toggled.connect(self.onRadioToggled) def initDialog(self): self.setupStateMachine() self.setupUiSignals() self._ui.bgrpLetter.setId(self._ui.radioLetter1, 1) self._ui.bgrpLetter.setId(self._ui.radioLetter2, 2) self._ui.textLog.hide() self.refreshView() # UI utility methods def refreshView(self): self.resizeTable() # twidth = self.ui.tableSuggestions.frameGeometry().width() - 30 # self.ui.tableSuggestions.setColumnWidth(0, twidth * 0.05) # self.ui.tableSuggestions.setColumnWidth(1, twidth * 0.10) # self.ui.tableSuggestions.setColumnWidth(2, twidth * 0.55) # self.ui.tableSuggestions.setColumnWidth(3, twidth * 0.10) # self.ui.tableSuggestions.setColumnWidth(4, twidth * 0.15) # self.ui.tableSuggestions.setColumnWidth(5, twidth * 0.05) def resizeTable(self): self._ui.tableMeasure.resizeRowsToContents() self._ui.tableMeasure.resizeColumnsToContents() def search(self): if not self._instrumentManager.findInstruments(): QMessageBox.information( self, "Ошибка", "Не удалось найти инструменты, проверьте подключение.\nПодробности в логах." ) return False print('found all instruments, enabling sample test') return True # event handlers def resizeEvent(self, event): self.refreshView() # TODO: extract to a measurement manager class def onBtnSearchInstrumentsClicked(self): if not self.search(): return self.stateReadyToCheck.assignProperty( self._ui.editSource, 'text', str(self._instrumentManager._source)) self.stateReadyToCheck.assignProperty( self._ui.editGen1, 'text', str(self._instrumentManager._generator1)) self.stateReadyToCheck.assignProperty( self._ui.editGen2, 'text', str(self._instrumentManager._generator2)) self.stateReadyToCheck.assignProperty( self._ui.editAnalyzer, 'text', str(self._instrumentManager._analyzer)) self.instrumentsFound.emit() def failWith(self, message): QMessageBox.information(self, "Ошибка", message) self.instrumentsFound.emit() def onBtnCheckSample(self): if not self._instrumentManager.checkSample(): self.failWith( "Не удалось найти образец, проверьте подключение.\nПодробности в логах." ) print('sample not detected') return if not self._instrumentManager.checkTaskTable(): self.failWith( "Ошибка при чтении таблицы с заданием на измерение.\nПодробности в логах." ) print('error opening table') return self.sampleFound.emit() self.refreshView() def onBtnMeasureStart(self): print('start measurement task') if not self._instrumentManager.checkSample(): self.failWith( "Не удалось найти образец, проверьте подключение.\nПодробности в логах." ) print('sample not detected') return self._instrumentManager.measure(self._ui.bgrpLetter.checkedId()) self.measurementFinished.emit() self.refreshView() def onBtnMeasureStop(self): # TODO implement print('abort measurement task') def onRadioToggled(self, checked): if not checked: return letter = self._ui.bgrpLetter.checkedId() print('switching to letter', letter) self._ui.tableMeasure.setModel(self.measureModels[letter]) self.refreshView()
class LifeCycle(object): def __init__(self, stickMan, keyReceiver): self.m_stickMan = stickMan self.m_keyReceiver = keyReceiver # Create animation group to be used for all transitions. self.m_animationGroup = QParallelAnimationGroup() stickManNodeCount = self.m_stickMan.nodeCount() self._pas = [] for i in range(stickManNodeCount): pa = QPropertyAnimation(self.m_stickMan.node(i), b"pos") self._pas.append(pa) self.m_animationGroup.addAnimation(pa) # Set up intial state graph. self.m_machine = QStateMachine() self.m_machine.addDefaultAnimation(self.m_animationGroup) self.m_alive = QState(self.m_machine) self.m_alive.setObjectName("alive") # Make it blink when lightning strikes before entering dead animation. lightningBlink = QState(self.m_machine) lightningBlink.assignProperty(self.m_stickMan.scene(), "backgroundBrush", Qt.white) lightningBlink.assignProperty(self.m_stickMan, "penColor", Qt.black) lightningBlink.assignProperty(self.m_stickMan, "fillColor", Qt.white) lightningBlink.assignProperty(self.m_stickMan, "isDead", True) timer = QTimer(lightningBlink) timer.setSingleShot(True) timer.setInterval(100) lightningBlink.entered.connect(timer.start) lightningBlink.exited.connect(timer.stop) self.m_dead = QState(self.m_machine) self.m_dead.assignProperty(self.m_stickMan.scene(), "backgroundBrush", Qt.black) self.m_dead.assignProperty(self.m_stickMan, "penColor", Qt.white) self.m_dead.assignProperty(self.m_stickMan, "fillColor", Qt.black) self.m_dead.setObjectName("dead") # Idle state (sets no properties). self.m_idle = QState(self.m_alive) self.m_idle.setObjectName("idle") self.m_alive.setInitialState(self.m_idle) # Lightning strikes at random. self.m_alive.addTransition(LightningStrikesTransition(lightningBlink)) lightningBlink.addTransition(timer.timeout, self.m_dead) self.m_machine.setInitialState(self.m_alive) def setDeathAnimation(self, fileName): deathAnimation = self.makeState(self.m_dead, fileName) self.m_dead.setInitialState(deathAnimation) def start(self): self.m_machine.start() def addActivity(self, fileName, key): state = self.makeState(self.m_alive, fileName) self.m_alive.addTransition(KeyPressTransition(self.m_keyReceiver, key, state)) def makeState(self, parentState, animationFileName): topLevel = QState(parentState) animation = Animation() file = QFile(animationFileName) if file.open(QIODevice.ReadOnly): animation.load(file) frameCount = animation.totalFrames() previousState = None for i in range(frameCount): animation.setCurrentFrame(i) frameState = QState(topLevel) nodeCount = animation.nodeCount() for j in range(nodeCount): frameState.assignProperty(self.m_stickMan.node(j), "pos", animation.nodePos(j)) frameState.setObjectName("frame %d" % i) if previousState is None: topLevel.setInitialState(frameState) else: previousState.addTransition(previousState.propertiesAssigned, frameState) previousState = frameState previousState.addTransition(previousState.propertiesAssigned, topLevel.initialState()) return topLevel
class HTTYD(Tab, HTTYD_tab_class): """Define some signals that will emit some string, signals a are usually sent by buttons these signals need to be connected to a slot/slots. so for example, when the CF is connected, a bunch of things in the GUI happen. https://youtu.be/GIg9ehmGJHY?t=1420 """ _connected_signal = pyqtSignal(str) _disconnected_signal = pyqtSignal(str) _log_data_signal = pyqtSignal(int, object, object) _log_error_signal = pyqtSignal(object, str) _param_updated_signal = pyqtSignal(str, str) cfStatusChanged = pyqtSignal(str) statusChanged = pyqtSignal(str) def __init__(self, tabWidget, helper, *args): super(HTTYD, self).__init__(*args) self.setupUi(self) self._machine = QStateMachine() self._setup_states() self._event = threading.Event() self.tabName = "HTTYD" self.menuName = "HTTYD Tab" self.tabWidget = tabWidget # the above helper cf instances are only assigned to _cf_L and _cf_R after they start logging self._helper = helper self._cf = None self.last_time = 0 # assign the label to the _cf_status_ string self._cf_status = self.cfStatusLabel.text() self._status = self.statusLabel.text() # initial flight mode self.flying_enabled = False self.switch_flight_mode(FlightModeStates.DISCONNECTED) self.path_pos_threshold = 0.2 # The position and rotation of the cf and wand obtained by the # lighthouse tracking, if it cant be tracked the position becomes Nan self.cf_pos = Position(0, 0, 0) self.wand_pos = Position(0, 0, 0) # The regular cf_pos can a times due to lost tracing become Nan, # this the latest known valid cf position self.valid_cf_pos = Position(0, 0, 0) # Always wrap callbacks from Crazyflie API though QT Signal/Slots # to avoid manipulating the UI when rendering it self._connected_signal.connect(self._connected) self._disconnected_signal.connect(self._disconnected) self._log_data_signal.connect(self._log_data_received) self._param_updated_signal.connect(self._param_updated) # connect the status change signal to the update status # funciton self.statusChanged.connect(self._update_status) self.cfStatusChanged.connect(self._update_cf_status) # Connect the Crazyflie API callbacks to the signals self._helper.cf.connected.add_callback(self._connected_signal.emit) self._helper.cf.disconnected.add_callback(self._disconnected_signal.emit) # Connect the UI elements self.liftButton.clicked.connect(self.set_lift_mode) self.landButton.clicked.connect(self.set_land_mode) self.followButton.clicked.connect(self.set_follow_mode) self.emergencyButton.clicked.connect(self.set_kill_engine) def _setup_states(self): parent_state = QState() # DISCONNECTED disconnected = QState(parent_state) disconnected.assignProperty(self, "status", "Disabled") disconnected.assignProperty(self.followButton, "text", "Follow Mode") disconnected.assignProperty(self.emergencyButton, "enabled", False) disconnected.assignProperty(self.liftButton, "enabled", False) disconnected.assignProperty(self.followButton, "enabled", False) disconnected.assignProperty(self.landButton, "enabled", False) disconnected.entered.connect(self._flight_mode_disconnected_entered) # HOVERING hovering = QState(parent_state) hovering.assignProperty(self, "status", "Hovering...") hovering.assignProperty(self.followButton, "text", "Follow Mode") hovering.assignProperty(self.emergencyButton, "enabled", True) hovering.assignProperty(self.liftButton, "enabled", False) hovering.assignProperty(self.followButton, "enabled", True) hovering.assignProperty(self.landButton, "enabled", True) hovering.entered.connect(self._flight_mode_hovering_entered) # GROUNDED grounded = QState(parent_state) grounded.assignProperty(self, "status", "Grounded") grounded.assignProperty(self.followButton, "text", "Follow Mode") grounded.assignProperty(self.emergencyButton, "enabled", True) grounded.assignProperty(self.liftButton, "enabled", True) grounded.assignProperty(self.followButton, "enabled", False) grounded.assignProperty(self.landButton, "enabled", False) grounded.entered.connect(self._flight_mode_grounded_entered) # FOLLOW follow = QState(parent_state) follow.assignProperty(self, "status", "Follow Mode") follow.assignProperty(self.followButton, "text", "Stop") follow.assignProperty(self.emergencyButton, "enabled", True) follow.assignProperty(self.landButton, "enabled", True) follow.assignProperty(self.followButton, "enabled", False) follow.assignProperty(self.liftButton, "enabled", False) follow.assignProperty(self.recordButton, "enabled", False) follow.entered.connect(self._flight_mode_follow_entered) # LIFT lift = QState(parent_state) lift.assignProperty(self, "status", "Lifting...") lift.assignProperty(self.emergencyButton, "enabled", True) lift.assignProperty(self.liftButton, "enabled", False) lift.assignProperty(self.followButton, "enabled", False) lift.assignProperty(self.landButton, "enabled", True) lift.entered.connect(self._flight_mode_lift_entered) # LAND land = QState(parent_state) land.assignProperty(self, "status", "Landing...") land.assignProperty(self.emergencyButton, "enabled", True) land.assignProperty(self.liftButton, "enabled", False) land.assignProperty(self.followButton, "enabled", False) land.assignProperty(self.landButton, "enabled", False) land.entered.connect(self._flight_mode_land_entered) def add_transition(mode, child_state, parent): transition = FlightModeTransition(mode) transition.setTargetState(child_state) parent.addTransition(transition) add_transition(FlightModeStates.LAND, land, parent_state) add_transition(FlightModeStates.LIFT, lift, parent_state) add_transition(FlightModeStates.HOVERING, hovering, parent_state) add_transition(FlightModeStates.FOLLOW, follow, parent_state) add_transition(FlightModeStates.GROUNDED, grounded, parent_state) add_transition(FlightModeStates.DISCONNECTED, disconnected, parent_state) parent_state.setInitialState(disconnected) self._machine.addState(parent_state) self._machine.setInitialState(parent_state) self._machine.start() """ update flight status is called when; - the CF is connected or disconnected - the QTM (or in our case the poseNet) is connected or disconnected it ensure that they are both connected before starting the flight controller. """ def _update_flight_status(self): """ assign old state to new state """ prev_flying_enabled = self.flying_enabled """ if there is a cf instance and a qtm connection instance (even if they are not connected) then flying is enabled """ self.flying_enabled = (self._cf is not None) # and \ # self._qtm_connection is not None """ if the flying enabled is not the same as prev_flying enabled" an additional check for security...? """ if not prev_flying_enabled and self.flying_enabled: self.switch_flight_mode(FlightModeStates.GROUNDED) t1 = threading.Thread(target=self.flight_controller) # t2 = threading.Thread(target=self.flight_logger) t1.start() # t2.start() """ if either the CF or QTM/Posenet Drops out. flight mode is disconnect """ if prev_flying_enabled and not self.flying_enabled: self.switch_flight_mode(FlightModeStates.DISCONNECTED) """ Although PyQt allows any Python callable to be used as a slot when connecting signals, it is sometimes necessary to explicitly mark a Python method as being a Qt slot and to provide a C++ signature for it. PyQt4 provides the pyqtSlot() function decorator to do this """ @pyqtSlot(str) def _update_cf_status(self, status): self.cfStatusLabel.setText(status) @pyqtSlot(str) def _update_status(self, status): self.statusLabel.setText("Status: {}".format(status)) """ A new Qt property may be defined using the pyqtProperty function. It is used in the same way as the standard Python property() function. In fact, Qt properties defined in this way also behave as Python properties. https://www.riverbankcomputing.com/static/Docs/PyQt5/qt_properties.html https://www.youtube.com/watch?v=jCzT9XFZ5bw """ @pyqtProperty(str, notify=cfStatusChanged) def cfStatus(self): return @cfStatus.setter def cfStatus(self, value): if value != self._cf_status: self._cf_status = value self.cfStatusChanged.emit(value) @pyqtProperty(str, notify=statusChanged) def status(self): return self._status @status.setter def status(self, value): if value != self._status: self._status = value self.statusChanged.emit(value) def _connected(self, link_uri): """Callback when the Crazyflie has been connected""" self._cf = self._helper.cf self._update_flight_status() logger.debug("Crazyflie connected to {}".format(link_uri)) # Gui self.cfStatus = ': connected' self.t2 = threading.Thread(target=self.flight_logger) self.t2.start() def _disconnected(self, link_uri): """Callback for when the Crazyflie has been disconnected""" logger.info("Crazyflie disconnected from {}".format(link_uri)) self.cfStatus = ': not connected' self._cf = None self._update_flight_status() def _param_updated(self, name, value): """Callback when the registered parameter get's updated""" logger.debug("Updated {0} to {1}".format(name, value)) def _log_data_received(self, timestamp, data, log_conf): """Callback when the log layer receives new data""" logger.debug("{0}:{1}:{2}".format(timestamp, log_conf.name, data)) def _logging_error(self, log_conf, msg): """Callback from the log layer when an error occurs""" QMessageBox.about(self, "Example error", "Error when using log config" " [{0}]: {1}".format(log_conf.name, msg)) def _flight_mode_land_entered(self): self.current_goal_pos = self.valid_cf_pos logger.info('Trying to land at: x: {} y: {}'.format( self.current_goal_pos.x, self.current_goal_pos.y)) self.land_rate = 1 print('flight_mode_land_entered') self._event.set() def _flight_mode_follow_entered(self): # self.last_valid_wand_pos = Position(0, 0, 1) self._event.set() def _flight_mode_lift_entered(self): self.current_goal_pos = self.valid_cf_pos logger.info('Trying to lift at: {}'.format( self.current_goal_pos)) self._event.set() def _flight_mode_hovering_entered(self): self.current_goal_pos = self.valid_cf_pos logger.info('Hovering at: {}'.format( self.current_goal_pos)) self._event.set() def _flight_mode_grounded_entered(self): self._event.set() print('flight_mode_grounded_entered') def _flight_mode_disconnected_entered(self): self._event.set() print('flight_mode_disconnected_entered') def flight_logger(self): logger.info('Starting flight logger thread') log_angle = LogConfig(name='lighthouse', period_in_ms=100) log_angle.add_variable('lighthouse.rawAngle0x', 'float') log_angle.add_variable('lighthouse.rawAngle0y', 'float') log_angle.add_variable('lighthouse.rawAngle1x', 'float') log_angle.add_variable('lighthouse.rawAngle1y', 'float') log_position = LogConfig(name='Position', period_in_ms=100) log_position.add_variable('stateEstimate.x', 'float') log_position.add_variable('stateEstimate.y', 'float') log_position.add_variable('stateEstimate.z', 'float') rawAngle0x = [0, 0] rawAngle0y = [0, 0] rawAngle1x = [0, 0] rawAngle1y = [0, 0] state_estimate = [0, 0, 0] with SyncLogger(self._cf, [log_angle,log_position]) as log: for log_entry in log: if 'lighthouse.rawAngle0x' in log_entry[1]: data_1 = log_entry[1] rawAngle0x.append(data_1['lighthouse.rawAngle0x']) rawAngle0x.pop(0) # rawAngle0y.append(data_1['lighthouse.rawAngle0y']) # rawAngle0y.pop(0) rawAngle1x.append(data_1['lighthouse.rawAngle1x']) rawAngle1x.pop(0) # rawAngle1y.append(data_1['lighthouse.rawAngle1y']) # rawAngle1y.pop(0) # if rawAngle0x[0] == rawAngle0x[1] and rawAngle0y[0] == rawAngle0y[1] and rawAngle1x[0] == \ # rawAngle1x[1] and rawAngle1y[0] == rawAngle1y[1]: print('0x-1x =',rawAngle0x[0]-rawAngle0x[1], '0y-1y =',rawAngle0y[0]-rawAngle1y[1]) if rawAngle0x[0] == rawAngle0x[1] and rawAngle1x[0] == rawAngle1x[1]: self.cf_pos = Position(float('nan'), float('nan'), float('nan')) print('setting cf_pos.x to {}'.format(self.cf_pos.x)) # print(self.cf_pos.x, self.cf_pos.y, self.cf_pos.z) if 'stateEstimate.x' in log_entry[1]: # if rawAngle0x[0] != rawAngle0x[1] and rawAngle0y[0] != rawAngle0y[1] and rawAngle1x[0] != \ # rawAngle1x[1] and rawAngle1y[0] != rawAngle1y[1]: if rawAngle0x[0] != rawAngle0x[1] or rawAngle1x[0] != rawAngle1x[1]: data_2 = log_entry[1] state_estimate[0] = data_2['stateEstimate.x'] state_estimate[1] = data_2['stateEstimate.y'] state_estimate[2] = data_2['stateEstimate.z'] self.cf_pos = Position(state_estimate[0], state_estimate[1], state_estimate[2]) print('updating state estimate to {}'.format(self.cf_pos.x)) # else: # print('unknown log_entry {}'.format(log_entry[1])) # raise Exception # except Exception as err: # logger.error(err) # self.cfStatus = str(err) # # logger.info('Terminating flight controller thread') def flight_controller(self): try: logger.info('Starting flight controller thread for {}'.format(self._cf)) self._cf.param.set_value('stabilizer.estimator', '2') self.reset_estimator(self._cf) self._cf.param.set_value('flightmode.posSet', '1') print('**PARAMETERS SET**') time.sleep(0.1) # The threshold for how many frames without tracking # is allowed before the cf's motors are stopped lost_tracking_threshold = 1000 frames_without_tracking = 0 position_hold_timer = 0 self.circle_angle = 0.0 # The main flight control loop, the behaviour # is controlled by the state of "FlightMode" while self.flying_enabled: print('cf_pos.x = {}'.format(self.cf_pos.x)) # print('start of the main control loop') # Check that the position is valid and store it if self.cf_pos.is_valid(): self.valid_cf_pos = self.cf_pos # print('valid cf pos is {}'.format(self.valid_cf_pos)) frames_without_tracking = 0 else: # if it isn't, count number of frames frames_without_tracking += 1 # print('frames without tracking {}'.format(frames_without_tracking)) if frames_without_tracking > lost_tracking_threshold: self.switch_flight_mode(FlightModeStates.GROUNDED) self.status = "Tracking lost, turning off motors" logger.info(self.status) # If the cf is upside down, kill the motors if self.flight_mode != FlightModeStates.GROUNDED and ( self.valid_cf_pos.roll > 120 or self.valid_cf_pos.roll < -120): self.switch_flight_mode(FlightModeStates.GROUNDED) self.status = "Status: Upside down, turning off motors" logger.info(self.status) # Switch on the FlightModeState and take actions accordingly # Wait so that any on state change actions are completed self._event.wait() if self.flight_mode == FlightModeStates.LAND: self.send_setpoint( Position( self.current_goal_pos.x, self.current_goal_pos.y, (self.current_goal_pos.z / self.land_rate), yaw=0)) # Check if the cf has reached the position, # if it has set a new position if self.valid_cf_pos.distance_to( Position(self.current_goal_pos.x, self.current_goal_pos.y, self.current_goal_pos.z / self.land_rate )) < self.path_pos_threshold: self.land_rate *= 1.1 if self.land_rate > 1000: self.send_setpoint(Position(0, 0, 0)) # if self.land_for_recording: # # Return the control to the recording mode # # after landing # mode = FlightModeStates.RECORD # self.land_for_recording = False # else: # # Regular landing # mode = FlightModeStates.GROUNDED mode = FlightModeStates.GROUNDED self.switch_flight_mode(mode) elif self.flight_mode == FlightModeStates.PATH: self.send_setpoint(self.current_goal_pos) # Check if the cf has reached the goal position, # if it has set a new goal position if self.valid_cf_pos.distance_to( self.current_goal_pos) < self.path_pos_threshold: if position_hold_timer > self.position_hold_timelimit: current = self.flight_paths[ self.pathSelector.currentIndex()] self.path_index += 1 if self.path_index == len(current): self.path_index = 1 position_hold_timer = 0 self.current_goal_pos = Position( current[self.path_index][0], current[self.path_index][1], current[self.path_index][2], yaw=current[self.path_index][3]) logger.info('Setting position {}'.format( self.current_goal_pos)) self._flight_path_select_row.emit( self.path_index - 1) elif position_hold_timer == 0: time_of_pos_reach = time.time() # Add som time just to get going, # it will be overwritten in the next step. # Setting it higher than the limit # will break the code. position_hold_timer = 0.0001 else: position_hold_timer = time.time( ) - time_of_pos_reach elif self.flight_mode == FlightModeStates.CIRCLE: self.send_setpoint(self.current_goal_pos) # Check if the cf has reached the goal position, # if it has set a new goal position if self.valid_cf_pos.distance_to( self.current_goal_pos) < self.circle_pos_threshold: if position_hold_timer >= self.position_hold_timelimit: position_hold_timer = 0 # increment the angle self.circle_angle = ((self.circle_angle + self.circle_resolution) % 360) # Calculate the next position in # the circle to fly to self.current_goal_pos = Position( round( math.cos(math.radians(self.circle_angle)), 4) * self.circle_radius, round( math.sin(math.radians(self.circle_angle)), 4) * self.circle_radius, self.circle_height, yaw=self.circle_angle) logger.info('Setting position {}'.format( self.current_goal_pos)) elif position_hold_timer == 0: time_of_pos_reach = time.time() # Add som time just to get going, it will be # overwritten in the next step. # Setting it higher than the imit will # break the code. position_hold_timer = 0.0001 else: position_hold_timer = time.time( ) - time_of_pos_reach elif self.flight_mode == FlightModeStates.FOLLOW: if self.wand_pos.is_valid(): self.last_valid_wand_pos = self.wand_pos # Fit the angle of the wand in the interval 0-4 self.length_from_wand = (2 * ( (self.wand_pos.roll + 90) / 180) - 1) + 2 self.send_setpoint( Position( self.wand_pos.x + round( math.cos(math.radians(self.wand_pos.yaw)), 4) * self.length_from_wand, self.wand_pos.y + round( math.sin(math.radians(self.wand_pos.yaw)), 4) * self.length_from_wand, ((self.wand_pos.z + round( math.sin( math.radians(self.wand_pos.pitch)), 4) * self.length_from_wand) if ((self.wand_pos.z + round( math.sin( math.radians(self.wand_pos.pitch)), 4) * self.length_from_wand) > 0) else 0))) else: self.length_from_wand = (2 * ( (self.last_valid_wand_pos.roll + 90) / 180) - 1) + 2 self.send_setpoint( Position( self.last_valid_wand_pos.x + round( math.cos( math.radians( self.last_valid_wand_pos.yaw)), 4) * self.length_from_wand, self.last_valid_wand_pos.y + round( math.sin( math.radians( self.last_valid_wand_pos.yaw)), 4) * self.length_from_wand, int(self.last_valid_wand_pos.z + round( math.sin( math.radians(self.last_valid_wand_pos. pitch)), 4) * self.length_from_wand))) elif self.flight_mode == FlightModeStates.LIFT: self.send_setpoint( Position(self.current_goal_pos.x, self.current_goal_pos.y, 1)) if self.valid_cf_pos.distance_to( Position(self.current_goal_pos.x, self.current_goal_pos.y, 1)) < 0.17: # Wait for hte crazyflie to reach the goal self.switch_flight_mode(FlightModeStates.HOVERING) else: print(self.valid_cf_pos.distance_to( Position(self.current_goal_pos.x, self.current_goal_pos.y, 1))) elif self.flight_mode == FlightModeStates.HOVERING: self.send_setpoint(self.current_goal_pos) elif self.flight_mode == FlightModeStates.RECORD: if self.valid_cf_pos.z > 1.0 and not self.recording: # Start recording when the cf is lifted self.recording = True # Start the timer thread self.save_current_position() # Gui self.status = "Recording Flightpath" logger.info(self.status) elif self.valid_cf_pos.z < 0.03 and self.recording: # Stop the recording when the cf is put on # the ground again logger.info("Recording stopped") self.recording = False # Remove the last bit (1s) of the recording, # containing setting the cf down for self.path_index in range(20): self.new_path.pop() # Add the new path to list and Gui now = datetime.datetime.fromtimestamp(time.time()) new_name = ("Recording {}/{}/{} {}:{}".format( now.year - 2000, now.month if now.month > 9 else "0{}".format(now.month), now.day if now.day > 9 else "0{}".format(now.day), now.hour if now.hour > 9 else "0{}".format( now.hour), now.minute if now.minute > 9 else "0{}".format(now.minute))) self.new_path.insert(0, new_name) self.flight_paths.append(self.new_path) self._path_selector_add_item.emit(new_name) # Select the new path self._path_selector_set_index.emit( len(self.flight_paths) - 1) self.path_changed() Config().set("flight_paths", self.flight_paths) # Wait while the operator moves away self.status = "Replay in 3s" time.sleep(1) self.status = "Replay in 2s" time.sleep(1) self.status = "Replay in 1s" time.sleep(1) # Switch to path mode and replay the recording self.switch_flight_mode(FlightModeStates.PATH) elif self.flight_mode == FlightModeStates.GROUNDED: # # testing multiple drone connection # uri_2 = 'radio://0/80/2M/E7E7E7E7ED' # with SyncCrazyflie(uri_2, cf=Crazyflie(rw_cache='./cache')) as scf: # print("yeah, I'm connected up!") # time.sleep(3) # print("now I will disconnect") pass # If gounded, the control is switched back to gamepad time.sleep(0.001) except Exception as err: logger.error(err) self.cfStatus = str(err) logger.info('Terminating flight controller thread') """change the state of the state machine (?)""" def set_lift_mode(self): self.switch_flight_mode(FlightModeStates.LIFT) def set_land_mode(self): self.switch_flight_mode(FlightModeStates.LAND) def set_follow_mode(self): # Toggle follow mode on and off if self.flight_mode == FlightModeStates.FOLLOW: self.switch_flight_mode(FlightModeStates.HOVERING) else: self.switch_flight_mode(FlightModeStates.FOLLOW) def set_kill_engine(self): # self.send_setpoint(Position(0, 0, 0)) self.switch_flight_mode(FlightModeStates.GROUNDED) logger.info('Stop button pressed, kill engines') def wait_for_position_estimator(self, cf): logger.info('Waiting for estimator to find stable position...') self.cfStatus = ( 'Waiting for estimator to find stable position... ' '(QTM needs to be connected and providing data)' ) log_config = LogConfig(name='Kalman Variance', period_in_ms=100) log_config.add_variable('kalman.varPX', 'float') log_config.add_variable('kalman.varPY', 'float') log_config.add_variable('kalman.varPZ', 'float') var_y_history = [1000] * 10 var_x_history = [1000] * 10 var_z_history = [1000] * 10 threshold = 0.001 with SyncLogger(cf, log_config) as log: for log_entry in log: data = log_entry[1] var_x_history.append(data['kalman.varPX']) var_x_history.pop(0) var_y_history.append(data['kalman.varPY']) var_y_history.pop(0) var_z_history.append(data['kalman.varPZ']) var_z_history.pop(0) min_x = min(var_x_history) max_x = max(var_x_history) min_y = min(var_y_history) max_y = max(var_y_history) min_z = min(var_z_history) max_z = max(var_z_history) print("x var = {} y var = {} z var = {}". format(max_x - min_x, max_y - min_y, max_z - min_z)) if (max_x - min_x) < threshold and ( max_y - min_y) < threshold and ( max_z - min_z) < threshold: logger.info("Position found with error in, x: {}, y: {}, " "z: {}".format(max_x - min_x, max_y - min_y, max_z - min_z)) self.cfStatus = ": connected" self.switch_flight_mode(FlightModeStates.GROUNDED) break def reset_estimator(self, cf): # Reset the kalman filter cf.param.set_value('kalman.resetEstimation', '1') time.sleep(0.1) cf.param.set_value('kalman.resetEstimation', '0') self.wait_for_position_estimator(cf) def switch_flight_mode(self, mode): # Handles the behaviour of switching between flight modes self.flight_mode = mode # Handle client input control. # Disable gamepad input if we are not grounded if self.flight_mode in [ FlightModeStates.GROUNDED, FlightModeStates.DISCONNECTED, FlightModeStates.RECORD ]: self._helper.mainUI.disable_input(False) else: self._helper.mainUI.disable_input(True) self._event.clear() # # Threadsafe call self._machine.postEvent(FlightModeEvent(mode)) logger.info('Switching Flight Mode to: %s', mode) def send_setpoint(self, pos): # Wraps the send command to the crazyflie latest_time = time.perf_counter() print('latest time =',latest_time) if latest_time - self.last_time < .100: return elif self._cf is not None: self._cf.commander.send_position_setpoint(pos.x, pos.y, pos.z, 0.0) self.last_time = time.perf_counter()
QPointF(((i % 8) - 4) * kineticPix.width() + kineticPix.width() / 2, ((i // 8) - 4) * kineticPix.height() + kineticPix.height() / 2)) # Centered. centeredState.assignProperty(item, 'pos', QPointF()) # Ui. view = View(scene) view.setWindowTitle("Animated Tiles") view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) view.setBackgroundBrush(QBrush(bgPix)) view.setCacheMode(QGraphicsView.CacheBackground) view.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) view.show() states = QStateMachine() states.addState(rootState) states.setInitialState(rootState) rootState.setInitialState(centeredState) group = QParallelAnimationGroup() for i, item in enumerate(items): anim = QPropertyAnimation(item, b'pos') anim.setDuration(750 + i * 25) anim.setEasingCurve(QEasingCurve.InOutBack) group.addAnimation(anim) trans = rootState.addTransition(ellipseButton.pressed, ellipseState) trans.addAnimation(group) trans = rootState.addTransition(figure8Button.pressed, figure8State)