Direct2D / GDI + и медленное рисование форм Windows - что можно сделать? - PullRequest
4 голосов
/ 17 сентября 2010

Я много работаю с Visual Studio 2008, .NET C # 2.0-3.5 и Windows Forms, и я заметил, как и многие другие до меня, что GDI + чрезвычайно медленно рисует элементы управления. Обратите внимание , что я не очень много работаю с изображениями (JPG, GIF и т. Д.). Изображения только в виде значков в определенных местах. На самом деле это элементы управления / формы / и т. Д., Которые медленно рисуются.

Проблема в том, что вы можете видеть нарисованные элементы управления, и может потребоваться несколько секунд, чтобы нарисовать, казалось бы, простой набор элементов управления. То есть это отстает и ужасно.

Я провел тесты, в которых я просто наложил несколько меток (40-50) на форму, нажимая F5 для запуска и должен ждать, пока они будут нарисованы. Опять же, лаг и не очень приятный опыт.

Итак, есть WPF, который может решить эту проблему, но я / мы не готовы перейти на WPF. Поэтому я искал обходные пути или исправления, и я наткнулся на Direct2D и читал некоторые другие библиотеки.

Я немного озадачен, и вот такие вопросы:

1) Во-первых, я хочу довольно аккуратный и простой способ просто заменить GDI + на что-то более быстрое и аппаратно ускоренное. Можно ли сделать это, не переходя в WPF и не переписывая весь мой код Windows Forms?

Всякий раз, когда я читаю что-либо в Direct2D, я вижу длинные блоки, как правило, ужасного кода C ++, рассказывающие о том, как вручную писать код для рисования. Я этого не хочу.

2) Читая в сети, я наткнулся на SlimDX, но я не могу понять, как его использовать (и я признаю, что я не очень старался писать). Допустим, у меня уже есть GUI-приложение (Windows Forms, стандартный код C #) - могу ли я каким-то образом использовать SlimDX (или что-то в этом роде), чтобы просто «заменить» GDI + без особых переписываний?

Моя проблема в том, что я не могу найти какие-либо примеры или тому подобное, говорящие мне, возможно ли использовать SlimDX, Direct2D или другие подобные вещи в моем уже созданном программном обеспечении Windows Forms, и если это возможно - как это сделать.

Надеюсь, я не слишком пушистый =)

== РЕДАКТИРОВАТЬ == 2010-09-22

Я провел несколько тестов в своем реальном приложении и выделил одну из медленных вещей:

Когда я добавляю текст к некоторым меткам в UserControl, элементы управления изменяют свой размер, чтобы соответствовать тексту. Например, содержащий GroupControl немного адаптируется к размеру текста, который был только что добавлен к свойству .Text меток.

Существует около 10 элементов управления Label. При первом обновлении меток и, соответственно, изменении размеров, весь процесс занимает около 500 мс. Во второй раз, когда метки обновляются, и размер no изменяется, это занимает около 0 мс.

== РЕДАКТИРОВАТЬ 2 == 2010-09-22

Нашел одно из замедлений. Затем добавление строки в свойство Text будет медленным, если добавляемый текст отличается в строке length от текста, который был до обновления.

Я использую библиотеки DevExpress, и LabelControls можно установить в AutoSizeMode. Если я установлю это на «Нет», то отставание исчезнет при добавлении текста, длина которого отличается от предыдущего текста. Я предполагаю, что эта проблема будет такой же для обычного элемента управления Label, поскольку она также имеет параметр AutoSize = true / false.

Тем не менее, это "обходной путь", но все же подтверждает мою точку зрения - он очень медленный при изменении размера, что довольно хромает.

Ответы [ 5 ]

2 голосов
/ 18 марта 2012

Многие из постеров выше идут с хорошими баллами. Я сам создал 3D CAD-приложение в GDI + и нашел его достаточно быстрым, если оно реализовано правильно. Использование Controls, однако, сразу бросается в глаза как очень неловкий способ делать вещи. Элемент управления - довольно большой объект, и в этом случае есть множество причин для создания собственного.

Я бы посоветовал вам взглянуть на систему рисования в сохраненном режиме . Это легко реализовать и в большинстве случаев охватит вашу ситуацию. Вы должны будете создать логику рисования самостоятельно, но это просто весело и даст вам больше гибкости:)

