1

我正在尝试以 C# 形式可视化我拥有的一些数据。我一直在考虑几种方法可以做到这一点,但无法弄清楚 C# 中最好的方法是什么。

首先,让我展示一个我在油漆中制作的示例。

例子
(来源:interstyles.nl

我认为我可以做到的一些方法:

  1. 绘制一张包含所有数据的巨大图片,然后在表单中滚动图片。这不是很好,因为数据可能变得非常广泛。通常我希望有大约 36000 像素宽的数据,所以这将是一个相当大的画面!所以它很容易编程,但会占用大量内存。

  2. 与一个相同,但每行只有 1 个像素高的数据有一张单独的图片,当我在屏幕上显示它时展开它。更难编程,但节省大量内存。还可以更轻松地对数据进行排序和打开/关闭行。简而言之,屏幕由几张相互叠加的图片组成。

  3. 根据滚动条的位置,仅绘制窗体大小的图片中的可见数据。更难编程,我想知道这是否足够快?

  4. c# 中也有绘图功能,但我找不到如何制作这样的东西。

  5. 其他一些我还不知道的图书馆。

我还希望当我将鼠标指针悬停在某个特定事件上时,我是否可以获得有关它的信息,这在选项 1、2 和 3 中会很困难.. 或者至少需要相当多的编程工作..

请提出建议

4

2 回答 2

0

我讨厌的一件事是对我撒谎的滚动条。所以我同意 Siantr 的观点:选择选项 1,创建完整尺寸,在真正遇到问题之前不要尝试优化。

关于 SO 最常被引用的评论可能是Knuth 的过早优化是万恶之源

特别是选项 2 听起来像是错误的方法:内部图像位图仍然具有完整大小,即使您从小块创建它,所以这里什么都没有,更有可能丢失。

您可能想选择 PixelFormat 之类的Format16bppRgb555Format16bppRgb565节省一些内存;但我不确定这是否真的会对记忆产生影响。写入文件时肯定会,但 Winforms 内部有神秘的方式..

要显示事件详细信息,假设您有一个工具提示控件toolTip1,您可以像这样简单地使用光标坐标:

private void pictureBox1_MouseHover(object sender, EventArgs e)
{
  Point p = pictureBox1.PointToClient(Cursor.Position);
  string msg = String.Format("row {0}  column {1}", p.Y , p.X );
  toolTip1.SetToolTip(pictureBox1, msg);
}

PointToClient()方法足够友好,可以为您计算滚动位置。

当然,您必须将坐标映射到您的事件..首先要获得滚动条,您将不得不使用这个老技巧..

于 2014-05-21T07:42:33.997 回答
0

绘制所有可见点(您提到根据滚动条值和宽度获取视口不是问题)。您不需要进行太多优化,只需找到minTimemaxTime然后继续所有点。我怀疑它是否真的需要,因为尝试绘制不可见的像素不会绘制任何内容,并且无论如何通过数组非常快,绘制几个像素将花费更多。

确保您启用了双缓冲:

[System.ComponentModel.DesignerCategory("Code")]
public class MyGraph : PictureBox
{
    public MyGraph()
    {
        SetStyle(ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
    }
    ...
}

如果您确实需要优化某些东西(例如,如果您在用户移动鼠标时绘制一些信息数据),那么您可以使用缓存来绘制位图,然后只需使用 bitblt ( DrawImage) 位图。请参阅此答案或从 bitmap搜索图形。当缓存数据变得无效(滚动、调整大小等)时,您将不得不处理这种情况。

另一种可能性是优化更新(例如,如果您绘制的数据定期更新)。为此,您将需要提供一种方法MyGraph来通知基础数据中发生了什么变化,以决定缓存何时变得无效或通过将更改直接绘制到缓存位图来更新缓存位图。

另一个,真正的开销,但优化:您可以将数据保存在尽可能接近位图的地方。这样,绘图功能MyGraph将简单地绘制位图(速度很快并且将支持客户端视口)。这种方式更新实际上就像更改像素并调用Invalidate().

于 2014-05-19T13:06:29.297 回答