【问题标题】:QML chartview crash when changing data更改数据时 QML chartview 崩溃
【发布时间】:2017-09-10 12:29:55
【问题描述】:

我是 qml 的新手,我还没有真正理解它的逻辑。

这是我的问题:我有一个带有条形图的图表视图,我希望当用户点击条形图时,条形图会发生变化。

所以我清除 barSeries 并将新数据附加到它。但它会导致分段错误。 如果我通过单击按钮进行相同的处理,则效果很好。 您知道问题出在哪里以及如何解决吗?

以下是代码示例。

main.qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

import QtCharts 2.2

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Chartview test")

    Item {
        id: histoView

        property int globalForJs: 0

        anchors.fill: parent
        visible: true

        Component.onCompleted: {
            redraw();
        }

        signal redrawSignal()

        ColumnLayout {
            anchors.fill: parent
            Button {
                id:myBtn
                anchors { top: parent.top; left: parent.left; leftMargin: 20 }
                height: 30
                width: 80
                text: "new chart"
                onClicked: {
                    console.debug("myBtn onClicked")
                    histoView.redrawSignal()
                }
            }

            ChartView {
                id: chartView
                anchors { bottom: parent.bottom; left: parent.left; right: parent.right }
                height: parent.height - 40

                title: "chartview"

                BarSeries {
                    id: mySeries

                    axisX: BarCategoryAxis { categories: [" "] }
                    axisY: ValueAxis {
                        id: ordinate
                        min:0
                        max:100
                    }    

                    onClicked: {
                        console.debug("mySeries onClicked")
                        histoView.redrawSignal();
                        //myBtn.clicked()
                    }
                }
            }
        }

        function redraw() {
            // clear data
            mySeries.clear();

            // add 5 new data
            for (var i=0;i<5;i++) {
                var tab=[];
                globalForJs++;
                tab.push(globalForJs);
                mySeries.append("tutu"+i,tab);
            }
            // update Y axis maximum value
            if (ordinate.max < globalForJs) {
                ordinate.max = globalForJs + 10;
            }
        }

        onRedrawSignal:redraw()
    }
}

main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));

    return app.exec();
}

【问题讨论】:

    标签: qt qml


    【解决方案1】:

    简答:

    看起来像 QGraphicsScene 或 Qt Charts 使用它的错误。请在bugreports.qt.io 报告错误。

    长答案(在 Qt 中调试崩溃):

    当您遇到只有 QML 的崩溃,而您的 C++ 代码中没有发生任何可疑的事情时,这可能是 Qt 中的错误。为了增加快速修复的错误的变化,获取堆栈跟踪是一个好主意,因为开发人员可以通过查看崩溃的位置来发现它的简单修复。要获得堆栈跟踪,您必须构建 Qt 的调试版本。

    在使用 Qt 调试版本调试您的应用程序时,我可以看到 QGraphicsItem::mouseReleaseEvent() 正在调用已删除对象的成员函数。验证这一点的一种简单方法是将一些调试代码添加到QGraphicsItem 的析构函数中,该析构函数会打印出每个被销毁对象的内存地址。此外,在QGraphicsItem::mouseReleaseEvent() 的开头添加一行,它使用qDebug()printf 语法(以避免调用QGraphicsItem&lt;&lt; 运算符,这会在它打印任何内容之前导致崩溃) :

    diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
    index f2b8b66..9f2302d 100644
    --- a/src/widgets/graphicsview/qgraphicsitem.cpp
    +++ b/src/widgets/graphicsview/qgraphicsitem.cpp
    @@ -1501,6 +1501,7 @@ QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent)
     */
     QGraphicsItem::~QGraphicsItem()
     {
    +    qDebug() << Q_FUNC_INFO << this;
         if (d_ptr->isObject) {
             QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
             QObjectPrivate *p = QObjectPrivate::get(o);
    @@ -7328,6 +7329,7 @@ void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
     */
     void QGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
     {
    +    qDebug("About to access %p\n", this);
         if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
             bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
             if (event->scenePos() == event->buttonDownScenePos(Qt::LeftButton)) {
    

    构建qtbase,然后再次调试您的应用程序。堆栈跟踪现在看起来像这样(从 Creator 复制):

    1   QGraphicsItem::flags                          qgraphicsitem.cpp    1854 0x6dcf8cf9     
    2   QGraphicsItem::mouseReleaseEvent              qgraphicsitem.cpp    7333 0x6dd05003     
    3   QtCharts::Bar::mouseReleaseEvent              bar.cpp              90   0x7ffd83fd4a9b 
    4   QGraphicsItem::sceneEvent                     qgraphicsitem.cpp    6845 0x6dd03ac6     
    5   QGraphicsScenePrivate::sendEvent              qgraphicsscene.cpp   1251 0x6dd58732     
    6   QGraphicsScenePrivate::sendMouseEvent         qgraphicsscene.cpp   1325 0x6dd594fd     
    7   QGraphicsScene::mouseReleaseEvent             qgraphicsscene.cpp   4099 0x6dd52c26     
    8   QGraphicsScene::event                         qgraphicsscene.cpp   3412 0x6dd51423     
    9   QApplicationPrivate::notify_helper            qapplication.cpp     3713 0x6d7772de     
    10  QApplication::notify                          qapplication.cpp     3085 0x6d771d83     
    11  QCoreApplication::notifyInternal2             qcoreapplication.cpp 1013 0x6cf72c16     
    12  QCoreApplication::sendEvent                   qcoreapplication.h   231  0x6cf7d5f2     
    13  QtCharts::DeclarativeChart::mouseReleaseEvent declarativechart.cpp 850  0x7ffd876dd16a 
    14  QQuickItem::event                             qquickitem.cpp       7756 0x7ffd7e206583 
    15  QApplicationPrivate::notify_helper            qapplication.cpp     3713 0x6d7772de     
    16  QApplication::notify                          qapplication.cpp     3085 0x6d771d83     
    17  QCoreApplication::notifyInternal2             qcoreapplication.cpp 1013 0x6cf72c16     
    18  QCoreApplication::sendEvent                   qcoreapplication.h   231  0x6cf7d5f2     
    19  QQuickWindow::sendEvent                       qquickwindow.cpp     2807 0x7ffd7e2305f9 
    20  QQuickWindowPrivate::deliverMouseEvent        qquickwindow.cpp     1671 0x7ffd7e235df1 
    ... <More>   
                                                                             
    

    控制台输出(缩短):

    Debugging starts
    QML debugging is enabled. Only use this in a safe environment.
    QML Debugger: Waiting for connection on port 52234...
    [...]
    __cdecl QGraphicsItem::~QGraphicsItem(void) QGraphicsItem(0x2da77915480, parent=0x2da77b0fc00, pos=0,0, flags=(ItemIsSelectable))
    [...]
    About to access 0x2da77915480
    

    可以看到内存地址为0x2da77915480QGraphicsItem被销毁,然后调用了它的mouseReleaseEvent()函数。

    【讨论】:

    • 感谢@Mitch。我希望所有的回答都这么全面。
    猜你喜欢
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    • 2018-05-05
    • 1970-01-01
    相关资源
    最近更新 更多