У меня есть приложение формы в С#. Когда я меняю монитор DPI, все элементы управления перемещаются.
Я использовал код this.AutoScaleMode = AutoScaleMode.Dpi
, но это не устранило проблему.
Есть ли у кого-нибудь идеи?
У меня есть приложение формы в С#. Когда я меняю монитор DPI, все элементы управления перемещаются.
Я использовал код this.AutoScaleMode = AutoScaleMode.Dpi
, но это не устранило проблему.
Есть ли у кого-нибудь идеи?
EDIT: с.NET 4.7 в формах окон улучшена поддержка High DPI. Подробнее об этом см. На docs.microsoft.com. Он работает только для Windows 10 Creators Update и выше, поэтому, возможно, нецелесообразно использовать это, но в зависимости от вашей пользовательской базы.
Трудно, но не невозможно. Ваш лучший вариант - переходить в WPF, но это может оказаться невыполнимым.
Я потратил много времени на эту проблему. Вот несколько правил/рекомендаций, чтобы заставить его работать правильно без FlowLayoutPanel или TableLayoutPanel:
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);//for design in 96 DPI
Я гарантирую, что если вы будете следовать этим рекомендациям, вы будете в порядке, даже если вы разместили элементы управления с конкретными якорями и не используете поточную панель. У нас есть приложение, построенное таким образом, развернутое на сотнях машин с разными настройками DPI, и у нас больше нет никаких жалоб. Все формы/контейнеры/сетки/кнопки/текстовое поле и т.д. Размеры масштабируются правильно, как и шрифт. Изображения тоже работают, но они, как правило, немного пикселируются при высоком DPI.
EDIT: эта ссылка содержит много полезной информации, особенно если вы решите использовать AutoScaleMode.DPI: fooobar.com/questions/95421/...
Наконец-то я нашел решение проблемы как ориентации экрана, так и обработки 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;
Итак, код для этих двух методов будет выглядеть следующим образом:
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);
}
Работает как очарование для меня.
примечание: это не исправит перемещение элементов управления при изменении dpi. это только исправит размытый текст !!.
Как исправить размытые Windows Forms в настройках с высоким разрешением:
Теперь перейдите в Program.cs (или в файл, где находится ваш метод Main) и измените его так:
namespace myApplication
{
static class Program
{
[STAThread]
static void Main()
{
// ***this line is added***
if (Environment.OSVersion.Version.Major >= 6)
SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
// ***also dllimport of that function***
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
}
}
Сохраните и скомпилируйте. Теперь ваша форма снова должна выглядеть хрустящей.
источник:http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/
Похоже, что это проблема с Windows. Вынимая эти две линии, все фиксировалось.
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Вот где я получил решение:
В Windows Forms действительно сложно создавать приложения с поддержкой DPI. Вам нужно будет использовать макеты компоновки, которые будут правильно изменяться при изменении DPI (например, TableLayoutPanel или FlowLayoutPanel). Все элементы управления также нуждаются в изменении размера. Конфигурация этих контейнеров может быть проблемой.
Для простых приложений это можно сделать в течение разумного промежутка времени, но для больших приложений это действительно много работы.
Из опыта:
AutoScaleMode
в None
для всех форм и пользовательских элементов управления в вашем приложении.Функция ScaleByDPI получит параметр Control, который обычно является формой, а не рекурсивно итерации через все вспомогательные элементы управления (if (control.HasChildren == true)), а также расположение и размеры шкалы от ваших элементов управления приложениями, а также размеры и размеры шрифты к настроенному ОС DPI. Вы можете попытаться реализовать его также для изображений, значков и графики.
Специальные примечания для функции ScaleByDPI:
а. Для всех элементов управления с размерами шрифта по умолчанию вам необходимо установить их Font.Size в 8.25.
б. Вы можете получить значения devicePixelRatioX и devicePixelRatioY (control.CreateGraphics().DpiX/96) и (control.CreateGraphics(). DpiY/96).
с. Вам понадобится масштаб Control.Size и Control.Location с помощью алгоритма, основанного на control.Dock и control.Anchor. Следует заметить, что control.Dock может иметь 1 из 6 возможных значений и что control.Anchor может иметь 1 из 16 возможных значений.
д. этот алгоритм будет иметь заданные значения для следующих переменных bool isDoSizeWidth, isDoSizeHeight, isDoLocationX, isDoLocationY, isDoRefactorSizeWidth, isDoRefactorSizeHeight, isDoRefactorLocationX, isDoRefactorLocationY, isDoClacLocationXBasedOnRight, isDoClacLocationYBasedOnBottom.
е. Если ваш проект использует библиотеку управления, отличную от Microsoft, для этого элемента управления может потребоваться специальное лечение.
Дополнительная информация о выше (d.) переменные bool:
* Иногда группа элементов управления (может быть кнопками) должна быть помещена одна за другой на одну и ту же вертикальную линию, а их значение Якоря включает в себя правое, но не левое, или их нужно размещать один за другим на одной горизонтальной линии, а их значение Anchor включает Bottom, но не Top, в этом случае вам нужно перерасчитать элементы управления. Значения местоположения.
* В случае элементов управления, в которых Anchor содержит верхние и нижние и\или левые и правые, вам нужно будет изменить параметры элементов управления Size и Location.
Использование функции ScaleByDPI:
а. Добавьте следующую команду в конец любого конструктора формы: ScaleByDPI (this);
б. Также при динамическом добавлении какого-либо элемента управления к вызову формы ScaleByDPI ([ControlName]).
Когда вы устанавливаете размер или местоположение любого элемента управления динамически после завершения конструктора, создайте и используйте одну из следующих функций, чтобы получить масштабированные значения размера или местоположения: ScaleByDPI_X\ScaleByDPI_Y\ScaleByDPI_Size\ScaleByDPI_Point
Чтобы отметить ваше приложение как средство DPI, добавьте элемент dpiAware в манифест сборки приложения.
Установите GraphicsUnit для всех Control.Font в System.Drawing.GraphicsUnit.Point
В файлах *.Designer.cs всех контейнеров установите значение AutoScaleMode в System.Windows.Forms.AutoScaleMode.None
в элементах управления, таких как ComboBox и TextBox, изменение Control.Size.Hieght не влияет. В этом случае изменение Control.Font.Size будет определять высоту управления.
Если форма StartPosition имеет значение FormStartPosition.CenterScreen, вам нужно будет пересчитать местоположение окна.
Поскольку форма заявки Winform может содержать элементы управления контентом и изображения, что позволяет изменять размер вашего ВАШЕГО окна, НЕ является решением, но если вы могли бы иметь одну форму в разрешении DPI, с правильно масштабированными изображениями... И это не хорошая идея, так как при увеличении размера экрана размер шрифта уменьшается.
При использовании другого разрешения 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) к новым координатам. Поэтому вам лучше настроить глобальную переменную DPIFactor из события application.startup.
И последнее, но не менее важное:
НЕ открывайте приложение в Visual Studio из другого разрешения, кроме оригинального, или ВСЕ ВАШИ УПРАВЛЕНИЯ будут перемещаться и изменять размер при открытии каждой формы, и нет пути назад...
Надеюсь, это поможет, счастливое программирование.