zoukankan      html  css  js  c++  java
  • 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)来计算,下面是示例代码:

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

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

    可伸缩界面示例

        我们先看效果后看代码。

    效果图

        下图是 PC 上的运行效果:

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

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

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

    代码分析

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

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

        

        图片我加到了 qrc 里。

        sizeUtil.h 如下:

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


        sizeUtil.cpp 如下:

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


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

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

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

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

    其他精彩文章文章

     

    在 android dialog中使用Autocompletetext 
    大型网站架构设计-Solr mysql哈希索引
    android学习笔记(32)网格视图(GridView )和图形切换器(ImageSwi...
    android学习笔记(31)可展开的列表组件(ExpandableListView )
  • 相关阅读:
    MCMC等采样算法
    【模拟退火】旅行商问题
    团队项目博客汇总
    2018年春季学期-助教总结
    linux简单命令常用随记
    记一次计算机网络作业
    [东北师大软工]Week2-作业2:个人项目实战 初步测试结果
    为什么你学过Java却忘光了——记第一次助教同学见面会
    ahk打印成pdf记录
    PSP总结报告
  • 原文地址:https://www.cnblogs.com/dyllove98/p/4211442.html
Copyright © 2011-2022 走看看