Vertical Touchscreen Slider with Confirm Button
I realise there have been quite a lot of threads on the implementation of sliders & their use on touch screens. So sorry to add another! But I have read through these and had lots of trial and error - but as a beginner my lack of python understanding is hindering me from achieving my desired outcome. I am hoping someone can help...
What I am trying to achieve is a vertical slider that works on a touchscreen with an image at the top and bottom, that when participants press or slide their finger up and down the bar/line it fills (or a marker moves up and down - I'm not too fussy on the aesthetics). As with the other threads - I'd prefer it if this only occurs within the area of the slider not just anywhere on the screen. Then, when participants are happy with their response, I'd like there to be a confirm button for them to press that then logs their response. I'm pretty sure much of the code has been presented on the threads I've looked at - but for the life of me I can't piece it all together!
Thanks in advance for any guidance...
Comments
Hi,
The existing solutions are indeed not entirely satisfying. So let's see how you can do this more elegantly, by adding a slider widget to the forms. The following code will inject a slider into the form widgets, meaning that from then on you can use this slider just like any of the other widgets. Ideally, you would do this in the Prepare phase of an
inline_scriptat the very start of the experiment.This particular variation of the slider simply registers a value between 0 and 1, and shows this as a vertically filled bar (empty = 0, filled = 1).
And then you can simply use the slider as a widget in a
form_base, like below. This snippet will show a slider at the top and a button at the bottom to close the form. Not the most elegant of configurations, but it shows the general idea.Hope this helps!
Cheers,
Sebastiaan
Check out SigmundAI.eu for our OpenSesame AI assistant!
Hi Sebastiaan,
Thank you for this. This looks like a much better solution moving forward - however when I paste the code above into the prepare section (or the run section) of an inline script at the beginning of my experiment, and then later on add a new form base with the code you suggest - I get a grey box above a button.... like it doesn't recognise that there is now a new slider widget...
Try clicking ont the grey box.
The slider adjusts to the form geometry, so if you adjust the geometry such that the slider isn't a box but an elongated vertical rectangle, it will look more like a slider.
Check out SigmundAI.eu for our OpenSesame AI assistant!
Ah! I see.... Thank you! With a bit of tinkering to make it look pretty this will work a treat.... (I will post the code when I have done so in case of use to others!)
One thing though... on a touchscreen this doesn't truly slide when you move your finger - only when you press in different places (presumably because its recognising clicks rather than drags/mouse-movement). The sliders on earlier discussion threads did this quite well (although they couldn't be added as a widget like this which I think is much better)...Is it possible to achieve this sliding movement - within the confines of the slider area on the form?
Partly, yes. OpenSesame's
mouseobject doesn't understand mouse-up events, so to implement this you need to access the underlying libraries directly. Below is a slight extension of the above slider that does so but only for the back-ends that rely on pygame (right now all except psycho).Check out SigmundAI.eu for our OpenSesame AI assistant!
This works beautifully! Thanks ever so much. A final side note - if I wanted a frame/box round the slider area (so min and max were clearer) - is the best thing to add into the above code instructions to draw a box, or to add an image of a box to the same space on the custom form?
There are various ways to do this, but for maximum flexibility, you could customize
slider.render()even further and directly draw to the form's canvas. For example like so:Check out SigmundAI.eu for our OpenSesame AI assistant!
Hi @sebastiaan, this works great now. Just a couple of questions for further tweaks:
How would I amend the code to have a horizontal slider if needed?
Is it possible to amend the slider from being a block that fills to something like a line with a marker?
For example - something like the Affective Slider (Betella et al., 2016)
That's possible. But I think it's a useful (and doable) exercise to try this yourself! If you look at the
render()function (where the drawing happens), you'll find all the ingredients you need.self.rectis anx, y, w, htuple that indicates the bounding box of the slider widget in pixels.self._fillis a value between 0 and 1 that indicates how full the slider is.self.form.canvasis a regularcanvasobject that you can draw on.You also need to modify the
_basic()function so that it determines the fill based on the horizontal position of the click (if you want a horizontal slider).Cheers!
Check out SigmundAI.eu for our OpenSesame AI assistant!
Hi @sebastiaan, so after a lot of trial and error I'm really close - but having a couple of issues I can't work out how to sort. My Inline Script is as follows:
and in my custom form I have:
My current issues are:
Apologies for all the questions - really appreciate the help. Will make sure I post the completed code incase of use to others viewing the forum.
Yes, your trigonometry is off
x*(1-self._fill)should bex+w*self._fill:That already happens. But the width/ height ratio is not changed, because that would distort the image. So you have to make sure that this ratio is correct in the original image, and then you will see that it will adjust to the size of the widget.
I wouldn't use an image for the outline. This will make it difficult to scale the size of the widget. Instead, I would use
canvas.polygon()to draw a slightly fancier (but scalable) outline in therender()function:Cheers!
Check out SigmundAI.eu for our OpenSesame AI assistant!
Thanks @sebastiaan I will have a go with that. For a curve using canvas.polygon - does that mean I just need to put in lots and lots of points to get something resembling a circle?
Exactly!
Check out SigmundAI.eu for our OpenSesame AI assistant!
@sebastiaan OK - so who thought drawing a curved line would be so hard - but its bamboozling me! Using some pythag to help me work out co-ordinates relative to the size of the widget I tried something like this:
from cmath import sqrt r=(h/2) n0 = x,y n1 = x-1,(y+sqrt((r**2)-(1**2))) n2 = x-2,(y+sqrt((r**2)-(2**2))) n3 = x-3,(y+sqrt((r**2)-(3**2))) ... n400 = x-400,(y+sqrt((r**2)-(400**2))) .... self.form.canvas.polygon([n0, n1, n2, n3, ...n400...])I only got so far in writing the remaining lines but nothing is showing up so far - and I'm probably barking up the wrong tree - is this even remotely close?
Here's another way to draw a rounded rectangle. An easier way probably. Do you see the logic? The corners are drawn with four circles, and the body is a cross of two rectangles. The rounded rectangle is filled, but to draw only an outline, you can simply draw a slightly smaller rounded rectangle inside.
Check out SigmundAI.eu for our OpenSesame AI assistant!
OK - that last bit went a bit beyond me - but incase this code is of use to others - this is what I used to implement the Affective Slider (Betella et al., 2016)...
In Inline Script:
`
from libopensesame.widgets._widget import widget
from libopensesame import widgets
from openexp._mouse.legacy import legacy
class slider(widget):
widgets.slider = slider`
In Custom Form
set timeout infinite set spacing 10 set rows "3;1;1;3;1;1;1;1" set only_render no set margins "50;50;50;50" set cols "1;5;1" set _theme gray widget 0 0 3 1 label text="Mark on the slider below how <b>Happy</b> you are right now" widget 1 1 1 1 slider var=s1response widget 1 2 1 1 image path="AS_intensity_cue-2.png" widget 0 1 1 2 image path="AS_happy-2.png" widget 2 1 1 2 image path="AS_unhappy-2.png" widget 0 3 3 1 label text="Mark on the slider below how <b>Alert</b> you are right now" widget 1 4 1 1 slider var=s2response widget 1 5 1 1 image path="AS_intensity_cue-2.png" widget 0 4 1 2 image path="AS_sleepy-2.png" widget 2 4 1 2 image path="AS_wideawake-2.png" widget 0 7 3 1 button text="<b>Confirm</b>"Seems to work well - Thanks @sebastiaan for all your help.
Hi all
Is this suggestion still valid?
I copied the original code to an inline script at the start of the experiment, then I call the widget in a inline_script, but an empty screen appears.
Any thoughts?
Thanks,
Fotis
Hi @fotisfotiadis ,
No this code is based on outdated version of OpenSesame. I would check out this discussion. I haven't tried it, but the code shown there by @Lara94 is for recent versions of OpenSesame.
— Sebastiaan
Check out SigmundAI.eu for our OpenSesame AI assistant!
Hi @sebastiaan
Thanks for the response, always appreciated!
Best,
Fotis