The only way I can see to give the slider the behavior you want would be to remove the track listener, and script the movements yourself, but that gets somewhat complex. It's possible that creating a custom slider would be simpler.
To remove the listener, add this to the slider's propertyChange event handler:
# Runs once and only once at run time
# Won't run in the designer unless preview mode is active prior to the window being opened.
if event.propertyName == 'componentRunning':
# Iterate through the various mouse listeners, and surgically remove the track listener
for listener in event.source.mouseListeners:
if 'SynthTrackListener' in listener.__class__.__name__:
event.source.removeMouseListener(listener)
Moving the knob around and setting values will require quite a bit of scaling in multiple event handlers, so I would set up a library script for this, or add a custom method to the component like this one here:
#Custom method on the slider component with parameters: value, originalMin, originalMax, scaledMin, scaledMax
#def getScaledValue(self, value, originalMin, originalMax, scaledMin, scaledMax):
"""
Arguments:
self: A reference to the[...]
"""
originalRange = originalMax - originalMin
# Cast one of the variables to float, or the rules of integer division will evaluate this as zero
percentage = (value - originalMin)/float(originalRange)
scaledRange = scaledMax - scaledMin
# Cast the scaled value back to an int, and return it
return int((percentage * scaledRange) + scaledMin)
Use the mousePressed event handler to determine whether or not the slider knob should be dragged. This can be conveyed to the mouseDragged event handler by adding a custom property to the component called "dragEnabled"
# Written for the mousePressed event handler
# Do not allow dragging if the component is disabled
if event.source.enabled:
from java.awt import Rectangle
knobRadius = 30
if event.source.inverted and event.source.horizontal:
valuePosition = event.source.getScaledValue(event.source.value, event.source.minimum, event.source.maximum, 0 , event.source.width)
knobBounds = Rectangle(event.source.width - valuePosition - knobRadius, event.source.height / 2 - knobRadius, 2 * knobRadius, 2 * knobRadius)
elif event.source.inverted and not event.source.horizontal:
valuePosition = event.source.getScaledValue(event.source.value, event.source.minimum, event.source.maximum, 0 , event.source.height)
knobBounds = Rectangle(event.source.width / 2 - knobRadius, valuePosition - knobRadius, 2 * knobRadius, 2 * knobRadius)
elif event.source.horizontal:
valuePosition = event.source.getScaledValue(event.source.value, event.source.minimum, event.source.maximum, 0 , event.source.width)
knobBounds = Rectangle(valuePosition - knobRadius, event.source.height / 2 - knobRadius , 2 * knobRadius, 2 * knobRadius)
else:
valuePosition = event.source.getScaledValue(event.source.value, event.source.minimum, event.source.maximum, 0 , event.source.height)
knobBounds = Rectangle(event.source.width / 2 - knobRadius, event.source.height - valuePosition - knobRadius, 2 * knobRadius, 2 * knobRadius)
if knobBounds.contains(event.x, event.y):
event.source.dragEnabled = True
event.source.parent.getComponent('Paintable Canvas').leftClick = True
When the user drags the slider, and the dragEnabled custom property has been set during the mouse pressed event, control the knob position with this script:
# Written for the mouse dragged event handler
# Enabled from the mousePressed event handler
if event.source.dragEnabled:
# There are four ways the slider can be configured that will change where the knob is positioned within the component in relationship to the slider value,
# ...so they all have to be accounted for to ensure the calculation comes out correct
if event.source.inverted and event.source.horizontal:
newValue = event.source.getScaledValue(event.source.width - event.x, 0, event.source.width, event.source.minimum, event.source.maximum)
elif event.source.inverted and not event.source.horizontal:
newValue = event.source.getScaledValue(event.y, 0, event.source.height, event.source.minimum, event.source.maximum)
elif event.source.horizontal: # horizontal and not inverted
newValue = event.source.getScaledValue(event.x, 0, event.source.width, event.source.minimum, event.source.maximum)
else: # not inverted and not horizontal
newValue = event.source.getScaledValue(event.source.height - event.y, 0, event.source.height, event.source.minimum, event.source.maximum)
# Prevent the calculated value from exceding the bounds of the component
if newValue < event.source.minimum:
newValue = event.source.minimum
elif newValue > event.source.maximum:
newValue = event.source.maximum
# When a the slider's value property changes, the knob automatically moves to the appropriate position
event.source.value = newValue
Finally, when the user releases the mouse button, disable slider movements with the mouse released event handler:
# Written for the mouseReleased event handler,
event.source.dragEnabled = False
Result:
Edit: Note that this approach relies on the componentRunning
event handler, so it won't work in the designer unless preview mode is already running when the window is opened.