Click here to Skip to main content
15,896,201 members

Region becomes invisible unstably?

supernorb asked:

Open original thread
I'm creating a control which represents some kind of arrow (including line). I create a class called GEdge inheriting the class Label. After creating a GraphicsPath (which is arrow-shaped), I assign the Region property of the my customized Label a new Region from that GraphicsPath. It displays OK on my form, I can move it well, but when try rotating one of two heads of the edge around another, it is also well if I do that slowly, otherwise my arrow (which is in fact my Region of the customized Label) disappears sometimes (I mean it can disappear or not). If I release the mouse, I will lose my arrow, but if I try continuing to rotate the arrow, I can see it display again on my form.

I can't understand why it is.
Here is some code of mine:

This is the overridden OnMouseMove method for the customized Label (my arrow):
C#
protected override void OnMouseMove(MouseEventArgs e)
        {

            if (e.Button == MouseButtons.Left)
            {
                //Check if mouse holds down on the middle of the arrow then just move it or translate it, not rotate.
                if (downPoint == MouseDownPoint.Middle)
                {
                    Left += e.X - oldPos.X;
                    Top += e.Y - oldPos.Y;
                }
                else //if mouse holds down on one of the two heads of the arrow then start rotating.
                {
                    if (downPoint == MouseDownPoint.First)
                    {
                        if (a != ArrowType.LastToFirst)
                            TurnTailPointTo(Parent.PointToClient(PointToScreen(e.Location)));
                        else TurnHeadPointTo(Parent.PointToClient(PointToScreen(e.Location)));
                    }
                    else if (a != ArrowType.LastToFirst)
                        TurnHeadPointTo(Parent.PointToClient(PointToScreen(e.Location)));
                    else TurnTailPointTo(Parent.PointToClient(PointToScreen(e.Location)));                    
                }
                Invalidate();
                first = Parent.PointToClient(PointToScreen(localFirst));
                last = Parent.PointToClient(PointToScreen(localLast));
            }
            base.OnMouseMove(e);
        }


TurnHeadPointTo and TurnTailPointTo are used to rotate the hold-down head to the specified point (the point where the mouse pointer is being located at when moving).

Here are the code for TurnHeadPointTo and TurnTailPointTo:

C#
void TurnPointTo(Point Tip, Point p)
        {
            if (Parent != null) Parent.SuspendLayout();
            Size = new Size(2 * Math.Abs(Tip.X - p.X) + 10 + fontHeight, 2 * Math.Abs(Tip.Y - p.Y) + 10 + fontHeight);
            turning = true;
            Location = new Point(Math.Min(p.X, Tip.X) - Width / 2, Math.Min(p.Y, Tip.Y) - Height / 2);
            turning = false;
            if (Parent != null) Parent.ResumeLayout();
        }
public void TurnHeadPointTo(Point p)
        {
            if (a != ArrowType.LastToFirst)
            {
                TurnPointTo(first, p);
                localLast = new Point(p.X - Location.X, p.Y - Location.Y);
                localFirst = new Point(first.X - Location.X, first.Y - Location.Y);
                last = p;
            }
            else
            {
                TurnPointTo(last, p);
                localFirst = new Point(p.X - Location.X, p.Y - Location.Y);
                localLast = new Point(last.X - Location.X, last.Y - Location.Y);
                first = p;
            }
            Invalidate();            
        }
public void TurnTailPointTo(Point p)
        {
            if (a != ArrowType.LastToFirst)
            {
                TurnPointTo(last, p);
                localLast = new Point(last.X - Location.X, last.Y - Location.Y);
                localFirst = new Point(p.X - Location.X, p.Y - Location.Y);
                first = p;
            }
            else
            {
                TurnPointTo(first, p);
                localLast = new Point(p.X - Location.X, p.Y - Location.Y);
                localFirst = new Point(first.X - Location.X, first.Y - Location.Y);
                last = p;
            }
            Invalidate();                        
        }


My idea is each time the rotating action happens, I will resize the customized label to the new size which can contain the 2 points of 2 heads of the arrow, and relocate it, update the localLast and localFirst (the co-ordinates of two heads of the arrow calculated in the Label not in the Form), these updates will change how the arrow looks.

