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()
{

}

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

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

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

------------回顾一下 Qt on Android 系列:

  • Qt on Android:图文详解Hello World全过程
  • Windows下Qt 5.2 for Android开发入门
  • Qt for Android 部署流程分析
  • Qt on Android:将Qt调试信息输出到logcat中
  • Qt on Android: Qt 5.3.0 发布,针对 Android 改进说明
  • Qt on Android Episode 1(翻译)
  • Qt on Android Episode 2(翻译)
  • Qt on Android Episode 3(翻译)
  • Qt on Android Episode 4(翻译)
  • Qt for Android 编译纯C工程
  • Windows下Qt for Android 编译安卓C语言可执行程序
  • Qt on Android: Android SDK安装
  • Qt on Android: http下载与Json解析
  • Qt on Android 之设置应用名为中文
  • Qt on Android:让 Qt Widgets 和 Qt Quick 应用全屏显示
  • Qt on Android:怎样适应不同的屏幕尺寸
  • Qt on Android:使用JNI与第三方jar包

  • 《Qt on Android核心编程》介绍

  • Qt on Android:资源文件系统qrc与assets

  • 时间: 2024-07-30 03:57:42

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

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

     这个手册描述了使用Qt Quick面访的方式在Android和ios设备上开发QtQuick应用程序的方法.我们使用Qt Creator实现一个QtQuick应用程序,这个应用程序基于加速器的值来加速一个SVG(可伸缩矢量图形). 设置开发环境: 要想能够在移动设备上构建和运行一个应用程序,您必须为设备平台设置开发环境,配置Qt Creator和手机设备之间的连接. 要想部署到Android设备,您必须下载和安装最新的Android NDK和SDK.更新SDK去获取为开发所需的API和工具

    Qt on Android: Qt Quick 组件与对象动态创建详解

    在<Qt on Android: Qt Quick 事件处理之信号与槽>一文中介绍自定义信号时,举了一个简单的例子,定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Connections 对象连接到组件的 colorPicked 信号,改变文本的颜色. 当时用到的 Component . Loader 两个特性,一直没来得及介绍,可能很多人都还在雾里看花呢.这次呢,我们就来仔仔细细地把他们讲清楚. 请给我的参赛文章<Qt on Androi

    Android研究之动态创建UI界面详解

     Android的基本UI界面一般都是在xml文件中定义好,然后通过activity的setContentView来显示在界面上,这是Android UI的最简单的构建方式.其实,为了实现更加复杂和更加灵活的UI界面,往往需要动态生成UI界面,甚至根据用户的点击或者配置,动态地改变UI,本文即介绍该技巧.对事件和进程的可能安卓设备实现触摸事件的监听,跨进程 假设Android工程的一个xml文件名为activity_main.xml,定义如下: 1 2 3 4 5 6 7 8 9 10 11

    Qt on Android: Qt 5.3.0 发布,针对 Android 改进说明

    5月20日,Qt 官方博客宣布 Qt 5.3.0 发布! 这个版本聚焦在性能.稳定性和可用性的提升上,与 5.1 / 5.2 相比有很大提升. 5.3.0 的主要变化: 稳定能.可用性大大提升 Qt for Windows Runtime Beta Official support for QNX 6.6 and QNX 6.5 SP1 引入的新特性 QQuickWidget,混合使用 Qt Widgets 和 Qt Quick 变得更加方便 Compiled Qt Quick Purchasi

    Qt on Android: Qt Quick 事件处理之信号与槽

    前面两篇文章< Qt on Android:QML 语言基础>和<Qt on Android: Qt Quick 简单教程>中我们介绍了 QML 语言的基本语法和 Qt Quick 的常见元素,亲们,通过这两篇文章,您应该已经可以完成简单的 Qt Quick 应用了.接下来呢,哈,我们要介绍 Qt Quick 中一个灰常灰常重要的主题:事件处理.这将是比较长长长长的一篇,哦,不还有后续好几篇--废话少说,还是谈正事儿吧兄弟姐妹们. 本文参加 CSDN 博文大赛,请点这里投我一票,谢

    Qt on Android: http下载与Json解析

    百度提供有查询 ip 归属地的开放接口,当你在搜索框中输入一个 ip 地址进行搜索,就会打开由 ip138 提供的百度框应用,你可以在框内直接输入 ip 地址查询.我查看了页面请求,提取出查询 ip 归属地的接口,据此使用 Qt 写了个简单的 ip 归属地查询应用.可以在电脑和 Android 手机上运行.这里使用了百度 API ,特此声明,仅可作为演示使用,不能用作商业目的. 版权所有 foruok,转载请注明出处( http://blog.csdn.net/foruok ). 这个例子会用到

    QT for Android HelloWorld实现

    1 新建工程 打开Qt Creator,文件->新建文件或项目:在出来的对话框里面,选择"Android 模板"->Application->Qt Widgets Application 然后点击"Choose-" 设置完"名称"和"创建路径",如果觉得有必要可以把"设为默认的项目路径"勾上:然后下一步: 在"Qt Widgets Application"中,我建议把&

    Qt on Android:使用JNI与第三方jar包

    很多朋友在论坛和QQ群里问到这个,今天有时间写了个简单的示例. 功能很简单,允许你输入一个web页面地址,使用Java的下载类库下载后用QTextEdit显示出来. 版权所有:foruok.转载请注明出处:http://blog.csdn.net/foruok. 效果展示 初始效果如图1所示: 图1 useJar示例初始效果 图2为点击"GET"按钮后下载到对应页面的效果: 图2 下载页面成功 下载部分,为了显示如何使用jar包,我用了asynchttpclient,参考我的博文:An

    Qt on Android: Qt Quick 简单教程

    上一篇<Qt on Android: Qt Quick 之 Hello World 图文详解>我们已经分别在电脑和 Android 手机上运行了第一个 Qt Quick 示例-- HelloQtQuickApp ,这篇呢,我们就来介绍 Qt Quick 编程的一些基本概念,为创建复杂的 Qt Quick 应用奠定基础. 版权所有 foruok ,如需转载请注明来自博客 http://blog.csdn.net/foruok . 首先看一下<Qt on Android: Qt Quick