def test_refleaks_in___init__(self): gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') fake_prop = Property(object, 'fget', 'fset', "freset", 'fdel', 'doc') refs_before = gettotalrefcount() for i in range(100): fake_prop.__init__(object, 'fget', 'fset', "freset", 'fdel', 'doc') self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
class NumberGenerator(QObject): def __init__(self): QObject.__init__(self) self.__Stg1Pres = 100 self.__Stg2Pres = 102 self.__Stg3Pres = 115 self.__Stg4Pres = 150 self.__Stg5Pres = 38 def get_number1(self): return self.__Stg1Pres def get_number2(self): return self.__Stg2Pres def get_number3(self): return self.__Stg3Pres def get_number4(self): return self.__Stg4Pres def get_number5(self): return self.__Stg5Pres number1 = Property(int, get_number1) number2 = Property(int, get_number2) number3 = Property(int, get_number3) number4 = Property(int, get_number4) number5 = Property(int, get_number5)
class PieChart (QQuickPaintedItem): def __init__(self, parent = None): QQuickPaintedItem.__init__(self, parent) self._name = u'' def paint(self, painter): pen = QPen(self.color, 2) painter.setPen(pen); painter.setRenderHints(QPainter.Antialiasing, True); painter.drawPie(self.boundingRect().adjusted(1,1,-1,-1), 90 * 16, 290 * 16); def getColor(self): return self._color def setColor(self, value): self._color = value def getName(self): return self._name def setName(self, value): self._name = value color = Property(QColor, getColor, setColor) name = Property(text_type, getName, setName) chartCleared = Signal() @Slot() # This should be something like @Invokable def clearChart(self): self.setColor(Qt.transparent) self.update() self.chartCleared.emit()
class StockModel(QObject): def __init__(self, symbol, unitPrice, transactions): QObject.__init__(self) self._symbol = symbol self.unitPrice = unitPrice self._transactions = JsonListModel('type') for transaction in transactions: self._transactions.append(transaction) self.valueChanged.emit() @Signal def valueChanged(self): pass def getLabel(self): return self._symbol symbol = Property(str, getLabel, notify=valueChanged) def getTransactions(self): return self._transactions # trick: to use a custom object as a property, use QObject ! transactions = Property(QObject, getTransactions, notify=valueChanged) def getAmount(self): sum = 0 for transaction in self._transactions.getList(): sum += transaction['amount'] return sum amount = Property(int, getAmount, notify=valueChanged)
class InternetWeather(QObject): def __init__(self): QObject.__init__(self) self._temperature = 30.0 self._humidity = 50.0 self._currentStateIconUrl = "" def begin(apiKey, location): pass def getHumidity(self): return _humidity def getTemperature(self): return _temperature def getCurrentStateIconUrl(self): return _currentStateIconUrl @Signal def temperatureChanged(self): pass @Signal def humidityChanged(self): pass @Signal def currentStateIconUrlChanged(self): pass temperature = Property(float, getTemperature, notify=temperatureChanged) humidity = Property(float, getHumidity, notify=humidityChanged) currentStateIconUrl = Property(QUrl, getCurrentStateIconUrl, notify=currentStateIconUrlChanged)
class TestObject(QObject): def __init__(self, parent=None): QObject.__init__(self, parent) self.m_name = "" self.m_color = "" def _name(self): return self.m_name def _color(self): return self.m_color def setName(self, name): if name != self.m_name: self.m_name = name self.nameChanged.emit() def setColor(self, color): if color != self.m_color: self.m_color = color self.colorChanged.emit() @Signal def nameChanged(self): pass @Signal def colorChanged(self): pass name = Property(str, _name, setName, notify=nameChanged) color = Property(str, _color, setColor, notify=colorChanged)
class PieChart(QQuickPaintedItem): def __init__(self, parent=None): QQuickPaintedItem.__init__(self, parent) self._name = u'' def paint(self, painter): pen = QPen(self.color, 2) painter.setPen(pen) painter.setRenderHints(QPainter.Antialiasing, True) painter.drawPie(self.boundingRect().adjusted(1, 1, -1, -1), 90 * 16, 290 * 16) def getColor(self): return self._color def setColor(self, value): self._color = value def getName(self): return self._name def setName(self, value): self._name = value nameChanged = Signal() color = Property(QColor, getColor, setColor) name = Property(text_type, getName, setName, notify=nameChanged)
class Change(QObject): actived = Signal() whenChanged = Signal(bool) componentChanged = Signal(QQmlComponent) def __init__(self): super(Change, self).__init__(None) self._when = False self._component = None def readWhen(self) -> bool: return self._when def setWhen(self, new_when: bool) -> None: self._when = new_when self.whenChanged.emit(self._when) if self._when: self.actived.emit() def readComponent(self) -> QQmlComponent: return self._component def setComponent(self, new_component: QQmlComponent) -> None: self._component = new_component self.componentChanged.emit(self._component) when = Property("bool", readWhen, setWhen, whenChanged) component = Property(QQmlComponent, readComponent, setComponent, componentChanged)
class TaxExportDialog(QDialog, Ui_TaxExportDlg): def __init__(self, parent, db): QDialog.__init__(self) self.setupUi(self) self.AccountWidget.init_db(db) self.FileSelectBtn.pressed.connect(self.OnFileBtn) # center dialog with respect to parent window x = parent.x() + parent.width()/2 - self.width()/2 y = parent.y() + parent.height()/2 - self.height()/2 self.setGeometry(x, y, self.width(), self.height()) @Slot() def OnFileBtn(self): filename = QFileDialog.getSaveFileName(self, g_tr('TaxExportDialog', "Save tax reports to:"), ".", g_tr('TaxExportDialog', "Excel files (*.xlsx)")) if filename[0]: if filename[1] == g_tr('TaxExportDialog', "Excel files (*.xlsx)") and filename[0][-5:] != '.xlsx': self.Filename.setText(filename[0] + '.xlsx') else: self.Filename.setText(filename[0]) def getYear(self): return self.Year.value() def getFilename(self): return self.Filename.text() def getAccount(self): return self.AccountWidget.selected_id year = Property(int, fget=getYear) filename = Property(int, fget=getFilename) account = Property(int, fget=getAccount)
class MessagesItem(ListModelItem): roles = { Qt.UserRole + 1: b'ts', Qt.UserRole + 2: b'date', Qt.UserRole + 3: b'time', Qt.UserRole + 4: b'user', Qt.UserRole + 5: b'text', } def getTimestamp(self): return self._data[b'ts'] timestamp = Property(QDateTime, getTimestamp) def getDate(self): return self._data[b'date'] date = Property(QDate, getDate) def getTime(self): return self._data[b'time'] time = Property(QDateTime, getTime) def getUser(self): return self._data[b'user'] user = Property(str, getUser) def getText(self): return self._data[b'text'] text = Property(str, getText)
class SeesawParam(SingleParam): """Base parameter for "seesaw" movement """ _n_currentSpeed = Signal() _n_moving = Signal() def __init__(self, *args): self._request_pending = asyncio.Lock() self._currentSpeed = 0 self._moving = False super().__init__(*args) def _g_currentSpeed(self) -> int: return self._currentSpeed def _s_currentSpeed(self, value: int): self._generic_setter('_currentSpeed', value) moving = value != 0 if moving != self._moving: self.moving = moving currentSpeed: int = Property(int, _g_currentSpeed, _s_currentSpeed, notify=_n_currentSpeed, ) """Current speed of movement from -8 to 8 """ def _g_moving(self) -> bool: return self._moving def _s_moving(self, value: bool): logger.debug(f'{self.moving=}, {value=}') self._generic_setter('_moving', value) if not value: if self._currentSpeed != 0: self.currentSpeed = 0 moving: bool = Property(bool, _g_moving, _s_moving, notify=_n_moving) """True if the parameter is moving
class Coordinate(QObject): xChanged = Signal(float) yChanged = Signal(float) valueChanged = Signal() def __init__(self, x=0, y=0, parent=None): super().__init__(parent) self._x = x self._y = y def getX(self) -> float: return self._x def setX(self, x: float): self._x = x self.xChanged.emit(x) self.valueChanged.emit() def getY(self) -> float: return self._y def setY(self, y: float): self._y = y self.yChanged.emit(y) self.valueChanged.emit() x = Property(float, getX, setX, notify=xChanged) y = Property(float, getY, setY, notify=yChanged)
class PieSlice(QQuickPaintedItem): def __init__(self, parent=None): QQuickPaintedItem.__init__(self, parent) self._color = QColor() self._fromAngle = 0 self._angleSpan = 0 def getColor(self): return self._color def setColor(self, value): self._color = value def getFromAngle(self): return self._angle def setFromAngle(self, value): self._fromAngle = value def getAngleSpan(self): return self._angleSpan def setAngleSpan(self, value): self._angleSpan = value color = Property(QColor, getColor, setColor) fromAngle = Property(int, getFromAngle, setFromAngle) angleSpan = Property(int, getAngleSpan, setAngleSpan) def paint(self, painter): pen = QPen(self._color, 2) painter.setPen(pen) painter.setRenderHints(QPainter.Antialiasing, True) painter.drawPie(self.boundingRect().adjusted(1, 1, -1, -1), self._fromAngle * 16, self._angleSpan * 16)
class Selector(QObject): def __init__(self): QObject.__init__(self) @Signal def templateOpened(self): pass @Signal def modelOpened(self): pass @Slot(str) def createTemplate(self, name: str): self.create_template(name) def create_template(self, name: str): stt = Template() stt.name = name self.templateOpened.emit(stt) new_template = Property(str, create_template, notify=templateOpened) @Slot(str) def openTemplate(self, filename: str): self.open_template(Path(filename)) def open_template(self, filename: Path): parser = XmlParser(context=XmlContext()) stt = parser.from_path(filename, Template) self.templateOpened.emit(stt) template = Property(str, open_template, notify=templateOpened) @Slot(str) def createModel(self, template: str): self.create_model(Path(template)) def create_model(self, template: Path): stm = Model() stm.template = self.openTemplate(template) self.modelOpened.emit(stm) new_model = Property(str, create_model, notify=modelOpened) @Slot(str) def openModel(self, filename: str): self.open_model(Path(filename)) def open_model(self, filename: Path): parser = XmlParser(context=XmlContext()) stm = parser.from_path(filename, Model) self.modelOpened.emit(stm) model = Property(str, open_model, notify=modelOpened)
class CartItem(QObject): _name = 'no-name' def __init__(self, name, quantity, price): super(CartItem, self).__init__() self._name = name self._price = price self._quantity = quantity def setQuantity(self, val): self._quantity = val def getQuantity(self): return self._quantity quantity = Property(int, getQuantity, setQuantity) def setPrice(self, val): self._price = float(val) def getPrice(self): return locale.format_string("%.2f", self._price) price = Property(str, getPrice, setPrice) def getSum(self): return locale.format_string("%.2f", self._price) sum = Property(str, getSum) def getName(self): return self._name name = Property(str, getName)
class BrowserProxy(QObject): type = Property(str, lambda self: 'browser', constant=True) data = Property('QVariant', lambda self: self._data, constant=True) def __init__(self, data): super().__init__() self._data = data
def makeProperty(T, attributeName, notify=None, resetOnDestroy=False): """ Shortcut function to create a Qt Property with generic getter and setter. Getter returns the underlying attribute value. Setter sets and emit notify signal only if the given value is different from the current one. Args: T (type): the type of the property attributeName (str): the name of underlying instance attribute to get/set notify (Signal): the notify signal; if None, property will be constant resetOnDestroy (bool): Only applicable for QObject-type properties. Whether to reset property to None when current value gets destroyed. Examples: class Foo(QObject): _bar = 10 barChanged = Signal() # read/write bar = makeProperty(int, "_bar", notify=barChanged) # read only (constant) bar = makeProperty(int, "_bar") Returns: Property: the created Property """ def setter(instance, value): """ Generic setter. """ currentValue = getattr(instance, attributeName) if currentValue == value: return resetCallbackName = '__reset__' + attributeName if resetOnDestroy and not hasattr(instance, resetCallbackName): # store reset callback on instance, only way to keep a reference to this function # that can be used for destroyed signal (dis)connection setattr(instance, resetCallbackName, lambda self=instance, *args: setter(self, None)) resetCallback = getattr(instance, resetCallbackName, None) if resetCallback and currentValue and shiboken2.isValid(currentValue): currentValue.destroyed.disconnect(resetCallback) setattr(instance, attributeName, value) if resetCallback and value: value.destroyed.connect(resetCallback) getattr(instance, signalName(notify)).emit() def getter(instance): """ Generic getter. """ return getattr(instance, attributeName) def signalName(signalInstance): """ Get signal name from instance. """ # string representation contains trailing '()', remove it return str(signalInstance)[:-2] if resetOnDestroy and not issubclass(T, QObject): raise RuntimeError( "destroyCallback can only be used with QObject-type properties.") if notify: return Property(T, getter, setter, notify=notify) return Property(T, getter, constant=True)
class WorkerManager(QObject): def __init__(self): QObject.__init__(self) self._progress = 0 self._running = False self._status = "" @Slot(str) def start_worker(self, target): self.start.emit(target) self._set_running(True) @Slot() def stop_worker(self): self.stop.emit() self._set_running(False) def receive_msg(self, msg): if isinstance(msg, dict): if 'status' in msg: if msg['status'] == 'done': self._set_running(False) else: self._set_status(msg['status']) elif 'progress' in msg: self._set_progress(msg['progress']) def _get_progress(self): return self._progress def _set_progress(self, progress): self._progress = progress self.on_progress.emit() def _get_running(self): return self._running def _set_running(self, running): self._running = running self.on_running.emit() def _get_status(self): return self._status def _set_status(self, status): self._status = status self.on_status.emit() on_progress = Signal() on_running = Signal() on_status = Signal() start = Signal(str) stop = Signal() progress = Property(float, _get_progress, _set_progress, notify=on_progress) running = Property(bool, _get_running, _set_running, notify=on_running) status = Property(str, _get_status, _set_status, notify=on_status)
class BatteryParamsModel(ParamBase): _param_group_key = 'battery' _prop_attr_map = {'state':'batteryState', 'level':'level'} _n_batteryState = Signal() _n_level = Signal() _n_textStatus = Signal() def __init__(self, *args): self._batteryState = BatteryState.UNKNOWN.name self._textStatus = '' self._level = 0. super().__init__(*args) def _g_batteryState(self) -> str: return self._batteryState def _s_batteryState(self, value: BatteryState): if value is not None: value = value.name self._generic_setter('_batteryState', value) batteryState: str = Property(str, _g_batteryState, _s_batteryState, notify=_n_batteryState, ) """Alias for :attr:`jvconnected.device.BatteryParams.state`""" def _g_level(self) -> float: return self._level def _s_level(self, value: float): self._generic_setter('_level', value) level: float = Property(float, _g_level, _s_level, notify=_n_level) """Alias for :attr:`jvconnected.device.BatteryParams.level`""" def _g_textStatus(self) -> str: return self._textStatus def _s_textStatus(self, value: BatteryState): self._generic_setter('_textStatus', value) textStatus: str = Property(str, _g_textStatus, _s_textStatus, notify=_n_textStatus) """Battery information from one of :attr:`~jvconnected.device.BatteryParams.minutes`, :attr:`~jvconnected.device.BatteryParams.percent` or :attr:`~jvconnected.device.BatteryParams.voltage` depending on availability """ def _on_param_group_set(self, param_group): super()._on_param_group_set(param_group) props = ['minutes', 'percent', 'voltage'] param_group.bind(**{prop:self._update_text_status for prop in props}) def _update_text_status(self, instance, value, **kwargs): if instance is not self.paramGroup: return if value == -1: return prop = kwargs['property'] if prop.name == 'minutes': txt = f'{value}min' elif prop.name == 'percent': txt = f'{value}%' elif prop.name == 'voltage': txt = f'{value:.1f}V' else: txt = '' self.textStatus = txt
class Funcionario(QObject): def __init__(self): QObject.__init__(self) self.__logo = "Imagens/logo.jpg" self.__nome_empresa = "Jabil do Brasil" self.__nome_funcionario = "Nome Funcionario" self.__img_funcionario = "Imagens/foto.png" def paint(self, painter): print(self.__qrCode) painter.drawPixmap(0, 0, self.__qrCode) # logo logoChanged = Signal(str) def get_logo(self): return self.__logo logo = Property(str, get_logo, notify=logoChanged) # nomeEmpresa nomeEmpresaChanged = Signal(str) def get_nome_empresa(self): return self.__nome_empresa nomeEmpresa = Property(str, get_nome_empresa, notify=nomeEmpresaChanged) # nomeFuncionario nomeFuncionarioChanged = Signal(str) def get_nome_funcionario(self): return self.__nome_funcionario nomeFuncionario = Property(str, get_nome_funcionario, notify=nomeFuncionarioChanged) # imgFuncionario imgFuncionarioChanged = Signal(str) def get_img_funcionario(self): return self.__img_funcionario imgFuncionario = Property(str, get_img_funcionario, notify=imgFuncionarioChanged) # qrCode qrCodeChanged = Signal(str) def get_qrCode(self): return self.__qrCode qrCode = Property(str, get_qrCode, notify=qrCodeChanged)
class AppImageModel(QObject): def __init__(self): QObject.__init__(self) self._name = '' self._file = '' self._image = '' def file(self): return self._file def set_file(self, file): if file != self._file: self._file = file self.file_changed.emit() def name(self): return self._name def set_name(self, name): if name != self._name: self._name = name self.name_changed.emit() def image(self): return self._image def set_image(self, image): if image != self._image: self._image = image self.image_changed.emit() # Change signals @Signal def name_changed(self): pass @Signal def file_changed(self): pass @Signal def image_changed(self): pass # QML Invokables @Slot() def launch(self): print('launch ' + self._file) subprocess.Popen([self._file]) name = Property(str, name, set_name, notify=name_changed) file = Property(str, file, set_file, notify=file_changed) image = Property(str, image, set_image, notify=image_changed)
class Message(QObject): """ Simple structure wrapping a high-level message. """ def __init__(self, title, text, detailedText="", parent=None): super(Message, self).__init__(parent) self._title = title self._text = text self._detailedText = detailedText title = Property(str, lambda self: self._title, constant=True) text = Property(str, lambda self: self._text, constant=True) detailedText = Property(str, lambda self: self._detailedText, constant=True)
class NumberGenerator(QObject): def __init__(self): QObject.__init__(self) self.__number = 42 self.__max_number = 99 @Slot() def updateNumber(self): self.__set_number(random.randint(0, self.__max_number)) # maxNumber @Signal def maxNumberChanged(self): pass @Slot(int) def setMaxNumber(self, val): self.set_max_number(val) def set_max_number(self, val): if val < 0: val = 0 if self.__max_number != val: self.__max_number = val self.maxNumberChanged.emit() if self.__number > self.__max_number: self.__set_number(self.__max_number) def get_max_number(self): return self.__max_number maxNumber = Property(int, get_max_number, set_max_number, notify=maxNumberChanged) # number numberChanged = Signal(int) def __set_number(self, val): if self.__number != val: self.__number = val self.numberChanged.emit(self.__number) def get_number(self): return self.__number number = Property(int, get_number, notify=numberChanged)
class PortfolioCurrency(QObject): def __init__(self, abbreviation, currencyAmount, parent=None): super().__init__(parent) self._abbreviation = abbreviation self._currencyAmount = currencyAmount def get_amount(self): return self._currencyAmount def get_abbreviation(self): return self._abbreviation currencyAmount = Property(float, fget=get_amount) abbreviation = Property(str, fget=get_abbreviation)
class NumberGenerator(QObject): """数据生成""" # 声明 numberChanged 的信号 numberChanged = Signal(int) # 声明 maxNumberChanged 的信号,也可以用@Signal槽方式 maxNumberChanged = Signal() def __init__(self): QObject.__init__(self) self.__number = 42 self.__max_number = 99 def set_max_number(self, val): if val < 0: val = 0 if self.__max_number != val: self.__max_number = val if self.__number > self.__max_number: self.__set_number(self.__max_number) def get_max_number(self): return self.__max_number def __set_number(self, val): if self.__number != val: self.__number = val self.numberChanged.emit(self.__number) def get_number(self): return self.__number @Slot(int) def setMaxNumber(self, val): self.set_max_number(val) @Slot() def updateNumber(self): self.__set_number(random.randint(0, self.__max_number)) # 定义一个 number 属性 # 属性构造函数有三个参数在本例中:类型(int)、getter(get_number)和 # 作为命名传递的通知信号参数(notify=numberChanged)。 # 注意getter有一个Python名称,即使用下划线而不是camelCase, # 因为它用于从Python中读取值。对于QML,使用属性名称和编号 number = Property(int, get_number, notify=numberChanged) # 提供了 setter maxNumber = Property(int, get_max_number, set_max_number, notify=maxNumberChanged)
class MouseEvent(QObject): """ Simple MouseEvent object, since QQuickMouseEvent is not accessible in the public API """ def __init__(self, evt): super(MouseEvent, self).__init__() self._x = evt.x() self._y = evt.y() self._button = evt.button() self._modifiers = evt.modifiers() x = Property(float, lambda self: self._x, constant=True) y = Property(float, lambda self: self._y, constant=True) button = Property(Qt.MouseButton, lambda self: self._button, constant=True) modifiers = Property(int, lambda self: self._modifiers, constant=True)
def makeProperty(T, attributeName, notify=None): """ Shortcut function to create a Qt Property with generic getter and setter. Getter returns the underlying attribute value. Setter sets and emit notify signal only if the given value is different from the current one. Args: T (type): the type of the property attributeName (str): the name of underlying instance attribute to get/set notify (Signal): the notify signal; if None, property will be constant Examples: class Foo(QObject): _bar = 10 barChanged = Signal() # read/write bar = makeProperty(int, "_bar", notify=barChanged) # read only (constant) bar = makeProperty(int, "_bar") Returns: Property: the created Property """ def setter(instance, value, notifyName): """ Generic setter. """ if getattr(instance, attributeName) == value: return setattr(instance, attributeName, value) getattr(instance, notifyName).emit() def getter(instance): """ Generic getter. """ return getattr(instance, attributeName) def signalName(signalInstance): """ Get signal name from instance. """ # string representation contains trailing '()', remove it return str(signalInstance)[:-2] if notify: return Property( T, getter, lambda self, value: setter(self, value, signalName(notify)), notify=notify) else: return Property(T, getter, constant=True)
class CameraParamsModel(ParamBase): _n_status = Signal() _n_menuStatus = Signal() _n_mode = Signal() _n_timecode = Signal() _param_group_key = 'camera' _prop_attr_map = { 'status':'status', 'menu_status':'menuStatus', 'mode':'mode', 'timecode':'timecode', } def __init__(self, *args): self._status = None self._menuStatus = False self._mode = None self._timecode = None super().__init__(*args) def _g_status(self) -> str: return self._status def _s_status(self, value: str): self._generic_setter('_status', value) status: str = Property(str, _g_status, _s_status, notify=_n_status) """Alias for :attr:`jvconnected.device.CameraParams.status`""" def _g_menuStatus(self) -> bool: return self._menuStatus def _s_menuStatus(self, value: bool): self._generic_setter('_menuStatus', value) menuStatus: bool = Property(bool, _g_menuStatus, _s_menuStatus, notify=_n_menuStatus) """Alias for :attr:`jvconnected.device.CameraParams.menu_status`""" def _g_mode(self) -> str: return self._mode def _s_mode(self, value: str): self._generic_setter('_mode', value) mode: str = Property(str, _g_mode, _s_mode, notify=_n_mode) """Alias for :attr:`jvconnected.device.CameraParams.status`""" def _g_timecode(self) -> str: return self._timecode def _s_timecode(self, value: str): self._generic_setter('_timecode', value) timecode: str = Property(str, _g_timecode, _s_timecode, notify=_n_timecode) """Alias for :attr:`jvconnected.device.CameraParams.status`""" @asyncSlot(str) async def sendMenuButton(self, value: str): """Send a menu button event Arguments: value (str): The menu button type as a string. Must be the name of a member of :class:`~jvconnected.device.MenuChoices` See :meth:`jvconnected.device.CameraParams.send_menu_button` """ enum_value = getattr(MenuChoices, value.upper()) await self.paramGroup.send_menu_button(enum_value)
class ColorField(Field): def __init__(self, property): super(ColorField, self).__init__(property) self._readOnly = False self._color = None self._widget = QPushButton() self._widget.setFlat(True) self._widget.setCursor(Qt.PointingHandCursor) self._widget.setMinimumWidth(100) self._widget.clicked.connect(self.clicked) self.setValue(QColor('#fff')) def styleString(self, color): return 'QPushButton { background-color: ' + color + '; border-radius: 0; border: none }' def clicked(self): color = QColorDialog.getColor(self._color) if color.isValid(): self.setValue(color) self.emitChanged() def value(self): return self._color def setValue(self, value): self._color = value self._widget.setStyleSheet(self.styleString(value.name())) def setReadOnly(self, value): self._readOnly = value valueProperty = Property(QColor, value, setValue) # C++: should be in parent class
class PaletteManager(QObject): """ Manages QApplication's palette and provides a toggle between a dark and a light theme. """ def __init__(self, qmlEngine, parent=None): super(PaletteManager, self).__init__(parent) self.qmlEngine = qmlEngine darkPalette = QPalette() window = QColor(50, 52, 55) text = QColor(200, 200, 200) disabledText = text.darker(170) base = window.darker(150) button = window.lighter(115) highlight = QColor(42, 130, 218) dark = window.darker(170) darkPalette.setColor(QPalette.Window, window) darkPalette.setColor(QPalette.WindowText, text) darkPalette.setColor(QPalette.Disabled, QPalette.WindowText, disabledText) darkPalette.setColor(QPalette.Base, base) darkPalette.setColor(QPalette.AlternateBase, QColor(46, 47, 48)) darkPalette.setColor(QPalette.ToolTipBase, base) darkPalette.setColor(QPalette.ToolTipText, text) darkPalette.setColor(QPalette.Text, text) darkPalette.setColor(QPalette.Disabled, QPalette.Text, disabledText) darkPalette.setColor(QPalette.Button, button) darkPalette.setColor(QPalette.ButtonText, text) darkPalette.setColor(QPalette.Disabled, QPalette.ButtonText, disabledText) darkPalette.setColor(QPalette.Mid, button.lighter(120)) darkPalette.setColor(QPalette.Highlight, highlight) darkPalette.setColor(QPalette.Disabled, QPalette.Highlight, QColor(80, 80, 80)) darkPalette.setColor(QPalette.HighlightedText, Qt.white) darkPalette.setColor(QPalette.Disabled, QPalette.HighlightedText, QColor(127, 127, 127)) darkPalette.setColor(QPalette.Shadow, Qt.black) darkPalette.setColor(QPalette.Link, highlight.lighter(130)) self.darkPalette = darkPalette self.defaultPalette = QApplication.instance().palette() self.togglePalette() @Slot() def togglePalette(self): app = QApplication.instance() if app.palette() == self.darkPalette: app.setPalette(self.defaultPalette) else: app.setPalette(self.darkPalette) if self.qmlEngine.rootObjects(): self.qmlEngine.reload() self.paletteChanged.emit() paletteChanged = Signal() palette = Property(QPalette, lambda self: QApplication.instance().palette(), notify=paletteChanged)