Transparent clear graphic buffer?

I am currently working on a project where I need to use GDI + ( System.Drawing ). I am trying to make a multi-purpose meter (clock wheel) with dynamic neons on it.

I do not want to draw a background image (with all marks) in each frame. I solved it right now by setting it as the background image of the graphic β€œcontainer”, which is a panel (remember this, I probably should do it differently).

So, I am drawing needles. The needle is updated 25 times per second (I could optimize this so that it is updated only when necessary). However, the problem is that I have to clear the buffer before starting to work with the new frame, causing the background image to become covered by the background color of the buffer. Obviously, I do not want this.

I tried to set the background color of the buffer to Color.Transparent , but instead it gives the buffer a color according to the parent transparency key (in my case it is black).

Here is my current code used to draw needles (in the Wheel class):

  /// <summary> /// Draws the wheel and the needles. /// </summary> public void Draw() { Graphics.Clear(Color.Transparent); // Draws all needles, works fine foreach (Needle Ndl in Needles) { Ndl.Draw(ref this.Graphics); } // Draws the little circle in the center of the wheel. Looks only. Graphics.FillEllipse(new Pen(Color.White).Brush, new Rectangle(120, 120, 16, 16)); } 

Yes, I followed the rules, I did my homework. Other people have solved this by simply drawing an image in each frame using BitBlt, which is a way to advance for understanding my brain.

I am very frank about this, so if you think I should use BitBlt anyway, and you know where I can find some detailed detailed examples, I will definitely do it with BitBlt. Of course, it would be even better if there were solutions without using BitBlt, or if it makes no sense to use it here anyway.

Is it possible to make the buffer buffer transparent or should I use a completely different approach?

Note. I prefer not to use XNA, since this application will be mainly used for maintenance on simple / old computers, so I do not want to have anything to do with redistributable ones.

+4
source share
1 answer

You can put your base image in a PictureBox. Your code can then handle the Paint event for the PictureBox to draw your needles. This way you don't have to worry about transparency or the slow performance of Graphics.Clear (): your code just needs to calculate the positions of the needles.

As a quick test, I wrote a small Forms application that creates a clock with an hour (red), second hand (greed) and a millisecond hand (blue). The minute hand does not receive any respect and therefore is not shown. The background is an image of a black rounded rectangle created in GIMP.

Clock with millisecond hand

To simulate your environment, I added a timer at intervals of 10 milliseconds (100 cycles per second). When the Timer.Tick event is processed, the PictureBox is redrawn.

I edited the code to leave only the code for the millisecond hand:

  public Form1() { InitializeComponent(); pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint); Center = new PointF((float)pBox1.Width / 2, (float)pBox1.Height / 2); MillisecondLength = (float)pBox1.Width / 4; //length of millisecond hand timer1.Interval = 10; timer1.Enabled = true; timer1.Tick += new EventHandler(timer1_Tick); } PointF Center; float MillisecondLength; Pen MillisecondsPen = new Pen(Brushes.Blue, (float)3); double HALF_PI = Math.PI / 2; double TWO_PI = 2 * Math.PI; double millisecondHandAngle(DateTime dt) { //12 o'clock is at the top! (- PI / 2) return TWO_PI * dt.Millisecond / 1000 - HALF_PI; } void pBox1_Paint(object sender, PaintEventArgs e) { DateTime dt = DateTime.Now; double mangle = millisecondHandAngle(dt); SizeF millisecondOffset = new SizeF( (float)(MillisecondLength * Math.Cos(mangle)), (float)(MillisecondLength * Math.Sin(mangle)) ); PointF endMillisecond = PointF.Add(Center, millisecondOffset); e.Graphics.DrawLine(MillisecondsPen, Center, endMillisecond); } void timer1_Tick(object sender, EventArgs e) { pBox1.Invalidate(); } 

Although not shown in this code, I added System.Diagnostics.Stopwatch and a counter variable to calculate the actual frame rate, which on my older laptop peaked at about 64 frames per second. Even if you set the minimum timer interval, the maximum redraw speed.

+1
source

Source: https://habr.com/ru/post/1390998/


All Articles