Narysuj pojedynczy piksel w Windows Forms

93

Utknąłem, próbując włączyć pojedynczy piksel w formularzu systemu Windows.

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

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

API naprawdę powinno mieć metodę ustawiania koloru jednego piksela, ale jej nie widzę.

Używam C #.

Mark T.
źródło
Zrobiłem kontrolę, która wykreśla kilka bardzo ładnych wykresów naukowych (z dodatkowymi możliwościami, których nie potrzebuję w żadnych komercyjnych kontrolkach). Mogę wykreślić punkt danych za pomocą i X lub + lub małego pola. Ale dla nieistotnych danych potrzebuję tylko jednego piksela.
Mark T
Wszystkie odpowiedzi, które widzę, wydają się być przesadą dla pojedynczego piksela? Dlaczego po prostu zrobienie bufora [y * szerokość + x] = kolor wydaje się łatwiejsze;
NoMoreZealots

Odpowiedzi:

114

Spowoduje to ustawienie pojedynczego piksela:

e.Graphics.FillRectangle(aBrush, x, y, 1, 1);
Henk Holterman
źródło
18
Kto by pomyślał, że DrawRectangle rysuje 2x2, ale FillRectange rysuje 1x1 z tymi samymi argumentami? Dzięki.
Mark T
9
@Mark: To ma jakiś sens ... DrawRectangle mówi „narysuj kontur zaczynający się od x i y tej szerokości i wysokości”, więc rysuje zarówno punkt początkowy, jak i końcowy (x, y; x + 1, y ; x, y + 1; x + 1, y + 1) i linie między nimi. FillRectangle mówi „narysuj solidną powierzchnię zaczynając od x, y tej szerokości i wysokości”. Nawiasem mówiąc, FillRectangle pobiera pędzel, a nie pióro.
Powerlord
5
@R. Bemrose: Właściwie to zależy od obiektu Pen, do którego przechodzisz DrawRectangle(). Jeśli tak, Pen.Alignment = PenAlignment.Outsetto narysuje Pen.Widthobrys o grubości pikseli wokół danego prostokąta. Ale jeśli to określisz Pen.Alignment = PenAlignment.Inset, narysuje "kontur" o grubości Pen.Width pikseli wewnątrz danego prostokąta.
Cipi,
2
To bardzo niezadowalająca odpowiedź. Chociaż powoduje to ustawienie pojedynczego piksela, nie zawsze jest wymagane ustawienie dosłownego piksela. Zawsze tego potrzebowałem, a często potrzebowałem, aby kropka była rysowana tym samym pisakiem, którym rysuje się linie, a nie pędzlem. Innymi słowy, potrzebujemy linii krótszej niż 2 piksele. Podejrzewam, że tego właśnie potrzebował OP.
RobertT
6
Nie podoba mi się ta odpowiedź. Ten sposób jest wysoce nieefektywny.
user626528
19

Aby pokazać pełny kod odpowiedzi Henka Holtermana:

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

g.FillRectangle(aBrush, x, y, 1, 1);
WoodyDRN
źródło
18

GraphicsObiekt nie posiada tego, ponieważ jest abstrakcją i mogą być wykorzystane do pokrycia format grafiki wektorowej. W tym kontekście ustawienie pojedynczego piksela nie miałoby sensu. BitmapFormat obrazu ma GetPixel()a SetPixel(), ale nie jest to obiekt graficzny zbudowany na jednym. W twoim scenariuszu twoja opcja naprawdę wydaje się jedyną, ponieważ nie ma jednego uniwersalnego sposobu na ustawienie pojedynczego piksela dla ogólnego obiektu graficznego (i nie wiesz DOKŁADNIE, co to jest, ponieważ twoja kontrolka / forma może być podwójnie buforowany itp.)

Dlaczego musisz ustawić pojedynczy piksel?

Adam Robinson
źródło
9

Kiedy rysuję wiele pojedynczych pikseli (dla różnych niestandardowych wyświetlania danych), zwykle rysuję je na mapie bitowej, a następnie umieszczam na ekranie.

Operacje Bitmap GetPixel i SetPixel nie są szczególnie szybkie, ponieważ wykonują bardzo dużo kontroli granic, ale dość łatwo jest utworzyć klasę „szybkiej bitmapy”, która ma szybki dostęp do mapy bitowej.

Will Dean
źródło
2

Strona MSDN w witrynie GetHdc

Myślę, że właśnie tego szukasz. Będziesz musiał pobrać HDC, a następnie użyć wywołań GDI, aby użyć SetPixel. Zauważ, że COLORREF w GDI to DWORD przechowujący kolor BGR. Nie ma kanału alfa i nie jest to RGB jak struktura kolorów GDI +.

To jest mała sekcja kodu, który napisałem, aby wykonać to samo zadanie:

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);
    }
    ...
}
ani
źródło
1

Wygląda na to, że DrawLine rysuje linię, która jest o jeden piksel krótsza od rzeczywistej określonej długości. Wygląda na to, że nie ma DrawPoint / DrawPixel / whatnot, ale zamiast tego możesz użyć DrawRectangle z szerokością i wysokością ustawioną na 1, aby narysować pojedynczy piksel.

Rytmis
źródło
2
Niezła próba, ale przy rozmiarze 1 rysuje 2x2 piksele. (Narysuj go obok linii, a zobaczysz, że jest dwukrotnie szerszy.) A przy rozmiarze zero oczywiście nic nie rysuje.
Mark T
Racja, mój błąd. :) Dobrze, że FillRectangle załatwia sprawę.
Rytmis
0

Rysowanie linii 2px za pomocą pióra z DashStyle.DashStyle.Dot rysuje pojedynczy piksel.

    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);
        }
    }
Wir
źródło