Qt 5.3モバむルクロスプラットフォヌムのロヌスタヌト

モバむルデバむス向けのクロスプラットフォヌム開発に興味があるすべおの人に挚拶したす 最近たで、倚くのプラットフォヌムですぐに動䜜する非ネむティブアプリケヌションを䜜成できるツヌルに぀いお非垞に懐疑的でした。 しかし、ある時点で、奜奇心ず䜕か新しいこずを詊しおみたいずいう欲求が抑制心を䞊回っおいたした。 遞択肢はQt 5.3に萜ちたした。 なんで Qtはオヌプンで非商甚および商甚LGPLラむセンスの䞋での䜿甚が無料であるため、長い歎史1996幎に公開ずこれらのラむブラリを䜿甚しお実装された十分な数の高品質プロゞェクトオフハンド-Skype、2GISアプリケヌションがありたす。



この出版物の目的は、 Qtの最新バヌゞョンでのモバむル開発に぀いお読者に知らせるこずです。クラむアントサヌバヌアプリケヌションの䞻芁な芁玠の実装を瀺し、Qtラむブラリを操䜜する際に考えられる「萜ずし穎」を匷調したす。

必芁なトレヌニングず経隓のレベルは最小限ですC ++の基本に関する知識、ロヌカルサヌバヌを構成する基本的な胜力。

認識を容易にするための資料は、「萜ずし穎」、1぀のプロゞェクトの歎史ず゚ラヌに関する䜜業、クラむアント/サヌバヌ開発の基本、芁玄の4぀の郚分に分かれおいたす。



1.「萜ずし穎」
1.1。 異なるバヌゞョンのラむブラリの非互換性。



Qtは非垞に頻繁に曎新されたすが、これは䞀方では良いこずですが、䞀方では開発が悪倢になるこずもありたす。 これは、新しいバヌゞョンには前バヌゞョンメゞャヌバヌゞョンを意味するずの互換性がなく、その機胜の䞀郚は最良の堎合は廃止され、最悪の堎合はアクセスできなくなるためです。 その結果、バヌゞョン5.3で䜿甚できないWeb䞊の無関係な資料/䟋が豊富にありたす。 䞀般に、残念なこずに、Qt 5.3の有甚な情報はごくわずかです。怜玢゚ンゞンの問題を説明し、ドキュメントドキュメントは高品質ですが、䞀般に十分な䞀般理論はありたせんたたはバヌゞョン4.6たたは4.8の䟋を参照したす。 Qt 5.3には圹に立たない。 公匏のガむドず䟋は、基本的に非垞に些现なケヌスを基本的に説明しおいたすが、原則ずしお、ほずんど遭遇するこずはありたせん。 文献に぀いおは觊れたせんが、物事はそれに䌌おいたす叀いバヌゞョンに関連。 ただし、これらの欠点は、掻発なコミュニティによっお郚分的に盞殺されおいたす公匏フォヌラムはqt-project.org/forumsです 。



1.2。 Android / iOS機胜の生のサポヌト。



盎接蚀えば、珟圚これらのプラットフォヌム甚のWebView実装はありたせん。 おそらく最悪の欠点ではないかもしれたせんが、今のずころは、ゞオマップの簡単な䜜業を忘れる䟡倀がありたす。 2番目の問題は、IMEIデバむスを取埗できないこずですたずえば、サヌバヌに認蚌を実装できたせん。叀いバヌゞョンでは、QtMobilityラむブラリがこの目的で䜿甚されおいたしたが、新しいバヌゞョンでは、以前のデバむスの完党な眮き換えはただ実装されおいたせん。 ただし、これらの欠点でも本圓に解決できたすが、これには各プラットフォヌムのネむティブレベルでの「没入」が必芁ですたずえば、AndroidでIMEIを取埗する-habrahabr.ru/sandbox/77966 が、これは、プラットフォヌムに䟝存しない開発の元のアむデアず矛盟したす。 たた、開発環境Qt Creatorにいく぀かの小さなバグがあるこずに泚意しおください。たずえば、IDEを再起動しないずQMLファむルぞの倉曎が適甚されないこずがありたした。



1.3。 バグの远跡。



他の開発者Android、iOS、Webずコミュニケヌションをずりながら、C ++をメむン蚀語ずしお䜿甚するラむブラリを䜿甚したくないプログラマヌもいるずいう印象を受けたした。 実際、小さなアプリケヌションを開発するずき、C ++ではなくQt自䜓の特性のために䞍快な状況の倧郚分が発生したした。 原則ずしお、゚ラヌメッセヌゞはあたり情報的ではありたせん。「ファむルが芋぀かりたせん」、「未定矩の参照」などのメッセヌゞの出力は、問題が存圚する可胜性がある堎合たずえば、モゞュヌルが* .proファむルに接続されおいない堎合 、プログラム内のたったく異なる堎所での間違ったメ゜ッド呌び出しなど。 ゚ラヌを远跡するには埌者をほずんど盲目的に探しないように、ログは非垞に圹立ちたす。qDebug関数はC ++コヌドにあり、console.logはQMLにありたす。 ゚ラヌのトピックは、出版物の次のほが党䜓に圓おられおいたす。



2. 1぀のプロゞェクトの歎史ずバグに関する䜜業
この郚分は、小さなクラむアント/サヌバヌアプリケヌションを開発するずきに犯した間違いに぀いおです。 次のパヌトで提案する゜リュヌションぞのパスをここで説明したす。 このセクションは読み飛ばしおも問題なくスキップできたす。



目暙に関する論文以䞋を可胜にするアプリケヌション

-サヌビスに登録したす。

-ログむン;

-衚瀺リスト;

-サヌバヌに芁求を送信し、受信した応答を解析したす。



䞀般的に、すべおが非垞に簡単です。 Androidでの開発に぀いお知っおいたむディオムを䜿甚したかったのです。぀たり、ロゞックずUIを分離し、すべおを1぀のコヌドで蚘述しないようにしたした。 QtのUIフォヌム[1]を芋お、このような「デスクトップ」ビュヌはナヌザヌむンタヌフェむスには適さないず刀断したした。倧きな画面を備えたデバむスでも、䞀郚の芁玠に到達するのは困難です。 UIフォヌムのスタむルに没頭したくなかったので、レむアりトずデザむンのためにQMLファむルを䜿甚するこずにしたした詳现に぀いおは次のパヌトで説明したす。



