Example #1
0
class TimerWidget(QWidget):
    def __init__(self):
        super(TimerWidget, self).__init__()

        self.setMinimumSize(400, 30)
        self.setup()
        self.show()

    def setup(self):
        font = QFont()
        font.setWeight(100)
        self.setWindowTitle('Threading Timer Window')
        self.timer_counter = 0
        self.timer_label = QLabel("Timer:\t")
        self.timer_label.setFont(font)
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.increase_timer)
        reset_btn = QPushButton('Reset')
        reset_btn.clicked.connect(self.reset)
        grid = QGridLayout()
        grid.addWidget(self.timer_label, 0, 0)
        grid.addWidget(reset_btn, 0, 1)
        self.setLayout(grid)

    def increase_timer(self):
        self.timer_counter += 1
        self.timer_label.setText(f"Timer: {self.timer_counter} s")

    def reset(self):
        self.timer_label.setText("Timer:\t")
Example #2
0
class PyXtremeW(QWidget):
    def __init__(self):
        super(PyXtremeW, self).__init__()
        self.widget = None
        self.motorSender = HubDataSender.HubDataSender()
        self.motorSender.connect_to_controller()

        self.hubReceiver = HubDataReceiver.HubDataReceiver()
        self.hubReceiver.connect_to_controller()
        self.hubReceiver.statusUpdate.connect(self.update_status)

        self.load_ui()

        if self.widget is not None:
            self.widget.motorSlider.sliderReleased.connect(
                self.on_motor_slider_released)
            self.widget.steeringSlider.sliderReleased.connect(
                self.on_steering_slider_released)

            self.timer = QTimer()
            self.timer.setInterval(200)
            self.timer.timeout.connect(self.on_timer)

            self.timer.start()
            self.hubReceiver.start()  # Run data receiver thread

    def load_ui(self):
        loader = QUiLoader()
        # path = os.path.join(os.path.dirname(__file__), "form.ui")
        ui_file = QFile('ui/pyxtremew.ui')
        ui_file.open(QFile.ReadOnly)
        self.widget = loader.load(ui_file, self)
        ui_file.close()

    def closeEvent(self, event):
        if self.motorSender is not None:
            self.motorSender.disconnect_from_controller()
            self.hubReceiver.disconnect_from_controller()

    @Slot()
    def on_motor_slider_released(self):
        self.widget.motorSlider.setValue(0)

    @Slot()
    def on_steering_slider_released(self):
        self.widget.steeringSlider.setValue(0)

    @Slot()
    def on_timer(self):
        if self.motorSender is not None:
            self.motorSender.send_motor_commands(
                self.widget.steeringSlider.value(),
                self.widget.motorSlider.value())

    @Slot()
    def update_status(self):
        self.widget.statusLabel.setText(self.hubReceiver.status)
        self.widget.fwVersionLabel.setText(self.hubReceiver.fw)
        self.widget.hwVersionLabel.setText(self.hubReceiver.hw)
        self.widget.batteryLvl.setValue(self.hubReceiver.batteryLevel)
Example #3
0
class EmcTimer_Qt(EmcTimer):
    """ PySide2 implementation of the EmcTimer """
    def __init__(self, *args, **kargs):
        super().__init__(*args, **kargs)

        self._timer = QTimer()
        self._timer.timeout.connect(self._call_user_callback)
        self._timer.setInterval(int(self._interval * 1000))
        self._timer.start()

    def delete(self) -> None:
        super().delete()
        if self._timer:
            self._timer.stop()
            self._timer = None

    def start(self) -> None:
        if not self.deleted:
            self._timer.start()

    def stop(self) -> None:
        if not self.deleted:
            self._timer.stop()

    def reset(self) -> None:
        if not self.deleted:
            self._timer.start()
class CelRecognizerWorker(QObject):
    update = Signal(list)

    def __init__(self):
        super().__init__()
        self.process = None

        self.timer = QTimer()
        self.timer.timeout.connect(self.check_for_results)
        self.timer.setInterval(1000)
        self.timer.start(1000)
    
    def submit(self, cel_path, video_path):
        # Cancel an existing process if it exists
        self.cancel()
        
        # Start a new process to run the CelRecognizer
        self.pipe, child_conn = Pipe()
        self.process = Process(
            target=_recognizer_worker_func,
            args=(child_conn, cel_path, video_path))
        self.process.start()
    
    def check_for_results(self):
        if self.process is not None:
            while self.pipe.poll():
                results = self.pipe.recv()
                self.update.emit(results)

    def cancel(self):
        if self.process is not None:
            self.process.terminate()
            self.process.join()
            self.process.close()
            self.process = None
Example #5
0
class Pacer(QObject):
    def __init__(self, model):
        super().__init__()

        self.model = model
        self.timer = QTimer()

        self.refresh_freq = 8
        self.refresh_period = 1 / self.refresh_freq
        self.theta = np.linspace(0, 2 * np.pi, 75)
        self.cos_theta = np.cos(self.theta)
        self.sin_theta = np.sin(self.theta)

    def breathing_pattern(self, t):
        return 0.5 + 0.5 * np.sin(
            2 * np.pi * self.model.breathing_rate / 60 *
            t)  # scale such that amplitude fluctuates in [0, 1]

    def start(self):
        self.timer.timeout.connect(self.update_pacer)
        self.timer.setInterval(self.refresh_period * 1000)
        self.timer.start()

    def update_pacer(self):
        """Update radius of pacer disc.

        Make current disk radius a function of real time (i.e., don't
        precompute radii with fixed time interval) in order to compensate for
        jitter or delay in QTimer calls.
        """
        t = time.time()
        radius = self.breathing_pattern(t)
        x = radius * self.cos_theta
        y = radius * self.sin_theta
        self.model.pacer_coordinates = (x, y)
Example #6
0
def test_QGLW_Cad2D():
    gui = dfm2.qt.QGLW_Cad2D()
    icnt = 0

    def events():
        nonlocal icnt, gui
        if icnt == 10:
            gui.cadobj = dfm2.Cad2D()
            gui.cadobj.add_polygon([-1, -1, +1, -1, +1, +1, -1, +1])
        if icnt == 20:
            gui.cadobj.pick(-1, +1, view_height=2)
            assert gui.cadobj.ivtx_picked() == 3
        if icnt > 20 and icnt < 30:
            gui.cadobj.motion([-1, +1, 0], [-1 - (icnt - 20) * 0.02, +1, 0],
                              [0, 0, 1])
        if icnt == 30:
            gui.close()
        icnt += 1
        gui.update()

    gui.show()
    timer = QTimer()
    timer.setInterval(50)
    timer.timeout.connect(events)
    timer.start()  # 1 sec
    app.exec_()  # loop
