示例#1
0
class Application:
    """cRIO GUI application class. Parses command line arguments. Runs
    application including splash screen (can be disabled by command line
    option). Splash screen is shown during SAL initialization.

    Parameters
    ----------
    eui_class : `class`
        Class, ideally child of QMainWindow, which will be instantiated after
        wait for SAL/DDS initialization. It's parameters are SALComm created
        with addComm method.

    Usage
    -----
    .. code-block:: python
       from PySide2.QtWidgets import QApplication


       class EUI(QMainWindow):
           ...

       if __name__ == "__main__":
           app = Application(EUI)
           app.addComm("MTM1M3")
           app.addComm("MTMount", include=["azimuth", "elevation"])
           app.run()
    """
    def __init__(self, eui_class):
        self._eui_class = eui_class
        self._app = QApplication(sys.argv)

        parser = QCommandLineParser()
        parser.addHelpOption()
        parser.addVersionOption()
        noSplash = QCommandLineOption(["n", "no-splash"],
                                      "don't show splash screen")
        parser.addOption(noSplash)
        parser.process(self._app)

        self._loop = QEventLoop(self._app)
        asyncio.set_event_loop(self._loop)

        self._comms = []
        self._splash = not (parser.isSet(noSplash))
        self._eui = None

    def addComm(self, name, manual=None, **kwargs):
        """Adds SALComm object to parameters of QMainWindow class.

        Parameters
        ----------
        name : `str`
            Remote name.
        manual : `hash`
            Events and telemetry topics created with optional arguments. Keys are
            events and telemetry names, values is a hash of additional arguments.

        **kwargs : `dict`
            Optional parameters passed to remote.
        """
        self._comms.append(create(name, manual=manual, **kwargs))

    def run(self):
        """Runs the application. Creates splash screen, display it if requested.
        Creates and display main window after SAL/DDS is initialized."""
        class AppSplashScreen(SplashScreen):
            def started(splash, *comms):
                self._eui = self._eui_class(*comms)
                splash.finish(self._eui)
                self._eui.show()

        splash = AppSplashScreen(*self._comms, show=self._splash)
        if self._splash:
            splash.show()

        def handler(signum, frame):
            print(f"Catching signal {signum}, exiting")
            self._loop.call_soon(splash.stop)
            self._loop.call_soon(self._app.closeAllWindows)

        for signum in [signal.SIGINT, signal.SIGHUP, signal.SIGTERM]:
            signal.signal(signum, handler)

        # Run the main Qt loop
        with self._loop:
            self._loop.run_forever()
示例#2
0
class Application(QtApplication):
    """ Add asyncio support . Seems like a complete hack compared to twisted
    but whatever.

    """

    loop = Instance(QEventLoop)

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

        #: Set event loop policy for windows
        if sys.platform == 'win32':
            asyncio.set_event_loop_policy(
                asyncio.WindowsSelectorEventLoopPolicy())

        self.loop = QEventLoop(self._qapp)
        asyncio.set_event_loop(self.loop)
        for name in ('asyncqt._unix._Selector', 'asyncqt._QEventLoop',
                     'asyncqt._SimpleTimer'):
            log = logging.getLogger(name)
            log.setLevel(logging.WARN)

    def start(self):
        """ Run using the event loop

        """
        log.info("Application starting")
        with self.loop:
            self.loop.run_forever()

    def deferred_call(self, callback, *args, **kwargs):
        """ Invoke a callable on the next cycle of the main event loop
        thread.

        Parameters
        ----------
        callback : callable
            The callable object to execute at some point in the future.

        args, kwargs
            Any additional positional and keyword arguments to pass to
            the callback.

        """
        if asyncio.iscoroutinefunction(callback):
            task = lambda: asyncio.ensure_future(callback(*args, **kwargs))
            return self.loop.call_soon(task)
        return super().deferred_call(callback, *args, **kwargs)

    def timed_call(self, ms, callback, *args, **kwargs):
        """ Invoke a callable on the main event loop thread at a
        specified time in the future.

        Parameters
        ----------
        ms : int
            The time to delay, in milliseconds, before executing the
            callable.

        callback : callable
            The callable object to execute at some point in the future.

        args, kwargs
            Any additional positional and keyword arguments to pass to
            the callback.

        """
        if asyncio.iscoroutinefunction(callback):
            task = lambda: asyncio.ensure_future(callback(*args, **kwargs))
            return self.loop.call_later(ms / 1000, task)
        return super().timed_call(ms, callback, *args, **kwargs)