2016-09-21 11 views
0

私はthis open source projectで作業しています。これは基本的にはライブQMLインタープリタです。ユーザーの主な活動はQMLコードを書くことなので、基本的なIDEのような機能を提供するために、すべてのログと警告などをアプリケーションに埋め込みたいと思っています。 LoggeraddEntry方法は、単にQStringList財産へのメッセージを追加し、-signal対応changed()を発するUIへの転送ランタイムQML出力に関する問題

auto Instance::HandleMessage(QtMsgType type, const QMessageLogContext& context, const QString& msg) -> void { 
    std::cout << "handle message: " << msg.toStdString() << std::endl; 
    Logger::GetInstance()->addEntry(msg); 
} 

:まず、私はQMLからすべてのランタイムメッセージを受信qInstallMessageHandlerを経由してカスタムメッセージハンドラをインストールしました。 QML側では、そのプロパティをListViewに送ります:

ListView { 
    anchors.fill: parent; 
    model: App.logger.entries; 
    delegate: Text { 
     text: modelData; 
    } 
} 

これは機能します。しかし、この問題は、動的QMLオブジェクトのインスタンス化と組み合わせて表示されます。私のアプリケーションの「魔法」の部分は文字列として、いくつかのQMLソースを期待し、新しく作成されたオブジェクトを返しますQt.createQmlObjectへの呼び出しです:「コンパイル」は失敗した場合

function compile() { 
    try { 
     qmlObject = Qt.createQmlObject(<qml_source>, container, "root"); 
    } catch (exc) { 
     // handle *compile-time* errors 
    } 
} 

を、すぐに制御がcatch節に移行しないと新たなQMLオブジェクトが作成されます。私は、以下のソース、アプリケーションのクラッシュからオブジェクトを作成しようとした場合でも:

function compile() { 
    try { 
     qmlObject = Qt.createQmlObject("import QtQuick 2.6\nItem { anchors.fill: parent; Rectangle { width: parent.width; height: a.height; } }", container, "root"); 
    } catch (exc) { 
     // handle *compile-time* errors 
    } 
} 

上記のソースは有効ですが、実行時エラーを生成します。何らかの理由で、のhandleMessage関数は、この特定のシナリオで二回呼び出されます:

handle message: [...]App/root:2: ReferenceError: a is not defined 
handle message: [...]App/root:2: ReferenceError: a is not defined 

そして結合ループ作成します。また、カスタムメッセージハンドラによって処理され

handle message: [...]/App/containerview.qml:76:9: QML Repeater: Binding loop detected for property "model" 

は...あなたが参照しますこれは起こっています:アプリケーションがループに詰まり、最終的にクラッシュします。

私の観察結果、これまで:

  1. は、カスタムメッセージハンドラのただ1つの呼び出しでQStringListプロパティ(ちょうどそれらをcout'ing)の結果に受信メッセージを転送しません。施工時間後に同じエラーを作成

  2. に支障が生じない:

    qmlObject = Qt.createQmlObject("import QtQuick 2.6\nimport QtQuick.Controls 1.4\nItem { anchors.fill: parent; Rectangle { id: rect; width: parent.width; } Button { anchors.centerIn: parent; text: \"do something stupid\"; onClicked: { rect.height = a.height; } } }", container, "root"); 
    
  3. (単一QStringオブジェクト内のすべてのメッセージを格納するなど)、リストベースのプロパティを使用しても問題が解決されていないが、明白な欠点がいくつかあります。

そして最後に質問:この問題が発生し、どのようにこの問題を解決するために、なぜ 誰かが説明できますか?

+1

IDEを実行するQMLエンジンと編集中のコンテンツを実行するQMLエンジンが2つある方が良いのではないかと思いますか? –

+0

@KevinKrammerそれは実際には良い点です!私はそれを試してみましょう、ありがとう! – qCring

答えて

1

メッセージハンドラを再入力させます。あなたはいけない:

class Instance { 
    QThreadStorage<bool> handlerEntered; 
    ... 
}; 

QThreadStorage<bool> Instance::handlerEntered; 

void Instance::HandleMessage(
    QtMsgType type, const QMessageLogContext& context, const QString& msg) 
{ 
    if (handlerEntered.localData()) return; 
    QScopedValueRollback<bool> roll(handlerEntered.localData(), true); 
    std::cout << "handle message: " << msg.toStdString() << std::endl; 
    Logger::GetInstance()->addEntry(msg); 
} 

またLogger::addEntry方法はイベントループを再入力したり任意のメッセージを発していないことを確認する必要があります。 QMLエンジンのような任意の直接接続されたスロットは、信号ながら、多くのものを行う可能性があり、そうでなければ

void Logger::addEntry(const QString & msg) { 
    ... 
    QMetaObject::invokeMethod(this, "listChanged(QStringList)", 
     Qt::QueuedConnection, Q_ARG(QStringList, data)); 
} 

- とaddEntryHandleMessageです:ほとんどの場合、あなたはそこchanged信号にコールをキューイングする必要があります依然としてコールスタック上にあります。

関連する問題