Linear and Rotary controls
These are intended to show MIDI CC values, hence the default min,max of 0..127.
Linear
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from rtmidi import MidiIn, MidiOut
import sys
import math
def radians(x):
return x*math.pi/180
def degrees(x):
return x*180/math.pi
app = QApplication([])
# Define Widgets
class Linear(QWidget):
def __init__(self):
super().__init__()
self.value = 45
self.maxval = 127
self.minval = 0
self.mx = 0
self.my = 0
def mousePressEvent(self,e):
self.mval = self.value
pos = e.pos()
self.mx = pos.x()
self.my = pos.y()
print(f"press {pos.x()} {pos.y()}")
def mouseMoveEvent(self,e):
pos = e.pos()
dy = - (pos.y() - self.my)
self.value = max(min(self.mval + dy,self.maxval),self.minval)
print(f"move {pos.x()} {pos.y()} -- {dy=}")
self.update()
def paintEvent(self, event: QPaintEvent):
"""Override method from QWidget
Paint the Pixmap into the widget
"""
rect = self.rect()
w = rect.width()
h = rect.height()
w1 = w*0.9
h1 = h*0.9
cx = w/2
cy = h/2
m = min(w,h)
r = (m/2) * 0.9
y0 = cy - h1/2
font = QFont("Arial",r/4)
metrics = QFontMetrics(font)
t = str(self.value)
twidth = metrics.horizontalAdvance(t)
theight = metrics.capHeight()
tx = cx-(twidth/2)
ty = cy+(theight/2)
svalue = (self.value-self.minval)/(self.maxval-self.minval)
with QPainter(self) as painter:
painter.fillRect(rect,Qt.white)
painter.setBrush(Qt.NoBrush)
path = QPainterPath()
path.moveTo(QPoint(cx,y0+h1))
path.lineTo(QPoint(cx,y0))
painter.setPen(QPen(Qt.black, 5))
painter.drawPath(path)
path.clear()
path.moveTo(QPoint(cx,y0+h1))
path.lineTo(QPoint(cx,y0+h1*(1-svalue)))
painter.setPen(QPen(Qt.red,10))
painter.drawPath(path)
painter.setFont(font)
painter.drawText(QPoint(tx,ty),t)
# Instantiate Widgets
linear = Linear()
linear.show()
# Loader
def main():
exit(app.exec())
if __name__ == "__main__":
main()
Rotary
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from rtmidi import MidiIn, MidiOut
import sys
import math
def radians(x):
return x*math.pi/180
def degrees(x):
return x*180/math.pi
app = QApplication([])
# Define Widgets
class Rotary(QWidget):
def __init__(self):
super().__init__()
self.value = 45
self.maxval = 127
self.minval = 0
self.mx = 0
self.my = 0
def mousePressEvent(self,e):
self.mval = self.value
pos = e.pos()
self.mx = pos.x()
self.my = pos.y()
print(f"press {pos.x()} {pos.y()}")
def mouseMoveEvent(self,e):
pos = e.pos()
dy = - (pos.y() - self.my)
self.value = max(min(self.mval + dy,self.maxval),self.minval)
print(f"move {pos.x()} {pos.y()} -- {dy=}")
self.update()
def paintEvent(self, event: QPaintEvent):
"""Override method from QWidget
Paint the Pixmap into the widget
"""
rect = self.rect()
w = rect.width()
h = rect.height()
cx = w/2
cy = h/2
m = min(w,h)
r = (m/2) * 0.9
x = cx - r
y = cy - r
ww = 2*r
wh = 2*r
wr = QRect(QPoint(x,y),QSize(ww,wh))
wtheta = 300
itheta = 270-((360-wtheta)//2)
dtheta = wtheta*(self.value/(self.maxval-self.minval))
font = QFont("Arial",r/2)
metrics = QFontMetrics(font)
t = str(self.value)
twidth = metrics.horizontalAdvance(t)
theight = metrics.capHeight()
tx = cx-(twidth/2)
ty = cy+(theight/2)
with QPainter(self) as painter:
painter.fillRect(rect,Qt.white)
path = QPainterPath()
path.arcMoveTo(wr,itheta)
path.arcTo(wr,itheta,-dtheta)
painter.setBrush(Qt.NoBrush)
painter.setPen(QPen(Qt.black, 5))
painter.drawPath(path)
painter.setFont(font)
painter.drawText(QPoint(tx,ty),t)
# Instantiate Widgets
rotary = Rotary()
rotary.show()
# Loader
def main():
exit(app.exec())
if __name__ == "__main__":
main()
Linear2
Illustrates how to use modifiers like shift and control (note mods.value and Qt.ShiftModifier.value if you
want to bitwise compare), and have shift do fine-grained movements, and control jumping straight to the mouse
position.
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from rtmidi import MidiIn, MidiOut
import sys
import math
def radians(x):
return x*math.pi/180
def degrees(x):
return x*180/math.pi
app = QApplication([])
# Define Widgets
class LinearSlider1(QWidget):
def __init__(self):
super().__init__()
self.value = 45
self.maxval = 127
self.minval = 0
self.mx = 0
self.my = 0
self.ly = 0
self.lv = 0
self.sens = 1 # scales so that dragging the height of the widget goes from min to max
def mousePressEvent(self,e):
self.mval = self.value
pos = e.pos()
self.mx = pos.x()
self.my = pos.y()
self.ly = self.my
self.lv = self.value
mods = e.modifiers()
if mods == Qt.ControlModifier:
return self.mouseMoveAbsolute(e)
print(f"press {pos.x()} {pos.y()}")
def mouseMoveAbsolute(self,e):
rect = self.rect()
h = rect.height()
pos = e.pos()
y = pos.y()
x = 1 - y/h
self.value = self.minval + x*(self.maxval - self.minval)
self.value = min(self.maxval,max(self.minval,self.value))
self.lv = self.value
self.ly = y
self.value = int(self.value)
self.update()
def mouseMoveEvent(self,e):
mods = e.modifiers()
sens = self.sens
if mods == Qt.ControlModifier:
return self.mouseMoveAbsolute(e)
if mods.value & Qt.ShiftModifier.value:
print("shift")
sens /= 10
rect = self.rect()
h = rect.height()
pos = e.pos()
dy = - (pos.y() - self.ly)
self.ly = pos.y()
dy1 = sens*(dy / h)*(self.maxval - self.minval)
print("aa",self.lv,dy1)
self.lv = max(min(dy1+self.lv,self.maxval),self.minval)
self.value = int(self.lv)
self.update()
return
dy = - (pos.y() - self.my)
rect = self.rect()
h = rect.height()
dy1 = sens*(dy / h)*(self.maxval-self.minval)
print(f"{h=} {dy=} {dy1=}")
self.value = int(max(min(self.mval + dy1,self.maxval),self.minval))
print(f"move {pos.x()} {pos.y()} -- {dy=}")
self.update()
def paintEvent(self, event: QPaintEvent):
"""Override method from QWidget
Paint the Pixmap into the widget
"""
rect = self.rect()
w = rect.width()
h = rect.height()
w1 = w
h1 = h
cx = w/2
cy = h/2
m = min(w,h)
r = (m/2)
y0 = cy - h1/2
font = QFont("Arial",r/4)
metrics = QFontMetrics(font)
t = str(self.value)
twidth = metrics.horizontalAdvance(t)
theight = metrics.capHeight()
tx = cx-(twidth/2)
ty = cy+(theight/2)
svalue = (self.value-self.minval)/(self.maxval-self.minval)
with QPainter(self) as painter:
painter.fillRect(rect,Qt.white)
painter.setBrush(Qt.NoBrush)
path = QPainterPath()
path.moveTo(QPoint(cx,y0+h1))
path.lineTo(QPoint(cx,y0))
painter.setPen(QPen(Qt.black, 5))
painter.drawPath(path)
path.clear()
path.moveTo(QPoint(cx,y0+h1))
path.lineTo(QPoint(cx,y0+h1*(1-svalue)))
painter.setPen(QPen(Qt.red,10))
painter.drawPath(path)
painter.setFont(font)
painter.drawText(QPoint(tx,ty),t)
# Instantiate Widgets
slider = LinearSlider1()
slider.show()
# Loader
def main():
exit(app.exec())
if __name__ == "__main__":
main()