Windows高DPI系列控件(一) - 饼图

原文连接:Windos高DPI系列控件(一) - 饼图html

1、醉一醉

眨眼功夫,2020年过去一半了。回想最近一段时间的工做和生活,总以为应该写点儿什么!缓存

因而,最近有空就在想啊想,想一想能够写点儿什么有用的东西好呢!恰好以前写过几篇关于高DPI的文章,不知道什么缘由,阅读量不是很高,所以打算以高DPI为索引开始引入一系列的控件使用案例,包括Qt自带的控件、简单图表和一些复杂的图表。框架

  1. Qt自带的控件就不说了,高DPI框架几乎能够完美适配
  2. 简单的图表这里主要会引入柱状图、折线图、饼图等
  3. 复杂图表主要是定制一些股票看盘相关图表,例如分时图、k线图等

对于大众软件来讲,友好的支持4k显示器真的颇有必要呢。一款好的大众桌面端软件须要适配各类操做系统,从快要被人们遗忘的Xp到如今占有率较高的Win10,若是想拥有一个好的用户体验,高DPI是必需要好好适配滴,这里做者准备了一个系列的高DPI控件适配文章分享给你们,主要整理我工做中遇到的各类控件,适配到已经开发好的高DPI框架中,并作出演示demo,提供给有须要的同窗,除过整理已有的控件,更多的是会开发一些更有意义的新控件,好比股票中的分时图、k线等。函数

目的:布局

  1. 推广我本身适配高DPI的方案,供你们讨论,是否有更好的优化空间
  2. 整理股票相关的控件,适配到个人高DPI框架中,提供给有须要的同窗参考
  3. 阶段性整理我本身的知识库,让零散的知识点汇聚起来

2、效果展现

以下图所示,适配高DPI交互效果。字体

左右两侧的显示物理尺寸一致,也就是占地面积同样大,不一样的是左侧是1080p显示器,右侧是4k显示器优化

由于是视频录制缘由,可能会有视觉偏差,实际看的话,左右两个窗体给人的视觉感觉大小是同样的。spa

《来回切换显示器》操作系统


《饼图支持操做》.net

3、高DPI适配

高DPI的适配思路以前已经系统的分析过,详情参看Qt之高DPI显示器(一) - 解决方案整理Qt之高DPI显示器(二) - 自适配解决方案分析两篇文章。

除过上述两篇文章外,以前计划中还有一篇文章要写,后来实在是太忙了,一直没有写完,第三篇文章主要是想讲下怎么优化现有框架,让DPI适配效率变的更高,后边有机会补上。

本票文章开始算是适配高DPI实践系列文章的开篇之做,饼图控件很早以前就分享过,详情参考Qt之自绘制饼图,怎么绘制饼图这里就再也不描述。本篇文章的核心主要是进行了饼图高DPI的显示适配,后边会主要描述下适配的细节,后期还会陆续接入更多更丰富的组件。

下面先带你们回顾下适配高DPI咱们都干了哪些事情,最后在看看饼图是怎么适配高DPI的。

一、高DPI框架运做

看过前两篇文章的同窗应该知道,咱们适配高DPI主要从两个方面进行的,分别是窗体的物理尺寸和字体

物理尺寸

物理尺寸从字面上看就是软件大小,不过咱们这里的物理尺寸也包含子窗口的大小,那也就是说子窗口之间的间隙也在物理尺寸这里进行适配。

为了让开发同窗无感知的使用,咱们新增了一样数量的可能会使用到的界面类,做为咱们本身的基础类,而且重写了界面类中跟尺寸相关的函数,让你们使用界面类的时候只换类名称,接口用法仍是跟之前同样。

重写了尺寸函数,若是咱们也知道当前显示器的DPI,缩放界面是否是就很简单了!当前开发设置的尺寸乘以须要缩放的系数就是最终须要显示的尺寸,框架只须要把最后须要显示的尺寸设置给Qt的接口,也就是当前类的父类接口,这样咱们的软件界面就实现了放大。作到这里算不算完呢?仔细想想,开发同窗使用这些接口的时候都是设置了96DPI下的尺寸,若是窗口移动到另外一台不一样DPI的显示器上,难道咱们要把全部set接口从新调用一遍?若是数量少了还行,但一个复杂的软件这样的set接口会多的令你发指,若是你让开发同窗都调用一遍,我估计他们会打死你。除过须要调用之外,调用顺序也相当重要,试想这样一种场景,若是须要缩放的窗体不少,你会但愿窗体局部忽然变大,没有汇率的跳动吗?答案固然是否。