Example #7
0
    def __init__(self, app, **kwargs):
        super().__init__(**kwargs)
        self.app = app
        self._bound_regions = []
        self._overlay = OverlayApi(self, parent=self)
        self.logger = logging.getLogger(__name__ + "." +
                                        self.__class__.__name__ + "." +
                                        self.app.manifest["appName"])

        self.rpc_funcs = {
            "getRegion": self.get_region,
            "getRegionRaw": self.get_region_raw,
            "bindRegion": self.bind_region,
            "bindGetRegion": self.bind_get_region,
            "bindGetRegionRaw": self.bind_get_region_raw,
        }

        self._update_screen_info()
        self._game_position = self.app.game_instance.get_position()
        self._game_scaling = self.app.game_instance.get_scaling()
        self._private = Alt1ApiPrivate(self, parent=self)
        self.app.game_instance.game_activity.connect(self.game_activity_signal)
        self.app.game_instance.worldChanged.connect(self.world_change_signal)

        poll_timer = QTimer(self)
        poll_timer.setInterval(250)

        if self.app.has_permission("gamestate"):
            poll_timer.timeout.connect(self.mouse_move_signal)

        poll_timer.start()
Example #8
0
class ShowProgressBasedOnTime(QObject):
    update_signal = Signal(int)

    def __init__(self, target, duration=5000):
        super(ShowProgressBasedOnTime, self).__init__()
        self.target = target
        self.duration = duration
        self.start_time = time()

        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update)

        self.update_signal.connect(self.target)

    def start(self, duration):
        # Update every 1/25 of a second
        self.update_timer.setInterval(round(duration / 25 * 1000))
        self.update_timer.start()
        self.duration = duration
        self.start_time = time()

    def stop(self):
        self.update_timer.stop()

    def update(self):
        elapsed_time = time() - self.start_time
        progress = round(elapsed_time * 100 / max(1, self.duration))
        self.update_signal.emit(progress)

        if elapsed_time > float(self.duration):
            self.update_timer.stop()
Example #9
0
def test_QGLWMesh():
    gui = dfm2.qt.QGLW_Mesh()
    icnt = 0

    def events():
        nonlocal icnt, gui
        icnt = icnt + 1
        if icnt == 10:
            gui.msh = dfm2.Mesh()
            gui.msh.read("../test_inputs/bunny_2k.ply")
            gui.msh.scale_xyz(0.03)
        if icnt == 20:
            gui.make_buffer()
            event = QMouseEvent(QEvent.MouseButtonPress, QPointF(200.0, 200.0),
                                Qt.LeftButton, Qt.NoButton, Qt.ShiftModifier)
            gui.mousePressEvent(event)
        if icnt > 20 and icnt < 30:
            event = QMouseEvent(QEvent.MouseMove,
                                QPointF(200.0 + (icnt - 20) * 5, 200.0),
                                Qt.LeftButton, Qt.NoButton, Qt.NoModifier)
            gui.mouseMoveEvent(event)
        if icnt >= 30:
            gui.close()
        gui.update()

    gui.show()
    timer = QTimer()
    timer.setInterval(30)
    timer.timeout.connect(events)
    timer.start()  # 1 sec
    app.exec_()  # event loop
Example #10
0
    def on_sceneLoaded(self, status):
        if(status != Kuesa.GLTF2Importer.Status.Ready):
            return

        # The glTF file has now been loaded, we can start fiddling with the scene.
        # Cube.001 is at the bottom-left.

        # Here, we are going to change the transform of an entity.
        # It is also possible to change other properties - refer to the collection documentation
        # to get an overview of what is possible.
        self.cubeAsset = self.rootEntity.entities().find("Cube.001")

        for child in self.cubeAsset.children():
            if isinstance(child, Qt3DCore.QTransform):
                # We found the transform of the cube we want to change
                self.cubeTransform = child

                # It can be modified like this
                child.setScale(2)

                # Let's change one of its properties regularly with a timer
                # Note: the next tutorial, 3-animation.py, will show how to use embedded glTF animations.
                self.cubeScaleDirection = 1

                timer = QTimer(self)
                timer.setInterval(16)
                timer.timeout.connect(self.changeCubeScale)
                timer.start()
Example #11
0
class CpuLoadModel(QAbstractListModel):
    def __init__(self):
        QAbstractListModel.__init__(self)

        self.__cpu_count = psutil.cpu_count()
        self.__cpu_load = [0] * self.__cpu_count

        self.__update_timer = QTimer(self)
        self.__update_timer.setInterval(1000)
        self.__update_timer.timeout.connect(self.__update)
        self.__update_timer.start()

        # The first call returns invalid data
        psutil.cpu_percent(percpu=True)

    def __update(self):
        self.__cpu_load = psutil.cpu_percent(percpu=True)
        self.dataChanged.emit(self.index(0, 0),
                              self.index(self.__cpu_count - 1, 0))

    def rowCount(self, parent):
        return self.__cpu_count

    def data(self, index, role):
        if (role == Qt.DisplayRole and index.row() >= 0
                and index.row() < len(self.__cpu_load)
                and index.column() == 0):
            return self.__cpu_load[index.row()]
        else:
            return None
Example #12
0
class CpuLoadModel(QAbstractListModel):
    def __init__(self):
        QAbstractListModel.__init__(self)
        
        self.__cpu_count = psutil.cpu_count()
        self.__cpu_load = [0] * self.__cpu_count
        
        self.__update_timer = QTimer(self)
        self.__update_timer.setInterval(1000)
        self.__update_timer.timeout.connect(self.__update)
        self.__update_timer.start()
        
        # The first call returns invalid data
        psutil.cpu_percent(percpu=True)
            
    def __update(self):
        self.__cpu_load = psutil.cpu_percent(percpu=True)
        self.dataChanged.emit(self.index(0,0), self.index(self.__cpu_count-1, 0))
        
    def rowCount(self, parent):
        return self.__cpu_count
    
    def data(self, index, role):
        if (role == Qt.DisplayRole and
            index.row() >= 0 and
            index.row() < len(self.__cpu_load) and
            index.column() == 0):
            return self.__cpu_load[index.row()]
        else:
            return None
