class ColorButton(QtGui.QPushButton): """ Color choosing push button """ colorChanged = QtCore.Signal(QtGui.QColor) def __init__(self, parent=None): QtGui.QPushButton.__init__(self, parent) self.setFixedSize(20, 20) self.setIconSize(QtCore.QSize(12, 12)) self.clicked.connect(self.choose_color) self._color = QtGui.QColor() def choose_color(self): color = QtGui.QColorDialog.getColor(self._color, self.parentWidget(), '') if color.isValid(): self.set_color(color) def get_color(self): return self._color @QtCore.Slot(QtGui.QColor) def set_color(self, color): if color != self._color: self._color = color self.colorChanged.emit(self._color) pixmap = QtGui.QPixmap(self.iconSize()) pixmap.fill(color) self.setIcon(QtGui.QIcon(pixmap)) color = QtCore.Property(QtGui.QColor, get_color, set_color)
class FormTabWidget(QtGui.QWidget): update_buttons = QtCore.Signal() def __init__(self, datalist, comment="", parent=None): QtGui.QWidget.__init__(self, parent) layout = QtGui.QVBoxLayout() self.tabwidget = QtGui.QTabWidget() layout.addWidget(self.tabwidget) self.setLayout(layout) self.widgetlist = [] for data, title, comment in datalist: if len(data[0]) == 3: widget = FormComboWidget(data, comment=comment, parent=self) else: widget = FormWidget(data, comment=comment, parent=self) index = self.tabwidget.addTab(widget, title) self.tabwidget.setTabToolTip(index, comment) self.widgetlist.append(widget) def setup(self): for widget in self.widgetlist: widget.setup() def get(self): return [widget.get() for widget in self.widgetlist]
class FormComboWidget(QtGui.QWidget): update_buttons = QtCore.Signal() def __init__(self, datalist, comment="", parent=None): QtGui.QWidget.__init__(self, parent) layout = QtGui.QVBoxLayout() self.setLayout(layout) self.combobox = QtGui.QComboBox() layout.addWidget(self.combobox) self.stackwidget = QtGui.QStackedWidget(self) layout.addWidget(self.stackwidget) self.combobox.currentIndexChanged.connect(self.stackwidget.setCurrentIndex) self.widgetlist = [] for data, title, comment in datalist: self.combobox.addItem(title) widget = FormWidget(data, comment=comment, parent=self) self.stackwidget.addWidget(widget) self.widgetlist.append(widget) def setup(self): for widget in self.widgetlist: widget.setup() def get(self): return [widget.get() for widget in self.widgetlist]
class FormWidget(QtGui.QWidget): update_buttons = QtCore.Signal() def __init__(self, data, comment="", parent=None): QtGui.QWidget.__init__(self, parent) from copy import deepcopy self.data = deepcopy(data) self.widgets = [] self.formlayout = QtGui.QFormLayout(self) if comment: self.formlayout.addRow(QtGui.QLabel(comment)) self.formlayout.addRow(QtGui.QLabel(" ")) if DEBUG: print("\n"+("*"*80)) print("DATA:", self.data) print("*"*80) print("COMMENT:", comment) print("*"*80) def get_dialog(self): """Return FormDialog instance""" dialog = self.parent() while not isinstance(dialog, QtGui.QDialog): dialog = dialog.parent() return dialog def setup(self): for label, value in self.data: if DEBUG: print("value:", value) if label is None and value is None: # Separator: (None, None) self.formlayout.addRow(QtGui.QLabel(" "), QtGui.QLabel(" ")) self.widgets.append(None) continue elif label is None: # Comment self.formlayout.addRow(QtGui.QLabel(value)) self.widgets.append(None) continue elif tuple_to_qfont(value) is not None: field = FontLayout(value, self) elif is_color_like(value): field = ColorLayout(to_qcolor(value), self) elif isinstance(value, six.string_types): field = QtGui.QLineEdit(value, self) elif isinstance(value, (list, tuple)): if isinstance(value, tuple): value = list(value) selindex = value.pop(0) field = QtGui.QComboBox(self) if isinstance(value[0], (list, tuple)): keys = [key for key, _val in value] value = [val for _key, val in value] else: keys = value field.addItems(value) if selindex in value: selindex = value.index(selindex) elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, int): print("Warning: '%s' index is invalid (label: " "%s, value: %s)" % (selindex, label, value), file=STDERR) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): field = QtGui.QCheckBox(self) if value: field.setCheckState(QtCore.Qt.Checked) else: field.setCheckState(QtCore.Qt.Unchecked) elif isinstance(value, float): field = QtGui.QLineEdit(repr(value), self) field.setValidator(QtGui.QDoubleValidator(field)) dialog = self.get_dialog() dialog.register_float_field(field) field.textChanged.connect(lambda text: dialog.update_buttons()) elif isinstance(value, int): field = QtGui.QSpinBox(self) field.setRange(-1e9, 1e9) field.setValue(value) elif isinstance(value, datetime.datetime): field = QtGui.QDateTimeEdit(self) field.setDateTime(value) elif isinstance(value, datetime.date): field = QtGui.QDateEdit(self) field.setDate(value) else: field = QtGui.QLineEdit(repr(value), self) self.formlayout.addRow(label, field) self.widgets.append(field) def get(self): valuelist = [] for index, (label, value) in enumerate(self.data): field = self.widgets[index] if label is None: # Separator / Comment continue elif tuple_to_qfont(value) is not None: value = field.get_font() elif isinstance(value, six.string_types) or is_color_like(value): value = unicode(field.text()) elif isinstance(value, (list, tuple)): index = int(field.currentIndex()) if isinstance(value[0], (list, tuple)): value = value[index][0] else: value = value[index] elif isinstance(value, bool): value = field.checkState() == QtCore.Qt.Checked elif isinstance(value, float): value = float(str(field.text())) elif isinstance(value, int): value = int(field.value()) elif isinstance(value, datetime.datetime): value = field.dateTime().toPyDateTime() elif isinstance(value, datetime.date): value = field.date().toPyDate() else: value = eval(str(field.text())) valuelist.append(value) return valuelist
class FigureWindow(QtGui.QMdiSubWindow): """ A basic MDI sub-window, but with a closing signal, and an activate QAction, which allows for switching between all FigureWindows (e.g. by a Windows-menu). An exclusive, static action group makes sure only one window can be active at the time. If you want to split the windows into different groups that can be treated separately, you will need to create your own QActionGroups. """ closing = QtCore.Signal() activeFigureActionGroup = QtGui.QActionGroup(None) activeFigureActionGroup.setExclusive(True) def __init__(self, *args, **kwargs): super(FigureWindow, self).__init__(*args, **kwargs) self._activate_action = None if os.environ['QT_API'] != 'pyside': self.windowStateChanged.connect(self._windowStateChanged) def closeEvent(self, event): self.closing.emit() super(FigureWindow, self).closeEvent(event) def activateAction(self): """ Returns a QAction that will activate the window with setActiveSubWindow as long as it has an mdiArea set. If not, it will use activateWindow to try to make it the active window. """ if self._activate_action is not None: return self._activate_action self._activate_action = QtGui.QAction(self.windowTitle(), self) self._activate_action.setCheckable(True) self._activate_action.triggered.connect(self._activate_triggered) self.activeFigureActionGroup.addAction(self._activate_action) return self._activate_action def setWindowTitle(self, title): # Overridden to keep action text updated super(FigureWindow, self).setWindowTitle(title) if self._activate_action is not None: self._activate_action.setText(title) def _windowStateChanged(self, oldState, newState): # Event for tracking if we're active or not isactive = newState & QtCore.Qt.WindowActive if isactive == oldState & QtCore.Qt.WindowActive: return # Another window state changed, e.g. activation self._activate_action.setChecked(isactive) def _activate_triggered(self, checked=True): # Activate action triggered, make window active if self.mdiArea(): self.mdiArea().setActiveSubWindow(self) else: self.activateWindow() # If not subwindow if self.isMinimized(): self.showNormal() # Restore minimized window if not checked: # User unchecked, which makes no sense, recheck self._activate_action.setChecked(True)