使用 Qt 來開發 Android 應用,也須要適配不一樣移動設備,適配多種多樣的屏幕和分辨率。此次咱們大概來說一下如何使用 Qt 提供的機制來建立可伸縮的界面。html
DPI
必需要解釋一下 DPI 。mysql
DPI , dot per inch ,即每英寸包含的點數。還有一個概念是 PPI ,即每英寸包含的像素數。android
這個值越大,像素密度越大,小尺寸的屏幕就能夠有大分辨率。好比有的 Android 手機, 3.7 吋屏幕就能提供 960x540 的分辨率,而有的手機, 5 吋屏幕卻提供 800x480 的分辨率。這兩種不一樣屏幕的尺寸和分辨率的手機,5 吋屏看起來會有顆粒感,而 3.7 吋看起來則很是細膩。這就是像素密度帶來的差異。web
DPI 對界面的影響是醬紫的:一樣分辨率(按像素來講)的圖片,在 DPI 越大的屏幕上,看起來就越小。sql
三類可伸縮元素
一個 Qt 移動應用,大概有三類可伸縮 UI 元素:架構
咱們分別來看一下。app
文字
對於文字來說,咱們只須要設置特定的文本顯示和輸入控件所使用的字體(QFont)的 pointSize 便可。像 QLabel 、 QPushButton 、 QLineEdit 等等都適用這種方式。oop
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 ,進而構造可伸縮的背景。
![](http://static.javashuo.com/static/loading.gif)
上圖是 Qt 幫助裏的,四條線把一張圖片切成了 9 份,使用時,能夠保持四個角不變,其它部分經過拉伸或平鋪填充來適應界面空間大小。
好啦,基本的背景就這麼多了,咱們來看一個簡單的例子。
可伸縮界面示例
咱們先看效果後看代碼。
效果圖
下圖是 PC 上的運行效果:
![](http://static.javashuo.com/static/loading.gif)
下圖是手機上的效果,此時圖片沒有設置 devicePixelRatio 。
![](http://static.javashuo.com/static/loading.gif)
沒有設置 devicePixelRatio ,圖片看起來要小不少,對比它和文字,能夠明顯看出來比例失調。
下圖是設置了 devicePixelRatio 的效果,看起來一致了。
![](http://static.javashuo.com/static/loading.gif)
代碼分析
建立了一個基於 Qt Widgets 的 應用,名字是 scalabeUI ,建立了兩個文件 sizeUtil.h 和 sizeUtil.cpp 。
項目裏用到了兩個圖片資源:
![](http://static.javashuo.com/static/loading.gif)
圖片我加到了 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);
-
-
- QLabel *label = new QLabel("Hello Scalable Label");
- layout->addWidget(label, 1);
-
- 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}");
-
-
- QLabel *head = new QLabel;
- QPixmap orig(":/head.png");
- orig.setDevicePixelRatio(SizeUtil::instance().dpiFactor());
- head->setPixmap(orig);
- layout->addWidget(head);
-
-
- QHBoxLayout *hlayout = new QHBoxLayout;
- layout->addLayout(hlayout);
- QPushButton *button = new QPushButton("Text Button");
- hlayout->addWidget(button);
- hlayout->addStretch(1);
- }
-
- Widget::~Widget()
- {
-
- }
這就是代碼的所有了,雖然簡單,基本能夠說明問題了。
博客之星評選,點擊投我一票,謝謝。投過了也能夠點哦,天天均可以投投一票。
完整的項目代碼能夠在這裏下載:點擊下載。
其餘精彩文章文章