Disegna un singolo pixel su Windows Form


92

Sono bloccato nel tentativo di attivare un singolo pixel su un Windows Form.

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

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

L'API dovrebbe davvero avere un metodo per impostare il colore di un pixel, ma non ne vedo uno.

Sto usando C #.


Ho creato un controllo che traccia alcuni grafici scientifici molto belli (con funzionalità aggiuntive che non sono disponibili in nessun controllo commerciale). Posso tracciare un punto dati con e X o un + o una piccola casella. Ma per dati non importanti, voglio solo un singolo pixel.
Mark T

Tutte le risposte che vedo sembrano davvero eccessive per un singolo pixel? Perché sembra più semplice fare un buffer [y * larghezza + x] = colore;
NoMoreZealots

Risposte:


113

Questo imposterà un singolo pixel:

e.Graphics.FillRectangle(aBrush, x, y, 1, 1);

18
Chi avrebbe mai immaginato che DrawRectangle disegna un 2x2 ma FillRectange disegna un 1x1 con gli stessi argomenti? Grazie.
Mark T

9
@Mark: ha una sorta di senso ... DrawRectangle dice "disegna un contorno a partire da xey di questa larghezza e altezza", quindi disegna sia il punto iniziale che quello finale (x, y; x + 1, y ; x, y + 1; x + 1, y + 1) e le linee tra di loro. FillRectangle dice "disegna una superficie solida a partire da x, y di questa larghezza e altezza". Per inciso, FillRectangle accetta un pennello, non una penna.
Powerlord

5
@R. Bemrose: In realtà, dipende dall'oggetto Penna a cui passi DrawRectangle(). In caso affermativo Pen.Alignment = PenAlignment.Outset, disegnerà un Pen.Widthcontorno spesso di pixel attorno al rettangolo specificato. Ma se lo specifichi Pen.Alignment = PenAlignment.Insetdisegnerà un "contorno" spesso di pixel Pen.Width all'interno del rettangolo specificato.
Cipi

2
Questa è una risposta molto insoddisfacente. Sebbene questo imposti un singolo pixel, il requisito non è sempre quello di impostare un pixel letterale. Tutte le volte che ne ho avuto bisogno, il che è spesso, ho avuto bisogno che il punto fosse disegnato dalla stessa penna con cui sono disegnate le linee, non da un pennello. In altre parole, abbiamo bisogno di una linea più corta di 2 pixel. Sospetto che fosse ciò di cui aveva bisogno l'OP.
RobertT

6
Non mi piace questa risposta. In questo modo è altamente inefficiente.
user626528

18

L' Graphicsoggetto non ha questo, poiché è un'astrazione e potrebbe essere utilizzato per coprire un formato di grafica vettoriale. In quel contesto, impostare un singolo pixel non avrebbe senso. Il Bitmapformato dell'immagine ha GetPixel()e SetPixel(), ma non un oggetto grafico costruito su uno. Per il tuo scenario, la tua opzione sembra davvero l'unica perché non esiste un modo valido per tutti per impostare un singolo pixel per un oggetto grafico generale (e non sai ESATTAMENTE cosa sia, come il tuo controllo / modulo potrebbe essere a doppio buffer, ecc.)

Perché è necessario impostare un singolo pixel?


18

Solo per mostrare il codice completo per la risposta di Henk Holterman:

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

g.FillRectangle(aBrush, x, y, 1, 1);

9

Laddove disegno molti pixel singoli (per vari display di dati personalizzati), tendo a disegnarli su una bitmap e poi a trasferirla sullo schermo.

Le operazioni Bitmap GetPixel e SetPixel non sono particolarmente veloci perché eseguono un enorme controllo dei limiti, ma è abbastanza facile creare una classe 'bitmap veloce' che abbia accesso rapido a una bitmap.


2

Pagina MSDN su GetHdc

Penso che questo sia quello che stai cercando. Sarà necessario ottenere l'HDC e quindi utilizzare le chiamate GDI per utilizzare SetPixel. Notare che un COLORREF in GDI è un DWORD che memorizza un colore BGR. Non esiste un canale alfa e non è RGB come la struttura Color di GDI +.

Questa è una piccola sezione di codice che ho scritto per svolgere la stessa operazione:

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

1

Apparentemente DrawLine disegna una linea che è un pixel più corto della lunghezza effettiva specificata. Non sembra esserci un DrawPoint / DrawPixel / whatnot, ma invece puoi usare DrawRectangle con larghezza e altezza impostate su 1 per disegnare un singolo pixel.


2
Bel tentativo, ma con la dimensione 1 disegna 2x2 pixel. (Disegnalo vicino a una linea e puoi vedere che è largo il doppio.) E con la dimensione zero, ovviamente, non disegna nulla.
Mark T

Giusto, errore mio. :) Meno male che FillRectangle fa il trucco.
Rytmis

0

Disegnare una linea 2px usando una penna con DashStyle.DashStyle.Dot disegna un singolo 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);
        }
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.