2014-11-12 5 views
5

Ich kann keine Möglichkeit finden, das Bild in einer Windows Form-Schaltfläche zu skalieren. Unten sehen Sie, wie es mit dem Windows Form Designer aussieht, der auf DPI 200% angezeigt wird (Ich bin mir bewusst, dass der Windows Form Designer nur auf DPI 100%/96 verwendet werden sollte, dieser Screenshot zeigt nur meinen Punkt richtig).Wie skaliert man auf High-DPI das Bild einer Windows Form-Schaltfläche?

Während die Tastengröße richtig skaliert wird (34x33), wird das Bild in der Tastengröße nicht skaliert/gestreckt/gezoomt (es bleibt 16x16). Ich habe viele Versuch, dies zu lösen:

  • Die Steuer Eltern AutoScaleMode wird auf Font, es Dpi Einstellung nicht, diese Arbeit macht.
  • Die Einstellungstaste AutoSize auf true oder false funktioniert nicht.
  • Einstellung Schaltfläche oder übergeordnete Steuerelement AutoSizeMode auf einen Wert nicht funktioniert es.
  • gibt es keine Button.ImageLayout, die auf Stretch oder Zoom eingestellt werden konnte.
  • Mit der neuen App.Config Einstellung <add key="EnableWindowsFormsHighDpiAutoResizing" value="true" /> funktioniert es nicht.
  • Das Ändern der Taste FlatStyle oder ImageAlign funktioniert nicht.

Wie haben Sie das in Ihrer App gelöst?

Windows Form Button Image doesn't scale

+0

Sie suchen ein Pony zu fragen . Sie können den Code einfach hinzufügen, um die Bitmaps zu skalieren, die einzige Garantie, die Sie erhalten, ist, dass Sie die Art, wie sie aussieht, absolut nicht mögen. –

+0

Eine neue Bitmap erstellen und selbst skalieren ist die Hacky/Plan B Lösung. Dies ist die Kontrollverantwortung, um sein Image zu erweitern und hier möchte ich wirklich sicherstellen, dass ich keine saubere Lösung vermisse. –

+2

Das ist der geheimnisvolle Teil dieser Frage. Wenn Sie wissen, dass die Bitmap-Skalierung ein hässlicher Hack ist, warum sollten Sie dann eine Standard-.NET-Klasse verwenden? Diese "Verantwortung", die Sie erwarten, ist einfach nicht da. Das Verwalten von Assets für ein dpiAware-Programm ist Aufgabe eines Programmierers. Die Implementierung ist ziemlich trivial, aber Sie werden niemals Hilfe bekommen, solange Sie die Frage auf diese Weise stellen. –

Antwort

4

So trotz der MS Philosophie ist to go toward out-of-the-box stretched images for Windows Form Controls when high DPI, scheint es Bilder auf Knopf manuell werden müssen gestreckt. Natürlich wäre eine noch bessere Lösung, dass für jede Bitmap, die dem Benutzer (auf der Schaltfläche und überall sonst) angezeigt wird, mehrere Bitmaps definiert werden, die an 250% 200% 150% und 125% DPI angepasst sind. Hier

ist der Code:

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; 
    } 

Beachten Sie, dass eine zählbare von Einweg-Bitmaps erstellt zurückgegeben wird. Wenn Sie Bitmap auf Schaltflächen nicht deponieren möchten, müssen Sie sich nicht darum kümmern, gestreckte Bitmap zu entfernen.

Beachten Sie, dass wir ursprüngliche Schaltflächen Bitmaps entsorgen.

Beachten Sie unsere eigenen Mitglieder mit DPI zu beschäftigen: MultipliedByDPIRatio(this int), DPIRatioIsOne:bool, s_DPIRatio. Sie können Ihre eigenen schreiben, der knifflige Punkt ist, das tatsächliche DPI-Verhältnis zu erhalten. Um DPI-Verhältnis zu sammeln, ist der beste Weg, den ich fand, this one. Beachten Sie den Verweis auf den Blogpost Improving High-DPI support for Visual Studio 2013, wo das VS-Team erklärt, dass für ihren Symbolstil, dass das Bild zwischen gestreckt 200%, 100% [wird am besten erreicht mit Bicubic-Algorithmus und über oder gleich 200% , wird am besten mit einem Naiven Nearest-Neighbor-Algorithmus erreicht. Der vorgestellte Code spiegelt diese Auswahl wider.


Edit: Screenshot unten verschiedenen Interpolationsmodus bei 200% DPI, IMHO InterpolationMode.HighQualityBicubic ist besser als InterpolationMode.NearestNeighbor.

Interpolation mode

1

Hier ist ein bereit, auf die akzeptierte Antwort basierte Hilfsklasse zu verwenden, die Rückholung der DPI-Skala umfasst, und fügt die Unterstützung von PictureBox Bildskalierung:

public static class HighDpiHelper 
{ 
    public static void AdjustControlImagesDpiScale(Control container) 
    { 
     var dpiScale = GetDpiScale(container).Value; 
     if (CloseToOne(dpiScale)) 
      return; 

     AdjustControlImagesDpiScale(container.Controls, dpiScale); 
    } 

    private static void AdjustButtonImageDpiScale(ButtonBase button, float dpiScale) 
    { 
     var image = button.Image; 
     if (image == null) 
      return; 

     button.Image = ScaleImage(image, dpiScale); 
    } 

    private static void AdjustControlImagesDpiScale(Control.ControlCollection controls, float dpiScale) 
    { 
     foreach (Control control in controls) 
     { 
      var button = control as ButtonBase; 
      if (button != null) 
       AdjustButtonImageDpiScale(button, dpiScale); 
      else 
      { 
       var pictureBox = control as PictureBox; 
       if (pictureBox != null) 
        AdjustPictureBoxDpiScale(pictureBox, dpiScale); 
      } 

      AdjustControlImagesDpiScale(control.Controls, dpiScale); 
     } 
    } 

    private static void AdjustPictureBoxDpiScale(PictureBox pictureBox, float dpiScale) 
    { 
     var image = pictureBox.Image; 
     if (image == null) 
      return; 

     if (pictureBox.SizeMode == PictureBoxSizeMode.CenterImage) 
      pictureBox.Image = ScaleImage(pictureBox.Image, dpiScale); 
    } 

    private static bool CloseToOne(float dpiScale) 
    { 
     return Math.Abs(dpiScale - 1) < 0.001; 
    } 

    private static Lazy<float> GetDpiScale(Control control) 
    { 
     return new Lazy<float>(() => 
     { 
      using (var graphics = control.CreateGraphics()) 
       return graphics.DpiX/96.0f; 
     }); 
    } 

    private static Image ScaleImage(Image image, float dpiScale) 
    { 
     var newSize = ScaleSize(image.Size, dpiScale); 
     var newBitmap = new Bitmap(newSize.Width, newSize.Height); 

     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 (dpiScale >= 2.0f) 
       interpolationMode = InterpolationMode.NearestNeighbor; 

      g.InterpolationMode = interpolationMode; 
      g.DrawImage(image, new Rectangle(new Point(), newSize)); 
     } 

     return newBitmap; 
    } 

    private static Size ScaleSize(Size size, float scale) 
    { 
     return new Size((int)(size.Width * scale), (int)(size.Height * scale)); 
    } 
} 
Verwandte Themen