简体   繁体   English

PictureBox中的工具提示FillPie协调C#

[英]Tooltip in PictureBox FillPie Coordinates C#

I'm drawing a Circle made of 360 FillPie. 我正在画一个由360 FillPie组成的圆圈。 Each FillPie color is taken from a List. 每个FillPie颜色都取自List。 I want to return a string that says at which degree is the mouse and how much is the value of the list to put it on a tooltip. 我想返回一个字符串,该字符串表示鼠标的度数以及将其放在工具提示上的列表值。

    List<int> datiDisco = new List<int>();

    public void Paint (Graphics grafica)
    {
        try
        {
            for (int i = 0; i < datiDisco.Count; i++)
            {
                Brush penna = new SolidBrush(Color.FromArgb(255, ScalaGrigi(valori[i]), ScalaGrigi(valori[i]), ScalaGrigi(valori[i])));
                grafica.FillPie(penna, 0, 0, 400, 400, i, 1.0f);
            }
        }
        catch
        {

        }
    }

until here the code is working and i managed to draw the circle with the correct color.Now i can't figure out how i can take the coordinate of each fillpie that i have drawn. 直到这里代码工作,我设法用正确的颜色绘制圆。现在我无法弄清楚我如何可以采取我绘制的每个填充的坐标。 Can someone help me? 有人能帮我吗?

Figuring out which pie segment the mouse cursor lies in is a simple application of trigonometry, specifically an application of the inverse tangent (aka arctangent or atan). 确定鼠标光标所在的饼图段是三角函数的简单应用,特别是反正切(又称反正切或atan)的应用。

As a quick reminder for those who've encountered this before, or as a lesson for those who haven't, let's look quickly at the tangent function. 作为对那些之前遇到过这种情况的人的快速提醒,或者作为那些没有遇到过的人的教训,让我们快速看一下切线函数。 Trigonometry deals with the geometry of right triangles, and by definition a right triangle has two sides and a hypotenuse. 三角函数处理直角三角形的几何,根据定义,直角三角形有两个边和一个斜边。 The hypotenuse is a special name for the side of the triangle opposite the right (90° or π/2) angle. 斜边是与右侧(90°或π/ 2)角相对的三角形边的特殊名称。 The other two sides are helpfully just called sides. 另外两个方面也很有帮助。

The tangent function's value is the ratio of the side opposite an angle to the side adjacent to that angle. 切线函数的值是与角度相邻的一侧的角度与该角度相邻的一侧的比率。 The arctangent is the angle whose tangent is equal to that ratio. 反正切是角度,其切线等于该比率。 Because of the symmetry of the function we need to calculate the angle, and then add or subtract an offset depending on the quadrant to extract the 'real' angle. 由于函数的对称性,我们需要计算角度,然后根据象限添加或减去偏移量以提取“实际”角度。 In diagram form this looks like: 在图表形式中,这看起来像:

映射到象限的反正切值图。

The tangent function has discontinuities at several points, namely when the adjacent side's length is 0 (90° and 270°), so we'll have to treat those points specially. 切线函数在几个点处具有不连续性,即当相邻边的长度为0(90°和270°)时,我们将不得不特别处理这些点。

OK, enough math, now on to the practical application. 好的,足够的数学,现在实际应用。

For this demo, create a new C# WinForms project, and on the default Form1 add a PictureBox . 对于此演示,请创建一个新的C#WinForms项目,并在默认的Form1添加一个PictureBox

First, since I don't have your color generation function, I use the following list of values and helper function: 首先,由于我没有您的颜色生成功能,我使用以下值列表和辅助函数:

List<int> values = Enumerable.Range(0, 360).ToList();
int Rescale(int x) => (int)(((double)x / 360.0) * 255.0);

In the constructor hook up a couple events, and set some properties: 在构造函数中挂钩一些事件,并设置一些属性:

