75

C# でフォーム アプリケーションを作成しています。モニターの DPI を変更すると、すべてのコントロールが移動します。コードを使用しましたthis.AutoScaleMode = AutoScaleMode.Dpiが、問題は回避されませんでした。

誰にもアイデアはありますか?

4

9 に答える 9

117

編集: .NET 4.7 の時点で、Windows フォームは高 DPI のサポートを改善しました。詳細については docs.microsoft.com を参照してください。ただし、Win 10 Creators Update 以降でのみ機能するため、ユーザー ベースによっては、まだこれを使用できない場合があります。


難しいですが、不可能ではありません。もちろん、最善の選択肢は WPF に移行することですが、それは現実的ではないかもしれません。

私はこの問題に多くの時間を費やしました。FlowLayoutPanel または TableLayoutPanel なしで正しく機能させるためのルール/ガイドラインを次に示します。

  • アプリを常にデフォルトの 96 DPI (100%) で編集/設計します。120DPI (125% f.ex) でデザインすると、後で作業するために 96 DPI に戻ったときに非常に悪くなります。
  • AutoScaleMode.Font を使用して成功しましたが、AutoScaleMode.DPI はあまり試していません。
  • すべてのコンテナー (フォーム、パネル、タブページ、ユーザーコントロールなど) でデフォルトのフォントサイズを使用していることを確認してください。8,25 ピクセル。コンテナー クラスの既定のフォントを使用するように、すべてのコンテナーの .Designer.cs ファイルにまったく設定しないことをお勧めします。
  • すべてのコンテナは同じAutoScaleModeを使用する必要があります
  • すべてのコンテナーに、Designer.cs ファイルで次の行が設定されていることを確認します。

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); // for design in 96 DPI

  • ラベル/テキストボックスなどに異なるフォントサイズを設定する必要がある場合は、コンテナクラスにフォントを設定するのではなく、コントロールごとに設定してください.winformsはコンテナのフォント設定を使用してコンテンツをスケーリングし、異なるフォントサイズのパネルをf.exに持つためです含まれているフォームよりも問題が発生することが保証されています。フォームとフォーム上のすべてのコンテナーが同じフォント サイズを使用している場合は機能する可能性がありますが、試したことはありません。
  • DPI 設定がより高い別のマシンまたは仮想 Windows インストール (VMware、Virtual PC、VirtualBox) を使用して、設計をすぐにテストします。DEV マシンの /bin/Debug フォルダーからコンパイル済みの .exe ファイルを実行するだけです。

特定のアンカーを使用してコントロールを配置し、フローパネルを使用しない場合でも、これらのガイドラインに従えば問題ないことを保証します。この方法で構築されたアプリを、さまざまな DPI 設定の数百台のマシンに展開しましたが、もはや不満はありません。すべてのフォーム/コンテナ/グリッド/ボタン/テキストフィールドなどのサイズは、フォントと同様に正しくスケーリングされます。画像も機能しますが、高 DPI では少しピクセル化される傾向があります。

編集: このリンクには、特に AutoScaleMode.DPI を使用することを選択した場合に、多くの良い情報があります:関連するスタックオーバーフローの質問へのリンク

于 2010-11-02T09:14:28.023 に答える
16

画面の向きと DPI 処理の両方の問題に対する解決策を最終的に見つけました。
Microsoft はすでにそれを説明するドキュメントを提供していますが、DPI 処理を完全に停止させる小さな欠陥があります。以下のドキュメントの「方向ごとに個別のレイアウト コードを作成する」の下にあるソリューションに従って ください http://msdn.microsoft.com/en-us/library/ms838174.aspx

それから重要な部分!それぞれの最後にある Landscape() および Portrait() メソッドのコード内に、次の行を追加します。

this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;

したがって、これら 2 つのメソッドのコードは次のようになります。

