Виталий Антипов
Виталий Антипов16 января 2018 г. 4:57

ChartView. Отображение метки данных точки серии при наведении курсора

Добрый день! Подскажите, как отобразить метки данных точки в LineSeries при наведении курсора? Из документации понял, что перехватить событие наведения можно через onHovered(), но как получить индекс/позицию/значение нужной точки?

ChartView {
                id: chartIzmerHh
                objectName: "chartIzmerHh"
                property int count
                property var array_dateX
                property var array_valueY
                property var array_valueY1
                property var array_valueY2
                visible: true
                anchors.top: rec_filter.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                anchors.bottom: parent.bottom
                antialiasing: true
                legend.visible: false
                title: "Средняя вибрация на холостом ходу"
                ValueAxis {
                    id: axiY
                    min: 0
                }
                DateTimeAxis {
                    id: axiX
                    format: "dd-MM-yyyy"
                    min: rec_filter.date_begin
                    max: rec_filter.date_end
                }
                LineSeries {
                    id: line1
                    property bool myBool: false
                    color: "lightgreen"
                    axisY: axiY
                    axisX: axiX
                    width: 5
                    onHovered: {
                       // ???
                    }
                }
                LineSeries {
                    id: line2
                    color: "tomato"
                    axisY: axiY
                    axisX: axiX
                    width: 5
                }
                LineSeries {
                    id: line
                    color: "#03a9f5"
                    axisY: axiY
                    axisX: axiX
                    width: 5
                }
                Component.onCompleted: {
                    var xx = []
                    var yy = []
                    var yy1 = []
                    var yy2 = []
                    var max = 0
                    for(var i=0;i<count;i++){
                        xx[i] = Date.parse(array_dateX[i])
                        yy[i] = Number(array_valueY[i])
                        yy1[i] = Number(array_valueY1[i])
                        yy2[i] = Number(array_valueY2[i])
                        if(yy[i]>max){
                            max = yy[i]
                        }
                        if(yy1[i]>max){
                            max = yy1[i]
                        }
                        if(yy2[i]>max){
                            max = yy2[i]
                        }
                        line.append(xx[i], yy[i])
                        line1.append(xx[i], yy1[i])
                        line2.append(xx[i], yy2[i])
                    }
                    max = Math.round(max) + 1
                    axiY.max = max
                }
            }
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

8
Evgenii Legotckoi
  • 16 января 2018 г. 9:07
  • Ответ был помечен как решение.

Добрый день!
Обработчик onHovered навешивается автоматически на сигнал hovered.

В документации дана следующая сигнатура этого сигнала
hovered(point point, bool state)
Вот описание из документации

This signal is emitted when a mouse is hovered over the point point in the chart. When the mouse moves over the point, state turns true , and when the mouse moves away again, it turns false .

