Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display scaling and size of forms and controls

Tags:

winforms

On my desktop I have a default display scaling factor of 100%. When I create a simple application with form size of 400x200 and with 3 pictureboxes of size 75x23 it displays as expected (Image 1).

Image 1

When I run the program on a laptop with display scaling factor of 125% it does not display as expected (Image 2).

Image 2

The form is out of ratio. It now is 530x244, width is 1.33x400, height is 1.22x200.

The red picturebox is out of ratio too, it is 100x28. The horizontal size is 1.33x75, the vertical size is 1.25x23.

The sizes of the green and blue pictureboxes are set in code.

public Form1()
{
  InitializeComponent();

  double factor = CreateGraphics().DpiX / 96f;
  pictureBox2.Size = new Size((int)(75 * factor), (int)(23 * factor));

  pictureBox3.Size = new Size(75, 23);


  label1.Text = String.Format("Form:{0}-{1}  DpiX:{2}  DpiY:{3}",
    this.Size.Width,
    this.Size.Height,
    CreateGraphics().DpiX,
    CreateGraphics().DpiY
    );

  label2.Text = String.Format("{0}-{1}", pictureBox1.Size.Width, pictureBox1.Size.Height);
  label3.Text = String.Format("{0}-{1}", pictureBox2.Size.Width, pictureBox2.Size.Height);
  label4.Text = String.Format("{0}-{1}", pictureBox3.Size.Width, pictureBox3.Size.Height);
}

The form and picturebox are initially sized in the InitializeComponent function.

          private void InitializeComponent()
{
  this.label1 = new System.Windows.Forms.Label();
  this.pictureBox1 = new System.Windows.Forms.PictureBox();
  this.pictureBox2 = new System.Windows.Forms.PictureBox();
  this.pictureBox3 = new System.Windows.Forms.PictureBox();
  this.label2 = new System.Windows.Forms.Label();
  this.label3 = new System.Windows.Forms.Label();
  this.label4 = new System.Windows.Forms.Label();
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
  this.SuspendLayout();
  // 
  // label1
  // 
  this.label1.AutoSize = true;
  this.label1.Location = new System.Drawing.Point(12, 9);
  this.label1.Name = "label1";
  this.label1.Size = new System.Drawing.Size(35, 13);
  this.label1.TabIndex = 0;
  this.label1.Text = "label1";
  // 
  // pictureBox1
  // 
  this.pictureBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
  this.pictureBox1.Location = new System.Drawing.Point(14, 32);
  this.pictureBox1.Name = "pictureBox1";
  this.pictureBox1.Size = new System.Drawing.Size(75, 23);
  this.pictureBox1.TabIndex = 8;
  this.pictureBox1.TabStop = false;
  // 
  // pictureBox2
  // 
  this.pictureBox2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
  this.pictureBox2.Location = new System.Drawing.Point(14, 61);
  this.pictureBox2.Name = "pictureBox2";
  this.pictureBox2.Size = new System.Drawing.Size(75, 23);
  this.pictureBox2.TabIndex = 11;
  this.pictureBox2.TabStop = false;
  // 
  // pictureBox3
  // 
  this.pictureBox3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
  this.pictureBox3.Location = new System.Drawing.Point(14, 90);
  this.pictureBox3.Name = "pictureBox3";
  this.pictureBox3.Size = new System.Drawing.Size(75, 23);
  this.pictureBox3.TabIndex = 15;
  this.pictureBox3.TabStop = false;
  // 
  // label2
  // 
  this.label2.AutoSize = true;
  this.label2.Location = new System.Drawing.Point(96, 41);
  this.label2.Name = "label2";
  this.label2.Size = new System.Drawing.Size(35, 13);
  this.label2.TabIndex = 16;
  this.label2.Text = "label2";
  // 
  // label3
  // 
  this.label3.AutoSize = true;
  this.label3.Location = new System.Drawing.Point(96, 71);
  this.label3.Name = "label3";
  this.label3.Size = new System.Drawing.Size(35, 13);
  this.label3.TabIndex = 17;
  this.label3.Text = "label3";
  // 
  // label4
  // 
  this.label4.AutoSize = true;
  this.label4.Location = new System.Drawing.Point(96, 100);
  this.label4.Name = "label4";
  this.label4.Size = new System.Drawing.Size(35, 13);
  this.label4.TabIndex = 18;
  this.label4.Text = "label4";
  // 
  // Form1
  // 
  this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  this.AutoScroll = true;
  this.ClientSize = new System.Drawing.Size(384, 162);
  this.Controls.Add(this.label4);
  this.Controls.Add(this.label3);
  this.Controls.Add(this.label2);
  this.Controls.Add(this.pictureBox3);
  this.Controls.Add(this.pictureBox2);
  this.Controls.Add(this.pictureBox1);
  this.Controls.Add(this.label1);
  this.Name = "Form1";
  this.Text = "Form1";
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
  ((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit();
  this.ResumeLayout(false);
  this.PerformLayout();

}

#endregion

private System.Windows.Forms.Label label1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.PictureBox pictureBox2;
private System.Windows.Forms.PictureBox pictureBox3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label4;

}

When scaling is set to 100%, DpiX will be 96f. When set to 125%, DpiX will be 120f. The green picture box uses the factor for scaling, size is 93x28, as expected (75*120/96=93 and 23*120/96=28). For reference the blue picture box shows the original size of 75x23.

Can someone help me to explain why the form and the red picture box are out of designed ratio? How can the factors 1.33 and 1.22 be explained?

like image 803
Arjen Avatar asked Nov 15 '25 15:11

Arjen


1 Answers

 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

That is a wise choice. Note the alternative selection for the AutoScaleMode property, you can also pick AutoScaleMode.Dpi. Which is what you hoped would happen.

But it didn't, the auto-scaling you got for the Form and pictureBox1 is based on AutoScaleMode.Font. What is hard to see, but you can notice if you look closely, is that you did not get the same font in the second screenshot. The default setting is "Microsoft Sans Serif", it is retired on newer Windows versions and you get a substitute. Should be Segoe. Part of the mechanics in Windows that makes old UI designs look fresh on a newer OS version. Note how its average character width is quite a bit higher. It compensated for that, which is why you got 1.33 instead of 1.25

You can pick AutoScaleMode.Dpi and then you'll get numbers you like. But at the risk that text no longer fits the controls. Consider making it more predictable with a font that available on both machines, like Tahoma.

You got 1.22 because the form auto-scales its ClientSize property, not Size. The border size is the same so the overall size increase is less than 1.25. Can be more drastically different if the user modifies his theme to display bigger caption text and buttons. Only ClientSize matters, that is the important property that ensures that window content fits.

Do watch out for your use of CreateGraphics(), it has too many side-effects. This method can only work by first creating the native window. That causes the autoscaling to take effect, much earlier than normally happens. So you are modifying sizes that were already rescaled, significantly adding to the confusion. A safer version here is Graphics.FromHwnd(IntPtr.Zero), now you can tinker with sizes using the original design metrics, at least up until the Load event fires.

like image 181
Hans Passant Avatar answered Nov 18 '25 21:11

Hans Passant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!