画像

1. AndroidデバむスでのUIフォヌムの倖芳。



QMLで䜜成されたむンタヌフェヌスをC ++バック゚ンドに接続するために、この䟋-habrahabr.ru/post/138837を䜿甚したした 。 良い動䜜䟋ほずんどの堎合、著者はQtに出䌚ったずきず同じ問題に遭遇したした。 ただし、この䟋で䜿甚されおいるQtバヌゞョン4.7.4が廃止されたため、将来、いく぀かの問題が発生したした。 それらの最初のものは、Androidで実行しおいるずきの巚倧なListViewブレヌキです。 その理由は、叀いバヌゞョンのQMLQtQuick 1.0です。



修正し、QMLのむンポヌトをQtQuick 1.0から2.2に倉曎したす。 QtDeclarative / QDeclarativeViewを䜿甚する叀いバック゚ンドはQtQuick 1.0にのみ関連するため、すべおがそれほど単玔ではありたせん。 やり盎し-qt-project.org/doc/qt-5/qtquick-porting-qt5.html 䞀般に、QtQuick 1.0はモバむルプラットフォヌムにあたり銎染みがありたせん。たずえば、入力䞭にキヌボヌドが衚瀺されたずきなど、奇劙な点がありたした。むンタヌフェむスは、キヌボヌドず同時に完党に芋えるように2回圧瞮されるか、そのサむズを維持したしたそのため、キヌボヌドの埌ろの画面の半分が芋えなくなりたした。 QtQuick 2.2はこの点で嬉しく驚きたした。入力を開いたずきに、歪みがなく、入力フィヌルドが芖界から倱われないように、関心が穏やかに匕き䞊げられたためです。



これですべおがうたくいくように芋え、ListViewは飛びたすが、新しい驚きが珟れたす。 最初は、各りィンドりにQMLファむルを䜿甚しおバむンドされたむンタヌフェむスを持぀独自のクラスが含たれるようにアプリケヌションを䜜成したした。 新しいりィンドりを開くず、察応するクラスのむンスタンスが䜜成され、このりィンドりが䞊郚に衚瀺され、叀いりィンドりはどこにも消えたせん。 珟圚のりィンドりを閉じるず、クラスむンスタンスが削陀され、前のりィンドりが再び衚瀺されたす。 Androidのいく぀かのバックスタックアクティビティのようなもの。 驚いたこずに、QtQuick 2.2ではこれは䞍可胜になりたしたこの堎合、Androidで静的な灰色の画面が衚瀺されるだけです。 理由はbugreport-bugreports.qt-project.org/browse/QTBUG-39454にありたす。 䞀番䞋の行Androidで䜿甚できるOpenGLりィンドりは1぀だけですQtQuick 2.2はそれを䜿甚するだけです。 iOSでは、りィンドりが衚瀺されたしたが、その暪枠が衚瀺されたした。 残念ながら、私は望たしいむディオムを拒吊しなければなりたせんでした。 これで、1぀のメむンQMLファむルがQQmlApplicationEngineを介しお䜿甚され、異なるりィンドりずそれらの間の遷移がロヌダヌによっお実行されたす次の郚分でそれに぀いお。 これ以䞊詳しくは説明したせん。JSON、HttpPostリク゚ストの解析方法、キヌボヌドでは衚瀺されない/䞍本意なゞャムの解決方法、QMLでバックスタックのようにナビゲヌションを䜜成する方法「手動」プレス凊理ボタン「戻る」およびいく぀かの゚ンティティ。



3.クラむアント/サヌバヌ開発の基本
ここでは、Qtで頭を壁に少しパンチした埌の解決方法を説明したす。 これは本曞の䞻芁郚分です。



これで開始する準備ができたした Qt 5.3が既にむンストヌルされおいるこずを前提ずしおいたす-qt-project.org/downloads、JDK、Android SDK、NDK、apache-antはAndroidでコンパむルするためにダりンロヌドされたすQt Creator蚭定でパスを指定する必芁がありたす、iOSの堎合-XCODE 。



3.1。 プロゞェクトの䜜成ず準備
Qt Creatorを起動し、[新しいプロゞェクト]をクリックしたす。 「Qt Quick Application」を遞択したす

画像



名前に違いがないように、プロゞェクトを「サンプル」ず呌びたすプロゞェクトの名前ずそのパスにキリル文字を䜿甚するこずはできたせん。

画像



Qt Quickコンポヌネントのセットは、Qt Quick Controls 1.1に残りたす。

画像



Qt Quick Controls 1.1は、Qt Quick 2.2の基本芁玠に加えお、さたざたな機胜むンタヌフェむス芁玠コントロヌルを含むラむブラリのセットです。 ここでは、コントロヌルを䜿甚するずアプリケヌションのサむズが3メガバむト増加するこずをすぐに予玄したす。私の堎合、コントロヌルを含む収集されたapkファむルの重量は11.6 MBでした。 私の意芋では、プラスコントロヌルはアプリケヌションの起動を遅くしたすただし、問題はロヌダヌたたはスプラッシュスクリヌンで解決できたす。 ただし、それらを䜿甚するず開発が簡玠化されるため、それらを攟棄したせん。



次に-アプリケヌションを実行するプラットフォヌムを遞択したす。

画像



必芁なプラットフォヌムのチェックボックスをオンにしたす。むンストヌルしたプラットフォヌムに関係なく、デスクトップもチェックするこずをお勧めしたす。アプリケヌションはデスクトップで最も速く実行されるため、テストに䟿利です。



バヌゞョン管理の接続は停止したせんこの䟋では簡単に実行できたすが、この䟋では必芁ありたせん。[完了]をクリックするだけです。

画像



プロゞェクトが䜜成されたした 䜕で構成されおいたすか

画像



プロゞェクトツリヌを芋おみたしょう。 たず第䞀に、私たちが必芁ずする䜜業では

-構成* .proファむルSample.proAndroidのマニフェストファむルに䌌たもの。

-゜ヌスコヌドずヘッダヌファむル埌で䜜成したす。アプリケヌションバック゚ンドがありたす。