class TimerMessageBox(QMessageBox):
    def __init__(self,
                 timeout=3,
                 title=None,
                 text='Closing automatically in {} seconds',
                 parent=None):
        super(TimerMessageBox, self).__init__(parent)
        self.text = text
        self.setWindowTitle(title)
        self.time_to_wait = timeout
        self.setText(self.text.format(timeout))
        self.setIcon(QMessageBox.Information)
        self.setStandardButtons(QMessageBox.NoButton)
        self.timer = QTimer(self)
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.change_content)
        self.timer.start()

    def change_content(self):
        self.setText(self.text.format(self.time_to_wait))
        if self.time_to_wait <= 0:
            self.close()
        self.time_to_wait -= 1

    def closeEvent(self, event):
        self.timer.stop()
        event.accept()
Example #14
0
class CountdownModel(QObject):
    """CountdownModel is the model class for the GUI. It holds the counter property
     and handles event generated by the click on the button."""

    def __init__(self):
        QObject.__init__(self)
        # Value to count from
        self.total = 30
        self._remaining = 30
        # Timer
        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.process_timer)

    def set_remaining(self, val):
        if val != self._remaining:
            self._remaining = val
            self.remaining_changed.emit()
            # If the timer is inactive, update also a value to count from
            if not self.timer.isActive():
                self.total = self.remaining

    remaining_changed = Signal()
    # Property holding actual remaining number of seconds
    remaining = Property(int, lambda self: self._remaining, set_remaining, notify=remaining_changed)

    timeout = Signal()

    @Slot()
    def process_timer(self):
        """Handler for the timer event.
        Decrease the remaining value or stop the timer and emit timeout signal if the time is over"""
        if self.remaining == 1:
            self.timer.stop()
            self.remaining = self.total     # Reset the timer value
            self.timeout.emit()
            return
        self.remaining -= 1

    @Slot()
    def start(self):
        """Start the countdown"""
        print("Starting")
        print(self.total,self.remaining)
        self.timer.start()

    @Slot()
    def pause(self):
        """Pause the countdown"""
        print("Pausing")
        print(self.total,self.remaining)
        self.timer.stop()

    @Slot()
    def stop(self):
        """Stop (and reset) the countdown"""
        print("Stopping")
        print(self.total,self.remaining)
        self.timer.stop()
        self.remaining = self.total
Example #15
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.counter = 0

        layout = QVBoxLayout()

        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)

        layout.addWidget(self.l)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

    def oh_no(self):
        time.sleep(5)

    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Counter: %d" % self.counter)
Example #16
0
def main():
    basePath = os.path.dirname(os.path.realpath(__file__))
    app = QApplication(sys.argv)
    contextMenu = QMenu()
    fixAction = QAction(
        "Run 'create__ap --fix-unmanaged' in the terminal as root to fix possible issues"
    )
    contextMenu.addAction(fixAction)
    activeIcon = QIcon()
    activeIcon.addFile(os.path.join(basePath, "wifi.svg"))
    inactiveIcon = QIcon()
    inactiveIcon.addFile(os.path.join(basePath, "wifi-off.svg"))
    trayIcon = QSystemTrayIcon(inactiveIcon)
    trayIcon.setContextMenu(contextMenu)
    trayIcon.activated.connect(handleTrayIconClick)

    def syncIcon():
        if serviceIsActive():
            trayIcon.setIcon(activeIcon)
        else:
            trayIcon.setIcon(inactiveIcon)

    timer = QTimer()
    timer.setInterval(1000)
    timer.timeout.connect(syncIcon)
    timer.start()
    trayIcon.show()
    sys.exit(app.exec_())
Example #17
0
class BPMmp():
    """Calculate BPM using Python's native multiprocessing module."""
    def __init__(self, bpm_set_fun, algorithm="multifeature"):
        self.bpm_set_fun = bpm_set_fun
        self.essentia_rhythm_algorithm = algorithm

        self.queue = mp.Queue()
        self.process = None

        self.bpm_timer = QTimer()
        self.bpm_timer.setInterval(1000)
        self.bpm_timer.timeout.connect(self.update_bpm)
        self.bpm_timer.start()

    def start_bpm_calculation(self, audio):
        """Start new process to calculate BPM."""
        self.process = mp.Process(target=self.bpm_helper,
                                  args=(self.queue, audio,
                                        self.essentia_rhythm_algorithm))
        self.process.start()

    def update_bpm(self):
        """Update BPM for changing Gandalf gif's playback speed."""
        try:
            bpm = self.queue.get(False)
            self.process.join()
            if 0 < bpm < 300:
                self.bpm_set_fun(bpm)
        except mp.queues.Empty:
            pass

    @staticmethod
    def bpm_helper(queue, audio, method="multifeature"):
        """Find Beats per Minute from audio data.

        Choose rhythm extractor algorithm based on CPU resources available.
        Multifeature is more accurate but slower. Degara also has no confidence
        level calculation (always returns 0), so remove it if using that algorithm.
        """
        min_tempo = 40
        max_tempo = 150
        if method == "degara":
            rhythm_extractor = essentia.standard.RhythmExtractor2013(
                method="degara", minTempo=min_tempo, maxTempo=max_tempo)
            bpm, _, _, _, _ = rhythm_extractor(audio)
            #print("BPM:", bpm)
            queue.put(bpm)

        else:
            rhythm_extractor = essentia.standard.RhythmExtractor2013(
                method="multifeature", minTempo=min_tempo, maxTempo=max_tempo)
            bpm, _, beats_confidence, _, _ = rhythm_extractor(audio)
            #print("BPM: {} Confidence: {}".format(bpm, beats_confidence))
            if beats_confidence > 2.5:
                queue.put(bpm)
            else:
                queue.put(-1)

        return 0
