C#学习教程:自动缩放但仍处理WM_DPICHANGED我希望应用程序在DPI更改时让Windows自动缩放,但我仍然需要挂钩WM_DPICHANGED事件以缩放一些自定义绘制的文本。困境是,如果我让应用程序DPI不知道WM_DPICHANGED消息从未在DefWndProc中被拦截并且永远不会检索正确的DPI比例,而是按照我想要的方式“自动缩放”。但是,如果我让应用程序知道DPI,WM_DPICHANGED消息会被拦截,并且可以计算出正确的DPI,但表单不会“自动缩放”。正如我所说,应用程序非常复杂并且使用了很多第3方控件,所以我不能花时间在WPF中重写应用程序或尝试自己扩展应用程序。我怎样才能让应用程序拦截WM_DPICHANGED消息,计算正确的DPI并仍然允许Windows管理表单缩放?在Program.cs中:staticclassProgram{[STAThread]staticvoidMain(){if(Environment.OSVersion.Version.Major>=6){//如果以下行被注释掉,则应用程序不再支持DPI,并且//WM_DPICHANGED事件永远不会在intretValue=SetProcessDpiAwareness(ProcessDPIAwareness.ProcessPerMonitorDPIAware)形式的DefWndProc中触发;}Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);应用程序运行(新Form1());}privateenumProcessDPIAwareness{ProcessDPIUnaware=0,ProcessSystemDPIAware=1,ProcessPerMonitorDPIAware=2}[DllImport("shcore.dll")]privatestaticexternintSetProcessDpiAwareness(ProcessDPIAwarenessvalue);}在Form1.cs中:protectedrefoverridevoidDefWndProc({switch(m.Msg){case0x02E0://WM_DPICHANGED{intnewDpi=m.WParam.ToInt32()&0xFFFF;floatscaleFactor=(float)newDpi/(float)96;}休息;}base.DefWndProc(refm);}更新:我正在使用带有多显示器设置的Windows10所有显示器都是相同型号,基本分辨率为1920x1080。我使用显示设置将其中一台显示器的大小设置为125%。不是捕获WM_DPICHANGED事件,而是在需要时(在Paint事件或其他事件中)询问当前的DPI设置?但这也不是立即显而易见的。如果您搜索StackOverflow,通常可以找到以下答案:using(Graphicsscreen=Graphics.FromHwnd(IntPtr.Zero))intdpiX=GetDeviceCaps(hdc,DeviceCaps.LOGPIXELSX);screen.ReleaseHdc(hdc);然而,无论实际的DPI设置如何,它总是会返回96,除非......真正的工作解决方案似乎是GetDeviceCaps函数没有在MSDN上完整记录。至少我发现pinvoke.net提到了一些可以通过这个函数获得的其他选项。最后我想出了以下解决方案:intvirtualWidth=GetDeviceCaps(hdc,DeviceCaps.HORZRES);intphysicalWidth=GetDeviceCaps(hdc,DeviceCaps.DESKTOPHORZRES);屏幕.ReleaseHdc(hdc);返回(int)(96f*physicalWidth/virtualWidth);}}上例中需要的附加代码:privateenumDeviceCaps{//////X中的逻辑像素英寸///LOGPIXELSX=88,//////以像素为单位的水平宽度///HORZRES=8,//////整个桌面的水平宽度(以像素为单位)///DESKTOPHORZRES=118}//////检索指定设备的设备特定信息。//////DC的句柄。///要返回的项目。[DllImport("gdi32.dll")]privatestaticexternintGetDeviceCaps(IntPtrhdc,DeviceCapsnIndex);我终于在taffer的帮助下完成了这项工作。设置它的方法是不将应用程序设置为DPI感知,并计算特定显示器的DPI设置,以便在进行任何自定义绘图或调整字体大小时使用。无需捕获无论如何都不会触发的WM_DPICHANGED事件。hwnd参数是程序窗口的句柄。Win32类用于保存所有PInvoke内容。这是解决方案:publicstaticintGetSystemDpi(IntPtrhwnd){Screenscreen=Screen.FromHandle(hwnd);IntPtrscreenHdc=Win32.CreateDC(null,screen.DeviceName,null,IntPtr.Zero);intvirtualWidth=Win32.GetDeviceCaps(screenHdc,(int)Win32.DeviceCap.HORZRES);intphysicalWidth=Win32.GetDeviceCaps(screenHdc,(int)Win32.DeviceCap.DESKTOPHORZRES);Win32.DeleteDC(screenHdc);return(int)(96f*physicalWidth/virtualWidth);示例:该方法的典型用途是在不支持DPI的应用程序中执行自定义绘图,并让操作系统自动缩放。例如,如果我从我的主窗体在屏幕上绘制字体,这就是我将如何使用代码:以上是C#学习教程:自动缩放但仍然处理WM_DPICHANGED分享整个事情,如果它对任何人都有用并且需要了解更多C#学习教程,希望大家多多关注—privatevoidDrawText(){//计算出任何需要的屏幕缩放floatfScale=((float)GetSystemDpi(this.Handle)/96f);Fontmyfont=newFont("whatever",10f*fScale,FontStyle.Regular);使用(Graphicsg=this.CreateGraphics()){g.DrawString("MyCustomText",myfont,Brushes.Black,newPointF(0,0));}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