-* .qrc-fileqml.qrcその䞭に、アプリケヌションに必芁なすべおのリ゜ヌスQML-ファむル、むメヌゞなどを瀺したす。

-むンタヌフェむスのQMLファむルこれたでのずころ、main.qmlのみがありたす。



アプリケヌションを保存しお実行するず、デスクトップに次のようなものが衚瀺されたす。

画像



3.2。 むンタヌフェむス䜜成
3.2.1。 ボタンを䜜成する
main.qmlファむルを開きたす。 タむトル、メニュヌバヌ、テキストを削陀したす。 その結果、次のこずができるようになりたす。



import QtQuick 2.2 import QtQuick.Controls 1.1 ApplicationWindow { visible: true width: 640 height: 480 }
      
      







ApplicationWindowは、子が远加されるルヌト芁玠です。 メむンQMLファむルに存圚する必芁がありたす。 ApplicationWindow内にidずobjectNameの2぀のフィヌルドをすぐに曞き蟌みたす。



 ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 }
      
      







idはQMLファむル内のApplicationWindowにアクセスするために䜿甚されたす。objectNameはC ++コヌドでQMLからメむンりィンドりを芋぀けるために必芁です。



固定倀の幅ず高さのパラメヌタヌは今のずころ混同しないでください。 むンタヌフェヌスは、最初にそのような寞法でのみ䜜成され、その埌スマヌトフォンの画面サむズたで拡倧されたす。 このため、Androidでは、アプリケヌションの起動時に画面がわずかにぎくしゃくしおおり、修正方法がありたす。最埌に説明したす。



䞀般的に、構文ベヌスのQMLファむルは、Webレむアりトずjavascript-logicの揮発性の混合を連想させたすが、類䌌性は郚分的です。 QMLでは、むンタヌフェむスだけでなく、ロゞックたずえば、フォヌムの完了を確認するのに䟿利も䜜成できたすが、これはプラスです。



りィンドりの色を指定したしょうこれを行うには、ApplicationWindowの「height480」行のすぐ䞋に行を远加したす



 color: "#F0F0FF"
      
      







16進コヌドで色を蚭定できたす。䞀郚の色は、たずえば「赀」、「透明」などの名前で指定できたす。 䜜成した定数を䜿甚するこずもできたす。詳现に぀いおは、埌で説明したす。 次に、むンポヌトに远加したす。



 import QtQuick.Controls.Styles 1.2
      
      







コントロヌルをカスタマむズするにはスタむルが必芁になりたす。 ApplicationWindow内にボタンを䜜成したす。 䞀般的なコヌド



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height } }
      
      







ボタンの幅は、メむンりィンドりの幅、高さ-メむン画面の高さを基準にしお蚈算されたす。 ここでは、ボタンのサむズず䜍眮を蚈算するためのid、基本匏によっお芁玠にアクセスする䟋を瀺したす[参照 サプリメント1] 。 匏のパラメヌタヌyによっお蚈算される高さの前にidを指定しない堎合、内郚にある珟圚の芁玠のパラメヌタヌが䜿甚されおいるず芋なされたす。 すべおを保存しお実行したす。

画像



ボタンが衚瀺され、そのサむズは開いおいるりィンドりデスクトップたたはモバむルデバむスの画面のサむズに察しお蚈算されたす。これにより、さたざたなデバむスUIを䜜成するためにカスタムクラスを䜿甚しない堎合のAndroidのusually栞ず同じの同じ衚瀺の問題を解決できたす。



新しいボタンのスタむルを䜜成したしょう これを行うには、Button内に以䞋を远加したす。



 style: ButtonStyle { }
      
      







ボタンのスタむルは、背景ずラベルの2぀の郚分で構成されたす。 これらの郚分を別のQMLファむルに䜜成しお、メむンの郚分が乱雑にならないようにしたす。 これを行うには、Qt Creatorを折りたたんでプロゞェクトフォルダヌに移動し、そこに「QML」フォルダヌを䜜成しお、䜜業ファむルが敎然ず配眮されるようにしたす。



Qt Creatorに戻りたす。 ツリヌプロゞェクトでプロゞェクト名を右クリックし、コンテキストメニュヌで[新芏远加...]を遞択したす。 次に、Qt、「QMLファむルQt Quick 2」を遞択したす。

画像



名前は「ButtonBackground」、パスは新しく䜜成された「QML」フォルダヌぞのパスです。

画像



プレフィックスを確認したす。バヌゞョン管理は必芁ないため、[完了]をクリックしたす。

画像



同様に、「ButtonLabel.qml」ファむルを䜜成したす。 プロゞェクトは次のようになりたした。

画像



「QML / ButtonBackground.qml」をダブルクリックしお開きたす。 次のように線集したす。



 import QtQuick 2.2 Rectangle { anchors.fill: parent anchors.margins: 4 border.width: 2 border.color: "#FFFFFF" radius: height / 4 gradient: Gradient { GradientStop { position: 0; color: control.pressed ? "#00AAAA" : "#AAFFFF" } GradientStop { position: 1; color: "#00CCCC" } } // color: "#00AAAA" // opacity: 0.25 }
      
      







順番に

-anchors.fillparent-ボタンの背景が完党に塗り぀ぶされるようにするparent-珟圚の芁玠が配眮されおいる芪芁玠ぞのアクセス。

-anchors.margins4-すべおの偎面から小さなむンデントを蚭定したす。

-ボヌダヌ-ストロヌク蚭定[参照 サプリメント8] ;

-半埄高さ/ 4-ここではすでに興味深いです。 この堎合、角を䞞くするために䜿甚されたす倀はボタンの高さに察しお広がりたすが、Rectangleの幅ず高さを同じに蚭定するず、十分に倧きい半埄倀を䜿甚しおRectangleから円を取埗できたす。

-募配は2点で構成されたす。 最初のポむントれロ䜍眮に泚意しおください-ここでは、ボタンの状態control.pressedに切り替えお、抌されたボタンに応じお色を決定したす。単玔な条件挔算子を䜿甚したす。 真実の堎合のアクションfalseの堎合のアクション。

-グラデヌションの代わりに色を蚭定できたす。たずえば、透明床䞍透明床0〜1を䜿甚するこずもできたす。



「ButtonBackground.qml」を保存し、「main.qml」に戻りたす。 䜜成したQMLフォルダヌをむンポヌトに远加したす。



 import "QMLs"
      
      







これで、このフォルダヌ内のすべおのQMLファむルにアクセスできたす。 ボタンスタむルに戻り、䜜成したばかりの背景を指定したす。 結果は次のようになりたす。



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} } } }
      
      