protected void Portrait()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(88, 216);
   this.crawlTime.Size = new System.Drawing.Size(136, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(10, 216);
   this.crawlTimeLabel.Size = new System.Drawing.Size(64, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(88, 200);
   this.crawlStartTime.Size = new System.Drawing.Size(136, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(10, 200);
   this.crawlStartedLabel.Size = new System.Drawing.Size(64, 16);
   this.light1.Location = new System.Drawing.Point(208, 66);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(192, 66);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(88, 182);
   this.linkCount.Size = new System.Drawing.Size(136, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(10, 182);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 84);
   this.currentPageBox.Size = new System.Drawing.Size(214, 90);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 68);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(214, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(10, 48);
   this.noProxyCheck.Size = new System.Drawing.Size(214, 20);
   this.startButton.Location = new System.Drawing.Point(8, 240);
   this.startButton.Size = new System.Drawing.Size(216, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 24);
   this.addressBox.Size = new System.Drawing.Size(214, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

protected void Landscape()
{
   this.SuspendLayout();
   this.crawlTime.Location = new System.Drawing.Point(216, 136);
   this.crawlTime.Size = new System.Drawing.Size(96, 16);
   this.crawlTimeLabel.Location = new System.Drawing.Point(160, 136);
   this.crawlTimeLabel.Size = new System.Drawing.Size(48, 16);
   this.crawlStartTime.Location = new System.Drawing.Point(64, 120);
   this.crawlStartTime.Size = new System.Drawing.Size(248, 16);
   this.crawlStartedLabel.Location = new System.Drawing.Point(8, 120);
   this.crawlStartedLabel.Size = new System.Drawing.Size(48, 16);
   this.light1.Location = new System.Drawing.Point(296, 48);
   this.light1.Size = new System.Drawing.Size(16, 16);
   this.light0.Location = new System.Drawing.Point(280, 48);
   this.light0.Size = new System.Drawing.Size(16, 16);
   this.linkCount.Location = new System.Drawing.Point(80, 136);
   this.linkCount.Size = new System.Drawing.Size(72, 16);
   this.linkCountLabel.Location = new System.Drawing.Point(8, 136);
   this.linkCountLabel.Size = new System.Drawing.Size(64, 16);
   this.currentPageBox.Location = new System.Drawing.Point(10, 64);
   this.currentPageBox.Size = new System.Drawing.Size(302, 48);
   this.currentPageLabel.Location = new System.Drawing.Point(10, 48);
   this.currentPageLabel.Size = new System.Drawing.Size(100, 16);
   this.addressLabel.Location = new System.Drawing.Point(10, 4);
   this.addressLabel.Size = new System.Drawing.Size(50, 16);
   this.noProxyCheck.Location = new System.Drawing.Point(168, 16);
   this.noProxyCheck.Size = new System.Drawing.Size(152, 24);
   this.startButton.Location = new System.Drawing.Point(8, 160);
   this.startButton.Size = new System.Drawing.Size(304, 20);
   this.addressBox.Location = new System.Drawing.Point(10, 20);
   this.addressBox.Size = new System.Drawing.Size(150, 22);

   //note! USING JUST AUTOSCALEMODE WILL NOT SOLVE ISSUE. MUST USE BOTH!
   this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); //IMPORTANT
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;   //IMPORTANT
   this.ResumeLayout(false);
}

私にとって魅力のように機能します。

于 2012-04-12T22:59:43.540 に答える
5

これはWindowsの問題のようです。これらの2行を取り出すと、すべてが修正されました。

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

これが私が解決策を得た場所です:

于 2017-03-30T19:31:20.590 に答える
4

Windows フォームで DPI 対応アプリケーションを設計するのは非常に困難です。DPI が変更されたときに適切にサイズ変更されるレイアウト コンテナー (TableLayoutPanel や FlowLayoutPanel など) を使用する必要があります。すべてのコントロールのサイズも変更する必要があります。これらのコンテナーの構成は難しい場合があります。

単純なアプリケーションの場合は妥当な時間内に実行できますが、大規模なアプリケーションの場合は非常に多くの作業が必要になります。

于 2010-11-02T08:08:30.860 に答える
3

経験から:

  • 重要でない限り、Windows フォームで DPI 認識を使用しないでください。
  • この目的のために、常にアプリ内のすべてのフォームとユーザー コントロールでAutoScaleModeプロパティをに設定しますNone
  • 結果: DPI 設定が変更されたときのインターフェイスの WYSIWYG タイプ
于 2010-11-02T08:53:44.987 に答える
-1

Winform アプリケーション フォームはコンテンツ コントロールと画像を含む可能性があるため、システムがウィンドウのサイズを変更できるようにすることは解決策ではありませんが、適切にスケーリングされた画像を使用して、DPI 解像度ごとに 1 つのフォームを持つことができれば...それは良い考えではありません。画面サイズが大きくなるにつれて、フォントサイズが小さくなるためです。

異なる DPI 解像度を使用する場合、システムはフォームにそのコントロールのサイズ、位置、およびフォントを強制的に再定義させますが、画像ではありません。解決策は、ロード時に実行時にフォームの DPI を変更して、すべてが元のサイズと位置に戻るようにすることです。

これは可能な解決策であり、80個の画像ボタン、TabControlsなどを持っているカードゲームアプリケーションでテストしました.

各フォームの form_Load イベントで、次のコード スニペットを追加します。

  Dim dpi As Graphics = Me.CreateGraphics
    Select Case dpi.DpiX
        Case 120
            '-- Do nothing if your app has been desigbned with 120 dpi
        Case Else
    '-- I use 125 AND NOT 120 because 120 is 25% more than 96
            Me.Font = New Font(Me.Font.FontFamily, Me.Font.Size * 125 / dpi.DpiX)
    End Select

さらに、再起動せずに同じコンピューターでさまざまな解像度をテストするための簡単なトリック:

コントロール パネルから、解像度を変更します。再起動しないでください!代わりに、セッションを閉じて、同じユーザーで新しいセッションを開きます。

別の注意点があります。実行時にコントロールのサイズと位置を設定する場合は、同じ DPI 係数 (例: 125 / Dpi.Dpix) を新しい座標に適用する必要があります。したがって、application.startup イベントから DPIFactor グローバル変数を設定することをお勧めします。

最後だが大事なことは:

元の解像度とは別の解像度から Visual Studio でアプリケーションを開かないでください。そうしないと、各フォームを開くたびにすべてのコントロールが移動してサイズが変更され、戻る方法がありません...

これが役に立てば幸いです、幸せなプログラミング。

于 2010-12-30T16:33:18.220 に答える