Example #18
0
class Collector(QObject):

    valuesChanged = Signal(object, object)

    def __init__(self, portName):
        super().__init__()
        self.portName = portName
        self.thread = QThread()
        self.moveToThread(self.thread)
        self.thread.started.connect(self.create)
        self.thread.start()

    def sendModeCmd(self, cmd):
        self.serialPort.write(cmd)
        #print("Sent CMD: ", cmd)

    def create(self):
        try:
            self.values = Values()
            self.serialPort = serial.Serial(self.portName,
                                            baudrate=460800,
                                            timeout=1)  #115200, timeout=1)
            self.serialPort.write(b'O')
            self.n = 0
            self.tstart = time.perf_counter_ns()
            self.timer = QTimer()
            self.timer.timeout.connect(self.readFromSerial,
                                       Qt.QueuedConnection)
            self.timer.setInterval(0)
            self.timer.start()
        except Exception as e:
            traceback.print_exc()

    def readFromSerial(self):
        try:
            buf = self.serialPort.read(1)
            numBytes, = struct.unpack("B", buf)
            while len(buf) < numBytes - 1:
                buf += self.serialPort.read(numBytes - 1)
            dbg = DebugStruct.from_buffer_copy(buf)
            self.n += len(buf) + 2
            if 0:
                print("read %d bytes in %.2f seconds: bits/second=%.1f" %
                      (self.n, (time.perf_counter_ns() - self.tstart) * 1e-9,
                       self.n * 8 /
                       ((time.perf_counter_ns() - self.tstart) * 1e-9)))
            if 0:
                print(
                    "Profiling 01: %.1f ms   12: %.1f ms   23: %.1f ms      03: %.1f ms"
                    % (
                        (items[-3] - items[-4]) * 1e-3,
                        (items[-2] - items[-3]) * 1e-3,
                        (items[-1] - items[-2]) * 1e-3,
                        (items[-1] - items[-4]) * 1e-3,
                    ))
            self.values.update(dbg)
            self.valuesChanged.emit(self.values, dbg)
        except Exception as e:
            traceback.print_exc()
Example #19
0
class cuisine(QMainWindow):
    def __init__(self, parent=None):
        super(cuisine, self).__init__(parent)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.timer = QTimer()
        self.timer.setInterval(5000)

        # connect timeout vers fonction Refresh
        self.timer.timeout.connect(self.refreshData)
        self.timer.start()

        # cellClicked.connect permet de changer d'Etat 1 à 2
        self.ui.tableWidget.cellClicked.connect(self.itemNouveauClicked)

    def itemNouveauClicked(self, rowClicked, colClicked):
        print('click', rowClicked, colClicked)

    def refreshData(self):
        req = requests.get('http://localhost:5000/cuisine')
        retour = req.json()
        self.updateTabletWidget(retour)
        self.updateTabletWidget2(retour)

    def updateTabletWidget(self,
                           dataJson):  # Nouvelles commandes (emplacement)
        self.ui.tableWidget.clear()

        header = ["id Commandes", "Noms Clients"]
        self.ui.tableWidget.setColumnCount(len(header))
        self.ui.tableWidget.setHorizontalHeaderLabels(header)

        cpt = 0
        for fiche in dataJson["commandes"]:
            if fiche["etat"] == 1:
                self.ui.tableWidget.setRowCount(cpt + 1)
                self.ui.tableWidget.setItem(cpt, 0, itemID)
                self.ui.tableWidget.setItem(cpt, 1, itemNom)
                itemID = QTableWidgetItem(str(fiche["id"]))
                itemNom = QTableWidgetItem(fiche["nom"])

                cpt = cpt + 1

    def updateTabletWidget2(self):  # commandes en cours
        self.ui.tableWidget2.clear()
        self.ui.tableWidget2.setRowCount(0)
        self.ui.tableWidget2.setColumnCount(2)

        cpt = 0
        for fiche in dataJson["commandes"]:
            if fiche["etat"] == 2:
                self.ui.tableWidget2.setRowCount(cpt + 1)
                itemID = QTableWidget2Item(str(fiche["id"]))
                itemNom = QTableWidget2Item(fiche["nom"])
                self.ui.tableWidget2.setItem(cpt, 0, itemID)
                self.ui.tableWidget2.setItem(cpt, 1, itemNom)
                cpt = cpt + 1
Example #20
0
class Qtlet(QObject):
    """
    Adapter between `traitlets` notification and Qt Signals and Slots.
    """
    data_changed = Signal(object)  # fallback

    def __init__(self, inst, attr, *a, **kw):
        super().__init__(*a, **kw)
        self.widgets = []  # holds weakref.proxy elements.
        self.inst = inst
        self.attr = attr
        self.timer = None

    @property
    def value(self):
        return getattr(self.inst, self.attr)

    @value.setter
    def value(self, value):
        setattr(self.inst, self.attr, value)

    @property
    def has_widgets(self):
        return len(self.widgets) > 0

    def on_widget_edited(self, value):  # this is a slot
        """
        Update the attribute to given value.
        """
        # note this is exactly the same as @value.setter...
        self.value = value

    def sync_widgets(self):
        """Force the update of all linked widgets with the current value."""
        self.data_changed.emit(self.value)

    def link_widget(self, widget, widget_signal=None, widget_slot=None):
        """Link a widget to the trait."""
        # todo: use a function and dispatch to get the two methods (widget.valueEdited, widget.setValue)
        # todo: add bounds to validator.. here is probably the best, in "link"
        if widget_signal is None:
            widget_signal = notifier_signal(widget)
        widget_signal.connect(self.on_widget_edited)
        if widget_slot is None:
            widget_slot = setter_slot(widget)
        self.data_changed.connect(widget_slot)
        self.widgets.append(proxy(widget))
        self.data_changed.emit(self.value)
        return self

    def use_polling(self, interval: float = 20):
        """Checks and update the value on a fixed interval, in ms."""
        if self.timer is None:
            self.timer = QTimer(parent=self)
        self.timer.setInterval(interval)
        self.timer.timeout.connect(self.sync_widgets)
        self.timer.start()
        # TODO: we could need a stop and a teardown...
        return self
Example #21
0
    def _prepare_overtime_check_timer(self):
        self._check_overtime()

        timer = QTimer()
        timer.setInterval(60 * 1000)
        timer.timeout.connect(self._check_overtime)

        return timer
