:orphan: Qt Interactive ============== *Example script* (scamp): `examples/Interactivity & visualization/Responding to a GUI/qt_interactive.py `__ *Download:* :download:`qt_interactive.py ` A draggable PyQt rectangle drives live playback in a server session. Moving the rectangle fires a callback that sets the tempo of the clock running the note loop; its vertical position still sets the pitch. *Topics:* :doc:`Interactivity & visualization › Responding to a GUI ` .. raw:: html .. code-block:: python from scamp import * from PyQt5 import QtCore, QtWidgets class DraggableRect(QtWidgets.QGraphicsRectItem): """Movable rectangle that calls `on_move(x, y)` each time it is dragged.""" def __init__(self, rect, on_move=None): super().__init__(rect) self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True) self.on_move = on_move def itemChange(self, change, value): if change == QtWidgets.QGraphicsItem.ItemPositionChange and self.on_move is not None: self.on_move(value.x(), value.y()) return super().itemChange(change, value) class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) scene = QtWidgets.QGraphicsScene(self) view = QtWidgets.QGraphicsView(scene) scene.setSceneRect(QtCore.QRectF(0, 0, 800, 800)) self.setCentralWidget(view) self.rect_item = DraggableRect(QtCore.QRectF(0, 0, 100, 100)) scene.addItem(self.rect_item) if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.setFixedSize(QtCore.QSize(800, 800)) w.show() # map the rectangle's x position (0–800) to a tempo in BPM tempo_response = Envelope([30, 600], [800], [3]) # leaving the `with` block kills the session (and the forked note loop), so closing # the window shuts everything down gracefully rather than leaking the scheduler thread with Session().run_as_server() as s: piano = s.new_part("piano") s.start_transcribing() def play_notes(): while True: piano.play_note((1 - w.rect_item.y() / 800) * 40 + 60, 1.0, 1.0) play_clock = s.fork(play_notes) # whenever the rectangle moves, retune the note loop's tempo from its x position w.rect_item.on_move = lambda x, y: setattr(play_clock, "tempo", tempo_response.value_at(x)) app.exec_() # blocks until the window is closed performance = s.stop_transcribing() performance.to_score().show()