通过HTTP服务UI(Serving UI via HTTP)

通过HTTP加载一个简单的用户界面,我们需要一个web服务器,它为UI文件服务。但是首先我们需要有用户界面,我们在项目里创建一个创建了红色矩形框的main.qml。

  1. // main.qml
  2. import QtQuick 2.0
  3. Rectangle {
  4. width: 320
  5. height: 320
  6. color: '#ff0000'
  7. }

我们加载一段python脚本来提供这个文件:

  1. $ cd <PROJECT>
  2. # python -m SimpleHTTPServer 8080

现在我们可以通过http://localhost:8000/main.qml来访问,你可以像下面这样测试:

  1. $ curl http://localhost:8000/main.qml

或者你可以用浏览器来访问。浏览器无法识别QML,并且无法通过文档来渲染。我们需要创建一个可以浏览QML文档的浏览器。为了渲染文档,我们需要指出qmlscene的位置。不幸的是qmlscene只能读取本地文件。我们为了突破这个限制,我们可以使用自己写的qmlscene或者使用QML动态加载。我们选择动态加载的方式。我们选择一个加载元素来加载远程的文档。

  1. // remote.qml
  2. import QtQuick 2.0
  3. Loader {
  4. id: root
  5. source: 'http://localhost:8080/main2.qml'
  6. onLoaded: {
  7. root.width = item.width
  8. root.height = item.height
  9. }
  10. }

我们现在可以使用qmlscene来加载remote.qml文档。这里仍然有一个小问题。加载器将会调整加载项的大小。我们的qmlscene需要适配大小。可以使用—resize-to-root选项来运行qmlscene。

  1. $ qmlscene --resize-to-root remote.qml

按照root元素调整大小,告诉qmlscene按照root元素的大小调它的窗口大小。remote现在从本地服务器加载main.qml,并且可以自动调整加载的用户界面。方便且简单。

注意

如果你不想使用一个本地服务器,你可以使用来自GitHub的gist服务。Gist是一个在线剪切板服务,就像PasteBin等等。可以在https://gist.github.com下使用。我创建了一个简单的gist例子,地址是https://gist.github.com/jryannel/7983492。这将会返回一个绿色矩形框。由于gist连接提供的是HTML代码,我们需要连接一个/raw来读取原始文件而不是HTML代码。

  1. // remote.qml
  2. import QtQuick 2.0
  3. Loader {
  4. id: root
  5. source: 'https://gist.github.com/jryannel/7983492/raw'
  6. onLoaded: {
  7. root.width = item.width
  8. root.height = item.height
  9. }
  10. }

从网络加载另一个文件,你只需要引用组件名。例如一个Button.qml,只要它们在同一个远程文件夹下就能够像正常一样访问。

11.1.1 网络组件(Networked Components)

我们做了一个小实验。我们在远程端添加一个按钮作为可以复用的组件。

  1. - src/main.qml
  2. - src/Button.qml

我们修改main.qml来使用button:

  1. import QtQuick 2.0
  2. Rectangle {
  3. width: 320
  4. height: 320
  5. color: '#ff0000'
  6. Button {
  7. anchors.centerIn: parent
  8. text: 'Click Me'
  9. onClicked: Qt.quit()
  10. }
  11. }

再次加载我们的web服务器:

  1. $ cd src
  2. # python -m SimpleHTTPServer 8080

再次使用http加载远mainQML文件:

  1. $ qmlscene --resize-to-root remote.qml

我们看到一个错误:

  1. http://localhost:8080/main2.qml:11:5: Button is not a type

所以,在远程加载时,QML无法解决Button组件的问题。如果代码使用本地加载qmlscene src/main.qml,将不会有问题。Qt能够直接解析本地文件,并且检测哪些组件可用,但是使用http的远程访问没有“list-dir”函数。我们可以在main.qml中使用import声明来强制QML加载元素:

  1. import "http://localhost:8080" as Remote
  2. ...
  3. Remote.Button { ... }

再次运行qmlscene后,它将正常工作:

  1. $ qmlscene --resize-to-root remote.qml

这是完整的代码:

  1. // main2.qml
  2. import QtQuick 2.0
  3. import "http://localhost:8080" 1.0 as Remote
  4. Rectangle {
  5. width: 320
  6. height: 320
  7. color: '#ff0000'
  8. Remote.Button {
  9. anchors.centerIn: parent
  10. text: 'Click Me'
  11. onClicked: Qt.quit()
  12. }
  13. }

一个更好的选择是在服务器端使用qmldir文件来控制输出:

  1. // qmldir
  2. Button 1.0 Button.qml

然后更新main.qml:

  1. import "http://localhost:8080" 1.0 as Remote
  2. ...
  3. Remote.Button { ... }

当从本地文件系统使用组件时,它们的创建没有延迟。当组件通过网络加载时,它们的创建是异步的。创建时间的影响是未知的,当其它组件已经完成时,一个组件可能还没有完成加载。当通过网络加载组件时,需要考虑这些。