Track Bar Only fire event on final value not ever time value changes
Asked Answered
S

9

7

I am working on a pretty basic C# visual studio forms application but am having some issue getting the track bar to act as I want it to so hoping someone in the community might have a solution for this.

What I have is a pretty basic application with the main part being a track bar with a value of 0 to 100. The user sets the value of the track to represent "the amount of work to perform" at which point the program reaches out to some devices and tells them to do "x" amount of work (x being the value of the trackbar). So what I do is use the track bars scroll event to catch when the track bars value has changed and inside the handler call out to the devices and tells them how much work to do.

My issue is that my event handler is called for each value between where the track bar currently resides and where ever it ends. So if it is slid from 10 to 30, my event handler is called 20 times which means I am reaching out to my devices and telling them to run at values I don't even want them to run at. Is there someway only to event when scroll has stopped happening so you can check the final value?

Stipendiary answered 9/2, 2012 at 23:39 Comment(1)
Please don't prefix your titles with "C# Visual Studio 2010 " and such. That's what the tags are for.Sip
T
7

Just check a variable, if the user clicked the track bar. If so, delay the output.

bool clicked = false;
trackBar1.Scroll += (s,
                        e) =>
{
    if (clicked)
        return;
    Console.WriteLine(trackBar1.Value);
};
trackBar1.MouseDown += (s,
                        e) =>
{
    clicked = true;
};
trackBar1.MouseUp += (s,
                        e) =>
{
    if (!clicked)
        return;

    clicked = false;
    Console.WriteLine(trackBar1.Value);
};

For the problem @roken mentioned, you can set LargeChange and SmallChange to 0.

Tomcat answered 10/2, 2012 at 0:30 Comment(1)
Why not just key off the MouseUp event? Doesn't this only fire on MouseUp anyway?Angeloangelology
C
3

Try the MouseCaptureChanged event - that is the best for this task

Cummings answered 5/9, 2016 at 15:20 Comment(0)
D
1

A user could also move the track bar multiple times in a short period of time, or click on the track multiple times to increment the thumb over instead of dragging the thumb. All being additional cases where the value that registers at the end of a "thumb move" is not really the final value your user desires.

Sounds like you need a button to confirm the change, which would then capture the current value of the trackbar and send it off to your devices.

Dolt answered 10/2, 2012 at 0:32 Comment(0)
A
0

Try this with the trackbar_valuechanged event handler:

trackbar_valuechanged(s,e) {
    if(trackbar.value == 10){
        //Do whatever you want
    } else{
        //Do nothing or something else
    }
}
Arletha answered 11/5, 2012 at 9:54 Comment(0)
S
0

I found a fairly reliable way to do this is to use a timer hooked up in the trackbar.Scroll event:

private Timer _scrollingTimer = null;

private void trackbar_Scroll(object sender, EventArgs e)
{
    if (_scrollingTimer == null)
    {
        // Will tick every 500ms (change as required)
        _scrollingTimer = new Timer() 
        {
                Enabled = false,
                Interval = 500,
                Tag = (sender as TrackBar).Value
        };
        _scrollingTimer.Tick += (s, ea) =>
        {
            // check to see if the value has changed since we last ticked
            if (trackBar.Value == (int)_scrollingTimer.Tag)
            {
                // scrolling has stopped so we are good to go ahead and do stuff
                _scrollingTimer.Stop();

                // Do Stuff Here . . .

                _scrollingTimer.Dispose();
                _scrollingTimer = null;
            }
            else
            {
                // record the last value seen
                _scrollingTimer.Tag = trackBar.Value;
            }
        };
        _scrollingTimer.Start();
    }
}
Saintmihiel answered 28/3, 2013 at 16:39 Comment(0)
T
0

I had this problem just now as I'm implementing a built in video player and would like the user to be able to change the position of the video but I didn't want to overload the video playback API by sending it SetPosition calls for every tick the user passed on the way to his/her final destination.

This is my solution:

First, the arrow keys are a problem. You can try your best to handle the arrow keys via a timer or some other mechanism but I found it more pain than it is worth. So set the property SmallChange and LargeChange to 0 as @Matthias mentioned.

