Link to home
Start Free TrialLog in
Avatar of i-Thomas
i-Thomas

asked on

User Control input / output with dynamic graphic elements or better use form?

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 with something like a rectangle (or maybe a button) that can be clicked with the mouse and then should make the waypoint moveable.

I 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...

So I need a dynamic control that resizes / reshapes itself dependent on user editing.

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

I have the following code that was put to a custom control to avoid flickering! Flickering is an important issue and may not appear in my app, so if you answer, please keep the flickering issues in mind!

---

The code of the custom control with a simpel 2-waypoint-example with green-to-blue color gradient,
works really FLICKER-FREE:

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();
    }

  }
}



*********************

The code of the simple demo app:


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

namespace Flicker1
{
       public class Form1 : System.Windows.Forms.Form
       {
                private Test.GradientPanel gradientPanel1;
                private System.ComponentModel.Container components = null;

                public Form1()
      {
             InitializeComponent();
           }

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

          #region
           private void InitializeComponent()
           {
            System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
            this.gradientPanel1 = new Test.GradientPanel();
            this.SuspendLayout();
            //
            // gradientPanel1
            //
            this.gradientPanel1.BackColor = System.Drawing.Color.Transparent;
            this.gradientPanel1.Location = new System.Drawing.Point(40, 32);
            this.gradientPanel1.Name = "gradientPanel1";
            this.gradientPanel1.Size = new System.Drawing.Size(696, 176);
            this.gradientPanel1.TabIndex = 0;
            this.gradientPanel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.gradientPanel1_MouseMove);
            //
            // Form1
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
            this.ClientSize = new System.Drawing.Size(800, 422);
            this.Controls.Add(this.gradientPanel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);

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

        private void gradientPanel1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            gradientPanel1.Width = Cursor.Position.X;
            gradientPanel1.Refresh();    
        }
    }
}


Thank you very much for helping me with this issue!
Avatar of Yurich
Yurich
Flag of New Zealand image

probably it's not exactly (or completely) what you want but have you thought of using a trackbar?

regards
Avatar of i-Thomas
i-Thomas

ASKER

Hello Yurich!

No, a trackbar does not meet it. Did you check my sample code and what it does? Imagine this, but n times copied side-by-side and mirrored on the horizontal axis, of course.


I will make a graphical design and post a link here in a few hours. Obviously it is a bit difficult to understand what I want to do when I just use words to describe.
Ok... here we go:

http://www.ingot.de/ee/usercontrol/DynamicUserControl.jpg


The diagram will be "very" dynamic, that means the height, width will be resizable as well as number of waypoints. Each waypoint can be adjusted with the handle as illustrated in the image with the arrows, waypoints can be added / deleted / inserted. Moreover it should support zooming in / out.

I do not expect the full code for such complex control, I would like to get advice

a) if I can / should / cannot use a UserControl for this ->

if yes: how to get parameters in / out of this UserControl and how to add / remove waypoints

if no: how to realize it on a panel on the main form without flickering?


If there are further questions, please let me know, I will answer everything as detailed as possible to avoid guessing on your side!


Thanks a lot in advance for caring!


ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Bob!

Thank you very much !!! I am happy that my illustration helped.

I will spend my weekend digging into it and I am SURE I will LEARN a lot :-)

I will post my experiences here!
Hi Bob!

This is so pretty nice what you've done for me... I don't want to exaggerate, but I ... really feel deeply thankful.

a question:

you used variable names like "_boundsX" ... what special mark is the underscore? for what kind of variables?
Is this your style or official .NET programming style?

And... don't misunderstand me:

When I change the width of the control, the rightmost segment changes in width / is cut away. If I want the whole control to be scaled evenly, do I have to re-calculate the points in the ArrayList? Or is there more elegant / automatic way?

In any case, I think I have understood how user controls work and that in principle they are complete "sub-programs" that can use own class methods etc.


Best regards!

i-Thomas



The underscore was a trick that I learned from a VB.NET trainer to indicate internal fields that are bound to external properties, which is where I started out going, and then changed my mind.  I didn't see any value to exposing the bounds to the outside world, but I didn't rename the variables.

Are these segments fixed in width?  If so, then you can make a simple change, and say that you want 5 points, and let the control recalculate the point coordinates.

Also, I didn't include anything to let the user click + drag the individual points.  I wanted to make sure that the rendering was appropriate before including anything that complicated.

Bob
Hi Bob!

Yes, the rendering is absolutely adequate. The only thing is that the handles should have rectangular size instead of circular, but that is simply cosmetics. For me it is important to learn and understand the principles.

So if you would like to help with extended version I would be very happy, but on the other hand you did more than enough for me so that I don't really expect anything more.

I could also offer to start another thread with 500 points to reward you, if this is ok from your point of view and also according to ee rules!

Best regards,

i-Thomas
If you want to figure out the next steps, then I would suggest start a new question.  

Otherwise, is this question completed?

Bob
Yes, it is completed. I missed your last comment somehow.

Should I accept now or tomorrow, when I start new question so that I can post the link here?

Or will you get notified about this thread also after I accepted it?

You can accept whenever you'd like.  Did you start another question?  If so, what is the URL?

Bob
I will start new question after I managed the object sender issue with my custom control... so hopefully tomorrow.

I will post new link here!
I wil come back soon. This week there is time to code again.
Hi Bob!

Sorry for not coming back till now. Business was throwing me here and there...

I will post new thread ASAP.


Thank you very much again!


Thomas