我也回答过很多次这种帖子,也做出来过半成品的左上角缩放的代码。但是都不完美。
今天又看到一个4k屏觉得窗体小的,我当时的感觉是“妈的!有钱人!开发都4k屏了!!!”,但是这让我想,能不能从根本上想个办法解决缩放的问题呢?
所以我就想到了最初写的那篇左上角缩放的代码,我在想不完美的地方在哪里?
看看图,可以看出由于原点坐标的错位,导致缩放后的控件头部偏移了。
这就产生了现在的解决方案:重新定位原点缩放控件(窗口)。
所以使用了最简单的方法,将整个控件(是的窗体也是控件)的中心点作为原点,利用现有坐标重新求出子控件坐标集合。
并且将子空间的大小重新用和父控件坐标比的形式计算。(我总觉得用不着,不过我觉得在有些特殊比例的时候这样做一下似乎比直接缩放会多一点兼容性。)
重新计算全部子控件的位置和大小,最后改变控件本身大小。
做完试了一下,效果不错,不过缩小的时候有几率把子控件丢到控件显示范围外,我并没有修复这个bug。
好啦下面是代码,我注释写的也比较详细,有相关需要的人可以直接拿去用了。
代码写得很烂,很多比如结构化那里,我本来是用的系统 Point 和 Size 但是因为int不能满足缩放计算的各种需求所以就用了很多c#自动生成的部分,代码中变量的生命周期我也没有做任何规划,这些都可以完善,拿个半成品玩具出来,给大家开拓点思维吧。
当然这不完善的地方还有很多,比如不支持非控件的调整等。我回头有时间开个GitHub坑好了。
private void ZoomEX(System.Windows.Forms.Control c, int Zoom)
{
//求出相对中心
System.Drawing.Point p0 = new System.Drawing.Point(c.Width / 2, c.Height / 2);
//获取控件列表,计算控件距离中心位置得出相对坐标。
System.Collections.Generic.LinkedList<ControlEx> Controls
= new System.Collections.Generic.LinkedList<ControlEx>();
foreach (System.Windows.Forms.Control item in c.Controls)
{
//查看该控件是否有子控件,如果有,便利子控件自调用本方法
if (item.HasChildren)
{
ZoomEX(item, Zoom);
}
ControlEx itemEx = new ControlEx(item);
itemEx.ExPoint = new ControlEx.exPoint(((float)item.Left - (float)p0.X) / (float)c.Width, ((float)item.Top - (float)p0.Y) / (float)c.Height);
itemEx.ExSize = new ControlEx.exSize((float)item.Width / (float)c.Width, (float)item.Height / (float)c.Height);
Controls.AddLast(itemEx);
}
//控件根据zoom重新缩放
System.Drawing.Size newSize = new System.Drawing.Size(c.Width * Zoom / 10, c.Height * Zoom / 10);
//求出新的相对中心
System.Drawing.Point pNew = new System.Drawing.Point(newSize.Width / 2, newSize.Height / 2);
//对每一个控件重新生成坐标
foreach (ControlEx item in Controls)
{
item.Control.Size = new System.Drawing.Size((int)(item.ExSize.Width * newSize.Width), (int)(item.ExSize.Height * newSize.Height));
item.Control.Location = new System.Drawing.Point((int)(item.ExPoint.X * newSize.Width + pNew.X), (int)(item.ExPoint.Y * newSize.Height + pNew.Y));
}
c.Size = newSize;//重置控件本身大小
}
class ControlEx
{
public System.Windows.Forms.Control Control { get; set; }
public ControlEx(System.Windows.Forms.Control c)
{
Control = c;
}
public exPoint ExPoint { get; set; }
public exSize ExSize { get; set; }
public class exPoint
{
public float X;
public float Y;
public exPoint(float x, float y)
{
// TODO: Complete member initialization
this.X = x;
this.Y = y;
}
}
public class exSize {
public exSize(float p1, float p2)
{
// TODO: Complete member initialization
this.Width = p1;
this.Height = p2;
}
public float Width { get; set; }
public float Height { get; set; }
}
}
//窗体使用 ZoomEX(this, 5); 实现缩放,1.0
24 个解决方案
#1
厚脸皮求@hanjun0612 推荐
厚脸皮无视错别字指责
厚脸皮无视错别字指责
#2
可以让大家一起讨论。
多种方案和方案的优劣。
多种方案和方案的优劣。
#3
这就是个已经上车的补票方案,当然没有什么优秀的,不过就是不用重构代码了。
#4
用wpf吧,winforms依赖win32 api渲染,总有一些没法缩放,看着怪怪的。
#5
只缩不放?没搞错吧!
#6
20不就放大了嘛…………注释写的不对,10是本大小,10~0是0.x缩小,放大倍数就高了,10~intmax是/10的等比放大。
#7
是的这段代码就是给标准winform在不得已的时候用来中心缩放的。
#8
#9
winform 就是有这个问题,他跟 分辨率 DPI 等等 都有关系 。如果你想根据分辨率来动态调整的话可以根据屏幕的分辨率解决方案来动态调整 。之前QQ 有个版本就是这么做的。
#10
是啊,要么换wpf、DirectX 一类并不基于Gui/Gui+的界面中间件,要么用web渲染加个nwjs、Electron 这样的中间件托起来。
但是有些远古项目非要缩放有了这段代码就能好很多,毕竟你不可能重构整个项目,有个方便的缩放类能解决太多问题。
#11
X、Y 同比例缩放显然不能适应不同规格的屏幕需要
非要让喜欢 winform 的人换用 wpf 岂不比美国佬还霸道?
非要让喜欢 winform 的人换用 wpf 岂不比美国佬还霸道?
#12
不等比缩放就拉变形了,这个也可以做,但是效果肯定就更不能保证了,我也就抛个砖,往认真里看我字体大小也没缩放呢。
#13
字体大小也没缩放 那只是下一步要求
既然拿出来展示,就不要怕人家提意见
能在 OnResize 事件中正常表现才是有用的
既然拿出来展示,就不要怕人家提意见
能在 OnResize 事件中正常表现才是有用的
#14
你可能想错这个东西的用处了,这是用在那种老程序做的窗体在现在的分辨率下窗体过小需要放大用的,顺带兼容了一下缩小 到1/10的比例。
这并不是在窗体改变大小时自动布局用的东西。
这东西就是我已经有一套系统正常运行有,有一天换了高分辨率显示器,原有程序变得太小了不方便操作,引入这个可以做个简单的等比缩放不用再一一修改窗体大小了。
拖放自动布局的东西是需要重新想一套类似web的渲染方式的。那个不是这么点小代码就能实现的。
#15
我觉得是昨天发帖的时候名称没取好导致的误解
“窗体/控件 等比缩放子控件不偏移 ” 这个名称更合适这套代码,麻烦版主帮忙改个名。
#16
感觉真的不错哦
#17
#18
#19
版主展示的这个有问题啊
#20
那只是动画截图软件的问题,实际并不是不是那样
但手动迎合截屏实在是困难了点,见谅
但手动迎合截屏实在是困难了点,见谅
#21
#22
按照比例的那种缩放吗?
#23
怎么没见缩小啊
#24
从来没有遇见这个问题
#1
厚脸皮求@hanjun0612 推荐
厚脸皮无视错别字指责
厚脸皮无视错别字指责
#2
可以让大家一起讨论。
多种方案和方案的优劣。
多种方案和方案的优劣。
#3
这就是个已经上车的补票方案,当然没有什么优秀的,不过就是不用重构代码了。
#4
用wpf吧,winforms依赖win32 api渲染,总有一些没法缩放,看着怪怪的。
#5
只缩不放?没搞错吧!
#6
20不就放大了嘛…………注释写的不对,10是本大小,10~0是0.x缩小,放大倍数就高了,10~intmax是/10的等比放大。
#7
是的这段代码就是给标准winform在不得已的时候用来中心缩放的。
#8
#9
winform 就是有这个问题,他跟 分辨率 DPI 等等 都有关系 。如果你想根据分辨率来动态调整的话可以根据屏幕的分辨率解决方案来动态调整 。之前QQ 有个版本就是这么做的。
#10
是啊,要么换wpf、DirectX 一类并不基于Gui/Gui+的界面中间件,要么用web渲染加个nwjs、Electron 这样的中间件托起来。
但是有些远古项目非要缩放有了这段代码就能好很多,毕竟你不可能重构整个项目,有个方便的缩放类能解决太多问题。
#11
X、Y 同比例缩放显然不能适应不同规格的屏幕需要
非要让喜欢 winform 的人换用 wpf 岂不比美国佬还霸道?
非要让喜欢 winform 的人换用 wpf 岂不比美国佬还霸道?
#12
不等比缩放就拉变形了,这个也可以做,但是效果肯定就更不能保证了,我也就抛个砖,往认真里看我字体大小也没缩放呢。
#13
字体大小也没缩放 那只是下一步要求
既然拿出来展示,就不要怕人家提意见
能在 OnResize 事件中正常表现才是有用的
既然拿出来展示,就不要怕人家提意见
能在 OnResize 事件中正常表现才是有用的
#14
你可能想错这个东西的用处了,这是用在那种老程序做的窗体在现在的分辨率下窗体过小需要放大用的,顺带兼容了一下缩小 到1/10的比例。
这并不是在窗体改变大小时自动布局用的东西。
这东西就是我已经有一套系统正常运行有,有一天换了高分辨率显示器,原有程序变得太小了不方便操作,引入这个可以做个简单的等比缩放不用再一一修改窗体大小了。
拖放自动布局的东西是需要重新想一套类似web的渲染方式的。那个不是这么点小代码就能实现的。
#15
我觉得是昨天发帖的时候名称没取好导致的误解
“窗体/控件 等比缩放子控件不偏移 ” 这个名称更合适这套代码,麻烦版主帮忙改个名。
#16
感觉真的不错哦
#17
#18
#19
版主展示的这个有问题啊
#20
那只是动画截图软件的问题,实际并不是不是那样
但手动迎合截屏实在是困难了点,见谅
但手动迎合截屏实在是困难了点,见谅
#21
#22
按照比例的那种缩放吗?
#23
怎么没见缩小啊
#24
从来没有遇见这个问题