1 голос
/ 17 февраля 2012

Я смотрю на некоторые из тех же проблем.Я пишу приложение, которое должно уметь очень эффективно отображать 2-мерную графику, поскольку у некоторых пользователей одновременно может быть открыто 10-50 окон.Следует учитывать, что никто больше не говорил здесь о том, что direct2d можно использовать только на компьютерах с Vista с пакетом обновления 2 и выше.Кроме того, по этой ссылке:

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

38,5% всех пользователей Windows по-прежнему использовали XP по состоянию на ноябрь 2011 года. Таким образом, при продаже приложения значительному количеству пользователейвсе еще работает XP (или ваша рыночная база относится к странам третьего мира, которые в основном используют XP), тогда вам следует либо:

  1. Direct2d для более новых операционных систем и GDI + для XPsystems.

  2. XNA - который совместим с XP и может также использоваться с более новыми операционными системами.Смотрите эту ссылку: http://msdn.microsoft.com/en-us/library/bb203925.aspx

  3. SlimDX - упоминается в первом ответе.Поддерживает XP, а также новые операционные системы.См .: http://slimdx.org/ и http://slimdx.org/features.php

  4. OpenTK, если вы заботитесь о совместимости между Windows, Linux, Max и т. Д.

Вам следуетТакже имейте в виду, что в GDI + была ошибка, из-за которой он страдал от очень низкой производительности при первоначальном выпуске.Посмотрите следующую ссылку, почему некоторые разработчики утверждают, что Microsoft сломала графический интерфейс для Windows7 для приложений, использующих GDI +:

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

или выполните поиск в сети из вашей любимой поисковой системы с помощью этой строки: "gdi + ошибка медленная на windows 7 ".

1 голос
/ 17 сентября 2010

По вашему первому вопросу, мне пришлось использовать GDI, чтобы сделать некоторые вещи для обработки изображений, которые ушли в прошлое под GDI +. Это было 4-5 лет назад, и работа с GDI с использованием управляемого C # была проблемой - не уверен, насколько она изменилась сейчас. Есть много хороших и быстрых функций, таких как BitBlt, которые очень быстро рисуют, но вы должны быть очень осторожны с высвобождением ресурсов (дескрипторов) и памяти. У меня также была другая проблема - сохранение результата в формате JPEG, которого нет в GDI, поэтому мне пришлось использовать CxImage, чтобы прочитать HBitmap, а затем сохранить его.

В целом, GDI очень быстрый и надежный. Если в DirectX есть лучшие абстракции, возможно, вам лучше их использовать.

0 голосов
/ 17 сентября 2010

Вы можете попробовать управляемый directx, но они больше не поддерживают его (перешли к XNA). Честно говоря, если у вас нет дерьмового компьютера или тонны элементов управления, я не знаю, почему он так сильно отстает. Если вы выполняете какие-то интенсивные процессы в своем основном потоке, перенесите его в отдельный поток. Это единственная другая причина, по которой я могу думать, что это вызвало такое отставание.

0 голосов
/ 17 сентября 2010

Мы используем SlimDX в нашем приложении на C # .... Но на самом деле мы делаем 3D.Мы написали нашу собственную 2D-библиотеку, чтобы иметь возможность делать простые 2D-чертежи.SlimDX - это легкая оболочка для DirectX.Таким образом, вы получите все плюсы и минусы DirectX.Например, ваша проблема - эмулировать видеокарту, если ее нет.

Если вы хотите что-то для рисования в закадровых растровых изображениях, я бы выбрал WPF, поскольку он хорошо интегрирован с C #, работает в основном везде и ускоряется, когда доступно оборудование.Вы можете скопировать вывод в растровое изображение и использовать его в обычных GDI / Winforms.Но это будет быстрее, чем GDI +, если вы делаете довольно сложные вещи (много фильтров, смешивание текстур и т. Д.).

Редактировать:

В ответ на комментарии я построил небольшую примерную форму.При первом переключении есть секундное ожидание, но после этого он отзывчивый.Медленнее, чем я ожидал, но во всех отношениях пригодный для использования.Хотел бы Тед прокомментировать, если речь идет о производительности, которую он видит в своем приложении.

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;
}
...