From edb617deb2e8862846ab9b612f765275cc8d3e4d Mon Sep 17 00:00:00 2001 From: Shuge Lee Date: Sun, 11 Dec 2011 13:28:14 +0800 Subject: [PATCH] Added qcommmons that some shortcuts for writing pythonic code convenience. --- qcommons/__init__.py | 23 ++++ qcommons/qthreadutils.py | 49 ++++++++ qcommons/qutils.py | 48 ++++++++ qcommons/winutils.py | 237 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 357 insertions(+) create mode 100644 qcommons/__init__.py create mode 100644 qcommons/qthreadutils.py create mode 100644 qcommons/qutils.py create mode 100644 qcommons/winutils.py diff --git a/qcommons/__init__.py b/qcommons/__init__.py new file mode 100644 index 0000000..c40c92e --- /dev/null +++ b/qcommons/__init__.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +from __future__ import generators +from __future__ import with_statement +from __future__ import print_function + + +__version__ = "201111" +__author__ = [ + "Shuge Lee ", +] +__license__ = "MIT License" +__contributors__ = "see http://iblah.org/changes" + + +import qutils +import qthreadutils +import winutils + + +from qutils import * +from qthreadutils import * +from winutils import * \ No newline at end of file diff --git a/qcommons/qthreadutils.py b/qcommons/qthreadutils.py new file mode 100644 index 0000000..a3babc5 --- /dev/null +++ b/qcommons/qthreadutils.py @@ -0,0 +1,49 @@ +import time + +try: + from PySide import QtCore +except ImportError: + from PyQt4 import QtCore + +__all__ = ['kill_qthread', 'QT', 'QTKiller'] + + +def kill_qthread(t): + if not t: + return + + t.terminate() +# t.wait() + + +class QT(QtCore.QThread): + def __init__(self, func, *args, **kwargs): + QtCore.QThread.__init__(self) + self._func = func + self._args = args + self._kwargs = kwargs + self._return = None + + def run(self): + self._return = self._func(*self._args, **self._kwargs) + self.emit(QtCore.SIGNAL('thread_finished()')) + + def get_return(self): + return self._return + + +class QTKiller(QtCore.QThread): + def __init__(self, target_t, timeout = 10): + QtCore.QThread.__init__(self) + self._target_t = target_t + self._timeout = timeout + + def run(self): + i = 0 + while i < self._timeout: + time.sleep(1) + self.emit(QtCore.SIGNAL('thread_running()')) + i += 1 + self.emit(QtCore.SIGNAL('kill_qthread()')) + while not self._target_t.isFinished(): + time.sleep(0.1) \ No newline at end of file diff --git a/qcommons/qutils.py b/qcommons/qutils.py new file mode 100644 index 0000000..6fea837 --- /dev/null +++ b/qcommons/qutils.py @@ -0,0 +1,48 @@ +""" +add custom theme name and search path for fix icon file not found on Mac OS X + +Install Oxygen icon on Mac OS X via MacPorts: + + sudo port install oxygen-icons + +""" +import sys + +try: + from PySide import QtGui + from PySide import QtCore +except ImportError: + from PyQt4 import QtGui + from PyQt4 import QtCore + + +__all__ = [ + "config_theme_path", + "icon2pix", +] + + +def config_theme_path(): + if sys.platform != "darwin": + return + + theme_name = str(QtGui.QIcon.themeName()) + + if theme_name != "Oxygen": + QtGui.QIcon.setThemeName("Oxygen") + + + search_paths = list(QtGui.QIcon.themeSearchPaths()) + + custom_path = "/opt/local/share/icons" + if custom_path not in search_paths: + search_paths.append(custom_path) + + QtGui.QIcon.setThemeSearchPaths(search_paths) + + +def icon2pix(icon, size = QtCore.QSize(30, 30), grayscaled = True): + if grayscaled: + return icon.pixmap(size, mode = QtGui.QIcon.Disabled) + else: + return icon.pixmap(size) diff --git a/qcommons/winutils.py b/qcommons/winutils.py new file mode 100644 index 0000000..fb1f387 --- /dev/null +++ b/qcommons/winutils.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +""" +auto save window geometry + +Test environment: + Mac OS X 10.6.8 + +http://doc.qt.nokia.com/latest/qdesktopwidget.html +http://www.pyside.org/docs/pyside/PySide/QtGui/QWidget.html +""" +import json +import os + +try: + from PySide import QtCore + from PySide import QtGui +except ImportError: + from PyQt4 import QtCore + from PyQt4 import QtGui + + +__all__ = [ + "AutoSaveGeo", + "CustomDlg", + "CustomWin", + ] + + +class AutoSaveGeo(QtGui.QMainWindow): + def __init__(self, user_data_path, w = 300, h = 500, parent = None): + super(AutoSaveGeo, self).__init__(parent) + + self.resize(w, h) + + self.user_data_path = user_data_path + if self.user_data_path: + self._load_win_geo() + + def closeEvent(self, evt): + if hasattr(self, "user_data_path") and self.user_data_path: + self._save_win_geo() + + return super(AutoSaveGeo, self).closeEvent(evt) + + def _save_win_geo(self): + config_path = os.path.join(self.user_data_path, "win_geometry.json") + + if not os.path.exists(self.user_data_path): + os.makedirs(self.user_data_path) + + if os.path.exists(config_path): + f = file(config_path) + buf = f.read() + f.close() + else: + buf = None + + datas = None + if buf: + datas = json.loads(buf) + + if not datas: + datas = {} + + win_geo_data = dict( + x = self.x(), + y = self.y(), + w = self.width(), + h = self.height()) + + datas[self.__class__.__name__] = win_geo_data + + path = config_path + content = json.dumps(datas) + + f = file(path, "w") + f.write(content) + f.close() + + def _load_win_geo(self): + config_path = os.path.join(self.user_data_path, "win_geometry.json") + + if not os.path.exists(self.user_data_path): + os.makedirs(self.user_data_path) + + desktop = QtGui.QApplication.desktop() + x = desktop.width() / 2 + y = (desktop.height() - self.height()) / 2 + w = self.width() + h = self.height() + + if os.path.exists(config_path): + f = file(config_path) + buf = f.read() + f.close() + else: + buf = None + + datas = None + if buf: + datas = json.loads(buf) + + if datas: + cls_name = self.__class__.__name__ + geo = datas.get(cls_name) + + if geo: + x, y, w, h = geo['x'], geo['y'], geo['w'], geo['h'] + + self.setGeometry(x, y, w, h) + + +class CustomDlg(QtGui.QDialog): + """ + Custom dialog template. + + You should override there method: + - __init__ + - get_inputs + - popup_and_get_inputs + """ + def __init__(self, parent, settings): + """ You should override this method """ + super(CustomDlg, self).__init__(parent) + + self.resize(400, 250) + + self._settings = settings + + # add custom sub-widgets here ... + + def show_and_raise(self): + self.show() + self.raise_() + + def keyPressEvent(self, evt): + close_win_cmd_w = (evt.key() == QtCore.Qt.Key_W and evt.modifiers() == QtCore.Qt.ControlModifier) + close_win_esc = (evt.key() == QtCore.Qt.Key_Escape) + + if close_win_cmd_w or close_win_esc: + self.close() + return self._settings + + def get_inputs(self): + """ You should override this method + update self._settings from custom sub-widgets ... + """ + return self._settings + + @staticmethod + def popup_and_get_inputs(parent, settings): + """ You should override this method """ + dlg = CustomDlg(parent, settings) + dlg.show() + dlg.exec_() + + return dlg.get_inputs() + + +class CustomWin(QtGui.QWidget): + """ + Custom window template. + + You should override there method: + - __init__ + - get_inputs + - popup_and_get_inputs + """ + def __init__(self, parent, settings): + """ You should override this method """ + super(CustomWin, self).__init__(parent) + + self.resize(400, 250) + + self._settings = settings + + # add custom sub-widgets here ... + + def show_and_raise(self): + self.show() + self.raise_() + + def keyPressEvent(self, evt): + close_win_cmd_w = (evt.key() == QtCore.Qt.Key_W and evt.modifiers() == QtCore.Qt.ControlModifier) + close_win_esc = (evt.key() == QtCore.Qt.Key_Escape) + + if close_win_cmd_w or close_win_esc: + self.close() + return self._settings + + def get_inputs(self): + """ You should override this method + update self._settings from custom sub-widgets ... + """ + return self._settings + + @staticmethod + def popup_and_get_inputs(parent, settings): + """ You should override this method """ + dlg = CustomWin(parent, settings) + dlg.show() + + return dlg.get_inputs() + + +class Demo(AutoSaveGeo): + def __init__(self, parent = None, user_data_path = None): + super(Demo, self).__init__(parent = parent, user_data_path = user_data_path) + + settings = {} + new_settings = CustomDlg.popup_and_get_inputs(parent = self, settings = settings) + print "new_settings:", new_settings + + def show_and_raise(self): + self.show() + self.raise_() + +def test1(): + import sys + + app_name = "foo" + #tmp_path = os.getenv("TMP") or "/tmp" + PWD = os.path.dirname(os.path.realpath(__file__)) + tmp_path = PWD + app_data_path = os.path.join(tmp_path, app_name) + + + app = QtGui.QApplication(sys.argv) + + demo = Demo(user_data_path = app_data_path) + demo.show_and_raise() + + sys.exit(app.exec_()) + + +if __name__ == "__main__": + test1() \ No newline at end of file