Пример #1
0
    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)
Пример #2
0
    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)
Пример #3
0
    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()
Пример #4
0
    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()
Пример #5
0
    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()
Пример #6
0
    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
Пример #7
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()
Пример #8
0
    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()
Пример #9
0
 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)
Пример #10
0
    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)
Пример #11
0
    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()
Пример #12
0
    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()
Пример #13
0
    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
Пример #14
0
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")
Пример #16
0
    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()
Пример #17
0
    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_())
Пример #18
0
    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))
Пример #19
0
    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()
Пример #20
0
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 }")
Пример #21
0
 def __init__(self):
     super().__init__()
     self.ocx = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")
     self.fsm = QStateMachine()
     self.createState()
Пример #22
0
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
Пример #23
0
    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)
Пример #24
0
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()
Пример #25
0
    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))
Пример #26
0
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 
Пример #27
0
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_())
Пример #28
0
    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)
Пример #29
0
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()
Пример #30
0
    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 (&permil;)"),
            "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)
Пример #31
0
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
Пример #32
0
    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()
Пример #33
0
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 (&permil;)"),
            "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 (&permil;)"),
            "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
Пример #34
0
    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)
Пример #35
0
                ((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)
Пример #36
0
    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()
Пример #37
0
    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,
Пример #38
0
    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()
Пример #39
0
    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()
Пример #40
0
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()
Пример #41
0
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
Пример #42
0
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()
Пример #43
0
                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)