Picture of current status Hello, I decided to write my analogue of Paint as a practice (I paint on the Panel, “processing” the canvas through the BitMap map , also put a “stub” on the PaintBackground so that the cleaning of the canvas is not caused) and encountered a number of problems

1) For some reason, if you use Graphics.Clear (fill color) to create BitMap, the background is absent as such, although if you use a ready-made picture, then everything is fine.

2) I just can’t figure out how to draw the elements so that “it doesn’t draw the map in the map”, and that’s what happens to me if I understand everything correctly.

I ask for advice on changing the method of drawing or how to fix the higher problems ...

Code (removed all unnecessary, so as not to interfere):

class Canvas : Panel { //################################################################### //Имя объекта типа Canvas на форме - canvas //################################################################### protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); } protected override void OnPaintBackground(PaintEventArgs e) //"заглушка", если это так называется { } } //описание формы, на которой находится canvas public partial class MainForm : Form { private bool enableBrush; private PointF coordinate; private PaintMode mode; private Bitmap map; private Color colorBrush; public enum PaintMode { None, Line, Brush, Rect, Rectangle } public MainForm() { InitializeComponent(); mode = PaintMode.None; Graphics g = canvas.CreateGraphics(); g.Clear(Color.White); //не отображает map = new Bitmap(canvas.Width, canvas.Height, g); colorBrush = Color.Green; enableBrush = false; } private void canvas_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { coordinate = e.Location; //запоминает позицию курсора при нажатии для рисования enableBrush = true; } } private void canvas_MouseUp(object sender, MouseEventArgs e) { if(e.Button == MouseButtons.Left) { enableBrush = false; map = new Bitmap(canvas.Width,canvas.Height); canvas.DrawToBitmap(map, new Rectangle(new Point(), canvas.Size)); // "сейвлю" текущую карту в map(BitMap) } } public void canvas_Paint(object sender, PaintEventArgs e) { if (enableBrush) { switch (mode) { case PaintMode.None: break; case PaintMode.Line: e.Graphics.DrawLine(new Pen(colorBrush), coordinate, canvas.PointToClient(MousePosition)); break; case PaintMode.Brush: break; case PaintMode.Rect: break; case PaintMode.Rectangle: break; default: break; } } } private void canvas_MouseMove(object sender, MouseEventArgs e) { canvas.Invalidate(); //вызываю перерисовку в каждый момент времени, когда курсор мыши находится над canvas } private void LineButton_CheckedChanged(object sender, EventArgs e) { if (mode == PaintMode.Line) mode = PaintMode.None; else mode = PaintMode.Line; } } 
  • 1) Is the FillRectangle not suitable for filling the background? 2) it is not clear what it means to map to map, and what behavior are you waiting for? - 4per
  • @ 4per 1) does not work; 2) Bitmap is drawn in Bitmap, because of which intermediate line drawing options are saved - Xambey

1 answer 1

The images in the figure can be divided into two groups.

  • permanent, this is actually the picture itself, which should eventually turn out

  • temporary, these are “technical” images that can be fixed as main ones after the completion of some action. For example, when drawing a straight line, you can rotate it around the starting point.

These two groups should be drawn on different layers. Constants can be drawn once on Bitmap , and temporary over Bitmap on the control itself. This is the easiest option, of course there are other options.

To do this, you will need to define such an entity as a “tool” (a pencil, for drawing points, a line, etc.). Then the rendering algorithm will be as follows:

  1. Bitmap with fixed image.
  2. The current selected instrument in its current state and position.

This order will ensure the correct location of the images - a tool over the image.

For a tool, a separate Bitmap not required, we do not need to store all its intermediate states. The tool is transferred to the main Bitmap only at the moment of fixation (click the mouse on the end point of the line, for example).

Ideally you need 3 layers:

  1. control context for drawing the current state of the tool
  2. Fixed-sized bitmap, independent of the size of the image being edited, to display the image being visible on a part of the image being edited.
  3. Bitmap editable image.

In this case, only 1 and 2 are drawn on the control. The 2nd is filled in with the necessary fragment at the required scale from 3. The results of the use of tools are recorded at 3.

If you want support for layers as in PhotoShop, then, respectively, 2 additional Bitmap for each layer, but this is another story.

Now, about the background and other amenities.

The work of Graphics.Clear(цвет заливки) depends on how and from what the Graphics object is derived. If you get it from the context of the control, then the background of the control will be repainted if Bitmap is repainted from the Bitmap context.

You do not need to place the picture as a background control, it will not give you the opportunity to make a normal zoom and scrolling for large pictures. In addition, there is no big difference between the output of the background image of the control or the call of Graphics.DrawImage in terms of performance.

So that the drawing does not "slow down" and the control does not "blink", you need to do two mandatory actions:

  • Enable double buffering, it does not require changing the drawing code, but it will already noticeably affect the smoothness of the drawing.

  • Take out heavy operations from handling the Paint event. These operations can be done without instant display.

  • Thank! All lucidly explained) - Xambey