Direct2D / GDI + und langsame Windows-Formulare zeichnen

  • Ich arbeite viel mit Visual Studio 2008, .NET C # 2.0-3.5 und Windows Forms und habe wie viele vor mir bemerkt, dass GDI + beim Zeichnen von Steuerelementen extrem langsam ist. Beachten Sie , dass ich mit Bildern (JPG, GIF usw.) nicht viel zu tun habe. Bilder sind nur an bestimmten Stellen als Symbole. Dies sind eigentlich Controls / Forms / etc, die langsam gezeichnet werden.

    Das Problem ist, dass Sie Controls sehen können, die gezeichnet werden, und es kann einige Sekunden dauern, bis ein scheinbar einfacher Satz von Controls angezeigt wird gezeichnet werden. Das heißt, es ist zurückhaltend und schrecklich.

    Ich habe Tests durchgeführt, bei denen ich gerade eine Anzahl von Labels (40-50) in ein Formular eingefügt habe. Drücken Sie die Taste F5, um zu laufen, und warten Sie, bis sie gezeichnet werden. Nochmals, lag und keine sehr schöne Erfahrung.

    Es gibt also WPF, das dieses Problem ansprechen könnte, aber ich / wir sind nicht bereit, zu WPF zu wechseln. Also schaue ich mich nach Workarounds oder Fixes um und bin über Direct2D gestolpert, und wenn ich darüber lese, einige andere Bibliotheken.

    Stellen Sie sich ein wenig verwirrt und damit diese Fragen :

    1) Zunächst möchte ich eine recht ordentliche und einfache Möglichkeit, einfach GDI + mit etwas schnellerem und hardwarebeschleunigtem Ansatz. Kann ich das tun, ohne zu WPF zu wechseln und meinen gesamten Windows Forms-Code nicht neu schreiben zu müssen?

    Wann immer ich etwas auf Direct2D lese, sehe ich In langen, normalerweise fürchterlichen C ++ - Blöcken wird erklärt, wie man manuell Code zum Zeichnen schreibt. Ich möchte das nicht.

    2) Beim Lesen im Netz bin ich über SlimDX gestolpert, kann aber nicht herausfinden, wie ich es verwenden soll es (und ich gebe zu, ich habe nicht viel versucht zu schreiben). Nehmen wir an, ich habe bereits eine GUI-Anwendung (Windows Forms, standardmäßiger C # -Code). Kann ich SlimDX (oder etwas ähnliches) verwenden, um GDI + einfach zu "ersetzen", ohne zu viel zu schreiben?

    Mein Problem ist, dass ich keine Beispiele oder ähnliches finden kann, die mir mitteilen, ob SlimDX, Direct2D oder andere ähnliche Geräte verwendet werden können

    16 September 2017
    ToolmakerStevetluck234
5 answers
  • Viele der oben genannten Poster sind mit guten Punkten versehen. Ich habe eine 3D-CAD-Anwendung in GDI + selbst erstellt und fand sie schnell genug, wenn sie richtig implementiert wurde. Die Verwendung von Steuerelementen erscheint mir jedoch sofort als sehr umständliche Vorgehensweise. Ein Control ist ein ziemlich großes Objekt und es gibt zahlreiche Gründe, in diesem Fall ein eigenes zu erstellen.

    Ich würde Ihnen raten, sich ein Zeichnungssystem mit beibehaltenem Modus . Es ist einfach zu implementieren und würde in den meisten Fällen Ihre Situation abdecken. Sie müssen die Zeichnungslogik selbst erstellen, aber das macht einfach Spaß und würde Ihnen mehr Flexibilität geben:)

    06 July 2017
    Christopher Kyle Hortonmike
  • Ich betrachte einige der gleichen Probleme. Ich schreibe eine Anwendung, die in der Lage sein muss, 2D-Grafiken sehr effizient wiederzugeben, da einige Benutzer möglicherweise 10 - 50 Fenster gleichzeitig geöffnet haben. Zu bedenken ist, dass sonst niemand darüber gesprochen hat, dass direct2d nur auf Computern mit Vista mit Service Pack 2 und höher verwendet werden kann. Entsprechend diesem Link:

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

    38,5% aller Windows-Benutzer haben ab November 2011 noch XP verwendet. Wenn Sie also die App an eine beträchtliche Anzahl von Benutzern verkaufen, die noch XP ausführen, ist dies ein Problem (oder Ihre Marktbasis) in Länder der 3. Welt, die hauptsächlich mit XP arbeiten), sollten Sie entweder Folgendes tun:

    1. Direct2d für neuere Betriebssysteme und GDI + für XP-Systeme .

    2. XNA - ist mit XP kompatibel und kann auch mit neueren Betriebssystemen verwendet werden. Siehe diesen Link: http://msdn.microsoft.com/en-us/library /bb203925.aspx

    3. SlimDX - in der ersten Antwort erwähnt. Unterstützt sowohl XP als auch neuere Betriebssysteme. Siehe: http://slimdx.org/ und http://slimdx.org/features.php

    4. OpenTK, wenn Sie sich für die Kompatibilität interessieren Windows, Linux, Max usw.

    Sie sollten auch wissen, dass es einen Fehler mit GDI + gab, durch den es sehr leiden musste schlechte Leistung bei der ersten Veröffentlichung. Lesen Sie den folgenden Link, warum einige Entwickler behaupten, dass Microsoft die GUI für Windows7 für Apps mit GDI + verletzt hat:

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

    oder

    17 February 2012
    Bob Bryan
  • Bei Ihrer ersten Frage musste ich GDI verwenden, um Bildverarbeitungsmaterial zu erstellen, das unter GDI + lange dauerte. Das war vor 4-5 Jahren und die Arbeit mit GDI mit verwaltetem C # war ein Schmerz - nicht sicher, wie sehr sich das jetzt geändert hat. Es gibt viele gute und schnelle Funktionen wie BitBlt, die sehr schnell zeichnen, aber Sie müssen sehr vorsichtig mit dem Freigeben von Ressourcen (Handles) und Speicher sein. Ich hatte auch ein anderes Problem, bei dem das Ergebnis als JPEG gespeichert wurde und in GDI nicht vorhanden ist. Daher musste ich CxImage verwenden, um die HBitmap zu lesen und sie dann zu speichern.

    All Insgesamt ist GDI sehr schnell und robust. Wenn es bessere Abstraktionen in DirectX gibt, ist es wahrscheinlich besser, sie zu verwenden.

    17 September 2010
    Aliostad
  • Wir verwenden SlimDX in unserer C # -App .... Aber wir machen eigentlich 3D. Wir haben unsere eigene 2D-Bibliothek geschrieben, um einfache 2D-Zeichnungen erstellen zu können. SlimDX ist nur ein leichter Wrapper für DirectX. Sie erhalten also alle Vor- und Nachteile von DirectX. So ist es Ihr Problem, die Videokarte zu emulieren, wenn sie nicht vorhanden ist.

    Wenn Sie etwas zum Zeichnen von Bitmaps im Offscreen-Modus benötigen, würde ich WPF verwenden, da es gut in C # integriert ist und meistens überall funktioniert. Sie können die Ausgabe in eine Bitmap kopieren und in regulären GDI / Winforms verwenden. Es wird jedoch nur dann schneller als GDI + sein, wenn Sie ziemlich komplexe Aufgaben erledigen (viele Filter, Texturen mischen usw.).

    Bearbeiten:

    Als Antwort auf die Kommentare habe ich ein kleines Beispielformular erstellt. Beim ersten Wechsel wird eine Sekunde gewartet, danach reagiert es. Langsamer als ich erwartet hätte, aber durchaus brauchbar. Möchte Ted etwas dazu sagen, wenn es um die Leistung geht, die er in seiner App sieht.

     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;
    }
     
    16 September 2017
    ToolmakerStevetluck234
  • Man könnte Managed DirectX ausprobieren, aber sie unterstützen es nicht mehr (weiter zu XNA). Ehrlich gesagt, wenn Sie nicht über einen beschissenen Computer oder eine Menge Steuerelemente verfügen, weiß ich nicht, warum es so schlimm ist. Wenn Sie in Ihrem Haupt-Thread ein paar CPU-intensive Sachen machen, verschieben Sie ihn in einen separaten Thread. Das ist der einzige andere Grund, aus dem ich mir vorstellen kann, dass diese Verzögerung entsteht.

    17 September 2010
    Phil Winkel