Dessinez un seul pixel sur Windows Forms

92

Je suis bloqué en essayant d'activer un seul pixel sur un formulaire Windows.

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

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

L'API devrait vraiment avoir une méthode pour définir la couleur d'un pixel, mais je n'en vois pas.

J'utilise C #.

Mark T
la source
J'ai créé un contrôle qui trace de très beaux graphiques scientifiques (avec des fonctionnalités supplémentaires dont je n'ai besoin dans aucun contrôle commercial). Je peux tracer un point de données avec et X ou un + ou une petite boîte. Mais pour les données sans importance, je veux juste un seul pixel.
Mark T
Toutes les réponses que je vois semblent vraiment exagérées pour un seul pixel? Pourquoi est-il plus simple de faire un tampon [y * largeur + x] = couleur;
NoMoreZealots

Réponses:

113

Cela définira un seul pixel:

e.Graphics.FillRectangle(aBrush, x, y, 1, 1);
Henk Holterman
la source
18
Qui aurait deviné que DrawRectangle dessine un 2x2 mais FillRectange dessine un 1x1 avec les mêmes arguments? Merci.
Mark T
9
@Mark: Cela a une sorte de sens ... DrawRectangle dit "dessine un contour commençant à x et y de cette largeur et hauteur", donc il dessine à la fois les points de début et de fin (x, y; x + 1, y ; x, y + 1; x + 1, y + 1) et les lignes entre eux. FillRectangle dit "dessine une surface solide commençant à x, y de cette largeur et hauteur." Incidemment, FillRectangle prend un Brush, pas un Pen.
Powerlord
5
@R. Bemrose: En fait, cela dépend de l'objet Pen auquel vous passez DrawRectangle(). Si c'est le cas, il Pen.Alignment = PenAlignment.Outsetdessinera Pen.Widthun contour épais de pixels autour du rectangle donné. Mais si vous spécifiez, Pen.Alignment = PenAlignment.Insetil dessinera Pen.Width pixels épais "contour" à l'intérieur du rectangle donné.
Cipi
2
C'est une réponse très insatisfaisante. Bien que cela définisse un pixel unique, la condition n'est pas toujours de définir un pixel littéral. Toutes les fois où j'en ai eu besoin, ce qui est souvent le cas, j'ai eu besoin que le point soit dessiné avec le même stylo avec lequel les lignes sont dessinées, pas un pinceau. En d'autres termes, nous avons besoin d'une ligne plus courte que 2 pixels. Je soupçonne que c'est ce dont le PO avait besoin.
RobertT
6
Je n'aime pas cette réponse. Cette manière est très inefficace.
user626528
18

L' Graphicsobjet n'a pas cela, car c'est une abstraction et pourrait être utilisé pour couvrir un format graphique vectoriel. Dans ce contexte, définir un seul pixel n'aurait pas de sens. Le Bitmapformat d'image a GetPixel()et SetPixel(), mais pas un objet graphique construit sur un. Pour votre scénario, votre option semble vraiment être la seule car il n'y a pas de moyen unique de définir un seul pixel pour un objet graphique général (et vous ne savez pas exactement ce que c'est, en tant que contrôle / formulaire pourrait être à double tampon, etc.)

Pourquoi avez-vous besoin de définir un seul pixel?

Adam Robinson
la source
18

Juste pour afficher le code complet de la réponse de Henk Holterman:

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

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

Là où je dessine beaucoup de pixels simples (pour divers affichages de données personnalisés), j'ai tendance à les dessiner sur une image bitmap, puis à les envoyer sur l'écran.

Les opérations Bitmap GetPixel et SetPixel ne sont pas particulièrement rapides car elles effectuent énormément de vérifications de limites, mais il est assez facile de créer une classe `` bitmap rapide '' qui a un accès rapide à un bitmap.

Will Dean
la source
2

Page MSDN sur GetHdc

Je pense que c'est ce que vous recherchez. Vous devrez obtenir le HDC, puis utiliser les appels GDI pour utiliser SetPixel. Notez qu'un COLORREF dans GDI est un DWORD stockant une couleur BGR. Il n'y a pas de canal alpha et ce n'est pas RVB comme la structure Color de GDI +.

Voici une petite section de code que j'ai écrite pour accomplir la même tâche:

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);
    }
    ...
}
ni
la source
1

Apparemment, DrawLine trace une ligne inférieure d'un pixel à la longueur réelle spécifiée. Il ne semble pas y avoir de DrawPoint / DrawPixel / whatnot, mais à la place, vous pouvez utiliser DrawRectangle avec une largeur et une hauteur définies sur 1 pour dessiner un seul pixel.

Rytmis
la source
2
Bien essayé, mais avec la taille 1, il dessine 2x2 pixels. (Dessinez-le à côté d'une ligne, et vous pouvez voir qu'il est deux fois plus large.) Et avec une taille zéro, bien sûr, il ne dessine rien.
Mark T
Oui, mon erreur. :) Heureusement que FillRectangle fait l'affaire.
Rytmis
0

Dessiner une ligne 2px à l'aide d'un stylo avec DashStyle.DashStyle.Dot dessine un seul 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);
        }
    }
Tourbillon
la source