[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 422
  • Last Modified:

Flickering with LinearGradientBrush

Hi Experts!

I want to draw a polygon filled with LinearGradientBrush. This works fine in static mode.

Now I want to make its right edge follow my mouse movement.


I use the following code:

:

using System.Runtime.InteropServices;       // for LockWindowUpdate

:

[DllImport("user32.dll", EntryPoint = "LockWindowUpdate")]
static extern Int32 LockWindowUpdate(Int32 hwndLock);

:
:

public int MouseX = 0;

:
:
       private void uxButtonPanel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
           
            LockWindowUpdate(uxButtonPanel.Handle.ToInt32());
           
            Graphics g = e.Graphics;

            Point[] PolyPoints = new Point[4];
            PolyPoints[0] = new Point(0,0);
            PolyPoints[1] = new Point(MouseX,0);
            PolyPoints[2] = new Point(MouseX,130);
            PolyPoints[3] = new Point(0,80);

            LinearGradientBrush myBrush = new LinearGradientBrush(new Point(0,0), new Point(MouseX,0), Color.Green,Color.Blue);

            g.FillPolygon(myBrush,PolyPoints,FillMode.Alternate);

            LockWindowUpdate(0);

        }

       private void uxButtonPanel_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {


            //SetStyle( ControlStyles.UserPaint, true );
            //SetStyle( ControlStyles.AllPaintingInWmPaint, true );
            //SetStyle( ControlStyles.DoubleBuffer, true );
           
            MouseX = Cursor.Position.X;
            uxButtonPanel.Refresh();
 
   

        }


I am not sure what is the best strategy to handle the events in the right sequence and when to lock which window so that everything works perfectly smooth.

I am also not sure, if I need double buffering and if I do so, where to place the lines of code..


Thank you very much for helping in advance!






0
i-Thomas
Asked:
i-Thomas
  • 6
  • 5
1 Solution
 
Bob LearnedCommented:
Put this code in the InitializeComponent section:

         this.SetStyle( ControlStyles.UserPaint, true );
         this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
         this.SetStyle( ControlStyles.DoubleBuffer, true );

You had it in the MouseMove event, which is the wrong place, and try without the LockWindowUpdate (which can cause unwanted behavior in certain situations--like preventing tool tips on controls).


Bob
0
 
i-ThomasAuthor Commented:
Hello Bob!

Unfortunately this does not help.

Some more ideas / questions:

Are the lines

SetStyle( ControlStyles.UserPaint, true );
SetStyle( ControlStyles.AllPaintingInWmPaint, true );
SetStyle( ControlStyles.DoubleBuffer, true );

correct? I read something that they only apply to classes derived from System.Windows.Form.Control. Is this the case with my panel and what I draw on it?

Do I have to manage the DoubleBuffering somehow or is it fully automatic process in principle?



I use

uxButtonPanel.Refresh();

to start the Paint event.

Is that correct proceeding or is there another way to trigger / manage the paint event?


I really hope that you can help me with that. In any case it should be quite interesting question for a lot of ee members, I think.

0
 
Bob LearnedCommented:
I think that I do not quite understand what you are working with here.

Where is this code running from?  At first, I assumed it was coming from a user control, but now I'm thinking that it is in a form.  You are right, those three lines should be in the InitializeComponent for the ButtonPanel control that I am also assuming is yours.

Bob
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
Bob LearnedCommented:
Also, you can get into a memory leak situation by repeatedly creating new brushes, and not disposing of them.

myBrush.Dispose();

Bob
0
 
i-ThomasAuthor Commented:
I am not using a user control.

The reason is simple: I never did it and I don't know how to do it.

You could help me with most simple example:

Create empty windows form app, add a panel and tell me how to draw flicker-free to that panel.


If I have to use a user-control or if that could help me and improve my programming style and efficiency, then I would be very very glad, if you could tell me how to do the above with a user control!

Thank you very much for caring!

If you have further questions, please do not hesitate to ask me! I will react immideatly for the next hours, as I am in need to solve the problem somehow!

Regards,

i-Thomas
0
 
Bob LearnedCommented:
Attempt #1:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Test
{
  /// <summary>
  /// Summary description for GradientPanel.
  /// </summary>
  public class GradientPanel : System.Windows.Forms.UserControl
  {
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public GradientPanel()
    {
      // This call is required by the Windows.Forms Form Designer.
      InitializeComponent();

      // Add any initialization after the InitializeComponent call
      this.SetStyle( ControlStyles.UserPaint, true );
      this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
      this.SetStyle( ControlStyles.DoubleBuffer, true );
      this.SetStyle( ControlStyles.SupportsTransparentBackColor, true );

      this.BackColor = Color.Transparent;

    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if(components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    #region Component Designer generated code
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      //
      // GradientPanel
      //
      this.Name = "GradientPanel";
      this.Size = new System.Drawing.Size(240, 212);
      this.Resize += new System.EventHandler(this.GradientPanel_Resize);
      this.Paint += new System.Windows.Forms.PaintEventHandler(this.GradientPanel_Paint);

    }
    #endregion

    private void GradientPanel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
   
      Graphics g = e.Graphics;

      Point[] PolyPoints = new Point[4];
      PolyPoints[0] = new Point(0, 0);
      PolyPoints[1] = new Point(this.Width, 0);
      PolyPoints[2] = new Point(this.Width, this.Height);
      PolyPoints[3] = new Point(0, this.Height / 2);

      LinearGradientBrush myBrush =
        new LinearGradientBrush(new Point(0,0), new Point(this.Width, 0),
        Color.Green, Color.Blue);

      g.FillPolygon(myBrush, PolyPoints, FillMode.Alternate);

      myBrush.Dispose();

    }

    private void GradientPanel_Resize(object sender, System.EventArgs e)
    {
      this.Invalidate();
    }

  }
}