Here is the code for the OnPaint method of the customized Label:

C#
protected override void OnPaint(PaintEventArgs e)
        {
            GraphicsPath gp = new GraphicsPath();            
            Point tail = a == ArrowType.FirstToLast || a == ArrowType.None ? localFirst : localLast;
            Point head = a == ArrowType.FirstToLast || a == ArrowType.None ? localLast : localFirst;
            int h = Math.Max(tail.Y, head.Y) - Math.Min(tail.Y, head.Y);
            int w = Math.Max(tail.X, head.X) - Math.Min(tail.X, head.X);
            float alpha = (float)Math.Atan((float)h / w);
            int dx = (int)((thick / 2) * Math.Sin(alpha));
            int dy = (int)((thick / 2) * Math.Cos(alpha));
            int signDx = 1, signDy = 1, signHeadX = 1, signHeadY = 1;
            if (tail.X >= head.X && tail.Y >= head.Y)
            {
                signDx = -1;                
            }
            else if (tail.X <= head.X && tail.Y <= head.Y)
            {
                signDy = -1;
                signHeadX = signHeadY = -1;                
            }
            else if (tail.Y >= head.Y)
            {
                signDx = signDy = -1;
                signHeadX = -1;                
            }
            else
            {
                signHeadY = -1;                
            }
           
            Point p1 = new Point(tail.X + signDx * dx, tail.Y + signDy * dy);
            Point p2 = new Point(tail.X - signDx * dx, tail.Y - signDy * dy);
            Point p3 = new Point(head.X + signDx * dx, head.Y + signDy * dy);
            Point p4 = new Point(head.X - signDx * dx, head.Y - signDy * dy);
            if (a == ArrowType.None)//Just shape a line
            {
                gp.AddLines(new Point[] { p1, p2, p4, p3 });
            }
            else//Shape an arrow
            {
                Point k = new Point((int)(head.X + signHeadX * 10 * Math.Cos(alpha)), (int)(head.Y + signHeadY * 10 * Math.Sin(alpha)));
                p3 = new Point(k.X + signDx * dx, k.Y + signDy * dy);
                p4 = new Point(k.X - signDx * dx, k.Y - signDy * dy);
                
                k = new Point((int)Math.Round((head.X + signHeadX * 20 * Math.Cos(alpha))), (int)Math.Round((head.Y + signHeadY * 20 * Math.Sin(alpha))));
                dx = (int)(2 * thick * Math.Sin(alpha));
                dy = (int)(2 * thick * Math.Cos(alpha));
                Point p5 = new Point(k.X + signDx * dx, k.Y + signDy * dy);
                Point p6 = new Point(k.X - signDx * dx, k.Y - signDy * dy);
                gp.AddLines(new Point[] { p1, p2, p4, p6, head, p5, p3 });
            }
            gp.AddPath(val, true);
            Region = new Region(gp);            
            base.OnPaint(e);
        }


Please don't suggest me the idea using AdjustableArrowCap with Pen, I know about it but it is just for paint. I want I can move and rotate the arrow, so using Region is the best, I think so.

I also tried overriding CreateParams of the form and add the ExStyle with 0x02000000 as many other sites discussed about preventing flicker. I think my problem is some kind of flicker.

Hope you understand my idea as well as my code to help me out!
Your help would be highly appreciated! Thanks!
Tags: C#, Windows Forms

Plain Text
ASM
ASP
ASP.NET
BASIC
BAT
C#
C++
COBOL
CoffeeScript
CSS
Dart
dbase
F#
FORTRAN
HTML
Java
Javascript
Kotlin
Lua
MIDL
MSIL
ObjectiveC
Pascal
PERL
PHP
PowerShell
Python
Razor
Ruby
Scala
Shell
SLN
SQL
Swift
T4
Terminal
TypeScript
VB
VBScript
XML
YAML

Preview



When answering a question please:
  1. Read the question carefully.
  2. Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  3. If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  4. Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question.
Let's work to help developers, not make them feel stupid.
Please note that all posts will be submitted under the http://www.codeproject.com/info/cpol10.aspx.



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900