WPF 绘制对齐像素的清晰显示的线条

WPF 绘制对齐像素的清晰显示的线条
原文:WPF 绘制对齐像素的清晰显示的线条

版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:http://blog.csdn.net/wpwalter/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系(walter.lv@qq.com)。 https://blog.csdn.net/WPwalter/article/details/78858762

此前有小伙伴询问我为何他 1 像素的线条显示发虚,然后我告诉他是“像素对齐”的问题,然而他设置了各种对齐像素的属性依旧没有作用。于是我对此进行了一系列试验,对 WPF 像素对齐的各种方法进行了一次总结。此后在 StackOverflow 中,我回答了 graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow 问题。

阅读本文,我们将了解解决 WPF 像素对齐的四种方法以及其各自的适用范围和副作用。


像素对齐

为什么要做像素对齐

我们在解决什么问题

看线条!这是 3 像素的线条:

线条发虚

然而论其原因,就是因为我们屏幕太渣~哦~不,是因为绘制的线条没有与屏幕像素对齐,具体来说是视觉对象(Visual)的位置不在整数像素上或尺寸不是整数像素。而与此同时屏幕的点距又太大以至于我们看出来绘制的线条和屏幕像素之间的差异。

然而为什么 WPF 不默认为我们对齐像素呢?这是因为要对齐像素必定带来尺寸上的偏差;这是绘制尺寸精度和最终呈现效果之间的平衡。在 MacBook、Surface Pro 这些高档显示屏上,根本不用管这样的平衡问题;但在渣渣显示器上,微软把这种平衡的控制交给了应用的开发者。

处理像素对齐的四种方法

方法一:布局取整 UseLayoutRounding

UseLayoutRounding

实际效果是:

UseLayoutRounding 的效果

逗我

根本就不起作用

事实上我们从 .NET Framework 源码可以得知,UseLayoutRounding 实际只处理 UI 元素对自己子级控件的布局取整。一旦整棵布局树种有任何一个不是整数(或者 DPI 相乘后不是整数),那么就依然没有解决问题。

方法二:对齐设备像素 SnapsToDevicePixels

这是一个会沿着逻辑树继承的属性,只要最顶层设置了这个属性,里面的元素都会具备此特性。不过,他只处理矩形的渲染,也就是说,只对 Border Rectangle 这些类型的元素生效,其他的包括自己写的元素基本都是不管用的。

它有一个好处,是像素对齐的情况下同时能够保证显示不足或超过 1 像素时,也能带一点儿透明或者超过一点像素。

方法三:使用 DrwingContext 绘制并配合 GuidelineSet

如果自己处理绘制,则可以在 OnRender 方法中使用 DrawingContext 来绘制各种各样的形状。DrawingContext 有方法 PushGuidelineSet,而 PushGuidelineSet 就是用来处理对齐的。

以下是四种不同方式的对齐效果对比,其中上面一半是直接对齐(即绘制过程是紧贴着的),下面一半则是多个部分带上一点偏移(即并不是紧贴):

四种方式对比
▲ 看不清的可以考虑方法看

于是要想像素对齐,必须:

  • 布局或绘制时,UI 元素之间一点偏移或空隙都不能有,一点都不行
  • SnapsToDevicePixelsGuidelineSet 在实际对齐中有效,而 UseLayoutRounding 就是在逗你

GuidelineSet 的使用可以参考我在 StackOverflow 上的回答:graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow。

以下是我编写的用于辅助绘制对齐线条的扩展方法:

public static class SnapDrawingExtensions
{public static void DrawSnappedLinesBetweenPoints(this DrawingContext dc,Pen pen, double lineThickness, params Point[] points){var guidelineSet = new GuidelineSet();foreach (var point in points){guidelineSet.GuidelinesX.Add(point.X);guidelineSet.GuidelinesY.Add(point.Y);}var half = lineThickness / 2;points = points.Select(p => new Point(p.X + half, p.Y + half)).ToArray();dc.PushGuidelineSet(guidelineSet);for (var i = 0; i < points.Length - 1; i = i + 2){dc.DrawLine(pen, points[i], points[i + 1]);}dc.Pop();}
}

注意添加到 GuidelineSet 的尺寸不需要是整数,也不需要计算对齐屏幕的位置,只需要随便指定一个值即可,但相邻的绘制元素的值需要在 double 级别完全相同,多一点少一点都不行

OnRender 中调用它绘制:

protected override void OnRender(DrawingContext dc)
{// Draw four horizontal lines and one vertical line.// Notice that even the point X or Y is not an integer, the line is still snapped to device.dc.DrawSnappedLinesBetweenPoints(_pen, LineThickness,new Point(0, 0), new Point(320, 0),new Point(0, 40), new Point(320, 40),new Point(0, 80.5), new Point(320, 80.5),new Point(0, 119.7777), new Point(320, 119.7777),new Point(0, 0), new Point(0, 120));
}

