5

我经常使用 Visual Studio 2008、.NET C# 2.0-3.5 和 Windows 窗体,我注意到,像我之前的许多人一样,GDI+ 在绘制控件方面非常慢。请注意,我不太会处理图像(JPG、GIF 等)。图像仅在某些地方作为图标。这实际上是绘制缓慢的控件/表单/等。

问题是您可以看到正在绘制的控件,并且可能需要几秒钟才能绘制一组看似简单的控件。即,它的滞后和可怕。

我已经进行了测试,我只是在表单上放置了一些标签(40-50),按 F5 运行并且必须等待它们被绘制。再次,滞后,不是一个很好的体验。

所以,有 WPF 可以解决这个问题,但我/我们还没有准备好迁移到 WPF。所以我四处寻找解决方法或修复程序,我偶然发现了 Direct2D,并且在阅读其他一些库时。

让我有点困惑,因此有这些问题:

1) 首先,我想要的是一种相当简洁的方法,只需用更快和硬件加速的方法替换GDI+。是否可以在不使用 WPF 且无需重写所有 Windows 窗体代码的情况下做到这一点?

每当我在 Direct2D 上阅读任何内容时,我都会看到一长串通常很糟糕的 C++ 代码,告诉我如何手动编写代码以进行绘图。我不要那个。

2) 在网上阅读时,我偶然发现了 SlimDX,但我不知道如何使用它(我承认,我在写作时没有尝试过很多)。假设我已经有一个 GUI 应用程序(Windows 窗体,标准 C# 代码)——我可以以某种方式使用 SlimDX(或类似的东西)来“替换”GDI+ 而无需过多重写吗?

我的问题是我找不到任何示例或类似的东西来告诉我是否可以在我已经创建的 Windows 窗体软件中使用 SlimDX、Direct2D 或其他类似的东西,如果可以的话 - 怎么做。

希望我不要太模糊=)

==编辑== 2010-09-22

我已经在我的真实应用程序中进行了一些测试,并将其中一件缓慢的事情隔离出来:

当我将文本添加到用户控件中的某些标签时,控件会自行调整大小以适应文本。例如,包含 GroupControl 会稍微适应刚刚添加到 Labels 的 .Text-property 的文本的大小。

大约有 10 个标签控件。第一次更新标签并因此更改大小时,整个过程大约需要 500 毫秒。第二次更新标签,大小没有变化,大约需要0毫秒。

==编辑 2== 2010-09-22

发现其中一个减速。然后将字符串添加到 Text-property 如果正在添加的文本的字符串长度与更新前的文本不同,则会很慢。

我正在使用 DevExpress 库,并且可以将 LabelControls 设置为 AutoSizeMode。如果我将其设置为“无”,那么当添加长度与前一个文本不同的文本时,延迟就会消失。我猜这个问题对于普通的标签控件来说是一样的,因为它也有一个 AutoSize = true/false 设置。

然而,它是一种“解决方法”,但仍然证明了我的观点——调整大小时它真的很慢,这很蹩脚。

4

5 回答 5

3

上面的许多海报都有很好的观点。我自己在 GDI+ 中创建了一个 3D CAD 应用程序,并且发现如果正确实施它足够快。然而,使用控件立即让我觉得这是一种非常尴尬的做事方式。控件是一个相当大的对象,在这种情况下有很多理由要自己制作。

我建议你研究一个保留模式绘图系统。它很容易实施,并且在大多数情况下可以涵盖您的情况。您必须自己创建绘图逻辑,但这很有趣,并且会给您更多的灵活性:)

于 2012-03-18T13:58:24.897 回答
1

关于你的第一个问题,我不得不使用 GDI 来做一些在 GDI+ 下需要很长时间的图像处理工作。这是 4 到 5 年前的事了,使用托管 C# 与 GDI 一起工作是一件痛苦的事——不知道它现在发生了多大的变化。有许多好的和快速的函数,例如 BitBlt,它们的绘制速度非常快,但是您需要非常小心地释放资源(句柄)和内存。我还有另一个问题,就是将结果保存为 JPEG,它在 GDI 中不存在,所以我不得不使用 CxImage 读取 HBitmap 然后保存它。

总而言之,GDI 非常快速和强大。如果 DirectX 中有更好的抽象,可能你最好使用它们。

于 2010-09-17T12:24:24.307 回答
1

我正在研究一些相同的问题。我正在编写一个需要能够非常有效地渲染 2d 图形的应用程序,因为某些用户可以同时打开 10-50 个窗口。需要考虑的一件事是,这里没有其他人谈论过,direct2d 只能在带有 Service Pack 2 及更高版本的 Vista 计算机上使用。另外,根据此链接:

http://www.tomshardware.com/news/msft-windows-xp-windows-7-market-share-win7,13876.html

截至 2011 年 11 月,所有 Windows 用户中有 38.5% 仍在使用 XP。因此,如果将应用程序出售给仍在运行 XP 的大量用户是一个问题(或者您的市场基础是主要使用 XP 的第三世界国家),那么你应该选择:

  1. Direct2d 用于较新的操作系统,GDI+ 用于 XP 系统。

  2. XNA - 与 XP 兼容,也可用于较新的操作系统。请参阅此链接:http: //msdn.microsoft.com/en-us/library/bb203925.aspx

  3. SlimDX - 在第一个答案中提到。支持 XP 以及更新的操作系统。请参阅: http ://slimdx.org/ 和 http://slimdx.org/features.php

  4. 如果您关心 Windows、Linux、Max 等之间的兼容性,请使用 OpenTK。