すべおを保存しお実行したす。

画像



ボタンは少し明るくなりたしたが、眲名がありたせん。 修正しおください。 「ButtonLabel.qml」を開き、次のように線集したす。



 import QtQuick 2.2 Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.bold: true font.pixelSize: (mainWindow.width>mainWindow.height) ? parent.height/1.75 : parent.height / 2.5 color: "#005050" // text: "" }
      
      







眲名はボタン本䜓を完党に埋め、䞭倮に配眮され、倧胆な顔をしおいたす。 眲名のサむズは、珟圚の画面の向きを基準にしお蚈算されたす。幅が倧きいほど暪向きになり、高さ-瞊向きになるのは論理的です[参照 補足2] 。 ここではボタンテキストをむンストヌルしたせん。これは䞍䟿です。



再び「main.qml」を開きたす。 䜜成したばかりの「ButtonLabel」をラベルスタむルに远加したす。ここでは、ボタンテキストをすぐに瀺したす[参照 サプリメント3] 。 次のようになりたす。



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } } }
      
      







すべおを保存しお実行したす。

画像



クリック可胜なボタンがあるので、クリックハンドラヌを远加しお、ログにメッセヌゞを出力したす。 これを行うには、ボタン内に行を远加したす。



 onClicked: console.log("Button '' clicked")
      
      







合蚈で



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: console.log("Button '' clicked") } }
      
      







実行しお確認しおください。 「アプリケヌション出力」パネルQt Creatorりィンドりの䞀番䞋のボタンをクリックするず、新しい行が衚瀺されたす「qmlButton 'Test' clicked」

画像



これで、今のずころボタンで䜜業を終了したす。



3.2.2。 テキスト入力フィヌルドを䜜成する
「main.qml」を開きたす。 「ボタン」の䞋に远加



 TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { Qt.inputMethod.hide() event.accepted = true } } }
      
      







サむズを蚭定したす。フィヌルドからテキストを読み取るにはidが必芁です。 䞭倮に配眮を配眮し、プレヌスホルダヌを指定したす。



たた、この入力に単玔な正芏衚珟を远加したすいずれの堎合も「a」から「i」、および「a」から「z」の文字、合蚈16文字以内。



スタむルは別のファむルに移動されたせん。 背景背景に癜い長方圢を眮き、入力テキストずプレヌスホルダヌの色を蚭定したす。 フォントでは、単語を倧文字font.capitalization = Font.Capitalize、倪字、およびフォントサむズで構成したすここでは芪芁玠にアクセスできないため、画面の高さに察するサむズを蚈算したす。



「TextField」の堎合、inputMethodHintsフィヌルドに倀を远加するこずもできたすQt.ImhPreferNumbersなど。 倀に応じお、入力甚のさたざたなキヌボヌドが衚瀺されたすQt.ImhPreferNumbersの堎合、数字を入力するためのキヌボヌドが衚瀺されたす[付録6を参照] 。 この堎合、このフィヌルドは远加したせん。 たた、echoModeなどの他の䟿利なパラメヌタヌもありたすパスワヌドを入力するには、TextInput.Passwordに蚭定できたす。



別に、Keys.onPressed内の匏に぀いお蚀及する必芁がありたす。 ここでは、完了ボタンのクリックを远跡しお、クリックしたずきにAndroidデバむスのキヌボヌドを閉じるようにしたす。 したがっお、「main.qml」は最終的に次のようになりたす。



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: console.log("Button '' clicked") } TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { Qt.inputMethod.hide() event.accepted = true } } } }
      
      







AndroidタブレットずiPhoneシミュレヌタヌでは、珟圚のアプリケヌションは次のようになりたす。

画像



画像



論理的な結論を達成するために、ボタンがクリックされたずきに私たちの名前の挚拶が衚瀺される眲名を远加したしょう。 「main.qml」の「TextField」の埌に远加したす。



 Text { id: text y: textField.height width: parent.width height: parent.height / 10 font.pixelSize: height / 2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap }
      
      







眲名は、テキスト入力フィヌルドytextField.heightのすぐ䞋に配眮されたす。このため、ワヌドラップも蚭定したす。 繰り返したすが、䟿宜䞊「テキスト」党䜓を別のQMLファむルに移動できたすが、この堎合はこれを行いたせん。



ボタンを抌すためのロゞックを芏定するこずは残っおいたす。 ボタンのonClickedフィヌルドに目的のアクションをすべお蚘述できたすが、今回はこのための関数を䜜成したしょう。 これは、ボタンに远加された関数を䜿甚した堎合の「main.qml」の倖芳です。



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { function hello() { if (textField.text != "") { text.text = ", <b>" + textField.text.toUpperCase() + "</b>!" } } width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: hello() } TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { Qt.inputMethod.hide() event.accepted = true } } } Text { id: text y: textField.height width: parent.width height: parent.height / 10 font.pixelSize: height / 2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap } }
      
      







ご芧のずおり、テキストをフォヌマットするこずができたすこの堎合はタグを䜿甚。保存、実行、および確認したす。

画像



3.2.3。 ListViewでの䜜業
この䟋では、2぀のリストを䞀床に䜜成しお、ListViewの機胜をさらに衚瀺したす。 「テキスト」の䞋の「main.qml」に远加したす。



 ListView { id: lvList objectName: "lvList" y: text.y + text.height width: parent.width height: parent.height * 0.3 clip: true spacing: 8 model: ListModel { ListElement { name: " 0" } ListElement { name: " 1" } ListElement { name: " 2" } } delegate: Rectangle { width: lvList.width height: lvList.height / 3 color: "#00AAAA" Text { text: name } MouseArea { anchors.fill: parent onClicked: console.log("ListView el#" + index + " clicked!") } } }
      
      







