.NET用户控件:线性数据可视化滑尺

在.NET开发领域,用户界面的直观性和功能性是至关重要的。本文将介绍一个.NET用户控件,它是一个图形滑尺,用于线性地表示数据。这个控件由一个静态指针(类似于指针)和一个可移动的线性刻度组成。静态指针指向移动刻度的当前位置,并通过刻度上的图形位置显示输入值。滑尺是无限的,可以在某一时刻表示一个无限大的值(类型为double)。

在CodeProject上,已经有许多非常有用且外观精美的仪器可供使用。想再添加一个到这个链条中。这个项目是用C#开发的,使用SharpDevelop和.NET 2.0,以及GDI+。

控件结构

滑尺继承自System.Windows.Forms.UserControl,重写了OnPaint方法,并添加了一些新属性:

  • Value:滑尺的当前位置。
  • ScaleRange:滑尺的可见范围。
  • LargeTicksCount:大刻度的数量。
  • SmallTickCount:小刻度的数量。
  • ShadowEnabled:是否启用阴影?
  • ShadowColor:组件的阴影颜色。
  • NeedleColor:滑尺指针的颜色。

在代码中,使用了父控件的以下属性:

  • BackColor:组件的背景颜色。
  • BorderStyle:指示控件是否应该有边框。
  • ForeColor:用于显示文本和刻度的前景颜色。

滑尺由四层组成:

  • 背景(带有背景颜色或透明)和边框。
  • 线性刻度(带有数量不定的小刻度和/或大刻度及其值)。
  • 阴影(用于3D效果,可以禁用)。
  • 指针。

完整的逻辑放在OnPaint方法中。有一个小的不变部分,对于纯粹主义者来说,被封闭在一个签名区域内,可以移动到OnPaint之外。其他一切都在几个简单的步骤中完成:

  1. 计算第一个大刻度的位置及其值。
  2. 遍历所有其他大刻度,绘制它们及其数值。
  3. 如果存在,遍历所有小刻度,并绘制它们。
  4. 如果启用,使用LinearGradientBrush绘制阴影。
  5. 在其定义的颜色上绘制指针。

代码实现

protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // Draw simple text, don't waste time with luxury render: e.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit; #region Can be moved outside OnPaint ... // Calculate help variables int W = this.ClientRectangle.Width; int H = this.ClientRectangle.Height; int Wm = W / 2; int Hm = H / 2; // Calculate distances between ticks double largeTicksDistance = scaleRange / largeTicksCount; double smallTicksDistance = largeTicksDistance / (smallTicksCount + 1); // Calculate number of pixel between small ticks float smallTicksPixels = (float)(W / scaleRange * smallTicksDistance); #endregion Can be moved outside OnPaint // Calculate first large tick value and position double tickValue = Math.Floor((curValue - scaleRange / 2) / largeTicksDistance) * largeTicksDistance; float tickPosition = (float)Math.Floor(Wm - W / scaleRange * (curValue - tickValue)); // Create drawing resources Pen pen = new Pen(ForeColor); Brush brush = new SolidBrush(ForeColor); // For all large ticks for (int L = 0; L <= largeTicksCount; L++) { // Draw large tick e.Graphics.DrawLine(pen, tickPosition - 0, 0, tickPosition - 0, 15); e.Graphics.DrawLine(pen, tickPosition - 1, 0, tickPosition - 1, 15); // Draw large tick numerical value StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; e.Graphics.DrawString(Math.Round(tickValue, 2).ToString(), Font, brush, new PointF(tickPosition, Hm), sf); // For all small ticks for (int S = 1; S <= smallTicksCount; S++) { // Update tick value and position tickValue += smallTicksDistance; tickPosition += smallTicksPixels; // Draw small tick e.Graphics.DrawLine(pen, tickPosition, 0, tickPosition, 10); } // Update tick value and position tickValue += smallTicksDistance; tickPosition += smallTicksPixels; } // Dispose drawing resources brush.Dispose(); pen.Dispose(); if (ShadowEnabled) { LinearGradientBrush LGBrush = null; // Draw left side shadow LGBrush = new LinearGradientBrush(new Rectangle(0, 0, Wm, H), Color.FromArgb(255, ShadowColor), Color.FromArgb(0, BackColor), 0, true); e.Graphics.FillRectangle(LGBrush, new Rectangle(0, 0, Wm, H)); // Draw right side shadow LGBrush = new LinearGradientBrush(new Rectangle(Wm + 1, 0, Wm, H), Color.FromArgb(255, ShadowColor), Color.FromArgb(0, BackColor), 180, true); e.Graphics.FillRectangle(LGBrush, new Rectangle(Wm + 1, 0, Wm, H)); LGBrush.Dispose(); } // Draw scale needle e.Graphics.DrawLine(new Pen(NeedleColor), Wm - 0, 0, Wm - 0, H); e.Graphics.DrawLine(new Pen(NeedleColor), Wm - 1, 0, Wm - 1, H); }

使用控件

这个控件有一组良好的默认属性值,因此一旦包含在解决方案中,就可以简单地从工具调色板中选择,拖放到表单中,并立即使用。否则,只有少数其他列出的属性需要配置。只需要一行代码就可以让它工作:

slidingScale1.Value = your value here!

包含的归档文件包含组件的完整源代码和编译的二进制文件,以及一个简单的测试应用程序。

可能的改进

有很多方法可以改进这个控件。这里有一些想法,如果有人想这样做:

  • 由于LinearGradientBrush的阴影,滑尺已经有了三维感觉,看起来已经像一个真正的仪器。个人缺少一些灵活性,以便在刻度面上绘制数字,并自定义刻度的长度。
  • 为了设置仪器,使其表现得像一个真正的仪器,必须关注两个重要领域:
    • 刻度应该是有限的和/或圆形的。
    • 一个真正的刻度不是一个无尽的带子,它有一个真正的大小。
    • 限制刻度不是一个难题。可以通过添加两个新属性MinValue和MaxValue,并通过控制现有Value属性的变化来实现。只有定义范围内的值才能被接受。
    • 圆形刻度不是那么简单就能实现的。为此,需要几个新属性和大量的计算。
  • 刻度不应该对值变化做出迅速反应。
  • 一个真正的刻度有一个自惯性矩,不能在短时间内从一端跳到另一端。值变化必须实现,使得刻度本身移动,并从小步骤平滑地从旧位置滑动/旋转到新位置。它应该立即开始从当前位置滑动/旋转,并且在一定时间后到达最终位置。
  • 这种行为可以通过首先设置一个新值作为当前值应该变化时的期望值,并启用一个计时器,该计时器以小步骤递增(递减)当前值,直到它到达期望值来实现。
  • 简单地说,应该制作一个动画滑尺。

这些是一些其他期望的特性:

  • 垂直刻度表示。
  • 带有标记的公差限制(OTL, UTL, ...)的刻度。
  • 不同颜色区域的刻度。
  • 这里展示的滑尺,在测量技术方面,是一个“指示器”。可以使其成为一个“控制器”。因此,应该覆盖OnMouseDown和OnMouseMove方法来处理鼠标事件,并实现一个ChangeValue方法来通知值变化。

这是控件的初步版本,还有许多特性需要实现。会尽快覆盖这些。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485