Example #22
0
class SearchUserQComboBox(QComboBox):
    def __init__(self):
        super().__init__()

        self.setEditable(True)
        self.results: List[MixcloudUser] = []
        self.selected_result: Any[MixcloudUser, None] = None
        self.search_artist_thread = SearchArtistThread()

        # Connections
        self._connect_with_delay(
            input=self.lineEdit().textEdited,
            slot=self.get_suggestions,
        )
        self.currentIndexChanged.connect(
            lambda user: self.set_selected_result(index=self.currentIndex()))
        self.search_artist_thread.new_result.connect(self.add_result)
        self.search_artist_thread.error_signal.connect(self.show_error)

    def _connect_with_delay(self,
                            input: Callable,
                            slot: Slot,
                            delay_ms: int = 750):
        """Connects a given input to a given Slot with a given delay."""
        self.timer = QTimer()
        self.timer.setInterval(delay_ms)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(slot)
        input.connect(self.timer.start)

    @Slot()
    def get_suggestions(self) -> None:
        phrase = self.currentText()

        if phrase:
            self.clear()
            self.results.clear()

            self.search_artist_thread.phrase = phrase
            self.search_artist_thread.start()

    @Slot()
    def show_error(self, msg: str):
        ErrorDialog(self.parent(), message=msg)

    @Slot()
    def add_result(self, item: MixcloudUser):
        self.results.append(item)

        if len(self.results) == 1:
            self.set_selected_result(index=0)

        self.addItem(f'{item.name} ({item.username})')

    @Slot(MixcloudUser)
    def set_selected_result(self, index: int):
        self.selected_result = self.results[index]
Example #23
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.counter = 0

        layout = QVBoxLayout()

        self.l = QLabel("Start")
        b = QPushButton("DANGER!")
        b.pressed.connect(self.oh_no)

        layout.addWidget(self.l)
        layout.addWidget(b)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.recurring_timer)
        self.timer.start()

    def progress_fn(self, n):
        print("%d%% done" % n)

    def print_output(self, s):
        print(s)

    def thread_complete(self):
        print("THREAD COMPLETE!")

    def oh_no(self):
        # Pass the function to execute
        worker = Worker(
            execute_this_fn
        )  # Any other args, kwargs are passed to the run function
        worker.signals.result.connect(self.print_output)
        worker.signals.finished.connect(self.thread_complete)
        worker.signals.progress.connect(self.progress_fn)

        # Execute
        self.threadpool.start(worker)

    def recurring_timer(self):
        self.counter += 1
        self.l.setText("Counter: %d" % self.counter)
Example #24
0
class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('计时器')
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.timer = QTimer(self)
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.handle_timeout)
        self.ui.zheng.setChecked(True)
        self.ui.stop.setEnabled(False)
        self.ui.dao.clicked.connect(handle_set)
        self.ui.start.clicked.connect(self.handle_start)
        self.ui.stop.clicked.connect(self.handle_stop)
        self.ui.zheng.clicked.connect(self.handle_zheng)
        self.ui.setzero.clicked.connect(self.handle_zero)
        self.setWindowIcon(QIcon('clock.gif'))
        self.change = 1
        self.method = 'zheng'
        self.time = 0

    def handle_timeout(self):
        minutes_total = self.time // 60
        seconds = self.time % 60
        self.time += self.change
        self.ui.min.display(str(minutes_total))
        self.ui.sec.display(str(seconds))
        if (minutes_total, seconds) <= (0, 0) and self.method == 'dao':
            self.ui.min.setStyleSheet('color: red; border: none;')
            self.ui.sec.setStyleSheet('color: red; border: none;')
            self.handle_stop()
        elif (minutes_total, seconds) == (0, 3) and self.method == 'dao':
            QSound.play('timer.wav')

    def handle_start(self):
        self.timer.start()
        self.ui.stop.setEnabled(True)
        self.ui.start.setEnabled(False)
        self.ui.min.setStyleSheet('color: green; border: none;')
        self.ui.sec.setStyleSheet('color: green; border: none;')

    def handle_stop(self):
        self.timer.stop()
        self.ui.stop.setEnabled(False)
        self.ui.start.setEnabled(True)
        self.ui.zheng.setChecked(True)
        self.time = 0 if self.method == 'dao' else self.time
        self.change = 1
        self.method = 'zheng'

    def handle_zheng(self):
        self.change = 1

    def handle_zero(self):
        self.time = 0
Example #25
0
class GameConnection(ConnectionBase):
    StatusUpdated = Signal(ConnectionStatus)

    _dt: float = 1.0
    _current_status: ConnectionStatus = ConnectionStatus.Disconnected
    backend: ConnectionBackend = None

    def __init__(self):
        super().__init__()

        self._timer = QTimer(self)
        self._timer.timeout.connect(self._update)
        self._timer.setInterval(self._dt * 1000)

    def set_backend(self, backend: ConnectionBackend):
        if self.backend is not None:
            self.backend.LocationCollected.disconnect(
                self.LocationCollected.emit)

        self.backend = backend
        self.backend.LocationCollected.connect(self.LocationCollected.emit)

    async def start(self):
        self._timer.start()

    async def stop(self):
        self._timer.stop()

    @asyncSlot()
    async def _update(self):
        await self.backend.update(self._dt)
        new_status = self.backend.current_status
        if self._current_status != new_status:
            self._current_status = new_status
            self.StatusUpdated.emit(new_status)

    @property
    def pretty_current_status(self) -> str:
        return f"{self.backend.name}: {self.backend.current_status.value}"

    @property
    def current_status(self) -> ConnectionStatus:
        return self.backend.current_status

    async def display_message(self, message: str):
        return await self.backend.display_message(message)

    async def get_inventory(self) -> CurrentResources:
        return await self.backend.get_inventory()

    def send_pickup(self, pickup: PickupEntry):
        return self.backend.send_pickup(pickup)

    def set_permanent_pickups(self, pickups: List[PickupEntry]):
        return self.backend.set_permanent_pickups(pickups)