为了让窗体有规律的缩放,那咱们就须要控制缩放的顺序了,这里就须要额外的继续重写一些关键方法,以前咱们重写类的时候重写了尺寸相关函数,这一次咱们还须要把布局相关的函数也进行重写,为的就是在界面布局的时候咱们把他们的关系记录下来,后续在出现DPI变化时,咱们根据以前维护的布局关系,按层调用每个须要缩放的界面。

界面布局

这里普及一个知识点,平时咱们所看到的软件界面是平面的,是一个二维的概念,可是软件界面在开发的过程当中,界面的布局关系实际上是一棵树,好比像下图这样的界面,界面A包括了界面B和界面C,而界面B又包括了两个界面D,这样当咱们构造两个界面A时,其实全部的界面都被构造了两份,而且界面D被构造了四份。

字体大小

咱们适配的高DPI框架,除过自绘文字之外,其余状况是不须要关注字体怎么变更的,这些字体适配都在咱们的高DPI适配框架中完成了,这里简单描述下字体适配高DPI的方式。

高DPI框架运行过程当中,主动维护了1x、2x和3x下的qss文件,若是检测到程序所须要的Qss文件不在这三个配置中,那么框架会动态的根据一个最接近当前缩放比的qss文件生成一个临时qss文件,好比当前缩放比是1.8x,那么程序将会根据2xqss文件,生成一个适合1.8x缩放比的qss文件,首先就是图片进行压缩显示,字号会乘以1.8而后除以2转换成1.8x缩放比下的字号,可能会有舍入,可是对于你们经常使用的0.5整数倍缩放比基本都是没有问题的,由于字号通常都是2的整数倍。

二、适配高DPI

高DPI框架设计之初就是想让开发同窗尽可能少的去操心DPI的事情,可是实际状况是还有少部分状况是须要本身去适配的,比方说自毁界面,这个时候咱们就须要本身去获取高DPI相关信息合理绘制

绘制文字

绘制文字时,咱们须要获取当前的缩放系数,在合适的实际去缩放绘制相关参数,比方说,当咱们绘制12px字体时,若是是在4k显示器下,咱们的dpi可能为192,那么缩放系数就是2x,绘制文字时就须要绘制24px字体

缩放系数 = 当前显示器DPI / 96.0

有时候绘制文字时可能会附带限制文字所在区域,96DPI下咱们不须要操心区域是否会出现问题,可是若是显示器DPI大于96时,文字绘制的区域咱们也就须要相应的适配下,不然可能会出现你不但愿的结果。比方说,咱们须要在坐标为10,10这个位置,以边框100px正方形框内绘制一段文本,96DPI下可能刚恰好能绘制完这段文字,若是192DPI下,咱们把字号放大了一倍,若是绘制区域仍是100px的正方形,那么文字极可能连一半都绘制不完。问题出在哪里呢?很显然,字体变大了,咱们的绘制区域确定也须要进行相应的放大,不妨试试200px的正方形是否是能够呢!答案是Yes。

绘制图片

自绘界面时每每少不了绘制图片,下面具体分析下怎么在任意DPI下绘制图片!

首先是获取1x缩放比下的图片路径,而后咱们经过一个转换函数转换成咱们当前显示器下须要的图片路径,并缩放图片,以达到最好的显示效果。

以下代码所示,是一个封装好的函数,主要完成了根据1x图片路径获取咱们将要绘制的图片,而且给咱们返回的是内存地址。这里须要额外补充下,Qt中的QPixmap是有作缓存机制的,当咱们第二次获取同一张图片时,Qt会直接从内存中获取到上一次图片的内存直接返回给咱们,所以这里不须要担忧效率问题。

QPixmap TIGERQTCOMM_EXPORT ImagePath::GetStretchPixmap(const std::string & path, float scale)
{
	std::string tpath = ImagePath::GetPixmapPath(path, (int)(scale + 0.5001));
	float factor = ImagePath::GetStretchFactor(scale);

	QPixmap pixmap(tpath.c_str());
	if (factor != 1.0)
	{
		pixmap = pixmap.scaled(pixmap.size() * factor);
	}

	return pixmap;
}

三、适配饼图

自绘界面时须要咱们本身去适配高DPI,主要是绘制所须要的的几何大小须要调整,说的直白一点儿就是看下图,左侧1080P显示器,右侧4K显示器,而且两个显示器尺寸是同样大的。看左右两侧的矩形区域坐标很清楚的展现出来了,右侧看着同样大的举行是左侧举行的两倍大,而且左上角的坐标也是两倍。

左侧矩形几何大小是(83, 104, 168, 211),右侧矩形几何大小是(166, 208, 336, 422) ,按照咱们高DPI适配的叫法左侧显示器的缩放比就是1x,右侧是2X

《1080P vs 4K》