Bob
0
 
i-ThomasAuthor Commented:
Hello Bob!

I just finished preparing a most simple version that you can just copy + paste and run and that shows my problem, so we "crossed" information somehow.

I copied and pasted your code, but I get error message that entry point is not found... Can you please paste the full version or tell me what to add?

----

Here is my code (maybe obsolete...):

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;

namespace Flicker
{
      public class Form1 : System.Windows.Forms.Form
      {
        private System.Windows.Forms.Panel panel1;
            private System.ComponentModel.Container components = null;

        private int MouseX = 200;

            public Form1()
            {
                  InitializeComponent();
            }

          
        protected override void Dispose( bool disposing )
            {
                  if( disposing )
                  {
                        if (components != null)
                        {
                              components.Dispose();
                        }
                  }
                  base.Dispose( disposing );
            }

            
        #region Vom Windows Form-Designer generierter Code
      
        private void InitializeComponent()
            {

            this.SetStyle( ControlStyles.UserPaint, true );
            this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
            this.SetStyle( ControlStyles.DoubleBuffer, true );


            this.panel1 = new System.Windows.Forms.Panel();
            this.SuspendLayout();
            //
            // panel1
            //
            this.panel1.BackColor = System.Drawing.SystemColors.ControlDark;
            this.panel1.Location = new System.Drawing.Point(24, 24);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(344, 216);
            this.panel1.TabIndex = 0;
            this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint);
            this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseMove);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(392, 266);
            this.Controls.Add(this.panel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

        }
            #endregion

            [STAThread]
            static void Main()
            {
                  Application.Run(new Form1());
            }


        private void panel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            MouseX = Cursor.Position.X;
            panel1.Refresh();
        }

        private void panel1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            int YOffset = 0;

            Point[] PolyPoints = new Point[4];
            PolyPoints[0] = new Point(0,0 + YOffset);
            PolyPoints[1] = new Point((MouseX), 0 + YOffset);
            PolyPoints[2] = new Point((MouseX), 130 + YOffset);
            PolyPoints[3] = new Point(0,80 + YOffset);

            Graphics g = e.Graphics;

            LinearGradientBrush myBrush = new LinearGradientBrush(new Point(0,0), new Point(MouseX,0), Color.Green,Color.Blue);
            g.FillPolygon(myBrush,PolyPoints,FillMode.Alternate);
            myBrush.Dispose();

           
        }
      }
}
0
 
Bob LearnedCommented:
Steps:

(1) Create a new test Windows Form application.
(2) Add a new user control item--name = GradientPanel.
(3) Paste the text shown above over the existing text in the control.
(4) Build the solution.
(5) From the toolbox, find the My User Controls tab, and there should be a GradientPanel control.  Drag/drop this onto the form, and tell me just how badly I did.

Bob
0
 
i-ThomasAuthor Commented:
Wow! Thanks Bob!

If I could, I would email you a box of German beer (...if you like that) to express how happy I am about your help :-)

Yes, so far it works and the redraw is pretty smooth ... and I learned a lot about user controls!

Are you sure that this smooth redraw works only with a custom user control? If yes: Do you know why?

I see no principle contradiction that it could work on a main form!?


---

Now I have a general question about using this user controls for my original purpose:

I want to create something like a tool to control light color and intensity along time axis.

There are waypoints (in this simple example two: a pure green and a pure blue one) with specified color and intensity (the height of the polygon). Between the waypoints light is smoothly blended (therefore the gradient story...)

As there can be hundreds of waypoints, I need to have a long polygonal shape that would look more or less like the teeth of a saw. Each waypoint should be moveable in x and / or y direction.

I just want to know, if I can create such dynamic editable polygon "thing", namely my graphical light timeline representation via a user control, or if this works only within the main form...

If this is possible with the custom control, how can I send / receive data like polygon point coordinates to / from it?

You did so much for me, should we start a new thread for this topic somehow? I would be ready to offer another 500 points, because I am really in need to solve this problem!




0
 
Bob LearnedCommented:
A new question would probably be needed here.

Bob
0
 
i-ThomasAuthor Commented:
Hello Bob!

Here you are:

http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_21406617.html


I hope that my explanation is good enough also for others, but you have the advantage that you know what I am talking about and to go for the points!

Many many thanks again and ... read you soon!

i-Thomas
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 6
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now