def test_unbound_channel(): '''Test unbound channel''' def receiver(): return True chan = channel('anon') # channel returns the same instance for a given identifier assert chan is channel('anon') # A channel is unbound by default assert not chan.bound # A channel starts with no receivers assert chan.send() == [] # Connect a receiver chan.connect(receiver) assert chan.send() == [True] # Connecting twice does not add the same receiver twice chan.connect(receiver) assert chan.send() == [True] # Disconnect a receiver chan.disconnect(receiver) assert chan.send() == [] # Reconnect receiver and ensure Band does not hold a reference # once it is out of scope / all refs are gone chan.connect(receiver) assert chan.send() == [True] del (receiver) assert chan.send() == []
class Component(object): started = channel('started') stopped = channel('stopped') def __init__(self, name): self.name = name self.started.connect(self.on_started) self.stopped.connect(self.on_stopped) def on_started(self): return self.name + '.on_started' def on_stopped(self): return self.name + '.on_stopped'
class ClickableLabel(QtWidgets.QLabel): valid = StyledProperty('valid', True) clicked = channel('clicked') right_clicked = channel('right_clicked') def __init__(self, *args, **kwargs): super(ClickableLabel, self).__init__(*args, **kwargs) StyledProperty.init(self) self.setMouseTracking(True) def mousePressEvent(self, event): if event.buttons() & QtCore.Qt.LeftButton: self.active = True self.clicked.send() elif event.buttons() & QtCore.Qt.RightButton: self.right_clicked.send() event.accept() def mouseReleaseEvent(self, event): self.active = False event.accept()
def test_strongref(): '''Test strong references''' weak = lambda: 'weak' strong = lambda: 'strong' chan = channel('anon') chan.connect(weak) chan.connect(strong, strong=True) assert chan.send() == ['weak', 'strong'] del (weak) del (strong) # Our strong receiver is still alive! assert chan.send() == ['strong'] # Make sure disconnecting strong receivers works strong = list(chan.receivers)[0] chan.disconnect(strong) assert chan.send() == []
class Control(object): ''' Mixin base class for all Control widgets. The purpose of the Control Mixin is to ensure a unified API across all Control widgets. - Controls emit a **changed** messaged when their control's value changes - `Control.get` returns the value of a Control - `Control.set` sets the value of a Control Control should be used as the first base class of a control QWidget. Subclasses must use the create method to setup and create their widget/s. Users should call the send_changed method when their contol widget's value changes. Subclasses must also implement the get and set methods. Arguments: name (str): Name of the control range (tuple): (min, max) default (int): Default value parent (QWidget): Parent widget Attributes: changed (bands.channel): Emitted when a Control's value is changed. name (str): Control name default: Control's default value valid (StyledProperty): True when control value is valid error (StyledProperty): True when control value is invalid Example: Here is how we would implement a simple IntControl:: class IntControl(Control, QtWidgets.QSpinBox): def create(self): self.setRange(0, 99) self.valueChanged.connect(self.send_changed) def get(self): return self.value() def set(self, value): return self.setValue(value) int_cntrl = IntControl() int_cntrl.set(10) assert int_cntrl.get() == 10 ''' changed = channel('changed') valid = StyledProperty('valid', True) error = StyledProperty('error', False) def __init__(self, name, default=None, parent=None): super(Control, self).__init__(parent=parent) self.setObjectName(name) self.name = name self.create() if default is not None: self.set(default) StyledProperty.init(self) def send_changed(self): self.changed.send(self) @abstractmethod def create(self): return NotImplemented @abstractmethod def get(self): return NotImplemented @abstractmethod def set(self, value): return NotImplemented