Example #26
0
class Tailer(QObject):

    startSignal = Signal()
    stopSignal = Signal()
    newLineSignal = Signal(str)

    def __init__(self):
        QObject.__init__(self)
        self.filePath = Settings().getLoggingFilepath()
        self.timer = QTimer(self)
        refershIntervalMs = Settings().getTailerRefreshTimeMs()
        self.timer.setInterval(int(refershIntervalMs))
        self.fp = None
        self.setupSignalsAndSlots()

    def setupSignalsAndSlots(self):
        self.timer.timeout.connect(self.processFile)

    @Slot()
    def stopProcess(self):
        self.timer.stop()
        self.fp.close()
        self.stopSignal.emit()

    @Slot()
    def startProcess(self):
        try:
            self.fp = open(self.filePath, "r")
            self.timer.start()
            self.startSignal.emit()
        except OSError as err:
            Logger().error("Errore apertura file: " + self.filePatherr)
            Logger().error("Codice Errore: " + str(err.errno))
            Logger().error("Descrizione Errore: " + err.strerror)
            QTimer.singleShot(self.startProcess, 1000)

        # with open(filepath, mode="r") as fp:
        #     while not self.stopped:
        #         line = fp.readline()
        #         if line:
        #             self.newLineSignal.emit(line.strip())
        #         else:
        #             time.sleep(self.waitTimeSec)
        #         QCoreApplication.processEvents()
        # self.stopSignal.emit()

    @Slot()
    def processFile(self):
        newLines = str()
        for line in self.fp:
            newLines += line
        if len(newLines) > 0:
            self.newLineSignal.emit(newLines.strip())
        else:
            time.sleep(self.waitTimeSec)
Example #27
0
class ErrorHandler(QObject):
    def __init__(self, parent=None):
        super(ErrorHandler, self).__init__(parent)
        self.mw = parent
        self.timer = None
        self._oldstderr = sys.stderr
        # self.error_received.connect(self.on_error_received)
        self.pool = ''
        self.timer = None
        sys.stderr = self

    def unload(self):
        sys.stderr = self._oldstderr
        sys.excepthook = None
        self.stop_timer()

    def stop_timer(self):
        if self.timer and self.timer.isActive():
            self.timer.stop()
        self.timer = None

    def start_timer(self):
        if not self.timer:
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.on_error_received)
            self.timer.setInterval(100)
            # self.timer.setSingleShot(True)
            self.timer.start()

    def write(self, data):
        # dump to stdout
        self.pool += data
        sys.stdout.write(data)
        self.start_timer()

    @Slot(str)
    def on_error_received(self):
        if not self.pool:
            return
        self.stop_timer()
        error = html.escape(self.pool)
        self.pool = ''
        txt = 'An error occurred, please report this error to maintainer:'
        # show dialog
        txt = txt + "<br><div style='white-space: pre-wrap'>" + error + "</div>" + f"<p>{self.support_msg}</p>"
        show_text(txt, parent=self.mw, send_issue=True)

    @property
    def support_msg(self) -> str:
        msg = f"--------------------<br>" \
            f"{APP_NAME_SHORT} ({VERSION})<br>" \
            f"Qt: {QT_VERSION}, PySide: {SHIBOKEN_VERSION}, Shiboken2: {SHIBOKEN_VERSION}<br>" \
            f"Platform: {sys.platform}" \
            f"<br>Environ:<br> {';'.join(k + '=' + v for k, v in os.environ.items())}"
        return msg
Example #28
0
class monHorloge(QWidget):
    def __init__(self, parent=None):
        super(monHorloge, self).__init__(parent)

        currentTime= QTime.currentTime()
        self.heure = currentTime.hour()
        self.minute = currentTime.minute()

        self.timer = QTimer()
        self.timer.setInterval(1000)
        self.timer.timeout.connect(self.increaseTime)
        self.timer.start()

    def changeFreq(self,val):
        self.timer.setInterval(val)
        self.timer.start()

    def increaseTime(self):
        self.minute += 1
        if self.minute == 60:
            self.minute = 0
            self.heure += 1
            if self.heure == 12:
                self.heure = 0
        self.update()

    def paintEvent(self, event:QPaintEvent):
        p = QPainter(self)
        p.setBrush(Qt.blue)
        p.drawRect(10,10,self.width()-20, self.height()-20)
        p.setBrush(Qt.yellow)
        p.drawEllipse(20,20,self.width()-40, self.height()-40)

        p.save()

        p.translate(self.width()/2,self.height()/2)

        p.save()

        p.rotate((-90 + self.heure*30)+(self.minute)/2)
        pen = QPen(Qt.green,10)
        p.setPen(pen)
        p.drawLine(0,0,(self.width()-40)/5,0)

        p.restore()

        p.rotate(-90 + self.minute*6)
        pen = QPen(Qt.black, 10)
        p.setPen(pen)
        p.drawLine(0, 0, (self.width() - 40) / 3, 0)

        p.restore()

        p.setBrush(Qt.red)
        p.drawEllipse((self.width()/2)-20,(self.height()/2)-20,40, 40)
Example #29
0
    def queue_command(self, name, command):
        timer = self.timers.get(name, None)
        if timer is None:
            timer = QTimer()
            timer.setInterval(200)
            timer.setSingleShot(True)
            timer.timeout.connect(self.timeout)
            timer.start()

        setattr(timer, 'command', command)
        self.timers[name] = timer
Example #30
0
 def set_intervals(self, intervals):
     self.timers.clear()
     self.intervals = intervals
     for val in intervals:
         timer = QTimer(self)
         timer.setSingleShot(True)
         timer.setInterval(val * 1000)
         timer.setTimerType(Qt.PreciseTimer)
         timer.timeout.connect(self.target)
         if (val == intervals[-1]): timer.timeout.connect(self.callback)
         self.timers.append(timer)
Example #31
0
class QtLoading(QtWidgets.QDialog, Ui_Loading):
    def __init__(self, owner):
        super(self.__class__, self).__init__(owner)
        Ui_Loading.__init__(self)
        self.setupUi(self)
        self.owner = weakref.ref(owner)
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
        self.setWindowFlag(QtCore.Qt.Dialog)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        self.setWindowModality(QtCore.Qt.ApplicationModal)
        # frmX = self.width()
        # frmY = self.height()
        # w = QDesktopWidget()
        # w.width()
        # movePoint = QPoint(int(w.width()/2-frmX/2), int(w.height()/2 - frmY/2))
        # self.move(movePoint)
        self.index = 1
        self.qMapList = []
        for i in range(1, 11):
            data = resources.DataMgr.GetData("loading_{}".format(str(i)))
            img = QImage()
            img.loadFromData(data)
            self.qMapList.append(img)

        self.label.setFixedSize(QPixmap.fromImage(self.qMapList[0]).size())
        self.label.setPixmap(QPixmap.fromImage(self.qMapList[0]))
        self.label.setScaledContents(True)
        self.timer = QTimer(self.label)
        self.timer.setInterval(100)

        self.cnt = 0
        self.closeCnt = 50
        self.timer.timeout.connect(self.UpdatePic)

    def show(self) -> None:
        self.timer.start()
        self.cnt = 0
        super(self.__class__, self).show()

    def close(self):
        self.timer.stop()
        super(self.__class__, self).close()

    def UpdatePic(self):
        self.index += 1
        if self.index >= 10:
            self.index = 0
        # self.label.setPixmap(QPixmap("resources/loading_{}_big.png".format(self.index)))
        self.label.setPixmap(QPixmap.fromImage(self.qMapList[self.index]))
        self.cnt += 1
        if self.cnt >= self.closeCnt:
            self.close()
        pass
