winforms – 如何在高DPI上扩展Windows窗体按钮的图像?

我找不到在Windows窗体按钮中缩放图像的方法.请参阅下面DPI 200%上显示的Windows窗体设计器的样子(我知道Windows窗体设计器应仅用于DPI 100%/ 96,此屏幕截图只是说明了我的观点).

当按钮大小正确缩放(34×33)时,按钮大小中的图像不会缩放/拉伸/缩放(它仍然是16×16).我做了很多尝试来解决这个问题:

>父控件AutoScaleMode设置为Font,将其设置为Dpi不会使其工作.
>将AutoSize设置按钮设置为true或false不会使其正常工作.
>将按钮或父controlAutoSizeMode设置为任何值都不起作用.
>没有可以设置为拉伸或缩放的Button.ImageLayout.
>使用新的App.Config设置< add key =“EnableWindowsFormsHighDpiAutoResizing”value =“true”/>不起作用.
>更改按钮FlatStyle或ImageAlign不起作用.

你是如何在你的应用中解决这个问题的?

最佳答案
因此,尽管MS哲学是to go toward out-of-the-box stretched images for Windows Form Controls when high DPI,但看起来Button上的图像需要手动拉伸.当然,更好的解决方案是,对于向用户显示的每个位图(在按钮上和其他地方),定义适合250%200%150%和125%DPI的几个位图.

这是代码:

  public static IEnumerable<IDisposable> AdjustControlsThroughDPI(this Control.ControlCollection controls) {
     Debug.Assert(controls != null);
     if (DPIRatioIsOne) {
        return new IDisposable[0]; // No need to adjust on DPI One
     }

     var list = new List<IDisposable>();
     foreach (Control control in controls) {
        if (control == null) { continue; }

        var button = control as ButtonBase;
        if (button != null) {
           button.AdjustControlsThroughDPI(list);
           continue;
        }

        // Here more controls tahn button can be adjusted if needed...

        // Recursive
        var nestedControls = control.Controls;
        Debug.Assert(nestedControls != null);
        if (nestedControls.Count == 0) { continue; }
        var disposables = nestedControls.AdjustControlsThroughDPI();
        list.AddRange(disposables);
     }
     return list;
  }

  private static void AdjustControlsThroughDPI(this ButtonBase button, IList<IDisposable> list) {
     Debug.Assert(button != null);
     Debug.Assert(list != null);
     var image = button.Image;
     if (image == null) { return; }

     var imageStretched = image.GetImageStretchedDPI();
     button.Image = imageStretched;
     list.Add(imageStretched);
  }


  private static Image GetImageStretchedDPI(this Image imageIn) {
     Debug.Assert(imageIn != null);

     var newWidth = imageIn.Width.MultipliedByDPIRatio();
     var newHeight = imageIn.Height.MultipliedByDPIRatio();
     var newBitmap = new Bitmap(newWidth, newHeight);

     using (var g = Graphics.FromImage(newBitmap)) {
        // According to this blog post http://blogs.msdn.com/b/visualstudio/archive/2014/03/19/improving-high-dpi-support-for-visual-studio-2013.aspx
        // NearestNeighbor is more adapted for 200% and 200%+ DPI
        var interpolationMode = InterpolationMode.HighQualityBicubic;
        if (s_DPIRatio >= 2.0f) {
           interpolationMode = InterpolationMode.NearestNeighbor;
        }
        g.InterpolationMode = interpolationMode;
        g.DrawImage(imageIn, new Rectangle(0, 0, newWidth, newHeight));
     }

     imageIn.Dispose();
     return newBitmap;
  }

请注意,返回了创建的可枚举的一次性位图.如果您不关心在按钮上处理位图,则不必关心处理拉伸位图.

请注意我们处理原始按钮位图.

注意我们自己的成员来处理DPI:MultipliedByDPIRatio(this int),DPIRatioIsOne:bool,s_DPIRatio.你可以写自己的,棘手的一点是获得实际的DPI比率.为了收集DPI比率,我找到的最好的方法是this one.

请注意对博客文章Improving High-DPI support for Visual Studio 2013的引用,其中VS团队解释说,对于他们的图标样式,他们确定图像延伸到200%,100%[最好用Bicubic算法实现,并且高于或等于200%,最好实现与朴素最近邻算法.提供的代码反映了这些选择.

编辑:在200%DPI下的各种插值模式的屏幕截图下,IMHO InterpolationMode.HighQualityBicubic优于InterpolationMode.NearestNeighbor.

转载注明原文:winforms – 如何在高DPI上扩展Windows窗体按钮的图像? - 代码日志