Qt on Android:创建可伸缩界面

时间:2022-05-25 17:06:31

使用 Qt 来开发 Android 应用,也需要适配不同移动设备,适配多种多样的屏幕和分辨率。这次我们大概来讲一下如何使用 Qt 提供的机制来创建可伸缩的界面。

DPI

必须要解释一下 DPI 。

DPI , dot per inch ,即每英寸包含的点数。还有一个概念是 PPI ,即每英寸包含的像素数。

这个值越大,像素密度越大,小尺寸的屏幕就可以有大分辨率。比如有的 Android 手机, 3.7 吋屏幕就能提供 960x540 的分辨率,而有的手机, 5 吋屏幕却提供 800x480 的分辨率。这两种不同屏幕的尺寸和分辨率的手机,5 吋屏看起来会有颗粒感,而 3.7 吋看起来则非常细腻。这就是像素密度带来的差别。

DPI 对界面的影响是酱紫的:同样分辨率(按像素来说)的图片,在 DPI 越大的屏幕上,看起来就越小。

三类可伸缩元素

一个 Qt 移动应用,大概有三类可伸缩 UI 元素:

  • 文字
  • 图片
  • 背景

我们分别来看一下。

文字

对于文字来讲,我们只需要设置特定的文本显示和输入控件所使用的字体(QFont)的 pointSize 即可。像 QLabel 、 QPushButton 、 QLineEdit 等等都适用这种方式。

QFont 的大小有两种表达方式: pixelSize 和 pointSize 。 pointSize 会根据应用所在的设备的 DPI 来调整字体,使得在不同 DPI 的设备上看起来效果一致。

Qt 里面可以单独改变一个 Widget 使用的字体,也可以通过 QApplication 来提供全局的字体,这样那些没有专门设置的 Widget ,就会使用全局的字体。

图片

前面我们说了,同样分辨率的图片,屏幕 DPI 越大,人眼看过去,就觉得越小。

Qt 可以处理这种情况,我们以 QPixmap 为例来说明。

QPixmap 有两个方法:

  • void  setDevicePixelRatio(qreal scaleFactor)
  • qreal  QPixmap::devicePixelRatio() const

这两个方法操作一个叫作 device pixel ratio 的属性,这个属性指定了设备相关的像素和设备无关的像素之间的换算比率。我们可以通过调整它来改变一个图片在手机屏幕上看起来的效果。

QImage 类同样有这两个方法。大家可以查阅 Qt 帮助来看 API 的细节。

那如何获取一个设备的 devicePixelRation 呢?

QScreen 有个方法可以返回这个值:qreal QScreen::​devicePixelRatio() const

QGuiApplication 、 QWindow 这两个类也有同名的方法。

我们也可以自己计算,使用 QScreen 的 logicalDotsPerInch() 方法结合一个常见的 DPI (比如 72)来计算,下面是示例代码:

  1. float SizeUtil::dpiFactor()
  2. {
  3. QScreen *screen = qApp->primaryScreen();
  4. return 72 / screen->logicalDotsPerInch();
  5. }

我在后面的示例中用了上面的方法。

要说明的是,Qt 的内建控件在使用 QPixmap 和  QImage 时,会结合 devicePixelRation 来决定这个控件的大小,我们的示例里使用 QLabel 来显示图片。

背景

背景要么是某种颜色,要么是一张图片。当使用图片做背景时,面临拉伸问题。 Android 使用 9patch 图片来解决这个问题, Qt 也提供了类似的东西:border-image 。

在基于 Qt Widgets 的应用里,我们可以通过 qss 来设置 border-image ,进而构造可伸缩的背景。

Qt on Android:创建可伸缩界面

上图是 Qt 帮助里的,四条线把一张图片切成了 9 份,使用时,可以保持四个角不变,其它部分通过拉伸或平铺填充来适应界面空间大小。

好啦,基本的背景就这么多了,我们来看一个简单的例子。

可伸缩界面示例

我们先看效果后看代码。

效果图

下图是 PC 上的运行效果:

Qt on Android:创建可伸缩界面

下图是手机上的效果,此时图片没有设置 devicePixelRatio 。

Qt on Android:创建可伸缩界面

没有设置 devicePixelRatio ,图片看起来要小很多,对比它和文字,可以明显看出来比例失调。

下图是设置了 devicePixelRatio 的效果,看起来一致了。

Qt on Android:创建可伸缩界面

代码分析

创建了一个基于 Qt Widgets 的 应用,名字是 scalabeUI ,创建了两个文件 sizeUtil.h 和 sizeUtil.cpp 。

