0

I have created a small line chart on a winform, using simple procedure (vb.net):

    MyGraphics = CreateGraphics()

    MyPenLine = New Pen(LineColor, 1)

    MyPenLine.DashStyle = DashStyle.Solid

    Dim pt1 As Point = New Point(X, Y)
    Dim pt2 As Point = New Point(X, Y)
    Dim pt3 As Point = New Point(X, Y)
    Dim pt4 As Point = New Point(X, Y)

    MyGraphics.DrawLine(MyPenLine, pt1, pt2)
    MyGraphics.DrawLine(MyPenLine, pt2, pt3)
    MyGraphics.DrawLine(MyPenLine, pt3, pt4)

The result is not what I expected:

enter image description here

The drawn lines lack sharpness. It looks like it is painted in "paint" and the lines look like they are made up of dozens of small lines.

Is there any particular reason why the chart lines look like this and why they are not smooth? Is there any other method to paint something on a winform to make it look more... professional and visually appealing?

Rafał Kowalski
  • 177
  • 1
  • 11
  • 2
    Use the Paint event of the Control that you want to use as *canvas*. Then use the Graphics object passed to the event handler to set `e.Graphics.SmoothingMode = SmoothingMode.AntiAlias` (before you draw your stuff, of course). - It's important tthat you don't ever do this: `MyGraphics = CreateGraphics()`. `CreateGraphics()` is used for some specific reasons; this is not one of those reasons. – Jimi Apr 04 '21 at 19:36
  • When I have added .SmoothingMode to my code it helped a lot, now it looks how I wanted it to look. Can you elaborate a bit more on why I should not use CreateGraphics() in my code when drawing on form? If for example I want to create multiple things on form and then "redraw" some of them, how can I do that if I put everything into main Paint event? What about drawing inside controls, like inside combobox items? I am using DrawItem event - is that correct approach? I am using it the same way you described = e.Graphics.XXX – Rafał Kowalski Apr 04 '21 at 20:00
  • 1
    Winforms graphics basic rule #1 : Never use `control.CreateGraphics`! Never try to cache a `Graphics` object that is bound to a control! Either draw into a `Bitmap bmp` using a `Graphics g = Graphics.FromImage(bmp)` or in the `Paint` event of a control, using the `e.Graphics` parameter.. You can test the persistance of your graphics by doing a Minimize/Maximize sequence.. The correct way is to keep a list of things to draw and whenever that list changes `Invalidate` the control you draw on. All drawing should be in the `Paint` event, using `e.Graphics` there! – TaW Apr 04 '21 at 20:06
  • 2
    The example you're making is correct and fits: to custom draw Items of Controls as a ComboBox, you need the Graphics object provided by the DrawItem event (or `OnDrawItem()` method). The same goes for other Controls. Most provide a Paint event, where you can access the currently generated Graphics object of that Control. Using the Paint event handler (or overriding `OnPaint()`), you have access to a valid Graphics object and also have means to preserve what you draw on this Context. - Try to minimize (or *obscure*) your Form after you have drawn something using `CreateGraphics()`. – Jimi Apr 04 '21 at 20:07
  • DrawItem indeed is the Paint event for a single Item in a listbox. Do use its e.Graphics param!! – TaW Apr 04 '21 at 20:08
  • 1
    For a simple example on how to preserve drawn objects and add/remove new ones seamlessly, see here: [How to use the Paint event to draw shapes at mouse coordinates](https://stackoverflow.com/a/53708936/7444103). Note that when you `Invalidate()` a buffered Device Context, only what needs to be drawn is actually drawn. There's a smart enough *function at work* behind the scene. But you can also `Invalidate()` a specific region of a Control, which can also speed up the process in some cases. – Jimi Apr 04 '21 at 20:11
  • 1
    Or with VB.Net, drawing Bezier curves to *hand-write* a signature: [How to draw a signature and save it to disc as a Bitmap?](https://stackoverflow.com/a/57084653/7444103) – Jimi Apr 04 '21 at 20:19
  • If I understood correctly then - If I create multiple drawings on a form and I want to remove one of them (from let's say 10 different ones) I need to Invalidate() the form, deleting all the drawings and then "redrawing" the remaining ones once again? Right now I have a few Subs, which I use to draw different things on one userform. How do I redraw/change selected drawings without changing the rest? For example, I am drawing 10 lines and I want to change color of one. Right now I simply "repaint" the chosen line with the new color. – Rafał Kowalski Apr 04 '21 at 20:28
  • As I/we wrote: you need to __keep a list__ of things to draw! In the Paint event you enumerate that List. When something changes or a thing should be removed you remove it from that list and call Invalidate, so that the new list gets drawn. Another example: [DrawAction](https://stackoverflow.com/questions/28714411/update-a-drawing-without-deleting-the-previous-one/28716887?s=3|28.8492#28716887) – TaW Apr 05 '21 at 09:16

0 Answers0