Qt on Android:创建可伸缩界面
使用 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)来计算,下面是示例代码:
- float SizeUtil::dpiFactor()
- {
- QScreen *screen = qApp->primaryScreen();
- return 72 / screen->logicalDotsPerInch();
- }
我在后面的示例中用了上面的方法。
要说明的是,Qt 的内建控件在使用 QPixmap 和 QImage 时,会结合 devicePixelRation 来决定这个控件的大小,我们的示例里使用 QLabel 来显示图片。
背景
背景要么是某种颜色,要么是一张图片。当使用图片做背景时,面临拉伸问题。 Android 使用 9patch 图片来解决这个问题, Qt 也提供了类似的东西:border-image 。
在基于 Qt Widgets 的应用里,我们可以通过 qss 来设置 border-image ,进而构造可伸缩的背景。
上图是 Qt 帮助里的,四条线把一张图片切成了 9 份,使用时,可以保持四个角不变,其它部分通过拉伸或平铺填充来适应界面空间大小。
好啦,基本的背景就这么多了,我们来看一个简单的例子。
可伸缩界面示例
我们先看效果后看代码。
效果图
下图是 PC 上的运行效果:
下图是手机上的效果,此时图片没有设置 devicePixelRatio 。
没有设置 devicePixelRatio ,图片看起来要小很多,对比它和文字,可以明显看出来比例失调。
下图是设置了 devicePixelRatio 的效果,看起来一致了。
代码分析
创建了一个基于 Qt Widgets 的 应用,名字是 scalabeUI ,创建了两个文件 sizeUtil.h 和 sizeUtil.cpp 。
项目里用到了两个图片资源:
图片我加到了 qrc 里。
sizeUtil.h 如下:
- #ifndef SIZEUTIL_H
- #define SIZEUTIL_H
- #include <QFont>
- #include <QString>
- class SizeUtil
- {
- private:
- SizeUtil(){}
- SizeUtil(const SizeUtil &);
- SizeUtil & operator=(const SizeUtil&);
- public:
- ~SizeUtil(){}
- static SizeUtil & instance();
- int defaultFontHeight();
- int widthWithDefaultFont(const QString &text);
- int widthWithFont(const QString &text, int fontPointSize);
- int fontHeight(int fontPointSize);
- float dpiFactor();
- };
- #endif // SIZEUTIL_H
sizeUtil.cpp 如下:
- #include "sizeUtil.h"
- #include <QApplication>
- #include <QFontMetrics>
- #include <QScreen>
- SizeUtil & SizeUtil::instance()
- {
- static SizeUtil util;
- return util;
- }
- int SizeUtil::defaultFontHeight()
- {
- return qApp->fontMetrics().height();
- }
- int SizeUtil::widthWithDefaultFont(const QString &text)
- {
- return qApp->fontMetrics().boundingRect(text).width();
- }
- int SizeUtil::widthWithFont(const QString &text, int fontPointSize)
- {
- QFont f = qApp->font();
- f.setPointSize(fontPointSize);
- QFontMetrics fm(f);
- return fm.boundingRect(text).width();
- }
- int SizeUtil::fontHeight(int fontPointSize)
- {
- QFont f = qApp->font();
- f.setPointSize(fontPointSize);
- QFontMetrics fm(f);
- return fm.height();
- }
- float SizeUtil::dpiFactor()
- {
- QScreen *screen = qApp->primaryScreen();
- return 72 / screen->logicalDotsPerInch();
- }
SizeUtil 类主要是用来计算文本的像素大小。
新建项目向导给我们生成了 widget.cpp 和 widget.h ,我修改了一下 widget.cpp ,针对文字、图片、背景三种情况,做了处理。代码如下:
- #include "widget.h"
- #include <QVBoxLayout>
- #include <QHBoxLayout>
- #include <QLabel>
- #include <QPushButton>
- #include "sizeUtil.h"
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- {
- QVBoxLayout *layout = new QVBoxLayout(this);
- //case 1. background
- QLabel *label = new QLabel("Hello Scalable Label");
- layout->addWidget(label, 1);
- /* top right bottom left */
- label->setStyleSheet(
- "QLabel{border-image:url(:/bkgnd.9.png) 38 6 6 16;"
- " border-left-width: 16; border-top-width: 38;"
- " border-right-width: 6; border-bottom-width: 6}");
- //case 2. image
- QLabel *head = new QLabel;
- QPixmap orig(":/head.png");
- orig.setDevicePixelRatio(SizeUtil::instance().dpiFactor());
- head->setPixmap(orig);
- layout->addWidget(head);
- //case 3. text button
- QHBoxLayout *hlayout = new QHBoxLayout;
- layout->addLayout(hlayout);
- QPushButton *button = new QPushButton("Text Button");
- hlayout->addWidget(button);
- hlayout->addStretch(1);
- }
- Widget::~Widget()
- {
- }
这就是代码的全部了,虽然简单,基本可以说明问题了。
博客之星评选,点击投我一票,谢谢。投过了也可以点哦,每天都可以投投一票。
完整的项目代码可以在这里下载:点击下载。
其他精彩文章文章
在 android dialog中使用Autocompletetext
大型网站架构设计-Solrmysql哈希索引
android学习笔记(32)网格视图(GridView )和图形切换器(ImageSwi...
android学习笔记(31)可展开的列表组件(ExpandableListView )
Qt on Android:创建可伸缩界面的更多相关文章
- 创建一个QT for Android的传感器应用应用程序(摘自笔者2015年将出的《QT5权威指南》,本文为试读篇)
这个手册描述了使用Qt Quick面访的方式在Android和ios设备上开发QtQuick应用程序的方法.我们使用Qt Creator实现一个QtQuick应用程序,这个应用程序基于加速器的值 ...
- Android研究之动态创建UI界面具体解释
Android的基本UI界面一般都是在xml文件里定义好,然后通过activity的setContentView来显示在界面上.这是Android UI的最简单的构建方式.事实上,为了实现更加复 ...
- Qt on Android 核心编程
Qt on Android 核心编程(最好看的Qt编程书!CSDN博主foruok倾力奉献!) 安晓辉 著 ISBN 978-7-121-24457-5 2015年1月出版 定价:65.00元 4 ...
- Qt on Android 蓝牙开发
版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...
- Qt on Android: Qt Quick 之 Hello World 图文具体解释
在上一篇文章,<Qt on Android:QML 语言基础>中,我们介绍了 QML 语言的语法,在最后我们遗留了一些问题没有展开,这篇呢,我们就正式開始撰写 Qt Quick 程序,而那 ...
- Qt on Android: Qt 5.3.0 公布,针对 Android 改进的说明
5月20日本,Qt 官方博客宣布 Qt 5.3.0 公布! 这个版本号聚焦在性能.稳定性和可用性的提升上,与 5.1 / 5.2 相比有非常大提升. 5.3.0 的主要变化: 稳定能.可用性大大提升 ...
- Qt on Android 蓝牙通信开发
版权声明:本文为MULTIBEANS ORG研发跟随文章,未经MLT ORG允许不得转载. 最近做项目,需要开发安卓应用,实现串口的收发,目测CH340G在安卓手机上非常麻烦,而且驱动都是Java版本 ...
- Qt on Android: http下载与Json解析
百度提供有查询 ip 归属地的开放接口,当你在搜索框中输入一个 ip 地址进行搜索,就会打开由 ip138 提供的百度框应用,你能够在框内直接输入 ip 地址查询.我查看了页面请求,提取出查询 ip ...
- Qt for Android修改应用程序的图标和名称
使用QT开发出的Android Apk安装后默认的图标是安卓的小机器人,下面介绍在QT5.12版本上修改APP名称和图标的方法. 1. 编译一次项目后,在编译目录下找到AndroidManifest ...
随机推荐
- 【oracle】union、union all、intersect、minus 的用法及区别
一.union与union all 首先建两个view create or replace view test_view_1 as as c from dual union as c from dua ...
- linux I/O stack cache 强制刷新
linux 存储子系统作为最为复杂的子系统之一,拥有很深的模块栈(如图),其中很多模块又有自己的缓存功能(如下图).实际应用中,用户下发的数据停留在哪个缓存中,是否已经写入磁盘,这些操作对用户来说是个 ...
- mac搭建nginx与php
第一步:关闭Apache及开机启动 要使用nginx,最好停用mac中自带的Apache.停用很简单: sudo launchctl unload -w /System/Library/LaunchD ...
- 【BFS】POJ 3414
直达 -> POJ 3414 Pots 相似题联动–>HDU 1495 非常可乐 题意:两个壶倒水,三种操作,两个桶其中一个满足等于C的最少操作,输出路径.注意a,b互倒的时候能不能倒满, ...
- 我听说 C...
我听说在 c 语言的世界里,goto 和异常处理都是声名狼藉的东西,而我认为它们在一起就能化解各自的问题.
- 案例1.通过Jquery来处理复选框
实现以下功能: 1:选中第一个复选框,那么下面所有的复选框都选中,去除选中第一个复选框,下面的都不选中 2:当点击全选按钮,上面足球.篮球.游泳.唱歌 全部选中 3:当点击全不选按钮,上面四个全部取消 ...
- ceil 模块
# 有时需要得到一个最小的整数,而这个数只能比自己大或相等,不能小于自己 #如: 2.1 我们需要得到的最小整数为3,即使后一位只有很小的一部分,一般用于分页 from math import cei ...
- bzoj 刷水
bzoj 3856: Monster 虽然是sb题,,但是要注意h可能<=a,,,开始忘记判了WA得很开心. #include <iostream> #include <cst ...
- 新版startssl 免费SSL证书申请 (实测 笔记 https http2 必要条件)
简单说明: 目前多个大型网站都实现全站HTTPS,而SSL证书是实现HTTPS的必要条件之一. StartSSL是StartCom公司旗下的.提供免费SSL证书服务并且被主流浏览器支持的免费SSL.包 ...
- CentOS7 编译安装 Mongodb (实测 笔记 Centos 7.0 + Mongodb 2.6.6)
环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7.0-1406-x86_64-DVD.iso 安装步骤: 1.准备 1.1 显示系统版 ...