您还应该知道,GDI+ 存在一个错误,导致它在最初发布时性能非常差。请参阅以下链接,为什么一些开发人员声称微软为使用 GDI+ 的应用程序破坏了 Windows7 的 gui:

http://www.windows7taskforce.com/view/3607

或使用以下字符串从您最喜欢的搜索引擎进行网络搜索:“gdi+ bug slow on windows 7”。

于 2012-02-17T01:27:49.800 回答
0

您可以尝试托管 directx,但他们不再支持它(移至 XNA)。老实说,除非你有一台糟糕的电脑或大量的控件,否则我不知道为什么它会滞后这么糟糕。如果您在主线程上执行一些 CPU 密集型工作,请将其移至单独的线程。这是我能想到的导致这种滞后的唯一其他原因。

于 2010-09-17T18:32:43.707 回答
0

我们在 C# 应用程序中使用 SlimDX....但我们实际上是在做 3D。我们编写了自己的 2D 库来进行简单的 2D 绘图。SlimDX 只是 DirectX 的轻量级包装器。因此,您将了解 DirectX 的所有优点和缺点。像这样,如果它不存在,模拟视频卡是你的问题。

如果您想要绘制到屏幕外位图的东西,我会选择 WPF,因为它与 C# 很好地集成,主要适用于任何地方,并且在有可用硬件时加速。您可以将输出复制到位图并在常规 GDI/Winforms 中使用。但是如果你做相当复杂的事情(大量的过滤器,混合纹理等......),它只会比 GDI+ 更快。

编辑:

为了回应评论,我建立了一个小样本表格。第一次切换时有几秒钟的等待时间,但之后它会响应。比我预期的要慢,但无论如何都可以使用。如果这是关于他在应用程序中看到的性能,希望 Ted 发表评论。

public class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        // *** EDIT ***
        this.tabPage1.SuspendLayout();
        this.tabPage2.SuspendLayout();
        this.tabControl1.SuspendLayout();
        this.SuspendLayout();

        FillTab(tabPage1, Color.White);
        FillTab(tabPage2, Color.Yellow);

        // *** EDIT ***
        this.tabPage1.ResumeLayout(false);
        this.tabPage2.ResumeLayout(false);
        this.tabControl1.ResumeLayout(false);
        this.ResumeLayout(false);
    }

    private static void FillTab(TabPage tabPage, Color color)
    {
        for (int i = 0; i < 200; ++ i)
        {
            int left = (i % 5) * 320;
            int topOffset = (i / 5) * 23;
            tabPage.Controls.Add(new Label { Left = left, Top = topOffset, Width = 100, Text = "Label" });
            tabPage.Controls.Add(new TextBox() { BackColor = color, Left = left + 100, Top = topOffset, Width = 100, Text = tabPage.Text });
            tabPage.Controls.Add(new ComboBox { BackColor = color, Left = left + 200, Top = topOffset, Width = 100 });
        }

    }

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.tabControl1 = new System.Windows.Forms.TabControl();
        this.tabPage1 = new System.Windows.Forms.TabPage();
        this.tabPage2 = new System.Windows.Forms.TabPage();
        this.tabControl1.SuspendLayout();
        this.SuspendLayout();
        // 
        // tabControl1
        // 
        this.tabControl1.Controls.Add(this.tabPage1);
        this.tabControl1.Controls.Add(this.tabPage2);
        this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
        this.tabControl1.Location = new System.Drawing.Point(0, 0);
        this.tabControl1.Name = "tabControl1";
        this.tabControl1.SelectedIndex = 0;
        this.tabControl1.Size = new System.Drawing.Size(292, 266);
        this.tabControl1.TabIndex = 0;
        // 
        // tabPage1
        // 
        this.tabPage1.Location = new System.Drawing.Point(4, 22);
        this.tabPage1.Name = "tabPage1";
        this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
        this.tabPage1.Size = new System.Drawing.Size(284, 240);
        this.tabPage1.TabIndex = 0;
        this.tabPage1.Text = "tabPage1";
        this.tabPage1.UseVisualStyleBackColor = true;
        // 
        // tabPage2
        // 
        this.tabPage2.Location = new System.Drawing.Point(4, 22);
        this.tabPage2.Name = "tabPage2";
        this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
        this.tabPage2.Size = new System.Drawing.Size(245, 217);
        this.tabPage2.TabIndex = 1;
        this.tabPage2.Text = "tabPage2";
        this.tabPage2.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(292, 266);
        this.Controls.Add(this.tabControl1);
        this.Name = "Form1";
        this.Text = "Form1";
        this.tabControl1.ResumeLayout(false);
        this.ResumeLayout(false);

    }

    #endregion

    private System.Windows.Forms.TabControl tabControl1;
    private System.Windows.Forms.TabPage tabPage1;
    private System.Windows.Forms.TabPage tabPage2;
}
于 2010-09-17T12:35:02.113 回答