From 270d5ddc31c26b62379e3caa9044dd75ccc71847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Picca=20Fr=C3=A9d=C3=A9ric-Emmanuel?= Date: Sun, 4 Mar 2018 10:20:27 +0100 Subject: New upstream version 0.7.0+dfsg --- silx/gui/_utils.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 3 deletions(-) (limited to 'silx/gui/_utils.py') diff --git a/silx/gui/_utils.py b/silx/gui/_utils.py index e29141f..d91a572 100644 --- a/silx/gui/_utils.py +++ b/silx/gui/_utils.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2017 European Synchrotron Radiation Facility +# Copyright (c) 2017-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,10 @@ # ###########################################################################*/ """This module provides convenient functions to use with Qt objects. -It provides conversion between numpy and QImage. +It provides: +- conversion between numpy and QImage: + :func:`convertArrayToQImage`, :func:`convertQImageToArray` +- Execution of function in Qt main thread: :func:`submitToQtMainThread` """ from __future__ import division @@ -38,6 +41,8 @@ __date__ = "16/01/2017" import sys import numpy +from silx.third_party.concurrent_futures import Future + from . import qt @@ -87,7 +92,7 @@ def convertQImageToArray(image): image = image.convertToFormat(qt.QImage.Format_RGB888) ptr = image.bits() - if qt.BINDING != 'PySide': + if qt.BINDING not in ('PySide', 'PySide2'): ptr.setsize(image.byteCount()) if qt.BINDING == 'PyQt4' and sys.version_info[0] == 2: ptr = ptr.asstring() @@ -100,3 +105,71 @@ def convertQImageToArray(image): array = array.reshape(image.height(), -1)[:, :image.width() * 3] array.shape = image.height(), image.width(), 3 return array + + +class _QtExecutor(qt.QObject): + """Executor of tasks in Qt main thread""" + + __sigSubmit = qt.Signal(Future, object, tuple, dict) + """Signal used to run tasks.""" + + def __init__(self): + super(_QtExecutor, self).__init__(parent=None) + + # Makes sure the executor lives in the main thread + app = qt.QApplication.instance() + assert app is not None + mainThread = app.thread() + if self.thread() != mainThread: + self.moveToThread(mainThread) + + self.__sigSubmit.connect(self.__run) + + def submit(self, fn, *args, **kwargs): + """Submit fn(*args, **kwargs) to Qt main thread + + :param callable fn: Function to call in main thread + :return: Future object to retrieve result + :rtype: concurrent.future.Future + """ + future = Future() + self.__sigSubmit.emit(future, fn, args, kwargs) + return future + + def __run(self, future, fn, args, kwargs): + """Run task in Qt main thread + + :param concurrent.future.Future future: + :param callable fn: Function to run + :param tuple args: Arguments + :param dict kwargs: Keyword arguments + """ + if not future.set_running_or_notify_cancel(): + return + + try: + result = fn(*args, **kwargs) + except BaseException as e: + future.set_exception(e) + else: + future.set_result(result) + + +_executor = None +"""QObject running the tasks in main thread""" + + +def submitToQtMainThread(fn, *args, **kwargs): + """Run fn(*args, **kwargs) in Qt's main thread. + + If not called from the main thread, this is run asynchronously. + + :param callable fn: Function to call in main thread. + :return: A future object to retrieve the result + :rtype: concurrent.future.Future + """ + global _executor + if _executor is None: # Lazy-loading + _executor = _QtExecutor() + + return _executor.submit(fn, *args, **kwargs) -- cgit v1.2.3