项目里用到了两个图片资源:

Qt on Android:创建可伸缩界面    Qt on Android:创建可伸缩界面

图片我加到了 qrc 里。

sizeUtil.h 如下:

  1. #ifndef SIZEUTIL_H
  2. #define SIZEUTIL_H
  3. #include <QFont>
  4. #include <QString>
  5. class SizeUtil
  6. {
  7. private:
  8. SizeUtil(){}
  9. SizeUtil(const SizeUtil &);
  10. SizeUtil & operator=(const SizeUtil&);
  11. public:
  12. ~SizeUtil(){}
  13. static SizeUtil & instance();
  14. int defaultFontHeight();
  15. int widthWithDefaultFont(const QString &text);
  16. int widthWithFont(const QString &text, int fontPointSize);
  17. int fontHeight(int fontPointSize);
  18. float dpiFactor();
  19. };
  20. #endif // SIZEUTIL_H

sizeUtil.cpp 如下:

  1. #include "sizeUtil.h"
  2. #include <QApplication>
  3. #include <QFontMetrics>
  4. #include <QScreen>
  5. SizeUtil & SizeUtil::instance()
  6. {
  7. static SizeUtil util;
  8. return util;
  9. }
  10. int SizeUtil::defaultFontHeight()
  11. {
  12. return qApp->fontMetrics().height();
  13. }
  14. int SizeUtil::widthWithDefaultFont(const QString &text)
  15. {
  16. return qApp->fontMetrics().boundingRect(text).width();
  17. }
  18. int SizeUtil::widthWithFont(const QString &text, int fontPointSize)
  19. {
  20. QFont f = qApp->font();
  21. f.setPointSize(fontPointSize);
  22. QFontMetrics fm(f);
  23. return fm.boundingRect(text).width();
  24. }
  25. int SizeUtil::fontHeight(int fontPointSize)
  26. {
  27. QFont f = qApp->font();
  28. f.setPointSize(fontPointSize);
  29. QFontMetrics fm(f);
  30. return fm.height();
  31. }
  32. float SizeUtil::dpiFactor()
  33. {
  34. QScreen *screen = qApp->primaryScreen();
  35. return 72 / screen->logicalDotsPerInch();
  36. }

SizeUtil 类主要是用来计算文本的像素大小。

新建项目向导给我们生成了 widget.cpp 和 widget.h ,我修改了一下 widget.cpp ,针对文字、图片、背景三种情况,做了处理。代码如下:

  1. #include "widget.h"
  2. #include <QVBoxLayout>
  3. #include <QHBoxLayout>
  4. #include <QLabel>
  5. #include <QPushButton>
  6. #include "sizeUtil.h"
  7. Widget::Widget(QWidget *parent)
  8. : QWidget(parent)
  9. {
  10. QVBoxLayout *layout = new QVBoxLayout(this);
  11. //case 1. background
  12. QLabel *label = new QLabel("Hello Scalable Label");
  13. layout->addWidget(label, 1);
  14. /* top right bottom left */
  15. label->setStyleSheet(
  16. "QLabel{border-image:url(:/bkgnd.9.png) 38 6 6 16;"
  17. " border-left-width: 16; border-top-width: 38;"
  18. " border-right-width: 6; border-bottom-width: 6}");
  19. //case 2. image
  20. QLabel *head = new QLabel;
  21. QPixmap orig(":/head.png");
  22. orig.setDevicePixelRatio(SizeUtil::instance().dpiFactor());
  23. head->setPixmap(orig);
  24. layout->addWidget(head);
  25. //case 3. text button
  26. QHBoxLayout *hlayout = new QHBoxLayout;
  27. layout->addLayout(hlayout);
  28. QPushButton *button = new QPushButton("Text Button");
  29. hlayout->addWidget(button);
  30. hlayout->addStretch(1);
  31. }
  32. Widget::~Widget()
  33. {
  34. }

这就是代码的全部了,虽然简单,基本可以说明问题了。

博客之星评选,点击投我一票,谢谢。投过了也可以点哦,每天都可以投投一票。

完整的项目代码可以在这里下载:点击下载

其他精彩文章文章