public Form1()
{
    InitializeComponent();

    this.pictureBox1.BorderStyle = BorderStyle.Fixed3D;
    this.pictureBox1.Size = new Size(50, 50);
    this.Size = new Size(450, 450);

    this.DoubleBuffered = true;
    this.Paint += Form1_Paint;
    this.MouseMove += Form1_MouseMove;
}

To paint the circle I use a slightly modified version of your OnPaint handler: 要绘制圆圈,我使用稍微修改过的OnPaint处理程序版本:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.Clear(Color.Black);

    for (int i = 0; i < values.Count; i++)
    {
        Brush b = new SolidBrush(Color.FromArgb(255, Rescale(values[i]), 0, 0));
        e.Graphics.FillPie(b, 0, 0, 400, 400, (float)i, 1.0f);
    }
}

In the MouseMove event is where we do most of the heavy lifting: MouseMove事件中,我们执行大部分繁重工作:

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    this.pictureBox1.Location = new Point(e.X + 5, e.Y - 5);
    int segment = (int)GetAngle(new Rectangle(0, 0, 400, 400), e.Location);
    this.pictureBox1.BackColor = Color.FromArgb(255, Rescale(segment), 0, 0);
}

You may notice that since there are 360 wedges are in increments of a degree, I just truncated the angle. 您可能会注意到,由于360度楔以一定程度的增量,我只是截断了角度。 If you need more precision, or you decide to use segments greater than 1 degree, then you could use various rounding algorithms to round the angle to the nearest section of the pie. 如果您需要更高的精度,或者您决定使用大于1度的段,则可以使用各种舍入算法将角度舍入到最接近的饼图部分。

At last, we're ready to implement the GetAngle function. 最后,我们准备实现GetAngle函数了。 First we calculate the center of the circle, because everything is relative to that. 首先,我们计算圆的中心,因为一切都与此相关。

int cx = (rect.Width + rect.X) / 2;
int cy = (rect.Height + rect.Y) / 2;

Next calculate the difference between the mouse's position and the center of the rectangle. 接下来计算鼠标位置和矩形中心之间的差异。 (I've inverted the y coordinate to line up with 'standard' Cartesian coordinates, to make things easier, and match the coordinates you'd see in a math textbook.) (我已将y坐标反转为与'标准'笛卡尔坐标对齐,以使事情更容易,并匹配您在数学教科书中看到的坐标。)

float x = pTo.X - cx;
float y = (cy - pTo.Y);

Next check for the arctangent's undefined points (and a couple of shortcuts we can take): 接下来检查arctangent的未定义点(以及我们可以采用的几个快捷方式):

if ((int)x == 0)
{
    if (y > 0) return 270;
    else return 90;
}
else if ((int)y == 0)
{
    if (x > 0) return 0;
    else return 180;
}

Calculate the internal angle: 计算内角:

float ccwAngle = (float)Math.Atan(Math.Abs(y) / Math.Abs(x));

And map that angle to the appropriate quadrant: 并将该角度映射到适当的象限:

if (x > 0 && y > 0)
{

}
else if (x < 0 && y > 0)
{
    ccwAngle = (float)Math.PI - ccwAngle;
}
else if (x < 0 && y < 0)
{
    ccwAngle = ccwAngle + (float)Math.PI;
}
else if (x > 0 && y < 0)
{
    ccwAngle *= -1f;
}

Convert the angle from degrees to radians and normalize (make sure it's between 0° and 360°) 将角度从度数转换为弧度并标准化(确保它在0°和360°之间)

ccwAngle *= (float)(180 / Math.PI);
while (ccwAngle > 360) ccwAngle -= 360;
while (ccwAngle < 0) ccwAngle += 360;

Finally convert the counter-clockwise angle we needed to do the math into the clockwise angle that GDI uses, and return the value: 最后将我们需要的逆时针角度转换为GDI使用的顺时针角度,并返回值:

return 360f - ccwAngle;

All that together produces the final result: 所有这些共同产生最终结果:

演示实现的屏幕截图。

(The code above is also available as a complete example in this gist ) (上面的代码也可以作为这个要点中的完整示例)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM