Title: Make a slider with a needle in C#
This example draws a vertical "needle" in a PictureBox to let the user select a value much as a TrackBar does. The code does all of the drawing, however, so you have control over the slider's appearance. The example also displays the current value in a tooltip above the slider.
The program uses a variable and two constants to track the slider's value and its minimum and maximum allowed values.
// The current value.
private float SliderValue = 0.3f;
// The minimum and maximum allowed values.
private const float MinimumValue = 0.0f;
private const float MaximumValue = 1.0f;
The program uses two methods to convert between X coordinates in the PictureBox and values between the minimum and maximum allowed values.
// Convert an X coordinate to a value.
private float XtoValue(int x)
{
return MinimumValue + (MaximumValue - MinimumValue) *
x / (float)(picSlider.ClientSize.Width - 1);
}
// Convert value to an X coordinate.
private float ValueToX(float value)
{
return (picSlider.ClientSize.Width - 1) *
(value - MinimumValue) /
(float)(MaximumValue - MinimumValue);
}
This is just math. The only trick here is that the code subtracts 1 from the PictureBox control's client width to map the rightmost visible pixel in the PictureBox to the largest allowed value. If you don't do this, then when the user selects the largest allowed value the needle is partly off the edge of the control.
When the user presses the mouse down on the PictureBox or moves the pressed mouse over the PictureBox, the MouseDown or MouseMove event handlers call the SetValue method to update the slider's value.
// Move the needle to this position.
private bool MouseIsDown = false;
private void picSlider_MouseDown(object sender, MouseEventArgs e)
{
MouseIsDown = true;
SetValue(XtoValue(e.X));
}
private void picSlider_MouseMove(object sender, MouseEventArgs e)
{
if (!MouseIsDown) return;
SetValue(XtoValue(e.X));
}
When the user releases the mouse, the following event handler sets MouseIsDown so future MouseMove events don't do anything.
private void picSlider_MouseUp(object sender, MouseEventArgs e)
{
MouseIsDown = false;
tipValue.Hide(this);
// Take action here if desired.
lblResult.Text = SliderValue.ToString("0.00");
}
The following SetValue method updates the slider's value.
// Set the slider's value. If the value has changed,
// display the value tooltip.
private void SetValue(float value)
{
// Make sure the new value is within bounds.
if (value < MinimumValue) value = MinimumValue;
if (value > MaximumValue) value = MaximumValue;
// See if the value has changed.
if (SliderValue == value) return;
// Save the new value.
SliderValue = value;
// Redraw to show the new value.
picSlider.Refresh();
// Display the value tooltip.
int tip_x = picSlider.Left + (int)ValueToX(SliderValue);
int tip_y = picSlider.Top;
tipValue.Show(SliderValue.ToString("0.00"),
this, tip_x, tip_y, 3000);
// Take action here if desired.
lblResult.Text = SliderValue.ToString("0.00");
}
The code first ensures that the new value is within range. If the user presses the mouse down over the control and then drags it off the right or left of the PictureBox, the value could be outside of the allowed range so this code fixes it.
Next if the new value and the old value are the same, the method exits.
If the method doesn't exit, it saves the new value and refreshes the PictureBox so it shows the new needle position. It then displays the new value in a tooltip above the PictureBox. Finally in this example the code displays the new value in a label.
The last piece of interesting code is the PictureBox control's Paint event handler.
// Draw the needle.
private void picSlider_Paint(object sender, PaintEventArgs e)
{
// Calculate the needle's X coordinate.
float x = ValueToX(SliderValue);
// Draw it.
using (Pen pen = new Pen(Color.Blue, 2))
{
e.Graphics.DrawLine(pen, x, 0,
x, picSlider.ClientSize.Height);
}
}
This code simply draws the needle at the corrent position.
Using a SetValue method may seem overly elaborate. You could simply set the new value directly and then refresh the PictureBox in the MouseDown and MouseMove event handlers. The program uses SetValue to avoid doing anything if the value doesn't change. That's important to avoid flicker caused by unnecessary redraws and unnecessarily redisplaying the tooltip.
Download the example to experiment with it and to see additional details.
|