Example #32
0
class QGameOfLife(QWidget):

    Games = {
        "Game of Life": (GameOfLife, {'fill_rate': 0.50}),
        "Bacteria": (GrayScottDiffusion, {'coeffs': (0.16, 0.08, 0.035, 0.065)}),
        "Coral": (GrayScottDiffusion, {'coeffs': (0.16, 0.08, 0.062, 0.062)}),
        "Fingerprint": (GrayScottDiffusion, {'coeffs': (0.19, 0.05, 0.060, 0.062)}),
        "Spirals": (GrayScottDiffusion, {'coeffs': (0.10, 0.10, 0.018, 0.050)}),
        "Unstable": (GrayScottDiffusion, {'coeffs': (0.16, 0.08, 0.020, 0.055)}),
        "Worms": (GrayScottDiffusion, {'coeffs': (0.16, 0.08, 0.050, 0.065)}),
        "Zebrafish": (GrayScottDiffusion, {'coeffs': (0.16, 0.08, 0.035, 0.060)}),
    }

    def __init__(self, size=(400, 400)):
        super(QGameOfLife, self).__init__()
        self.size = size
        self.game = None
        self.initUI()
        self.show()

    def initUI(self):
        self.setWindowTitle(self.tr("Game of Life"))
        self.setLayout(QVBoxLayout())
        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0, 0, 0, 0)

        self.comboBox = QComboBox()
        self.comboBox.addItems([*QGameOfLife.Games.keys()])
        self.comboBox.currentTextChanged.connect(self.select)
        self.layout().addWidget(self.comboBox)

        self.scene = QGraphicsScene()
        self.view = QGraphicsView(self.scene)
        self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.view.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
        self.view.setFrameShape(QFrame.NoFrame)
        self.layout().addWidget(self.view)

        self.item = None
        self.timer = QTimer()
        self.timer.setInterval(10)
        self.timer.timeout.connect(self.tick)
        initialGame = random.choice([*QGameOfLife.Games.keys()])
        self.select(initialGame)
        self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding)
        self.comboBox.setCurrentText(initialGame)

    def select(self, name: str):
        self.timer.stop()
        Game, args = QGameOfLife.Games[name]
        self.game = Game(self.size, **args)
        self.tick()
        self.timer.start()

    def tick(self):
        self.game.tick()
        bitmap = self.game.visualize()
        image = QImage(bitmap.data, bitmap.shape[1], bitmap.shape[0], QImage.Format_Grayscale8)
        self.scene.removeItem(self.item)
        pixmap = QPixmap.fromImage(image)
        self.item = self.scene.addPixmap(pixmap)

    def resizeEvent(self, event: QResizeEvent):
        self.view.fitInView(self.item, Qt.KeepAspectRatioByExpanding)

    def sizeHint(self) -> QSize:
        return QSize(self.size[0], self.size[1])