绘制的四条线

方法四:RenderOptions.EdgeMode

这是纯渲染级别的附加属性,对所有 UI 元素有效。这个属性很神奇,一旦设置,元素就再也不会出现模糊的边缘了,一定是硬像素边缘。不足半像素的全部删掉,超过半像素的变为 1 个像素。

以为它可以解决问题?——Too young, too simple.

你希望能够绘制 1 像素的线条,实际上它会让你有时看得见 1 像素线条,有时看的是 2 像素线条,有时居然完全看不见!!!

如果你都作用对象上还有其它视觉对象,它们也会一并变成了“硬边缘”,是可以看得见一个个像素的边缘。

硬边缘

各种方法适用范围总结

适用范围总结

  1. 如果画粗线条粗边框,那么 RenderOptions.EdgeMode 最适合了,因为设置起来最方便,可以设置到所有的 UI 元素上。由于边框很粗,所以多一个少一个像素用户也注意不到。
  2. 如果是画细边框,那么使用 Border 配合 SnapsToDevicePixels 可以解决,无论是 0.8 像素还是 1.0 像素,1.2 像素,都能在准确地显示其粗细的基础之上还保证像素对齐。
  3. 如果图形比较复杂,比如绘制表格或者其它各种交叉了线条的图形,那么使用 DrawingContext 绘制,并设置 GuidelineSet 对齐。
  4. 如果窗口非常简单,既没有缩放,UI 元素也不多,可以考虑使用 UseLayoutRounding 碰碰运气,万一界面简单到只需要整数对齐就够了呢?
  5. 特别说明,上面四种方法不足与应对所有的像素对齐情况,如果还是没办法对齐……节哀把……我们一起找偏方……
posted on 2018-09-21 22:03 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/9688697.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中输入learn_Scikit-learn新版本发布,一行代码秒升级

十三 发自 凹非寺 量子位 报道 | 公众号 QbitAIScikit-learn&#xff0c;这个强大的Python包&#xff0c;一直深受机器学习玩家青睐。而近日&#xff0c;scikit-learn 官方发布了 0.22 最终版本。此次的更新修复了许多旧版本的bug&#xff0c;同时发布了一些新功能。安装最新版…

禁用删除键退回历史记录_如何在Windows 8中删除或禁用搜索超级按钮历史记录

禁用删除键退回历史记录When you use the Search Charm in Windows 8 it remembers everything you search for, which is very useful, but if you share your PC with someone you may want to delete your history or even disable it. Here’s how to do it. 在Windows 8中…

【概率论】1-2:计数方法(Counting Methods)

title: 【概率论】1-2:计数方法(Counting Methods) categories: MathematicProbability keywords:Counting Methods技术方法Combinatorial Methods组合方法Multiplication乘法法则Permutations排列Stirling’s Formula斯特林公式 toc: true date: 2018-01-25 10:35:46Abstract:…

使用sql服务器发送贺卡_创建和发送免费电子贺卡的最佳网站

使用sql服务器发送贺卡With the holiday season upon us, it’s time to pull out the holiday card list and get writing. However, how would you like to save some money this year and also help save the environment? 随着假期的到来&#xff0c;是时候抽出节日贺卡清…

WordCount--统计输入文件的字符数、行数、单词数(java)--初级功能

码云地址&#xff1a; https://gitee.com/YuRenDaZ/WordCount 个人PSP表格&#xff1a; PSP2.1 PSP阶段 预估耗时 &#xff08;分钟&#xff09; 实际耗时 &#xff08;分钟&#xff09; Planning 计划 180 120 Estimate 估计这个任务需要多少时间 180 120 D…

荣耀9igoogle模式_iGoogle个性化主页的6种替代方法

荣耀9igoogle模式iGoogle has less than a year to go before it’s shut down for good on November 1, 2013. While Google seems to think that iGoogle isn’t necessary anymore, there are other services waiting to take its place. iGoogle距离其2013年11月1日永久关闭…

华为堡垒机_安恒信息成为“华为云优秀严选合作伙伴”,携手保障“云上”资产安全访问...

加快5G持续创新能力&#xff0c;为云计算行业注入新动能。近日&#xff0c;以“智者•同行•共赢”为主题的2020华为云ISV(严选)合作伙伴大会在杭州隆重举行。上百位华为云合作伙伴、行业大咖等专业人士齐聚一堂&#xff0c;探讨云计算产业热门话题。作为华为云重要的生态合作伙…

非三星手机无法登录三星账号_如何解决所有三星手机的烦恼