在 android dialog中使用Autocompletetext
大型网站架构设计-Solrmysql哈希索引
android学习笔记(32)网格视图(GridView )和图形切换器(ImageSwi...
android学习笔记(31)可展开的列表组件(ExpandableListView )

Qt on Android:创建可伸缩界面的更多相关文章

  1. 创建一个QT for Android的传感器应用应用程序(摘自笔者2015年将出的《QT5权威指南》,本文为试读篇)

     这个手册描述了使用Qt Quick面访的方式在Android和ios设备上开发QtQuick应用程序的方法.我们使用Qt Creator实现一个QtQuick应用程序,这个应用程序基于加速器的值 ...

  2. Android研究之动态创建UI界面具体解释

     Android的基本UI界面一般都是在xml文件里定义好,然后通过activity的setContentView来显示在界面上.这是Android UI的最简单的构建方式.事实上,为了实现更加复 ...

  3. Qt on Android 核心编程

    Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著   ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...

  4. Qt on Android 蓝牙开发

    版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...

  5. Qt on Android&colon; Qt Quick 之 Hello World 图文具体解释

    在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式開始撰写 Qt Quick 程序,而那 ...

  6. Qt on Android&colon; Qt 5&period;3&period;0 公布,针对 Android 改进的说明

    5月20日本,Qt 官方博客宣布 Qt 5.3.0 公布! 这个版本号聚焦在性能.稳定性和可用性的提升上,与 5.1 / 5.2 相比有非常大提升. 5.3.0 的主要变化: 稳定能.可用性大大提升 ...

  7. Qt on Android 蓝牙通信开发

    版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...

  8. Qt on Android&colon; http下载与Json解析

    百度提供有查询 ip 归属地的开放接口,当你在搜索框中输入一个 ip 地址进行搜索,就会打开由 ip138 提供的百度框应用,你能够在框内直接输入 ip 地址查询.我查看了页面请求,提取出查询 ip ...

  9. Qt for Android修改应用程序的图标和名称

    使用QT开发出的Android Apk安装后默认的图标是安卓的小机器人,下面介绍在QT5.12版本上修改APP名称和图标的方法. 1.  编译一次项目后,在编译目录下找到AndroidManifest ...

随机推荐

  1. 数据结构:队列 链表,顺序表和循环顺序表实现(python版)

    链表实现队列: 尾部 添加数据,效率为0(1) 头部 元素的删除和查看,效率也为0(1) 顺序表实现队列: 头部 添加数据,效率为0(n) 尾部 元素的删除和查看,效率也为0(1) 循环顺序表实现队列 ...

  2. linux history命令显示时间

    在CentOS上使用history查看历史使用的CMD记录时,发现没有时间,在当前用户的.bash_profile里面,添加 export HISTTIMEFORMAT="%F %T  `w ...

  3. js中的逻辑与(&amp&semi;&amp&semi;)和逻辑或(&vert;&vert;)

    之前有一个同事去面试,面试过程中碰到这样一个问题: 在js中写出如下的答案 : var a = 2; var b = 3; var andflag = a && b ; var orf ...

  4. python 线程编程

    在threading模块中,定义两种类型的锁:threading.Lock和threading.RLock.它们之间有一点细微的区别,通过比较下面两段代码来说明: import threading l ...

  5. Effective C&plus;&plus; -----条款50:了解new 和delete 的合理替换时机

    有许多理由需要写个自定的new 和delete ,包括改善效能.对heap 运用错误进行调试.收集heap 使用信息.

  6. HDU5319

    题意:给一个矩形染色,顺笔表示红色,逆笔表示蓝色(既一捺和一丿),交叉表示绿色,然后给你一个图,问你用多少笔能画出这个图来. 思路:对这个图直接模拟即可,如果点i,j坐标为红色,那么判断上一个路径点是 ...

  7. 【ZJOI2010】网络扩容

    费用流+最大流 先一遍最大流 再所有边扩容,新加节点限制扩容量k # include <bits/stdc++.h> # define IL inline # define RG regi ...

  8. Java堆和栈的区别和介绍,JVM的堆和栈

    一.Java的堆内存和栈内存 Java把内存划分成两种:一种是堆内存,一种是栈内存.   堆:主要用于存储实例化的对象,数组.由JVM动态分配内存空间.一个JVM只有一个堆内存,线程是可以共享数据的. ...

  9. 20175202 《Java程序设计》第九周学习总结

    20175202 2018-2019-2 <Java程序设计>第九周学习总结 教材知识点总结 第11章 JDBC与MySQL数据库 MySQL数据库管理系统 MySQL数据库管理系统,简称 ...

  10. SQL Server 表值函数

    表值函数还是很有意思的,我现在想实现一个功能.就是我查询出来的内容,我要对结果进行再次查询,也要输入参数,我想了想 1.存储过程  不能对执行后的结果进行再次查询,需要创建临时表,太麻烦 2.视图  ...