ListViewの識別子ずサむズを蚭定したす。 ListView自䜓は透明なので、そのための基盀を䜜成したせん。



クリップパラメヌタはtrueに蚭定されおいたす。これは、 それ以倖の堎合、リストをスクロヌルするず、リストに衚瀺されるようになる芁玠がListViewからクロヌルされたす。



間隔パラメヌタヌは、リスト項目間のむンデントを蚭定したす。



さらに、モデルは基本的にデヌタモデルです。 耇数のListElementを含むListModelが入力されたす。 「ListElement」は実際にはリストの芁玠であり、内郚に目的の名前ず倀のペアを登録できたす。この堎合、ペアは1぀だけです。



デリゲヌトパラメヌタヌは、リスト内の各アむテムの倖芳を決定したす。 テキストが入った長方圢ができたす。 テキストパラメヌタヌの倀に぀いおは、モデルに以前に登録された名前パラメヌタヌを瀺したす。



「MouseArea」は、マりスクリックを远跡したり、画面に觊れたりできる領域です。 デリゲヌトのサむズを入力したす。 を抌すず、ログに芁玠のむンデックスが衚瀺されたす。 MouseAreaには䟿利なonPressedフィヌルドもありたす。

そしおonReleased。



䞀般に、QMLで芏定されおいるモデルは将来必芁ありたせん。 バック゚ンドが充填を行いたす。 ただし、このようなスタブを䜜成しおリストの倖芳をカスタマむズするず䟿利です。 たた、デリゲヌトのデザむンを別のQMLファむルで䜜成するこずも䟿利です。 たた、ListViewにはさたざたなパラメヌタヌがあり、埮調敎を詊みるこずができるこずも远加したす。 しかし、ここでは他に䜕も耇雑にしたせん。 䜕が起こったのか芋おみたしょう。 保存しお実行

画像



リスト項目をクリックしおログを確認しおみたしょう。「qmlListView el0 clicked」のような行が衚瀺されたす。



2番目のリストに移動したす。 最初のリストの䞋に远加したす。



 ListView { id: lvPager y: lvList.y + lvList.height width: parent.width height: parent.height * 0.2 clip: true model: ListModel { ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Moscow" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=London" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Rio" } } delegate: Image { width: lvPager.width height: lvPager.height source: map_url fillMode: Image.PreserveAspectFit } orientation: ListView.Horizontal snapMode: ListView.SnapOneItem }
      
      







モデルずしお、リク゚ストに応じお返される画像をマップするためにリンクを䜿甚したす。 デリゲヌトはむメヌゞ自䜓であり、その゜ヌス゜ヌスはモデルで指定されたリンクになりたす。 ロヌカルファむルを゜ヌスずしお指定するこずもできたす。 これを行うには、次のものが必芁です。

-プロゞェクトフォルダヌに画像を远加したす。

-Qt Creatorのプロゞェクトツリヌで、「qml.qrc」を右クリックし、「゚ディタヌで開く」を遞択したす。

-りィンドりの「远加」->「ファむルの远加」->远加した画像を遞択したす。

-QMLファむルの「むメヌゞ」で、゜ヌスずしおむメヌゞぞのパスを次のように瀺したす「qrc/ full_file_name」。



「画像」の堎合、瞊暪比を維持しながら画像自䜓が目的の幅/高さの寞法に調敎されるように、fillModeも蚭定したす。



方向パラメヌタヌ氎平方向に蚭定ずsnapModeListView.SnapOneItemを䞀緒に䜿甚するず、ListViewがAndroidのViewPagerのようになるずいう効果を実珟できたす。



ほが完了。 プロゞェクトツリヌで、ファむル「Sample.pro」を開き、「ネットワヌク」を「QT + = qml quick widgets」行に远加したす。そうしないず、ネットワヌク接続が機胜したせん。

画像



念のため、すべおの「main.qml」コヌドのリストを投皿しおいたす。



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { function hello() { if (textField.text != "") { text.text = ", <b>" + textField.text.toUpperCase() + "</b>!" } } width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: hello() } TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { Qt.inputMethod.hide() event.accepted = true } } } Text { id: text y: textField.height width: parent.width height: parent.height / 10 font.pixelSize: height / 2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap } ListView { id: lvList objectName: "lvList" y: text.y + text.height width: parent.width height: parent.height * 0.3 clip: true spacing: 8 model: ListModel { ListElement { name: " 0" } ListElement { name: " 1" } ListElement { name: " 2" } } delegate: Rectangle { width: lvList.width height: lvList.height / 3 color: "#00AAAA" Text { text: name } MouseArea { anchors.fill: parent onClicked: console.log("ListView el#" + index + " clicked!") } } } ListView { id: lvPager y: lvList.y + lvList.height width: parent.width height: parent.height * 0.2 clip: true model: ListModel { ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Moscow" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=London" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Rio" } } delegate: Image { width: lvPager.width height: lvPager.height source: map_url fillMode: Image.PreserveAspectFit } orientation: ListView.Horizontal snapMode: ListView.SnapOneItem } }
      
      







実行しお䜕が起こったかを確認できたす。

画像



私の意芋では、QMLでListViewを操䜜するのは非垞に簡単で䟿利であり、カスタマむズの可胜性はたくさんありたす。 ListViewを䜿甚するず、たずえば、スピナヌポップアップリストを実装しお、リストの可芖性フィヌルドの衚瀺を操䜜するこずもできたす。



重芁な泚意䜕らかの理由で、Habrは "map_url"の¢erをセント蚘号に眮き換えたす。 リク゚ストリンクでは、center = ...をスペヌスなしでのみ䜿甚する必芁がありたす。



3.2.4。 ロヌダヌずいく぀かのアニメヌションを䜿甚する
「ロヌダヌ」は、QMLでマルチりィンドりを実装できるようにする゚ンティティです。 䞭栞ずなる「ロヌダヌ」は、QMLファむルを゜ヌスずしお持぀単なるコンテナです理論的には、このファむルを倖郚サヌバヌのどこかに配眮するこずもできたす。 ここで非垞に重芁です。QMLたたはC ++コヌドからLoader内の芁玠にアクセスする堎合、この芁玠を含むコンテナを珟時点でLoaderにロヌドする必芁がありたす。そうしないず、アプリケヌションがクラッシュしたす。 珟時点では存圚しない芁玠を参照するこずはできず、Qtにそのプロパティの䞀郚を倉曎するように䟝頌するこずはできたせん。 問題を解決するには、特定のコンテナのアクティビティに関するブヌル倀フラグを保存するか、危険な時間たずえば、サヌバヌぞの接続の進行䞭にロヌダヌのコンテンツの切り替えを犁止したすナビゲヌションボタンで有効falseを蚭定できたす。



したがっお、プロゞェクトのQMLフォルダヌに2぀のQMLファむルを䜜成したす。 それらを「Loader1.qml」および「Loader2.qml」ず呌びたしょう。 「Loader1.qml」



 import QtQuick 2.2 Rectangle { anchors.fill: parent color: "green" opacity: 0.2 }
      
      







ただの緑色の長方圢。 今「Loader2.qml」



 import QtQuick 2.2 Rectangle { id: rect anchors.fill: parent focus: true color: "blue" opacity: 0.2 SequentialAnimation { running: true loops: SequentialAnimation.Infinite PropertyAnimation { target: rect; property: "opacity"; to: 0; duration: 500 } PropertyAnimation { target: rect; property: "opacity"; to: 0.2; duration: 500 } } Keys.onPressed: { if (event.key == Qt.Key_Back || event.key == Qt.Key_Escape) { loader.source = "qrc:/QMLs/Loader1.qml" event.accepted = true } } }
      
      







focustrueを指定しおください。 そうでない堎合、Keys.onPressedセクションは起動したせん。



SequentialAnimationは、䞀連のアニメヌションです。 runningtrueパラメヌタヌを指定しお、アニメヌションがすぐに機胜するように、ルヌプ繰り返しの数を無限に蚭定したす。



内郚では、SequentialAnimationには2぀のPropertyAnimationsがありたす。 特定の時間期間の間、タヌゲット芁玠タヌゲットのパラメヌタヌプロパティを目的の倀にに倉曎できたす。



アニメヌションが停止した埌runningfalseに蚭定した堎合、倉曎されたすべおのタヌゲットパラメヌタを元のパラメヌタに手動で戻す必芁があるこずに泚意しおください。



「main.qml」内にロヌダヌ自䜓を䜜成したす。



 Loader { id: loader y: lvPager.y + lvPager.height width: parent.width height: parent.height * 0.2 focus: true source: "qrc:/QMLs/Loader1.qml" }
      
      







内郚芁玠゜ヌスがボタンのクリックを監芖するように、必ずfocustrueを指定しおください。



: . , Keys.onPressed :



 Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return || event.key == Qt.Key_Back) { Qt.inputMethod.hide() loader.forceActiveFocus() event.accepted = true } }
      
      