前边小节说过了,自绘界面时适配高DPI主要是针对绘制的几何大小,饼图也不例外,这里我贴一个饼图各模块几何大小计算的函数,已经适配太高DPI,方法也很简单

适配过程主要是用宏来完成的,宏定义以下:#define SCALE_NUMBER(n) ((n) * dpi_scale),dpi_scale为每一个高DPI框架下类的成员变量,该变量由框架维护,表示当前窗口须要缩放的系数

废话很少说,以下代码是适配太高DPI后的函数,主要是对一些影响几何位置计算的参数进行了缩放。

void CPieChart::ConstructCornerLayout(const QSize & size)
{
	int currentR = SCALE_NUMBER(d_ptr->m_MinDiameter);
	int diameter;
	int horiWidth = size.width();
	if (d_ptr->m_bLegendVisible)
	{
		horiWidth -= SCALE_NUMBER(d_ptr->m_LegendWidth * 2);
	}
	int PieHeight;
	if (d_ptr->m_MutiDay.size() >= 1)
	{
		PieHeight = size.height() - SCALE_NUMBER(d_ptr->m_BarHeight) * d_ptr->m_MutiDay.size()
			- SCALE_NUMBER(d_ptr->m_BottomMargin + d_ptr->m_Space + d_ptr->m_BarSpace * (d_ptr->m_MutiDay.size() - 1))
			- SCALE_NUMBER(d_ptr->m_LabelHeight * 2);
	}
	else
	{
		PieHeight = size.height();
	}
	if (horiWidth > PieHeight)
	{
		diameter = PieHeight;
	}
	else
	{
		diameter = horiWidth;
	}

	int x, y;
	int r = diameter - SCALE_NUMBER(d_ptr->m_Minx * 2);
	currentR = r > currentR ? r : currentR;
	if (d_ptr->m_bLegendVisible)
	{
		d_ptr->m_Items.resize(4);

		x = width() / 2 - currentR / 2;
		y = (PieHeight - currentR) / 2;

		d_ptr->m_Items[1].m_LegendRect = QRect(SCALE_NUMBER(d_ptr->m_Minx), SCALE_NUMBER(d_ptr->m_Miny)
			, SCALE_NUMBER(d_ptr->m_LegendWidth), SCALE_NUMBER(30));

		d_ptr->m_Items[0].m_LegendRect = QRect(size.width() - Margin - SCALE_NUMBER(d_ptr->m_LegendWidth)
			, SCALE_NUMBER(d_ptr->m_Miny)
			, SCALE_NUMBER(d_ptr->m_LegendWidth), SCALE_NUMBER(30));

		d_ptr->m_Items[3].m_LegendRect = QRect(size.width() - Margin - SCALE_NUMBER(d_ptr->m_LegendWidth)
			, PieHeight - SCALE_NUMBER(d_ptr->m_Miny + 30)
			, SCALE_NUMBER(d_ptr->m_LegendWidth), SCALE_NUMBER(30));

		d_ptr->m_Items[2].m_LegendRect = QRect(SCALE_NUMBER(d_ptr->m_Minx)
			, PieHeight - SCALE_NUMBER(d_ptr->m_Miny + 30)
			, SCALE_NUMBER(d_ptr->m_LegendWidth), SCALE_NUMBER(30));

		d_ptr->m_Items[0].m_bAlign = false;
		d_ptr->m_Items[3].m_bAlign = false;
	}
	else
	{
		x = SCALE_NUMBER(d_ptr->m_Minx);
		y = SCALE_NUMBER(d_ptr->m_Miny);
	}

	d_ptr->m_PieRect = QRect(x, y, currentR, currentR);
	d_ptr->m_BarsRect = QRect(SCALE_NUMBER(20), 2 * y + currentR + SCALE_NUMBER(d_ptr->m_Space)
		, width() - SCALE_NUMBER(50)
		, size.height() - PieHeight);
}

到目前为止,本篇文章要分享的内容算基本完成了。饼图控件的其余的代码逻辑,包括绘制逻辑适配高DPI方式都合上述函数相似,你们自行脑补便可。感兴趣的朋友能够到饼图-高DPI下载,CSDN连接中的资源只包含适配太高DPI的饼图绘制代码,仅供你们参考,并不能经过编译。

4、相关文章

  1. Qt之高DPI显示器(一) - 解决方案整理
  2. Qt之高DPI显示器(二) - 自适配解决方案分析
  3. Qt之自绘制饼图

值得一看的优秀文章:

  1. 财联社-产品展现
  2. 广联达-产品展现
  3. Qt定制控件列表
  4. 牛逼哄哄的Qt库

若是您以为文章不错,不妨给个 打赏,写做不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!




很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 or Twowords

  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时经过修改本文达到有利于转载者的目的。

相关文章
相关标签/搜索