For mouse input, the user is going to have to click down, move it, and let go so handle the MouseDown, MouseUp, and the Scroll events of the trackbar like so:

    private bool trackbarMouseDown = false;
    private bool trackbarScrolling = false;

    private void trackbarCurrentPosition_Scroll(object sender, EventArgs e)
    {
        trackbarScrolling = true;
    }

    private void trackbarCurrentPosition_MouseUp(object sender, MouseEventArgs e)
    {
        if (trackbarMouseDown == true && trackbarScrolling == true)
            Playback.SetPosition(trackbarCurrentPosition.Value);
        trackbarMouseDown = false;
        trackbarScrolling = false;
    }

    private void trackbarCurrentPosition_MouseDown(object sender, MouseEventArgs e)
    {
        trackbarMouseDown = true;
    }
Touter answered 22/4, 2013 at 18:22 Comment(0)
E
0

I had a similar problem, only with a range TrackBar Control. Same idea applies to this also, only it's easier for this case.

I handled the MouseUp Event on the TrackBar to launch the procedures I needed, only after you would let go of the mouse button. This works if you drag the bar to your desired position or just click it.

private void rangeTrackBarControl1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { YourProcedureHere(); }

Elisabeth answered 4/12, 2014 at 13:35 Comment(0)
N
0

i solved the problem for my application with two events:

  1. catch the Trackbar-ValueChange-Event
  2. whithin the value-change event disable the valuechange event and enable the MouseUp-Event
    public MainWindow()
        {
            //Event for new Trackbar-Value
            trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
        }
    
    private void trackbar_ValueChanged(object sender, EventArgs e)
        {
            //enable Trackbar Mouse-ButtonUp-Event
            trackbar.MouseUp += ch1_slider_MouseUp;
            //disable Trackbar-ValueChange-Event
            trackbar.ValueChanged -= ch1_slider_ValueChanged;
        }

        private void trackbar_MouseUp(object sender, EventArgs e)
        {
            //enable Trackbar-ValueChange-Event again
            trackbar.ValueChanged += new System.EventHandler(trackbar_ValueChanged);
            //disable Mouse-ButtonUp-Event
            trackbar.MouseUp -= trackbar_MouseUp;

            //This is the final trackbar-value
            textBox.AppendText(trackbar.Value);
        }

ATTENTION: this works if the trackbar is moved by mose. It is also possible to move the trackbar by keyboard. Then futher code must be implemented to handle this event.

Naoma answered 1/12, 2021 at 20:44 Comment(0)
P
0

This is wpf but the same problem. I use a slider to set a value from 0 ... 8 in steps of 1. It was easy to get a TextBox updated with the final value of the trackbar. But for 'ValueChanged' never served the actual value but always the one before, I finally landed using the PreviewMouseLeftButtonUp-event as well as the KeyUp-event for moving the slider with the keyboard.

<StackPanel Grid.Row="5" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" MinHeight="20">
    <Slider Name="SliderResistor" Maximum="8" Minimum="0" TickFrequency="1" IsSnapToTickEnabled="True" HorizontalAlignment="Left" Margin="0,0" VerticalAlignment="Top" Width="135">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewMouseLeftButtonUp">
                <i:InvokeCommandAction Command="{Binding UseValueCommand}" CommandParameter="{Binding ElementName=SliderResistor, Path=Value}"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="KeyUp">
                <i:InvokeCommandAction Command="{Binding UseValueCommand}" CommandParameter="{Binding ElementName=SliderResistor, Path=Value}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
    <TextBox Name="tbResistorValue" MinWidth="20" Height="20" IsReadOnly="True" Text="{Binding ElementName=SliderResistor, Path=Value, UpdateSourceTrigger=PropertyChanged}" AcceptsReturn="True">
    </TextBox>
    <Label Content="Ω"></Label>
</StackPanel>

Both events trigger a command 'UseValueCommand' that carries the value of the slider to the underlying model to do some work there. So in case I would move from position '2' to '5' using the mouse the command will be called with parameter '5' when releasing the mouse button. Pressing the right arrow key will set the value from '2' to '3', the command will be called with parameter '3'.

Prussianism answered 7/6 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.