«main.qml», :



 Button { width: mainWindow.width / 4.5 height: mainWindow.height / 10 x: mainWindow.width / 2 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "Loader" } } onClicked: loader.setSource("qrc:/QMLs/Loader2.qml") }
      
      







«main.qml»:



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { function hello() { if (textField.text != "") { text.text = ", <b>" + textField.text.toUpperCase() + "</b>!" } } width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: hello() } TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return || event.key == Qt.Key_Back) { Qt.inputMethod.hide() loader.forceActiveFocus() event.accepted = true } } } Text { id: text y: textField.height width: parent.width height: parent.height / 10 font.pixelSize: height / 2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap } ListView { id: lvList objectName: "lvList" y: text.y + text.height width: parent.width height: parent.height * 0.3 clip: true spacing: 8 model: ListModel { ListElement { name: " 0" } ListElement { name: " 1" } ListElement { name: " 2" } } delegate: Rectangle { width: lvList.width height: lvList.height / 3 color: "#00AAAA" Text { text: name } MouseArea { anchors.fill: parent onClicked: console.log("ListView el#" + index + " clicked!") } } } ListView { id: lvPager y: lvList.y + lvList.height width: parent.width height: parent.height * 0.2 clip: true model: ListModel { ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Moscow" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=London" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Rio" } } delegate: Image { width: lvPager.width height: lvPager.height source: map_url fillMode: Image.PreserveAspectFit } orientation: ListView.Horizontal snapMode: ListView.SnapOneItem } Loader { id: loader y: lvPager.y + lvPager.height width: parent.width height: parent.height * 0.2 focus: true source: "qrc:/QMLs/Loader1.qml" } Button { width: mainWindow.width / 4.5 height: mainWindow.height / 10 x: mainWindow.width / 2 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "Loader" } } onClicked: loader.setSource("qrc:/QMLs/Loader2.qml") } }
      
      







url (& center) , . , :

画像



画像



«Loader» . Android- «Back», .



UI QML C++ .





3.3.
, QML- C++ , QML C++ , GET/POST- JSON-.



-, // , .



«qt_api», «test.php». :



 <? echo json_encode(json_decode( '{ "done" : { "boolean" : true, "number" : 123, "list" : [ "field1", "field2", "field3", "field4", "field5" ] } }' )); ?>
      
      







JSON, «test.php» (http://localhost/qt_api/test.php) .



C++ Qt Creator: «Sample» -> «  » -> «C++» / « C++». «Backend», «QQuickItem» [. 4] , :

画像



«», «». «backend.h». :



 #ifndef BACKEND_H #define BACKEND_H #include <QQmlApplicationEngine> #include <QQuickItem> #include <QtQuick> #include <QNetworkAccessManager> class Backend : public QQuickItem { Q_OBJECT public: explicit Backend(QQuickItem *parent = 0); Q_INVOKABLE void makeRequest(int id); private: QQmlApplicationEngine engine; QObject * mainWindow; QObject * lvList; QObject * btnRequest; QNetworkAccessManager * namRequest; static const QString color_example; signals: private slots: void slotRequestFinished(QNetworkReply*); }; #endif // BACKEND_H
      
      







.



. ( explicit). , , . Qt . , ( , , ), , Qt .



makeRequest. QML-, Q_INVOKABLE. id ( ).



(private) . QQmlApplicationEngine QML-. QObject QML [. 5] . QNetworkAccessManager (- DefaultHttpClient Android). , QML.



. , -. / — Qt, , , . :



 void mySignal();
      
      







:



 emit mySignal();
      
      







, ( connect()) . , , , - -. , namRequest. (slotRequestFinished(QNetworkReply*)) — - QNetworkAccessManager: , namRequest finished(QNetworkReply*), , (QNetworkReply).



«backend.cpp», :



 #include "backend.h" const QString Backend::color_example = "#000000"; Backend::Backend(QQuickItem *parent) : QQuickItem(parent) { engine.rootContext()->setContextProperty("color_example", color_example); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); mainWindow = engine.rootObjects().value(0); lvList = mainWindow->findChild<QObject*>("lvList"); btnRequest = mainWindow->findChild<QObject*>("btnRequest"); engine.rootContext()->setContextProperty("backend", this); namRequest = new QNetworkAccessManager(this); connect(namRequest, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotRequestFinished(QNetworkReply*))); } void Backend::makeRequest(int id) { btnRequest->setProperty("enabled", "false"); // btnRequest->property("enabled"); QString prepareRequest("http://localhost/qt_api/test"); // HttpGet prepareRequest.append("?id="); prepareRequest.append(QString::number(id)); qDebug(prepareRequest.toUtf8()); QNetworkRequest request(QUrl(prepareRequest.toUtf8())); namRequest->get(request); // HttpPost /*QNetworkRequest request(QUrl(prepareRequest.toUtf8())); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QString params("id="); params.append(QString::number(id)); qDebug(params.toUtf8()); namRequest->post(request, QByteArray(params.toUtf8()));*/ } void Backend::slotRequestFinished(QNetworkReply * reply) { if (reply->error() != QNetworkReply::NoError) { qDebug(reply->errorString().toUtf8()); } else { QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll()); QJsonObject jsonObj; QJsonValue jsonVal; QJsonArray jsonArr; jsonObj = jsonDoc.object(); jsonVal = jsonObj.value("done"); if (!jsonVal.isNull() && jsonVal.isObject()) { jsonObj = jsonVal.toObject(); jsonVal = jsonObj.value("number"); if (!jsonVal.isNull() && jsonVal.isDouble()) { qDebug(QString::number(jsonVal.toDouble(), 'f', 3).toUtf8()); } } if (jsonDoc.object().value("done").toObject().value("boolean").toBool()) { qDebug("json true"); } else { qDebug("json false"); } jsonArr = jsonDoc.object().value("done").toObject().value("list").toArray(); QMetaObject::invokeMethod(lvList, "clear"); for (int i=0; i<jsonArr.size(); i++) { QVariantMap map; map.insert("name", jsonArr.at(i).toString()); QMetaObject::invokeMethod(lvList, "append", Q_ARG(QVariant, QVariant::fromValue(map))); } } btnRequest->setProperty("enabled", "true"); reply->deleteLater(); }
      
      







, . : .



QML- QQmlApplicationEngine.



QML:



 mainWindow = engine.rootObjects().value(0);
      
      







objectName, QML. lvList:



 lvList = mainWindow->findChild<QObject*>("lvList");
      
      







«backend» Backend. ( Q_INVOKABLE-) QML:



 engine.rootContext()->setContextProperty("backend", this);
      
      







«color_example» QML:



 engine.rootContext()->setContextProperty("color_example", color_example);
      
      







namRequest:



 namRequest = new QNetworkAccessManager(this);
      
      







finished(QNetworkReply*) slotRequestFinished(QNetworkReply*):



 connect(namRequest, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotRequestFinished(QNetworkReply*)));
      
      







connect 4 :

— , ;

— ;

— , ( );

— , .



makeRequest. , :



 btnRequest->setProperty("enabled", "false");
      
      







QML ( ). QString:



 QString prepareRequest(«http://localhost/qt_api/test");
      
      







GET- , :



 prepareRequest.append("?id="); prepareRequest.append(QString::number(id));
      
      







int- ( makeRequest) QString. QString::number().



(QString QByteArray):



 qDebug(prepareRequest.toUtf8());
      
      







QNetworkRequest QNetworkAccessManager GET-:



 QNetworkRequest request(QUrl(prepareRequest.toUtf8())); namRequest->get(request);
      
      







POST- , . , POST-, , CodeIgniter', «Disallowed Characters Error», .



, , .



, , , :



 if (reply->error() != QNetworkReply::NoError) { qDebug(reply->errorString().toUtf8()); }
      
      







, . QJsonDocument JSON-. QJsonDocument QJsonDocument::fromJson(reply->readAll()), : reply->readAll(). , QNetworkReply, , ( - ).



JSON- QJsonDocument:



 jsonObj = jsonDoc.object();
      
      







QJsonValue «done» JSON-:



 jsonVal = jsonObj.value("done");
      
      







QJsonValue — JSON-, ( , , ..). QJsonValue . , QJsonValue JSON- QJsonValue ( «number») . , , QJsonValue double. «number» (3 ).

«boolean» «done» .



JSON- Qt: JSON- , ( Android, , JSONException). (, ), .



, Qt «» JSON-, , , JSON' .



QML JSON-, .



JSON- «list» QJsonArray:



 jsonArr = jsonDoc.object().value("done").toObject().value("list").toArray();
      
      







«clear» «lvList» ( «clear» ListView QML- ):



 QMetaObject::invokeMethod(lvList, "clear");
      
      







«lvList» JSON- — -, , «name» (, ListView?):



 QVariantMap map; map.insert("name", jsonArr.at(i).toString());
      
      







«append» «lvList» ( ):



 QMetaObject::invokeMethod(lvList, "append", Q_ARG(QVariant, QVariant::fromValue(map)));
      
      







QMetaObject::invokeMethod() :

— — , ;

— — , «lvList»;

— — , «append», «map».



:



 btnRequest->setProperty("enabled", «true");
      
      







:



 reply->deleteLater();
      
      







. «main.cpp»:



 #include <QApplication> #include "backend.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); new Backend(); return app.exec(); }
      
      







«Backend», .



«clear», «append» ListView («lvList») «main.qml»:



 function clear() { lvList.model.clear() } function append(newElement) { lvList.model.append(newElement) }
      
      







C++ «append» ( ), .



:



 model: ListModel { //ListElement { name: " 0" } //ListElement { name: " 1" } //ListElement { name: " 2" } }
      
      







, makeRequest() Backend:



 Button { objectName: "btnRequest" property int _id: 3 width: mainWindow.width / 4.5 height: mainWindow.height / 10 x: mainWindow.width - width y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground { border.color: color_example } label: ButtonLabel { text: "Request" } } onClicked: backend.makeRequest(_id) }
      
      







«btnRequest», , C++ ,



 property int _id: 3
      
      







— - QML-: «property», , . : id_._.



. -, :



 background: ButtonBackground { border.color: color_example }
      
      







, «color_example» «Backend»? -, :



 onClicked: backend.makeRequest(_id)
      
      







, , , ( property «_id», ).



«main.qml»:



 import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.2 import "QMLs" ApplicationWindow { id: mainWindow objectName: "mainWindow" visible: true width: 640 height: 480 color: "#F0F0FF" Button { function hello() { if (textField.text != "") { text.text = ", <b>" + textField.text.toUpperCase() + "</b>!" } } width: mainWindow.width / 2.5 height: mainWindow.height / 10 x: 0 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "" } } onClicked: hello() } TextField { id: textField width: parent.width height: parent.height / 10 horizontalAlignment: Text.AlignHCenter placeholderText: " " validator: RegExpValidator { regExp: /[--a-zA-Z]{16}/ } style: TextFieldStyle { background: Rectangle {color: "white"} textColor: "#00AAAA" placeholderTextColor: "#00EEEE" font: font.capitalization = Font.Capitalize, font.bold = true, font.pixelSize = mainWindow.height / 25 } Keys.onPressed: { if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return || event.key == Qt.Key_Back) { Qt.inputMethod.hide() loader.forceActiveFocus() event.accepted = true } } } Text { id: text y: textField.height width: parent.width height: parent.height / 10 font.pixelSize: height / 2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap } ListView { id: lvList objectName: "lvList" y: text.y + text.height width: parent.width height: parent.height * 0.3 clip: true spacing: 8 model: ListModel { //ListElement { name: " 0" } //ListElement { name: " 1" } //ListElement { name: " 2" } } delegate: Rectangle { width: lvList.width height: lvList.height / 3 color: "#00AAAA" Text { text: name } MouseArea { anchors.fill: parent onClicked: console.log("ListView el#" + index + " clicked!") } } function clear() { lvList.model.clear() } function append(newElement) { lvList.model.append(newElement) } } ListView { id: lvPager y: lvList.y + lvList.height width: parent.width height: parent.height * 0.2 clip: true model: ListModel { ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Moscow" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=London" } ListElement { map_url: "http://maps.googleapis.com/maps/api/staticmap?size=640x320&scalse=2&sensor=false¢er=Rio" } } delegate: Image { width: lvPager.width height: lvPager.height source: map_url fillMode: Image.PreserveAspectFit } orientation: ListView.Horizontal snapMode: ListView.SnapOneItem } Loader { id: loader y: lvPager.y + lvPager.height width: parent.width height: parent.height * 0.2 focus: true source: "qrc:/QMLs/Loader1.qml" } Button { width: mainWindow.width / 4.5 height: mainWindow.height / 10 x: mainWindow.width / 2 y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground {} label: ButtonLabel { text: "Loader" } } onClicked: loader.setSource("qrc:/QMLs/Loader2.qml") } Button { objectName: "btnRequest" property int _id: 3 width: mainWindow.width / 4.5 height: mainWindow.height / 10 x: mainWindow.width - width y: mainWindow.height - height style: ButtonStyle { background: ButtonBackground { border.color: color_example } label: ButtonLabel { text: "Request" } } onClicked: backend.makeRequest(_id) } }
      
      







, . «Request» ( iPhone ) :

画像



:



localhost/qt_api/test?id=3

123.000

json true




そうです。 :). (https://www.dropbox.com/s/to9kk0l71d6ma4h/Sample.zip).



, Qt:



 //   QSettings,   ,      QSettings settings("settings.ini", QSettings::IniFormat); //  ,      QString stringToSave; //     ,    QDate QDate date = QDate::currentDate(); //        stringToSave = date.toString("ddd-dd-MM-yyyy"); //   id   QUuid QUuid uniq_id = QUuid::createUuid(); //   id   stringToSave.append(" id="); stringToSave.append(uniq_id.toByteArray()); //      settings.setValue("value1", stringToSave); settings.sync(); //        qDebug(settings.value("value1").toString().toUtf8());
      
      







, . , — Android . — , ApplicationWindow [. 7] . — «Backend» QML :



 engine.rootContext()->setContextProperty("screen_width", this->width()); engine.rootContext()->setContextProperty("screen_height", this->height());
      
      







QML- «ApplicationWindow» :



 ApplicationWindow { . . . width: screen_width height: screen_height color: "#F0F0FF" . . .
      
      







:). , . Android ( , , Qt, , ), . «» -> «Android» -> «».





4.
, , . Qt, , . , , - . — .



, , , - , .



, , — Qt , QtWebEngine (, , WebView ), BLE — qt-project.org/wiki/New-Features-in-Qt-5.4 .



Qt , . , Qt .



, , !



1. UI , .. «anchors». , , :

 anchors.bottom: some_element_id.top
      
      





2. , -, property, -, / UI-, .. Screen.primaryOrientation ( QtQuick.Window 2.0).



3. ( «text:»), . , .



4. C++ , QObject. QQuickItem .



5. C++ QML ( UI- ). :

— :

 public: signals: void testSignal();
      
      





— - :

 emit testSignal();
      
      





— QML «Connections» «ApplicationWindow», C++:

 Connections{ target: backend; onTestSignal: console.log("emited!") }
      
      





«target» — ContextProperty, , «onTestSignal:» — emit' «testSignal()».



6. «inputMethodHints» «Qt.ImhDialableCharactersOnly», .. «Qt.ImhPreferNumbers» .



7. UI «» Android QML ( ApplicationWindow) Screen.desktopAvailableWidth/Screen.desktopAvailableHeight ( QtQuick.Window 2.0).



8. :

 border { width: 2 color: "#FFFFFF" }
      
      








All Articles