简体   繁体   English

放大C#Winforms中面板的中间位置

[英]Zoom into the middle of a panel in C# Winforms

I have an app that I can zoom in and out, only problem I want to zoom in and out but focused into the current middle of the panel location , instead of using mouse position 我有一个可以放大和缩小的应用程序,只有我想放大和缩小的问题但是聚焦到面板位置的当前中间,而不是使用鼠标位置

any ideas? 有任何想法吗?

private void panel1_Paint(object sender, PaintEventArgs e)
{
    SolidBrush brushs = new SolidBrush(Color.White);
    e.Graphics.Clip = new Region(new Rectangle(0, 0, Viewer.Width, Viewer.Height));
    e.Graphics.FillRegion(brushs, e.Graphics.Clip);

    Graphics g = e.Graphics;
    g.TranslateTransform(_ImgX, _ImgY);
    g.ScaleTransform(_Zoom, _Zoom);
    g.SmoothingMode = SmoothingMode.AntiAlias;
    SolidBrush myBrush = new SolidBrush(Color.Black);
    Pen p = new Pen(Color.Red);
    foreach (CircuitData.ResistorRow resistorRow in ResistorData.Resistor)
    {
        RectangleF rec = new RectangleF((float)(resistorRow.CenterX  - resistorRow.Length/ 2), (float)(resistorRow.CenterY - resistorRow.Width/ 2), (float)resistorRow.Length, (float)resistorRow.Width);
        float orientation = 360 - (float)resistorRow.Orientation;
        PointF center = new PointF((float)resistorRow.CenterX, (float)resistorRow.CenterY);
        PointF[] points = CreatePolygon(rec, center, orientation);
        if (!Double.IsNaN(resistorRow.HiX) && !Double.IsNaN(resistorRow.HiY))
        {
            g.FillEllipse(myBrush, (float)resistorRow.HiX  - 2 , (float)resistorRow.HiY - 2, 4, 4);
            g.DrawLine(p, new PointF((float)resistorRow.HiX , (float)resistorRow.HiY ), center);
    }

    g.FillPolygon(myBrush, points);
}

} }

Update The zooming function, I know it is wrong but if anyone can help me fixing the logic or better Idea. 更新缩放功能,我知道这是错误的,但如果有人可以帮助我修复逻辑或更好的想法。

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        float oldZoom = _Zoom;
        _Zoom = zoomTrackPad.Value / 10f;

        int x = Math.Abs(Viewer.Width / 2 );
        int y = Math.Abs(Viewer.Height / 2 );

        int oldImageX = (int)(x / oldZoom);
        int oldImageY = (int)(y / oldZoom);

        int newImageX = (int)(x / _Zoom);
        int newImageY = (int)(y / _Zoom);

        _ImgX = newImageX - oldImageX + _ImgX;
        _ImgY = newImageY - oldImageY + _ImgY;

        Viewer.Invalidate();
    }

Thanks 谢谢

As you said, your logic for zooming is wrong. 正如你所说,你的缩放逻辑是错误的。 And it's wrong because of how transformation matrices work. 由于转换矩阵的工作方式,这是错误的。

Transformation matrices are appended one after other, in you case you are translating the image as if it where already scaled and then you zoom it, this will change the zoom origin and will not be centered. 转换矩阵是一个接一个地附加的,在这种情况下,您正在翻译图像,就像它已经缩放的那样,然后你缩放它,这将改变缩放原点而不会居中。

I'm going to assume some things here, if anything is wrong pelase comment. 我将在这里假设一些事情,如果有任何错误的pelase评论。

Suppose your visible area (panel size) is 100 * 100 pixels, and you want a "virtual" content size of 200 * 200 pixels. 假设您的可见区域(面板大小)为100 * 100像素,并且您希望“虚拟”内容大小为200 * 200像素。 I think you have two scrollbars to displace the content inside the panel, if you are just using the panel size and have no scrollbars then you should adapt how you calculate your displacement. 我认为你有两个滚动条来取代面板内的内容,如果你只是使用面板尺寸而没有滚动条,那么你应该调整计算位移的方式。

So, your scrollbars will range from 0 to (panel.(with/height) - content.(width/height)), in this case will range from 0 to 100. 因此,您的滚动条的范围从0到(面板。(带/高度) - 内容。(宽度/高度)),在这种情况下,范围从0到100。

Let's first do our content be centered at the start. 让我们首先将我们的内容集中在一开始。 To center it we apply a TranslateTransform to the Graphics object with the half of the size of our visible area less half of the size of the virtual area: 为了使它居中,我们将TranslateTransform应用于Graphics对象,其可见区域的一半大小减去虚拟区域大小的一半:

e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);

This will do the drawing to be centered, but,hey! 这将使绘图集中,但是,嘿! we're not using the positioning scrollbars! 我们没有使用定位滚动条!

