There is a "Custom Trackbar", which can take negative and positive values. If you set Min = -50, Max = 100, the slider moves outside the scrollbar. I need it to behave in the same way as "Standard Trackbar" (it should not go beyond the scrollbar boundaries). How to do it?
The screenshot shows 2 Trackbars for both I set (Minimum = -50, Maximum = 100, Value = -50), but after building the project I got the following picture:
If we set (Minimum = 0, Maximum = 100, Value = 25), we get the following:
[Code Custom Trackbar]
[DefaultEvent("ValueChanged")]
public class HandyHTrackbarWorked : Control {
#region Установка начальных параметров
public HandyHTrackbarWorked() {
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint
| ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw, true); UpdateStyles();
Size = new Size(250, 12);
ThumbSize = new Size(ThumbRect.Width = 15, ThumbRect.Height = 12);
}
#endregion
#region Основные свойства
private double _value;
public double Value {
get { return _value; }
set {
_value = value;
//if (_value < Minimum) { _value = Minimum; }
//if (_value > Maximum) { _value = Maximum; }
OnScroll(); Refresh();
}
}
private double minimum;
public double Minimum {
get { return minimum; }
set { minimum = value; Invalidate(); }
}
private double maximum = 100;
public double Maximum {
get { return maximum; }
set { maximum = value; Invalidate(); }
}
private double smallStep = 1;
public double SmallStep {
get { return smallStep; }
set {
smallStep = (value > 0) ? value : 1;
}
}
#endregion
#region Свойства, отвечающие за оформление
[Description("Размер ползунка")]
private Size thumbSize;
public Size ThumbSize {
get { return thumbSize; }
set {
thumbSize = value;
//if (thumbSize.Width % 2 == 0 && thumbSize.Width > 0) thumbSize.Width += 1;
Invalidate();
}
}
[Description("Цвет ползунка")]
private Color thumbBackColor = Color.FromArgb(255, 255, 255);
public Color ThumbBackColor {
get { return thumbBackColor; }
set { thumbBackColor = value; Invalidate(); }
}
private Color trackBackColor = Color.Transparent;
public Color TrackBackColor {
get { return trackBackColor; }
set { trackBackColor = value; Invalidate(); }
}
private Color trackBorderColor = Color.FromArgb(221, 0, 49);
public Color TrackBorderColor {
get { return trackBorderColor; }
set { trackBorderColor = value; Invalidate(); }
}
private Color trackBorderColor2 = Color.FromArgb(64, 64, 64);
public Color TrackBorderColor2 {
get { return trackBorderColor2; }
set { trackBorderColor2 = value; Invalidate(); }
}
[Description("Толщина")]
private int trackThickness = 2;
public int TrackThickness {
get { return trackThickness; }
set { trackThickness = value; Invalidate(); }
}
public new Padding Padding {
get { return base.Padding; }
set { base.Padding = value; Invalidate(); }
}
public Rectangle ThumbRect;
#endregion
#region Основные события
public event EventHandler ValueChanged;
#endregion
#region Обработчики событий
private Point startMouseClickPosition;
private Point currentMousePosition;
protected override void OnCreateControl() {
base.OnCreateControl();
this.MouseDown += (sender, e) => {
// When clicking on the ScrollBar, center the Thumb relative to the mouse cursor
if (!ThumbRect.Contains(e.Location)) {
MoveThumb(e, false);
}
// When clicking on Thumb, determine the startMouseClickPosition
if (ThumbRect.Contains(e.Location)) {
startMouseClickPosition.X = e.X - ThumbRect.Left; // OR ... - ThumbRect.X
ThumbBackColor = Color.Green;
}
};
this.MouseMove += (sender, e) => {
ThumbBackColor = ThumbRect.Contains(e.Location)
? ThumbBackColor = Color.Orange : ThumbBackColor = Color.Gray;
if (e.Button == MouseButtons.Left) {
ThumbBackColor = Color.Green; MoveThumb(e);
}
};
this.MouseLeave += (sender, e) => { ThumbBackColor = Color.Gray; };
}
int PaddingLR = 10;
// padding(left/right) must be the same,
// if the orientation of the scroll bar is HORIZONTAL
private void MoveThumb(MouseEventArgs e, bool useStartMouseClickPosition = true) {
double newValue;
if (useStartMouseClickPosition) {
currentMousePosition.X = e.X - startMouseClickPosition.X;
// works correctly
newValue = Maximum * (currentMousePosition.X - (ThumbSize.Width / 2) + (ThumbSize.Width / 2) - PaddingLR)
/ (Width - ThumbSize.Width - PaddingLR * 2);
} else {
newValue = Maximum * (e.X - ThumbSize.Width / 2 - PaddingLR)
/ (Width - ThumbSize.Width - PaddingLR * 2);
}
// does NOT work correctly (although the calculation result is the same)
//double newValue = Maximum * (newThumbLeft + (ThumbSize.Width / 2) - PaddingLR) /
// (Width - ThumbSize.Width - PaddingLR * 2);
Value = Math.Max(0, Math.Min(Maximum, newValue));
}
public void OnScroll() {
ValueChanged?.Invoke(this, EventArgs.Empty);
}
#endregion
#region Отрисовка элементов управления
protected override void OnPaint(PaintEventArgs e) {
ThumbRect = new Rectangle(
Convert.ToInt32(Value * (Width - ThumbSize.Width - Padding.Left * 2) / Maximum + Padding.Right),
0 + Padding.Top,
ThumbSize.Width, // fixed slider width
Height - Padding.Bottom - Padding.Top // dynamic slider height
// (example) Height - 4, means to move the slider by 2 px above and below
);
// Filling the scroll bar
using (SolidBrush brush = new SolidBrush(TrackBackColor)) {
e.Graphics.FillRectangle(brush, new Rectangle(0, 0, Width, Height));
}
// The colored line in front of the slider
using (Pen pen = new Pen(TrackBorderColor2, TrackThickness)) {
e.Graphics.DrawLine(pen, Padding.Left, Height / 2, Width - Padding.Right, Height / 2);
}
// The colored line following the slider
using (Pen pen = new Pen(TrackBorderColor, TrackThickness)) {
e.Graphics.DrawLine(pen, Padding.Left, Height / 2, ThumbRect.Right, Height / 2);
}
// Filling the slider
using (SolidBrush brush2 = new SolidBrush(Color.FromArgb(100, 0, 0, 0))) {
e.Graphics.FillRectangle(brush2, ThumbRect);
}
}
#endregion
}


Thanks to the help of user @IVSoftware, in writing auxiliary methods calcValueFromPosition() and calcXfromValue(), the following solution was obtained, which allows you to set different paddings:
[Code Custom Trackbar]