Виталий Антипов
Виталий АнтиповJan. 16, 2018, 4:57 a.m.

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
                }
            }
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

8
Evgenii Legotckoi
  • Jan. 16, 2018, 9:07 a.m.
  • The answer was marked as a solution.

Добрый день!
Обработчик 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);
}
    Виталий Антипов
    • Jan. 16, 2018, 9:21 a.m.
    • (edited)

    Спасибо, тоже нашел и получил значения благодаря 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
      • Jan. 16, 2018, 9:38 a.m.
      • (edited)

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

        Виталий Антипов
        • Jan. 16, 2018, 9:46 a.m.

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

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

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

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

              Evgenii Legotckoi
              • Jan. 16, 2018, 10:25 a.m.
              • (edited)

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

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

                Спасибо большущее за советы! Все получилось через 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)
                                }
                            }

                  Comments

                  Only authorized users can post comments.
                  Please, Log in or Sign up
                  Lz

                  C ++ - Test 004. Pointers, Arrays and Loops

                  • Result:70points,
                  • Rating points1
                  РК

                  Qt - Test 001. Signals and slots

                  • Result:84points,
                  • Rating points4
                  Last comments
                  k
                  kmssrFeb. 9, 2024, 5:43 a.m.
                  Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                  Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                  EVA
                  EVADec. 25, 2023, 9:30 p.m.
                  Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                  J
                  JonnyJoDec. 25, 2023, 7:38 p.m.
                  Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                  G
                  GvozdikDec. 19, 2023, 8:01 a.m.
                  Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                  Now discuss on the forum
                  BlinCT
                  BlinCTJune 25, 2024, 11 a.m.
                  Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
                  Evgenii Legotckoi
                  Evgenii LegotckoiJune 25, 2024, 1:11 a.m.
                  добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                  BlinCT
                  BlinCTMay 5, 2024, 3:46 p.m.
                  Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
                  Evgenii Legotckoi
                  Evgenii LegotckoiMay 3, 2024, 12:07 a.m.
                  Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
                  IscanderChe
                  IscanderCheApril 30, 2024, 2:22 p.m.
                  Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…

                  Follow us in social networks