Соответственно обработчик можно написать так
onHovered: {
    console.log(point);
    console.log(point.x);
    console.log(point.y);
    console.log(state);
}
    Виталий Антипов
    • 16 января 2018 г. 9:21
    • (ред.)

    Спасибо, тоже нашел и получил значения благодаря point.x и point.y. Отформатировал значение даты и вывел искомые значения в прямоугольник. Теперь столкнулся с проблемой перемещения прямоугольника к курсору мыши при срабатывании onHovered(). Использовать MouseArea и брать оттуда mouseX и mouseY не вариант, так как MouseArea перекроет LineSeries и события onHovered никогда не получим. Подскажите, есть какие-нибудь варианты решить проблему?

    ChartView {
                    id: chartIzmerHh
                    objectName: "chartIzmerHh"
                    property int count
                    property var array_dateX
                    property var array_valueY
                    property var array_valueY1
                    property var array_valueY2
                    visible: false
                    anchors.top: rec_filter.bottom
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.bottom: parent.bottom
                    antialiasing: true
                    legend.visible: false
                    title: "Средняя вибрация на холостом ходу"
                    Rectangle {
                        id: rec_hovered
                        color: "yellow"
                        width: text_hovered1.width
                        height: text_hovered1.height + text_hovered2.height
                        Text {
                            id: text_hovered1
                            anchors.bottom: text_hovered2.top
                            text: line1.date_x //сюда выводим значение x при срабатывании onHovered
                        }
                        Text {
                            id: text_hovered2
                            anchors.bottom: parent.bottom
                            text: line1.value_y ////сюда выводим значение y при срабатывании onHovered
                        }
                    }
                    ValueAxis {
                        id: axiY
                        min: 0
                    }
                    DateTimeAxis {
                        id: axiX
                        format: "dd-MM-yyyy"
                        min: rec_filter.date_begin
                        max: rec_filter.date_end
                    }
                    LineSeries {
                        id: line1
                        property string date_x
                        property string value_y
                        color: "lightgreen"
                        axisY: axiY
                        axisX: axiX
                        width: 5
                        onHovered: {
                            var d = new Date(point.x),                    //форматируем дату
                            month = '' + (d.getMonth() + 1),
                            day = '' + d.getDate(),
                            year = d.getFullYear();
                            if (month.length < 2) month = '0' + month;
                            if (day.length < 2) day = '0' + day;
                            date_x = ([day, month, year].join('-')).toString()
                            value_y = ((point.y).toFixed(2)).toString()   //форматируем значение по y
                        }
    
                    }
                    LineSeries {
                        id: line2
                        color: "tomato"
                        axisY: axiY
                        axisX: axiX
                        width: 5
                    }
                    LineSeries {
                        id: line
                        color: "#03a9f5"
                        axisY: axiY
                        axisX: axiX
                        width: 5
                    }
                    Component.onCompleted: {
                        var xx = []
                        var yy = []
                        var yy1 = []
                        var yy2 = []
                        var max = 0
                        for(var i=0;i<count;i++){
                            xx[i] = Date.parse(array_dateX[i])
                            yy[i] = Number(array_valueY[i])
                            yy1[i] = Number(array_valueY1[i])
                            yy2[i] = Number(array_valueY2[i])
                            if(yy[i]>max){
                                max = yy[i]
                            }
                            if(yy1[i]>max){
                                max = yy1[i]
                            }
                            if(yy2[i]>max){
                                max = yy2[i]
                            }
                            line.append(xx[i], yy[i])
                            line1.append(xx[i], yy1[i])
                            line2.append(xx[i], yy2[i])
                        }
                        max = Math.round(max) + 1
                        axiY.max = max
                    }
                }

      Evgenii Legotckoi
      • 16 января 2018 г. 9:38
      • (ред.)

      Пока мыслей нет, но попробуйте всё-таки MouseArea. Дело в том, что у неё есть свойство propagateComposedEvents , которое по умолчанию установлено на false , а если его установить на true, то события должны передаваться на объекты, которые перекрываются этой самой MouseArea.

        Виталий Антипов
        • 16 января 2018 г. 9:46

        Спасибо, попробую! Тут еще вариант придумал - создать ScatterSeries и при onHovered создать точку с требуемыми координатами. Попробовал scatter.append(point.x, point.y) - получается очень красиво. Только надо изучить как ее заменять на новую и как форматировать значения pointLabels

          Evgenii Legotckoi
          • 16 января 2018 г. 10:04

          У ScatterSeries есть методы

          • remove(int index),
          • remove(real x, real y),
          • removePoints(int index, int count)
          Если будете оперировать только одной точкой в каждом графике ScatterSeries для каждой LineSeries (то есть один ScatterSeries для одной LineSeries ), то удалять можно будет точку по индекс при каждом срабатывании onHovered , то есть scatter1.remove(0), а потом просто добавлять новую точку. Ну или наверняк можно просто изменить координаты точки через метод replace.
            Виталий Антипов
            • 16 января 2018 г. 10:10

            Спасибо за ответ! Кстати, propagateComposedEvents: true не дает получить событие onHovered .

              Evgenii Legotckoi
              • 16 января 2018 г. 10:25
              • (ред.)

              Если честно у меня пока только одна идиотская идея есть. Брать по таймеру текущую позицию курсора глобально из C++ специальным классом. И этот класс будет зарегистрирован в QML, у него будет сигнал, который будет высылать информацию о положении курсора, что позволит обновлять информацию так, как вам будет нужно (используя конечно манипуляции с мапингом глобальных координат в координаты графика).

              Ещё я бы рекомендовал покапаться в исходниках, хотя бы заголовочных файлах QQuickItem, от которого, по моему мнению, должен быть наследован ChartView в результате. Дело в том, что в официальной документации нет полного описания всех методов, которыми обладают Quick компоненты, я это заметил, когда разбирался с написанием кастомных Quick компонентов и использованием OpenGL в них. Часто приходилось заглядывать в заголовочники того же самого QQuickItem и не все публичные методы были описаны в документации.
                Виталий Антипов
                • 16 января 2018 г. 11:47

                Спасибо большущее за советы! Все получилось через ScatterSeries. Методы remove() как-то сходу не дались, удаляет в первый раз, а потом программа падает... Не стал тратить время и воспользовался методом replace(). Все идеально, работает шустро! Еще раз спасибо!

                ChartView {
                                id: chartIzmerHh
                                objectName: "chartIzmerHh"
                                property int count
                                property var array_dateX
                                property var array_valueY
                                property var array_valueY1
                                property var array_valueY2
                                property real oldX        //сюда записываем координату текущей точки scatter для метода replace()
                                property real oldY        //сюда записываем координату текущей точки scatter для метода replace()
                                visible: false
                                anchors.top: rec_filter.bottom
                                anchors.left: parent.left
                                anchors.right: parent.right
                                anchors.bottom: parent.bottom
                                antialiasing: true
                                legend.visible: false                
                                title: "Средняя вибрация на холостом ходу"
                                ValueAxis {
                                    id: axiY
                                    min: 0
                                }
                                DateTimeAxis {
                                    id: axiX
                                    format: "dd-MM-yyyy"
                                    min: rec_filter.date_begin
                                    max: rec_filter.date_end
                                }
                                LineSeries {
                                    id: line1
                                    property string date_x
                                    property string value_y
                                    color: "lightgreen"
                                    axisY: axiY
                                    axisX: axiX
                                    width: 5
                                    onHovered: {
                //форматируем дату по x и значение по y
                                        var d = new Date(point.x),
                                        month = '' + (d.getMonth() + 1),
                                        day = '' + d.getDate(),
                                        year = d.getFullYear();
                                        if (month.length < 2) month = '0' + month;
                                        if (day.length < 2) day = '0' + day;
                                        date_x = ([day, month, year].join('-')).toString()
                                        value_y = ((point.y).toFixed(2)).toString()
                //заменяем старую точку на новую
                                        scatter.replace(chartIzmerHh.oldX, chartIzmerHh.oldY, point.x, point.y)
                //перезаписываем текущие координаты, они станут старыми при следующем вызове onHovered и уйдут в replace()
                                        chartIzmerHh.oldX = point.x
                                        chartIzmerHh.oldY = point.y
                                    }
                                }
                                ScatterSeries {
                                    id: scatter
                                    pointLabelsVisible: true
                                    pointLabelsClipping: false
                                    pointLabelsFont: bold
                                    pointLabelsFormat: "" + line1.value_y +" ; "+ line1.date_x + ""  //сюда пишем отформатированные текущие значения
                                    color: "lightgreen"
                                    borderColor: "black"
                                    axisY: axiY
                                    axisX: axiX
                                }
                                LineSeries {
                                    id: line2
                                    color: "tomato"
                                    axisY: axiY
                                    axisX: axiX
                                    width: 5
                                }
                                LineSeries {
                                    id: line
                                    color: "#03a9f5"
                                    axisY: axiY
                                    axisX: axiX
                                    width: 5
                                }
                                Component.onCompleted: {
                                    var xx = []
                                    var yy = []
                                    var yy1 = []
                                    var yy2 = []
                                    var max = 0
                                    for(var i=0;i<count;i++){
                                        xx[i] = Date.parse(array_dateX[i])
                                        yy[i] = Number(array_valueY[i])
                                        yy1[i] = Number(array_valueY1[i])
                                        yy2[i] = Number(array_valueY2[i])
                                        if(yy[i]>max){
                                            max = yy[i]
                                        }
                                        if(yy1[i]>max){
                                            max = yy1[i]
                                        }
                                        if(yy2[i]>max){
                                            max = yy2[i]
                                        }
                                        line.append(xx[i], yy[i])
                                        line1.append(xx[i], yy1[i])
                                        line2.append(xx[i], yy2[i])                        
                                    }
                //ставим сразу точку на график (меня интересует последняя) и записываем ее текущее значение, которое потом уйдет в replace()
                                    oldX = xx[count-1]
                                    oldY = yy1[count-1]
                                    scatter.append(xx[count-1], yy1[count-1])
                                    max = Math.round(max) + 1
                                    axiY.max = max
                                    console.log(oldX,oldY)
                                }
                            }

                  Комментарии

                  Только авторизованные пользователи могут публиковать комментарии.
                  Пожалуйста, авторизуйтесь или зарегистрируйтесь
                  e
                  • ehot
                  • 1 апреля 2024 г. 0:29

                  C++ - Тест 003. Условия и циклы

                  • Результат:78баллов,
                  • Очки рейтинга2
                  B

                  C++ - Тест 002. Константы

                  • Результат:16баллов,
                  • Очки рейтинга-10
                  B

                  C++ - Тест 001. Первая программа и типы данных

                  • Результат:46баллов,
                  • Очки рейтинга-6
                  Последние комментарии
                  k
                  kmssr9 февраля 2024 г. 5:43
                  Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                  АК
                  Анатолий Кононенко5 февраля 2024 г. 12:50
                  Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                  EVA
                  EVA25 декабря 2023 г. 21:30
                  Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                  J
                  JonnyJo25 декабря 2023 г. 19:38
                  Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                  G
                  Gvozdik19 декабря 2023 г. 8:01
                  Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                  Сейчас обсуждают на форуме
                  a
                  a_vlasov14 апреля 2024 г. 16:41
                  Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                  Павел Дорофеев
                  Павел Дорофеев14 апреля 2024 г. 12:35
                  QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                  f
                  fastrex4 апреля 2024 г. 14:47
                  Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
                  P
                  Pisych27 февраля 2023 г. 15:04
                  Как получить в массив значения из связанной модели? Спасибо, разобрался:))
                  AC
                  Alexandru Codreanu19 января 2024 г. 22:57
                  QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

                  Следите за нами в социальных сетях