Okokoko, let's apply those scrollbar offsets. Okokoko,让我们应用那些滚动条偏移量。 First, as we have our content centered, set the values of these scrollbars to the half of it's max value, in our example we should set those to 50. 首先,当我们将内容集中在一起时,将这些滚动条的值设置为其最大值的一半,在我们的示例中,我们应将它们设置为50。

Now, as we said, transformations are appended, so, nothing impedes you to add a new TranslateTransform. 现在,正如我们所说,转换是附加的,因此,没有什么阻碍您添加新的TranslateTransform。 You can do this in only one call, but for simplicity we are doing this in two calls (also, it will be better for applying zoom later). 你只能在一次调用中完成这项工作,但为了简单起见,我们在两次调用中执行此操作(此外,稍后应用缩放会更好)。

e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);
e.Graphics.TranslateTransform(hScrollBar1.Value - (hScrollbar1.Maximum / 2), vScrollBar1.Value - (vScrollbar1.Maximum / 2));

As you see we are subtracting half of it's max value, we already have our content centered so when the scrollbars are in the center we need to apply a translation of 0, we will range from -Maximum / 2 to Maximum / 2, in this example from -50 to 50. 如你所见,我们正在减去其最大值的一半,我们已经将内容集中在一起,所以当滚动条位于中心时我们需要应用0的平移,我们的范围从-Maximum / 2到Maximum / 2,在此示例从-50到50。

Well, we now have a virtual content area centered in our screen and we can displace on it, now we need to apply that zoom. 好吧,我们现在有一个虚拟内容区域位于屏幕中心,我们可以替换它,现在我们需要应用该缩放。

As I see you have an scrollbar, so let's follow our example using it. 我看到你有一个滚动条,所以让我们按照我们的例子使用它。

The ranging of the scrollbar would be your choice, I see you're using value / 10f, so if your scrollbar ranges from 1 to 100 you will have a zoom from 0.1 to 10, It's a good choice for start. 滚动条的范围将是您的选择,我看到您正在使用值/ 10f,因此如果您的滚动条范围从1到100,您将有0.1到10的缩放,这是一个很好的选择。

Now, lets set this scrollbar to 10, to initally have a unitary zoom. 现在,让我们将此滚动条设置为10,以初始进行单一缩放。

Now comes the interesting part, the transformations are applied in the order you set them, so it's not the same to apply a zoom before a translation than doing it after . 现在是有趣的部分,转换按照您设置的顺序应用,因此翻译之前应用缩放比在之后应用缩放不同。

In our case we first want to center the content, translate to the position we want to see (the scrollbars values) and then zoom. 在我们的例子中,我们首先想要将内容居中,转换到我们想要看到的位置(滚动条值),然后缩放。

e.Graphics.TranslateTransform(panel.With / 2 - content.Width / 2, panel.Height / 2 - content.Height / 2);
e.Graphics.TranslateTransform(hScrollBar1.Value - (hScrollbar1.Maximum / 2), vScrollBar1.Value - (vScrollbar1.Maximum / 2));
float scale = zScrollBar.Value / 10f;
e.Graphics.ScaleTransform(scale, scale);

Ok, it sounds good, but wait! 好的,听起来不错,但是等等! it will fail miserably. 它会悲惨地失败。 Why? 为什么? because when we zoom our virtual size is being also scaled up respect to the view area (panel size), so we need to apply this scale to the content size (and thus, to the scrollbar values): 因为当我们缩放时,我们的虚拟大小也会相对于视图区域(面板大小)进行放大,因此我们需要将此比例应用于内容大小(因此,应用于滚动条值):

float scale = zScrollBar.Value / 10f;
e.Graphics.TranslateTransform(panel.With / 2 - ((content.Width / 2) * scale), panel.Height / 2 - ((content.Height / 2) * scale));
e.Graphics.TranslateTransform((hScrollBar1.Value - (hScrollbar1.Maximum / 2)) * scale, (vScrollBar1.Value - (vScrollbar1.Maximum / 2)) * scale);
e.Graphics.ScaleTransform(scale, scale);

And finally we have a fully working virtual area where you can zoom and displace through it's bounds. 最后,我们有一个完全工作的虚拟区域,您可以通过它来缩放和移动它的边界。

I'm a bit rusty with graphics, so maybe some calculation is wrong, I hope not, in any case this will give you the general idea on how to do this. 我对图形有点生疏,所以也许有些计算是错误的,我希望不会,无论如何这会给你一般的想法如何做到这一点。

Cheers! 干杯!

PD: if you don't want to be able to displace the virtual area and just zoom on the center of your panel skip the second translate transform, also if you want to zoom in the current visible center of your virtual area just use the displacement (without scaling it, the transforms already have the logic for this) instead of the scrollbars values. PD:如果您不想替换虚拟区域并且只是缩放面板中心,请跳过第二个平移变换,如果您想放大虚拟区域的当前可见中心,也只需使用位移(没有缩放它,变换已经有了这个逻辑)而不是滚动条值。

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

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