Example #33
0
class QTetris(QWidget):

    class QTile(QGraphicsObject):
        colorMap = {Tetris.I: QColor("#53bbf4"), Tetris.J: QColor("#e25fb8"),
                    Tetris.L: QColor("#ffac00"), Tetris.O: QColor("#ecff2e"),
                    Tetris.S: QColor("#97eb00"), Tetris.T: QColor("#ff85cb"),
                    Tetris.Z: QColor("#ff5a48")}

        def __init__(self, qTetris: 'QTetris', tetrimino: Tetris.Tetrimino, tile: Tetris.Tile):
            super(QTetris.QTile, self).__init__()
            tile.delegate = self
            self.color = self.colorMap[type(tetrimino)]
            self.qTetris = qTetris
            self.moveAnimation = QParallelAnimationGroup()
            self.dropAnimation = QPropertyAnimation(self, b'pos')
            self.collapseAnimation = QPropertyAnimation(self, b'pos')
            self.shiftAnimation = QPropertyAnimation(self, b'pos')
            self.collapseAnimation.finished.connect(lambda tl=tile: tile.delegate.disappeared(tl))
            self.qTetris.scene.addItem(self)
            self.setPos(QPointF(0, 4))
            self.moved(tile)

        def moved(self, tile: Tetris.Tile):
            translation = QPropertyAnimation(self, b'pos')
            start, end = self.pos(), QPointF(tile.row, tile.column)
            curve, speed, delay = QEasingCurve.OutBack, 1 / 50, -1
            self.animate(translation, start, end, curve, speed, delay)

            rotation = QPropertyAnimation(self, b'rotation')
            start, end = self.rotation(), tile.rotation
            curve, speed, delay = QEasingCurve.OutBack, 1, -1
            self.animate(rotation, start, end, curve, speed, delay)
            rotation.setDuration(translation.duration())

            self.moveAnimation.clear()
            self.moveAnimation.addAnimation(translation)
            self.moveAnimation.addAnimation(rotation)
            self.moveAnimation.start()

        def dropped(self, tile: Tetris.Tile):
            start, end = self.pos(), QPointF(tile.row, tile.column)
            curve, speed, delay = QEasingCurve.OutBounce, 1 / 50, 0
            self.animate(self.dropAnimation, start, end, curve, speed, delay)

        def collapsed(self, tile: Tetris.Tile):
            start, end = self.pos(), QPointF(tile.row, tile.column + 2 * tile.tetris.num_columns)
            curve, speed, delay = QEasingCurve.InOutExpo, 1 / 50, 800
            if self.dropAnimation.state() == QAbstractAnimation.Running:
                start = self.dropAnimation.endValue()
            self.animate(self.collapseAnimation, start, end, curve, speed, delay)

        def shifted(self, tile: Tetris.Tile):
            start, end = self.pos(), QPointF(tile.row, tile.column)
            curve, speed, delay = QEasingCurve.OutBounce, 1 / 100, 1200
            if self.dropAnimation.state() == QAbstractAnimation.Running:
                start = self.dropAnimation.endValue()
            self.animate(self.shiftAnimation, start, end, curve, speed, delay)

        def disappeared(self, tile: Tetris.Tile):
            self.qTetris.scene.removeItem(self)

        def paint(self, painter: QPainter, styleOption: QStyleOptionGraphicsItem, widget: QWidget=None):
            pen = QPen()
            pen.setWidthF(0.05)
            pen.setColor(Qt.darkGray)
            painter.setPen(pen)
            brush = QBrush()
            brush.setColor(self.color)
            brush.setStyle(Qt.SolidPattern)
            painter.setBrush(brush)
            topLeft = QPointF(0, 0)
            bottomRight = QPointF(1, 1)
            rectangle = QRectF(topLeft, bottomRight)
            rectangle.translate(-0.5, -0.5)
            painter.drawRect(rectangle)

        @staticmethod
        def animate(animation: QPropertyAnimation, start: Union[QPointF, int, float], end: Union[QPointF, int, float],
                    curve: QEasingCurve=QEasingCurve.Linear, speed: float=1 / 50, delay: int=-1):
            animation.setStartValue(start)
            animation.setEndValue(end)
            animation.setEasingCurve(curve)
            if type(start) == type(end) == QPointF:
                distance = (end - start).manhattanLength()
            else:
                distance = abs(end - start)
            animation.setDuration(round(distance / speed))
            if delay == 0:
                animation.start()
            if delay > 0:
                QTimer.singleShot(delay, animation.start)

        def boundingRect(self):
            topLeft = QPointF(0, 0)
            bottomRight = QPointF(1, 1)
            rectangle = QRectF(topLeft, bottomRight)
            rectangle.translate(-0.5, -0.5)
            return rectangle

    class QScene(QGraphicsScene):
        def __init__(self, tetris: Tetris):
            super(QTetris.QScene, self).__init__()
            self.tetris = tetris

            pen = QPen()
            pen.setWidthF(0.05)
            pen.setColor(Qt.lightGray)
            brush = QBrush(Qt.NoBrush)
            rect = QRectF(0, 0, tetris.num_rows, tetris.num_columns)
            rect.translate(-0.5, -0.5)
            self.setSceneRect(rect)
            self.addRect(rect, pen, brush)
            self.setBackgroundBrush(self.palette().window())

            for column in range(0, tetris.num_columns, 2):
                pen = QPen(Qt.NoPen)
                brush = QBrush(Qt.SolidPattern)
                brush.setColor(Qt.lightGray)
                topLeft = QPointF(0, column)
                bottomRight = QPointF(tetris.num_rows, column + 1)
                rectangle = QRectF(topLeft, bottomRight)
                rectangle.translate(-0.5, -0.5)
                self.addRect(rectangle, pen, brush)

        def mouseMoveEvent(self, sceneMouseEvent: QGraphicsSceneMouseEvent):
            mousePoint = sceneMouseEvent.scenePos()
            mouseRow, mouseColumn = round(mousePoint.x()), round(mousePoint.y())
            row, column = self.tetris.falling_tetrimino.row, self.tetris.falling_tetrimino.column
            if mouseColumn - column > 0:
                self.tetris.move_right()
            if mouseColumn - column < 0:
                self.tetris.move_left()

        def mouseReleaseEvent(self, sceneMouseEvent: QGraphicsSceneMouseEvent):
            if sceneMouseEvent.button() == Qt.LeftButton:
                self.tetris.drop()
            if sceneMouseEvent.button() == Qt.RightButton:
                self.tetris.rotate()

        def wheelEvent(self, sceneWheelEvent: QGraphicsSceneWheelEvent):
            if sceneWheelEvent.delta() > 10:
                self.tetris.move_down()

        def keyReleaseEvent(self, sceneKeyEvent: QKeyEvent):
            if sceneKeyEvent.key() == Qt.Key_Left:
                self.tetris.move_left()
            if sceneKeyEvent.key() == Qt.Key_Right:
                self.tetris.move_right()
            if sceneKeyEvent.key() == Qt.Key_Down:
                self.tetris.move_down()
            if sceneKeyEvent.key() == Qt.Key_Up:
                self.tetris.rotate()

    class QView(QGraphicsView):
        def __init__(self, scene: 'QTetris.QScene'):
            super(QTetris.QView, self).__init__()
            self.setTransform(QTransform().rotate(+90).scale(+1, -1))
            self.setMinimumSize(100, 200)
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            self.setRenderHints(QPainter.Antialiasing)
            self.setFrameStyle(QFrame.NoFrame)
            self.setMouseTracking(True)
            self.setScene(scene)

    def __init__(self):
        super(QTetris, self).__init__()
        self.tetris = None
        self.timer = None
        self.initGame()

        self.view = None
        self.scene = None
        self.initUI()

        self.show()
        self.tetris.spawn()
        self.timer.start()

    def initGame(self):
        self.tetris = Tetris()
        self.tetris.delegate = self
        self.timer = QTimer(self)
        self.timer.setInterval(350)
        self.timer.timeout.connect(lambda: self.tetris.tick())

    def initUI(self):
        self.setLayout(QGridLayout())
        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.scene = QTetris.QScene(self.tetris)
        self.view = QTetris.QView(self.scene)
        self.layout().addWidget(self.view)
        self.scored(0)

    def appeared(self, tetrimino: Tetris.Tetrimino):
        for tile in tetrimino:
            QTetris.QTile(self, tetrimino, tile)

    def scored(self, score: int):
        self.setWindowTitle(self.tr("Tetris - {score}").format(score=score))

    def terminated(self):
        QMessageBox.critical(self, self.tr("Game Over!"), self.tr("You toppped out."), QMessageBox.Ok)
        self.tetris.restart()

    def resizeEvent(self, resizeEvent: QResizeEvent):
        boundingRect = self.scene.itemsBoundingRect()
        self.view.fitInView(boundingRect, Qt.KeepAspectRatio)
        self.view.centerOn(boundingRect.center())

    def sizeHint(self) -> QSize:
        return QSize(self.tetris.num_columns * 22, self.tetris.num_rows * 22)