Zeichnen Sie ein einzelnes Pixel in Windows Forms

92

Ich versuche nicht, ein einzelnes Pixel in einem Windows Form einzuschalten.

graphics.DrawLine(Pens.Black, 50, 50, 51, 50); // draws two pixels

graphics.DrawLine(Pens.Black, 50, 50, 50, 50); // draws no pixels

Die API sollte wirklich eine Methode haben, um die Farbe eines Pixels festzulegen, aber ich sehe keine.

Ich benutze C #.

Mark T.
quelle
Ich habe ein Steuerelement erstellt, das einige sehr schöne wissenschaftliche Grafiken darstellt (mit zusätzlichen Funktionen, die ich für keine kommerziellen Steuerelemente benötige). Ich kann einen Datenpunkt mit und X oder einem + oder einem kleinen Kästchen zeichnen. Aber für unwichtige Daten möchte ich nur ein einziges Pixel.
Mark T
Alle Antworten, die ich sehe, scheinen für ein einzelnes Pixel wirklich übertrieben zu sein? Warum scheint es einfacher zu sein, nur einen Puffer [y * width + x] = color zu erstellen?
NoMoreZealots

Antworten:

113

Dadurch wird ein einzelnes Pixel festgelegt:

e.Graphics.FillRectangle(aBrush, x, y, 1, 1);
Henk Holterman
quelle
18
Wer hätte gedacht, dass DrawRectangle eine 2x2 zeichnet, FillRectange jedoch eine 1x1 mit denselben Argumenten? Vielen Dank.
Mark T
9
@Mark: Es macht irgendwie Sinn ... DrawRectangle sagt "zeichne einen Umriss beginnend bei x und y dieser Breite und Höhe", also zeichnet es sowohl den Start- als auch den Endpunkt (x, y; x + 1, y) ; x, y + 1; x + 1, y + 1) und Linien zwischen ihnen. FillRectangle sagt: "Zeichnen Sie eine feste Oberfläche ab x, y dieser Breite und Höhe." FillRectangle nimmt übrigens einen Pinsel, keinen Stift.
Powerlord
5
@R. Bemrose: Eigentlich hängt es von dem Stiftobjekt ab, an das Sie übergeben DrawRectangle(). Wenn dies der Fall ist Pen.Alignment = PenAlignment.Outset, werden Pen.Widthpixeldicke Umrisse um das angegebene Rechteck gezogen. Wenn Sie jedoch angeben Pen.Alignment = PenAlignment.Inset, wird Pen.Width Pixel dicke "Kontur" innerhalb des angegebenen Rechtecks ​​gezeichnet.
Cipi
2
Dies ist eine sehr unbefriedigende Antwort. Obwohl dies ein einzelnes Pixel setzt, besteht die Anforderung nicht immer darin, ein wörtliches Pixel zu setzen. Immer wenn ich das brauchte, was oft der Fall ist, musste der Punkt mit demselben Stift gezeichnet werden, mit dem Linien gezeichnet werden, nicht mit einem Pinsel. Mit anderen Worten, wir brauchen eine Linie, die kürzer als 2 Pixel ist. Ich vermute, dass das OP genau das brauchte.
RobertT
6
Diese Antwort gefällt mir nicht. Dieser Weg ist sehr ineffizient.
user626528
18

Das GraphicsObjekt hat dies nicht, da es eine Abstraktion ist und verwendet werden kann, um ein Vektorgrafikformat abzudecken. In diesem Zusammenhang wäre es nicht sinnvoll, ein einzelnes Pixel festzulegen. Das BitmapBildformat hat GetPixel()und SetPixel(), aber kein Grafikobjekt, das darauf aufgebaut ist. Für Ihr Szenario scheint Ihre Option wirklich die einzige zu sein, da es keine einheitliche Möglichkeit gibt, ein einzelnes Pixel für ein allgemeines Grafikobjekt festzulegen (und Sie wissen nicht genau, was es ist, als Ihr Steuerelement / Formular könnte doppelt gepuffert sein usw.)

Warum müssen Sie ein einzelnes Pixel einstellen?

Adam Robinson
quelle
18

Nur um den vollständigen Code für die Antwort von Henk Holterman anzuzeigen:

Brush aBrush = (Brush)Brushes.Black;
Graphics g = this.CreateGraphics();

g.FillRectangle(aBrush, x, y, 1, 1);
WoodyDRN
quelle
9

Wenn ich viele einzelne Pixel zeichne (für verschiedene benutzerdefinierte Datenanzeigen), neige ich dazu, sie auf eine Bitmap zu zeichnen und diese dann auf den Bildschirm zu bringen.

Die Bitmap-Operationen GetPixel und SetPixel sind nicht besonders schnell, da sie sehr viele Grenzprüfungen durchführen. Es ist jedoch recht einfach, eine 'schnelle Bitmap'-Klasse zu erstellen, die schnellen Zugriff auf eine Bitmap hat.

Will Dean
quelle
2

MSDN-Seite auf GetHdc

Ich denke, das ist es, wonach Sie suchen. Sie müssen den HDC herunterladen und dann die GDI-Aufrufe verwenden, um SetPixel zu verwenden. Beachten Sie, dass ein COLORREF in GDI ein DWORD ist, in dem eine BGR-Farbe gespeichert ist. Es gibt keinen Alphakanal und es ist nicht RGB wie die Farbstruktur von GDI +.

Dies ist ein kleiner Codeabschnitt, den ich geschrieben habe, um dieselbe Aufgabe auszuführen:

public class GDI
{
    [System.Runtime.InteropServices.DllImport("gdi32.dll")]
    internal static extern bool SetPixel(IntPtr hdc, int X, int Y, uint crColor);
}

{
    ...
    private void OnPanel_Paint(object sender, PaintEventArgs e)
    {
        int renderWidth = GetRenderWidth();
        int renderHeight = GetRenderHeight();
        IntPtr hdc = e.Graphics.GetHdc();

        for (int y = 0; y < renderHeight; y++)
        {
            for (int x = 0; x < renderWidth; x++)
            {
                Color pixelColor = GetPixelColor(x, y);

                // NOTE: GDI colors are BGR, not ARGB.
                uint colorRef = (uint)((pixelColor.B << 16) | (pixelColor.G << 8) | (pixelColor.R));
                GDI.SetPixel(hdc, x, y, colorRef);
            }
        }

        e.Graphics.ReleaseHdc(hdc);
    }
    ...
}
Noch
quelle
1

Anscheinend zeichnet DrawLine eine Linie, die ein Pixel unter der tatsächlich angegebenen Länge liegt. Es scheint kein DrawPoint / DrawPixel / so weiter zu geben, aber stattdessen können Sie DrawRectangle mit einer Breite und Höhe von 1 verwenden, um ein einzelnes Pixel zu zeichnen.

Rytmis
quelle
2
Netter Versuch, aber mit Größe 1 zeichnet es 2x2 Pixel. (Zeichnen Sie es neben eine Linie, und Sie können sehen, dass es doppelt so breit ist.) Und mit der Größe Null zeichnet es natürlich nichts.
Mark T
Richtig, mein Fehler. :) Gut, dass FillRectangle den Trick macht.
Rytmis
0

Zeichnen einer Linie 2px mit einem Stift mit DashStyle.DashStyle.Dot zeichnet ein einzelnes Pixel.

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        using (Pen p = new Pen(Brushes.Black))
        {
            p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
            e.Graphics.DrawLine(p, 10, 10, 11, 10);
        }
    }
Eddy
quelle