如何创建具有非线性比例的滑块?

ala*_*a27 22 .net c# wpf

我有一个最小值为0且最大值为500的滑块.

我想当滑块变为100时,拇指位于滑块的中间.

我知道它看起来很奇怪,但有些程序使用缩放滑块来做,我相信它会更好.

sam*_*var 39

显示值的良好公式是单调函数,例如幂曲线,采用以下形式:

DisplayValue = A + B * Math.Exp(C * SliderValue);
Run Code Online (Sandbox Code Playgroud)

通过反转公式获得内部滑块值(例如从0到1):

SliderValue = Math.Log((DisplayValue - A) / B) / C;
Run Code Online (Sandbox Code Playgroud)

现在如何获得A,B和C?通过使用您给出的三个约束:

f(0.0) = 0
f(0.5) = 100
f(1.0) = 500
Run Code Online (Sandbox Code Playgroud)

三个方程式,三个未知数,这是使用基本数学解决的:

A + B = 0
A + B exp(C * 0.5) = 100
A + B exp(C) = 500

B (exp(C * 0.5) - 1) = 100
B (exp(C) - 1) = 500

exp(C) - 5 exp(C * 0.5) + 4 = 0  // this is a quadratic equation

exp(C * 0.5) = 4

C = log(16)
B = 100/3
A = -100/3
Run Code Online (Sandbox Code Playgroud)

产生以下代码:

double B = 100.0 / 3;
double C = Math.Log(16.0);
DisplayValue = B * (Math.Exp(C * SliderValue) - 1.0);
Run Code Online (Sandbox Code Playgroud)

当内部值位于中间时,您可以看到显示值为100:

最终曲线

编辑:由于要求通用公式,这里是.鉴于:

f(0.0) = x
f(0.5) = y
f(1.0) = z
Run Code Online (Sandbox Code Playgroud)

A,B和C的值为:

A = (xz - y²) / (x - 2y + z)
B = (y - x)² / (x - 2y + z)
C = 2 * log((z-y) / (y-x))
Run Code Online (Sandbox Code Playgroud)

请注意,如果x - 2y + z为零,则没有解决方案,您将得到除零.那是因为在这种情况下,比例实际上是线性的.你需要照顾那个特例.

  • 对于那些在家里玩的人,请记住Math.Exp和Math.Log是基数e,所以在C = 2*ln((zy)/(yx))的公式中使用自然对数,特别是如果你在计算常数A,B&C代码之外. (4认同)
  • 很有帮助!是否有可能一般地解决A,B,C,即使用变量x,y,z而不是固定值0,100,500? (3认同)
  • 我添加了通用公式.我省略了所有步骤,因为这会使得答案真的太冗长了. (3认同)

Car*_*ten 11

让滑块保持原样,并使用ValueConverter进行绑定.在ValueConverter中,使用非线性缩放来根据需要缩放值.

  • 另一个例子是很多工作,但这个是更正确的方法. (5认同)

Ces*_*sar 8

作为进一步的参考; 如果您对滑块的确切位置不感兴趣,以对应于比例尺中的特定值,但仍希望滑块对比例开始时的值比对结束时的值更敏感,那么可能使用简单的对数比例可能就够了.

public class LogScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double x = (int)value;
        return Math.Log(x);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double x = (double)value;
        return (int)Math.Exp(x);
    }
}
Run Code Online (Sandbox Code Playgroud)


Fre*_*lad 2

这是一个非常有趣的问题,我不能置之不理,希望我能正确理解你的问题:)

当拇指位于中间时,您想要通过指定函数的 Y 值将 a 从线性函数更改Value为二次函数。Slider

二次函数写在表格上
公式

由于我们有 3 个点,因此我们有 3 组 X 和 Y 值。

(X1, Y1) = 0, 0  
(X2, Y2) = MiddleX, CenterQuadraticValue (in your case 100)  
(X3, Y3) = Maximum, Maximum (in your case 500)
Run Code Online (Sandbox Code Playgroud)

从这里,我们可以创建一个二次方程(例如,请参阅此链接),结果为
公式

不幸的是,该图中的某些值最终低于 0,因此它们必须强制为 0(我在答案的底部包含了一个图表)。

我创建了一个控件QuadraticSlider,它派生Slider并添加了两个依赖属性:QuadraticValueCenterQuadraticValue。它根据、、和QuadraticValue使用上面的公式进行计算。它还执行相反的操作:设置更新。因此,不要绑定到,而是绑定到。ValueMaximumMinimumCenterQuadraticValueQuadraticValueValueValueQuadraticValue

编辑:最后一个版本有点错误。修复了一些问题

  • 当“a”为0时计算Value不再中断QuadraticValue
  • 当导数为负时,使用了二次解的错误根

我上传了一个QuadraticSlider用于缩放图片的示例应用程序。所有参数都可以指定,第一张图片使用 ,Value另一张图片使用QuadraticValue

如果您想尝试一下,请在此处下载。

看起来像这样
在此输入图像描述

这就是图表的样子,注意低于 0 的值

在此输入图像描述

  • @SamHocevar:+1,从表面上看,这是一个更好的答案。-1表示尖叫和不必要的态度 (13认同)
  • 不,不,不,不!将此投票至无穷大!这可能是最糟糕的方法!您必须使用严格单调的函数。 (8认同)