非三星手机无法登录三星账号Samsung is the biggest manufacturer of Android phones in the world, but that doesn’t mean these handsets are perfect out of the box. In fact, most of these phones have several annoyances initially—here’s how to fix many of thes…

设置单元格填充方式_单元格的选择及设置单元格格式

数据输入完毕&#xff0c;接下来可以设置字体、对齐方式、添加边框和底纹等方式设置单元格格式&#xff0c;从而美化工作表。要对单元格进行设置&#xff0c;首先要选中单元格。选择单元格选择单元格是指在工作表中确定活动单元格以便在单元格中进行输入、修改、设置和删除等操…

springboot三种过滤功能的使用与比较

若要实现对请求的过滤&#xff0c;有三种方式可供选择&#xff1a;filter、interceptort和aop。本文主要讨论三种拦截器的使用场景与使用方式。 下文中的举例功能是计算每个请求的从开始到结束的时间&#xff0c;例子来源是慕课网。 一、filter 特点&#xff1a;可以获取原始的…

后缀的形容词_构词法(18)构成形容词的常见后缀 3

即时练习一、按要求改写下列单词。1. Japan →___________ adj. 日本(人)的2. Canton →_________ adj. 广东(人)的3. Vietnam →__________ adj. 越南(人)的4. Europe →__________ adj. 欧洲(人)的5. India → ________ adj. 印度(人)的6. Africa →_______ adj. 非洲(人)的7…

批量删除推文_如何搜索(和删除)您的旧推文

批量删除推文“The internet never forgets” is an aphorism that isn’t entirely true, but it’s worth thinking about whenever you post to social media. If you think your Twitter profile needs a bit of a scrub, here’s how to search and delete those old twee…

智能记忆功能nest_如何设置和安装Nest Protect智能烟雾报警器

智能记忆功能nestIf you want to add a bit more convenience and safety to your home’s smoke alarm setup, the Nest Protect comes with a handful of great features to make that a reality. Here’s how to set it up and what all you can do with it. 如果您想为您的…

网格自适应_ANSYS 非线性自适应(NLAD)网格划分及应用举例

文章来源&#xff1a;安世亚太官方订阅号&#xff08;搜索&#xff1a;Peraglobal&#xff09;在复杂的结构设计分析中&#xff0c;通常很难确定在高应力区域中是否生成适当的细化网格。在做非线性大应变分析仿真时&#xff0c;可能由于单元变形过大&#xff0c;导致网格畸变&a…

python---[列表]lsit

内置数据结构&#xff08;变量类型&#xff09; -list -set -dict -tuple -list&#xff08;列表&#xff09; -一组又顺序的数据组合 -创建列表 -空列表 list1 []        print(type(list1))        print(list1)        list2 [100]       …

唤醒计算机运行此任务_如何停止Windows 8唤醒计算机以运行维护

唤醒计算机运行此任务Windows 8 comes with a new hybrid boot system, this means that your PC is never really off. It also means that Windows has the permission to wake your PC as it needs. Here’s how to stop it from waking up your PC to do maintenance tasks…

转整型_SPI转can芯片CSM300详解、Linux驱动移植调试笔记

一口君最近移植了一款SPI转CAN的芯片CSM300A&#xff0c;在这里和大家做个分享。一、CSM300概述CSM300(A)系列是一款可以支持 SPI / UART 接口的CAN模块。1. 简介CSM300(A)系列隔离 SPI / UART 转 CAN 模块是集成微处理器、 CAN 收发器、 DC-DC 隔离电源、 信号隔离于一体的通信…

matlab练习程序(二值图像连通区域标记法,一步法)

这个只需要遍历一次图像就能够完全标记了。我主要参考了WIKI和这位兄弟的博客&#xff0c;这两个把原理基本上该介绍的都介绍过了&#xff0c;我也不多说什么了。一步法代码相比两步法真是清晰又好看&#xff0c;似乎真的比两步法要好很多。 代码如下&#xff1a; clear all; c…

pc微信不支持flash_在出售PC之前,如何取消对Flash内容的授权

pc微信不支持flashWhen it comes to selling your old digital equipment you usually should wipe it of all digital traces with something like DBAN, however if you can’t there are some precautions you should take–here’s one related to Flash content you may h…

绘制三维散点图_SPSS统计作图教程:三维散点图

作者&#xff1a;豆沙包&#xff1b;审稿&#xff1a;张耀文1、问题与数据最大携氧能力是身体健康的一项重要指标&#xff0c;但检测该指标成本较高。研究者想根据性别、年龄、体重、运动后心率等指标建立预测最大携氧能力的模型&#xff0c;招募了100名研究对象&#xff0c;测…