私はBlackberry 10 Cascades、QML、およびC++ QTで作業しており、私が書いた小さなphp WebサービスからXMLデータを取得して、使用しているBlackberry 10 Dev Alpha Simulatorのリストにロードしようとしています-しかし、それは動作していません。
つまり、xml データは QML ドキュメントの ListView に読み込まれず、Blackberry シミュレータの画面に表示されません。その仕事を得るには助けが必要です。
通常の http リクエストを含む例から始めて、目的に合わせてカスタマイズするように変更しました (これは http ポスト リクエストです)。(このコードは、テキスト フィールドに世代番号 (1 ~ 5) を入力し、その世代のポケモン ゲームの色のリストを出力します)。
これは私が始めたQMLファイルです:
import bb.cascades 1.0
TabbedPane {
activePane: Page {
actions: [
// An action item that calls the C++ function that retrieves
// the contact list
ActionItem {
title: "Refresh"
onTriggered: app.initiateRequest()
}
]
content: Container {
layout: DockLayout {}
// A list that has two list item components, one for a header
// and one for contact names. The list has an object name so
// that we can set the data model from C++.
ListView {
objectName: "list"
layout: FlowListLayout {
topPadding: 6
rightPadding: 6
bottomPadding: 6
leftPadding: 6
}
// A simple data model is loaded with just a header.
// This will be replaced when we load the real one
// from C++.
dataModel: XmlDataModel {
source: "model.xml"
}
listItemComponents: [
// The header list item displays a title along with a counter
// that displays the number of children
ListItemComponent {
type: "header"
HeaderListItem {
topMargin: 8
title: ListItemData.title
subtitle: (ListItem.initialized ?
ListItem.view.dataModel
.childCount(ListItem.indexPath) : 0);
}
},
// The contact list item displays the name of the contact
ListItemComponent {
type: "contacts"
StandardListItem {
title: ListItemData.title
}
}
]
}
// The activity indicator has an object name set so that
// we can start and stop it from C++
ActivityIndicator {
objectName: "indicator"
layoutProperties: DockLayoutProperties {
verticalAlignment: VerticalAlignment.Fill
horizontalAlignment: HorizontalAlignment.Fill
}
}
} // Ends the root Container
} // Ends the Page
} // Ends the TabbedPane
そして、これは私のQMLファイルです:
import bb.cascades 1.0
TabbedPane {
activePane: Page {
actions: [
// An action item that calls the C++ function that retrieves
// the contact list
ActionItem {
title: "Refresh"
onTriggered: app.initiateRequest(txtGen.text)
}
]
content: Container {
layout: StackLayout {}
Button {
text: "Get Games"
onClicked: app.initiateRequest(txtGen.text)
}
Label {
text: "Enter Generation (1-5)"
}
TextField {
id: txtGen
}
// A list that has two list item components, one for a header
// and one for contact names. The list has an object name so
// that we can set the data model from C++.
ListView {
objectName: "list"
layout: FlowListLayout {
topPadding: 6
rightPadding: 6
bottomPadding: 6
leftPadding: 6
}
// A simple data model is loaded with just a header.
// This will be replaced when we load the real one
// from C++.
dataModel: XmlDataModel {
source: "model.xml"
}
listItemComponents: [
// The header list item displays a title along with a counter
// that displays the number of children
ListItemComponent {
type: "games"
HeaderListItem {
topMargin: 8
title: ListItemData.generation
subtitle: (ListItem.initialized ?
ListItem.view.dataModel
.childCount(ListItem.indexPath) : 0);
}
},
// The contact list item displays the name of the contact
ListItemComponent {
type: "game"
StandardListItem {
title: ListItemData.title
}
}
]
}
// The activity indicator has an object name set so that
// we can start and stop it from C++
ActivityIndicator {
objectName: "indicator"
layoutProperties: DockLayoutProperties {
verticalAlignment: VerticalAlignment.Fill
horizontalAlignment: HorizontalAlignment.Fill
}
}
} // Ends the root Container
} // Ends the Page
} // Ends the TabbedPane
また、プロジェクト ディレクトリの assets/model.xml の下に、次の内容の xml フォルダーが保存されています。
<?xml version="1.0" encoding="utf-8"?>
<xml>
<games>
</games>
</xml>
また、ここに私が書いた App.cpp コードがあります:
#include "app.hpp"
#include <bb/cascades/Application>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include <bb/cascades/Button>
#include <bb/cascades/TextField>
#include <QDir>
using namespace bb::cascades;
App::App()
{
// Load the QML document and retrieve the root node
QmlDocument *qml = QmlDocument::create("main.qml");
mRoot = qml->createRootNode<AbstractPane>();
// Retrieve the activity indicator from QML so that we can start
// and stop it from C++
mActivityIndicator = mRoot->findChild<ActivityIndicator*>("indicator");
// Retrieve the list so we can set the data model on it once
// we retrieve it
mListView = mRoot->findChild<ListView*>("list");
//mTextField = mRoot->findChild<TextField*>("textField");
//qDebug() << "Generation: " << mTextField->text();
// Expose this class to QML so that we can call its functions from there
qml->setContextProperty("app", this);
// Create a network access manager and connect a custom slot to its
// finished signal
mNetworkAccessManager = new QNetworkAccessManager(this);
Q_ASSERT(connect(mNetworkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*))));
// Displays a warning message if there's an issue connecting the signal
// and slot. This is a good practice with signals and slots as it can
// be easier to mistype a slot or signal definition
//Q_ASSERT(result);
//Q_UNUSED(result);
// Create a file in the application's data directory
mFile = new QFile("data/model.xml");
// Set the scene using the root node
Application::setScene(mRoot);
}
void App::initiateRequest(QString text)
{
// Start the activity indicator
mActivityIndicator->start();
// Create and send the network request
QNetworkRequest request = QNetworkRequest();
request.setUrl(QUrl("http://192.168.1.109/TESTWEBSERVICE/MAKEXML.php")); //https://developer.blackberry.com/cascades/files/documentation/device_platform/networking/model.xml"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QByteArray bytes;
QUrl params;
params.addQueryItem(QString::fromStdString("generation"), text);
bytes = params.encodedQuery();
mNetworkAccessManager->post(request, bytes);
}
void App::requestFinished(QNetworkReply* reply)
{
// Check the network reply for errors
if (reply->error() == QNetworkReply::NoError) {
// Open the file and print an error if the file cannot be opened
if (!mFile->open(QIODevice::ReadWrite))
{
qDebug() << "\n Failed to open file";
return;
}
mFile->resize(0);
// Write to the file using the reply data and close the file
QByteArray xml = reply->readAll();
mFile->write(xml);
qDebug() << xml;
mFile->flush();
mFile->close();
// Create the data model using the contents of the file. The
// location of the file is relative to the assets directory.
XmlDataModel *dataModel = new XmlDataModel();
dataModel->setSource(QUrl("../../../data/model.xml"));
// Set the new data model on the list and stop the activity indicator
mListView->setDataModel(dataModel);
mActivityIndicator->stop();
}
else
{
qDebug() << "\n Problem with the network";
qDebug() << "\n" << reply->errorString();
}
}
そして、ここに私の App.h ファイルがあります:
#ifndef APP_H
#define APP_H
#include <QObject>
#include <QFile>
#include <bb/cascades/ActivityIndicator>
#include <bb/cascades/ListView>
#include <bb/cascades/XMLDataModel>
#include <bb/cascades/AbstractPane>
#include <bb/cascades/TextField>
using namespace bb::cascades;
/*!
* @brief Application GUI object
*/
class App : public QObject
{
Q_OBJECT
public:
/*!
* Constructor.
*/
App();
/*!
* Initiates the network request.
*/
Q_INVOKABLE void initiateRequest(QString text);
private slots:
/*!
* Handles the network reply.
*/
void requestFinished(QNetworkReply* reply);
private:
AbstractPane *mRoot;
ActivityIndicator *mActivityIndicator;
ListView *mListView;
TextField *mTextField;
QNetworkAccessManager *mNetworkAccessManager;
QFile *mFile;
QString apiKey;
QString apiString;
};
#endif // ifndef APP_H
QDebug() ストリームは、生成パラメーターが 1 の場合に次のように出力します。
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="1">
<game title="green">green</game>
<game title="red">red</game>
<game title="blue">blue</game>
<game title="yellow">yellow</game>
</games>
</xml>"
世代パラメータが 2 の場合:
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="2">
<game title="gold">gold</game>
<game title="silver">silver</game>
<game title="crystal">crystal</game>
</games>
</xml>"
世代パラメータが 3 の場合:
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="3">
<game title="ruby">ruby</game>
<game title="sapphire">sapphire</game>
<game title="emerald">emerald</game>
</games>
</xml>"
Generation パラメータが 4 の場合:
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="4">
<game title="perl">perl</game>
<game title="diamond">diamond</game>
<game title="platinum">platinum</game>
</games>
</xml>"
Generation パラメータが 5 の場合:
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="5">
<game title="black">black</game>
<game title="white">white</game>
<game title="black 2">black 2</game>
<game title="white 2">white 2</game>
</games>
</xml>"
パラメータ生成が foo であるその他の場合 (foo はプレースホルダーです):
"<?xml version="1.0" encoding="utf-8"?>
<xml>
<games generation="foo">
</games>
</xml>"
なぜこれが機能しないのか、よくわかりません。他の例を探して、それを使用してコードを適切に機能させる方法を見つけようとしましたが、うまくいきませんでした。
この質問が長いことは承知していますが、最良の回答を得るために、私が行っていたことについてできるだけ詳しく説明したいと思いました. そうは言っても、私の main.cpp ファイルは関連性があるとは思えないので、誰かがそれを見るように頼まない限り、ここには入れません。
(xml コードのゲーム タグに title 属性を追加し、これらのタグの主なデータ値と同じ値を入れました。
<game>yellow</game>
の中へ
<game title="yellow">yellow</game>
title 属性を使用せずに機能させようとした後、前者だけで問題が解決するかもしれないと思ったので、少しハックでしたが、解決しませんでした。理想的には、ゲーム タグに title 属性がある場合とない場合の両方で、これを機能させる方法を見つけたいと考えています。