选点配置示例

此示例展示了如何配置QLineSeries的各个点。

Line chart with controls for configuring selected points

展示的功能

在这个应用程序中,您将学习如何:

  • 点击选择一系列点

  • 覆盖特定点的以下属性的配置:

    • 颜色

    • 大小

    • 标签可见性

    • 标签的文本格式

子类化 QMainWindow

创建一个QMainWindow的子类来包含图表和控件。

16class ChartWindow(QMainWindow):
17    def __init__(self, parent=None):
18        super().__init__(parent)

创建一个线系列

创建一个包含要绘制的点的QLineSeries。给它一个名称并使点可见。

20        self.setWindowTitle("Chart")
21        self._series = QLineSeries(self)
22        self._series.setName("Customized series")
23        self._series.setPointsVisible(True)
24        self._series.append([QPointF(0, 7), QPointF(2, 4),
25                             QPointF(3, 5), QPointF(7, 4),
26                             QPointF(10, 5), QPointF(11, 1),
27                             QPointF(13, 3), QPointF(17, 6),
28                             QPointF(18, 3), QPointF(20, 2)])

创建点配置控件

现在,创建控件来配置点的颜色、大小和标签可见性属性。

  1. 为每个控件创建一个关联的标签,以便用户知道该控件的作用。

  2. 对于颜色和大小,使用一个QComboBox,并用各种颜色和大小选项填充它。

  3. 创建最后两个控件。创建一个QCheckbox来控制所选点的可见性,以及一个QLineEdit以允许用户为其提供自定义标签。

注意

不要为任何控件设置初始值,因为总是会选择一个点来显示其当前设置。

31        self._selected_point_index_lineedit = QLineEdit()
32        self._selected_point_index_lineedit.setReadOnly(True)
33        self._selected_point_index_lineedit.setStyleSheet(
34            "background-color: rgba(0, 0, 0, 0); border: 0px")
35
36        color_label = QLabel("Color: ")
37        self._color_combobox = QComboBox()
38        color_strings = ["red", "orange", "yellow", "green", "blue",
39                         "indigo", "violet", "black"]
40        for color_str in color_strings:
41            self._color_combobox.addItem(QIcon(), color_str, QColor(color_str))
42
43        size_label = QLabel("Size: ")
44        self._size_combobox = QComboBox()
45        for size in [2, 3, 4, 6, 8, 10, 12, 15]:
46            self._size_combobox.addItem(QIcon(), str(size), size)
47
48        label_visibility_label = QLabel("Label Visibility: ")
49        self._label_visibility_checkbox = QCheckBox()
50
51        custom_label_label = QLabel("Custom Label: ")
52        self._custom_label_lineedit = QLineEdit()

在选择一个点时填充控件

添加逻辑以根据所选点设置当前控件值。请注意,如果没有为所选点进行自定义,则使用整个系列的值。在这种情况下,如果系列设置为显示蓝色点,颜色组合框中将显示蓝色值。

点击线条系列时执行一些操作。查找点击的点并移除之前选择的点。最后,选择被点击的点。这会使该点变大以指示其被选中。当前选中点的索引和PointConfigurations被保存到一个成员变量中供以后使用。

查询PointConfigurations,并使用这些信息在组合框中找到匹配的索引。 将组合框的当前索引设置为您查找的相应值。同样地, 查找PointConfigurations中的值,并更新复选框和行编辑控件。

54        self._series.clicked.connect(self._select_point)
 97    @Slot(QPointF)
 98    def _select_point(self, point: QPointF | int):
 99        try:
100            index = (self._series.points().index(point.toPoint()) if
101                     isinstance(point, QPointF) else point)
102        except ValueError:
103            # Do nothing if the place that was clicked on wasn't a point.
104            return
105
106        self._series.deselectAllPoints()
107        self._series.selectPoint(index)
108        self._selectedPointIndex = index
109        self._selectedPointConfig = self._series.pointConfiguration(index)
110        selected_point = self._series.at(index)
111        selected_index_lineedit = self._selected_point_index_lineedit
112        selected_index_lineedit.setText("(" + str(selected_point.x()) + ", "
113                                        + str(selected_point.y()) + ")")
114        config = self._series.pointConfiguration(index)
115
116        color = config.get(PointConfig.Color) or self._series.color()
117        size = config.get(PointConfig.Size) or self._series.markerSize()
118        labelVisibility = (config.get(PointConfig.LabelVisibility)
119                           or self._series.pointLabelsVisible())
120        customLabel = config.get(PointConfig.LabelFormat) or ""
121
122        combobox_value_list = [
123            (self._color_combobox, color.name(), color),
124            (self._size_combobox, str(size), size)
125        ]
126        for box, value_str, value in combobox_value_list:
127            if box.findData(value) < 0:
128                box.addItem(value_str, value)
129            box.setCurrentIndex(box.findData(value))
130
131        self._label_visibility_checkbox.setChecked(labelVisibility)
132        self._custom_label_lineedit.setText(customLabel)

提供配置选定点的逻辑

现在控件已经填充了一些值,添加逻辑以在值更改时执行某些操作。连接控件信号和逻辑,根据控件中选择的值配置所选点。您可以通过将与控件关联的QXYSeries::PointConfiguration值设置为m_selectedPointConfigPointConfigurations成员变量,并调用QXYSeries::setPointConfiguration来实现这一点。

55        self._color_combobox.activated.connect(self._set_color)
56        self._size_combobox.activated.connect(self._set_size)
57        label_vis_checkbox = self._label_visibility_checkbox
58        label_vis_checkbox.clicked.connect(self._set_label_visibility)
59        clabel_lineedit = self._custom_label_lineedit
60        clabel_lineedit.editingFinished.connect(self._set_custom_label)
140    @Slot(int)
141    def _set_size(self, index: int):
142        spc = self._selectedPointConfig
143        spc[PointConfig.Size] = self._size_combobox.currentData()
144        self._series.setPointConfiguration(self._selectedPointIndex, spc)
145
146    @Slot(bool)
147    def _set_label_visibility(self, checked: bool):
148        spc = self._selectedPointConfig
149        spc[PointConfig.LabelVisibility] = checked
150        self._series.setPointConfiguration(self._selectedPointIndex, spc)
151
152    @Slot()
153    def _set_custom_label(self):
154        spc = self._selectedPointConfig
155        spc[PointConfig.LabelFormat] = self._custom_label_lineedit.text()
156        self._series.setPointConfiguration(self._selectedPointIndex, spc)

创建图表并布局控件

最后,创建图表及其视图,将系列添加到图表中,创建窗口的布局,并选择一个初始点。

62        self._chart = QChart()
63        self._chart.addSeries(self._series)
64        self._chart.createDefaultAxes()
65
66        chart_view = QChartView(self._chart)
67        chart_view.setRenderHint(QPainter.RenderHint.Antialiasing)
68
69        control_widget = QWidget(self)
70        control_layout = QGridLayout(control_widget)
71        control_layout.setColumnStretch(1, 1)
72
73        control_layout.addWidget(selected_point_index_label, 0, 0)
74        control_layout.addWidget(self._selected_point_index_lineedit, 0, 1)
75
76        control_layout.addWidget(color_label, 1, 0)
77        control_layout.addWidget(self._color_combobox, 1, 1)
78
79        control_layout.addWidget(size_label, 2, 0)
80        control_layout.addWidget(self._size_combobox, 2, 1)
81
82        control_layout.addWidget(label_visibility_label, 3, 0)
83        control_layout.addWidget(self._label_visibility_checkbox, 3, 1, 1, 2)
84
85        control_layout.addWidget(custom_label_label, 4, 0)
86        control_layout.addWidget(self._custom_label_lineedit, 4, 1)
87
88        main_widget = QWidget(self)
89        main_layout = QHBoxLayout(main_widget)
90        main_layout.addWidget(chart_view)
91        main_layout.setStretch(0, 1)
92        main_layout.addWidget(control_widget)
93        self.setCentralWidget(main_widget)
94
95        self._select_point(4)

在我们的入口文件 pointconfiguration.py 中,实例化 ChartWindow,调整其大小,显示它,并启动事件循环。

11
12if __name__ == "__main__":
13
14    a = QApplication(sys.argv)
15    main_window = ChartWindow()
16    main_window.resize(640, 480)
17    main_window.show()

你现在有一个完全功能的应用程序,展示了如何自定义单个图表点。

用法

要使用此示例,请单击您想要自定义的任何点,更改控制单个点颜色、大小、标签可见性的任何组合框和复选框。您可以在底部的行编辑中自定义标签文本。

标签有三种特殊的格式化字符串可以使用:@pointX, @pointY, 和 @index。这些分别被替换为点的x值、y值和索引。 更多相关信息可以在 QtCharts.QXYSeries.pointLabelsFormat的文档中找到。

下载 这个 示例

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations

"""PySide6 port of the Light Markers Points Selection example from Qt v6.2"""
import sys
from PySide6.QtWidgets import QApplication

from chartwindow import ChartWindow


if __name__ == "__main__":

    a = QApplication(sys.argv)
    main_window = ChartWindow()
    main_window.resize(640, 480)
    main_window.show()
    sys.exit(a.exec())
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from __future__ import annotations

"""PySide6 port of the Selected Point Configuration Example from Qt 6.5"""
from PySide6.QtCore import QPointF, Slot
from PySide6.QtGui import QColor, QIcon, QPainter
from PySide6.QtWidgets import QMainWindow, QLineEdit, QLabel, QComboBox
from PySide6.QtWidgets import QCheckBox, QWidget, QGridLayout, QHBoxLayout
from PySide6.QtCharts import QLineSeries, QXYSeries, QChart, QChartView


PointConfig = QXYSeries.PointConfiguration


class ChartWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle("Chart")
        self._series = QLineSeries(self)
        self._series.setName("Customized series")
        self._series.setPointsVisible(True)
        self._series.append([QPointF(0, 7), QPointF(2, 4),
                             QPointF(3, 5), QPointF(7, 4),
                             QPointF(10, 5), QPointF(11, 1),
                             QPointF(13, 3), QPointF(17, 6),
                             QPointF(18, 3), QPointF(20, 2)])

        selected_point_index_label = QLabel("Selected Point: ")
        self._selected_point_index_lineedit = QLineEdit()
        self._selected_point_index_lineedit.setReadOnly(True)
        self._selected_point_index_lineedit.setStyleSheet(
            "background-color: rgba(0, 0, 0, 0); border: 0px")

        color_label = QLabel("Color: ")
        self._color_combobox = QComboBox()
        color_strings = ["red", "orange", "yellow", "green", "blue",
                         "indigo", "violet", "black"]
        for color_str in color_strings:
            self._color_combobox.addItem(QIcon(), color_str, QColor(color_str))

        size_label = QLabel("Size: ")
        self._size_combobox = QComboBox()
        for size in [2, 3, 4, 6, 8, 10, 12, 15]:
            self._size_combobox.addItem(QIcon(), str(size), size)

        label_visibility_label = QLabel("Label Visibility: ")
        self._label_visibility_checkbox = QCheckBox()

        custom_label_label = QLabel("Custom Label: ")
        self._custom_label_lineedit = QLineEdit()

        self._series.clicked.connect(self._select_point)
        self._color_combobox.activated.connect(self._set_color)
        self._size_combobox.activated.connect(self._set_size)
        label_vis_checkbox = self._label_visibility_checkbox
        label_vis_checkbox.clicked.connect(self._set_label_visibility)
        clabel_lineedit = self._custom_label_lineedit
        clabel_lineedit.editingFinished.connect(self._set_custom_label)

        self._chart = QChart()
        self._chart.addSeries(self._series)
        self._chart.createDefaultAxes()

        chart_view = QChartView(self._chart)
        chart_view.setRenderHint(QPainter.RenderHint.Antialiasing)

        control_widget = QWidget(self)
        control_layout = QGridLayout(control_widget)
        control_layout.setColumnStretch(1, 1)

        control_layout.addWidget(selected_point_index_label, 0, 0)
        control_layout.addWidget(self._selected_point_index_lineedit, 0, 1)

        control_layout.addWidget(color_label, 1, 0)
        control_layout.addWidget(self._color_combobox, 1, 1)

        control_layout.addWidget(size_label, 2, 0)
        control_layout.addWidget(self._size_combobox, 2, 1)

        control_layout.addWidget(label_visibility_label, 3, 0)
        control_layout.addWidget(self._label_visibility_checkbox, 3, 1, 1, 2)

        control_layout.addWidget(custom_label_label, 4, 0)
        control_layout.addWidget(self._custom_label_lineedit, 4, 1)

        main_widget = QWidget(self)
        main_layout = QHBoxLayout(main_widget)
        main_layout.addWidget(chart_view)
        main_layout.setStretch(0, 1)
        main_layout.addWidget(control_widget)
        self.setCentralWidget(main_widget)

        self._select_point(4)

    @Slot(QPointF)
    def _select_point(self, point: QPointF | int):
        try:
            index = (self._series.points().index(point.toPoint()) if
                     isinstance(point, QPointF) else point)
        except ValueError:
            # Do nothing if the place that was clicked on wasn't a point.
            return

        self._series.deselectAllPoints()
        self._series.selectPoint(index)
        self._selectedPointIndex = index
        self._selectedPointConfig = self._series.pointConfiguration(index)
        selected_point = self._series.at(index)
        selected_index_lineedit = self._selected_point_index_lineedit
        selected_index_lineedit.setText("(" + str(selected_point.x()) + ", "
                                        + str(selected_point.y()) + ")")
        config = self._series.pointConfiguration(index)

        color = config.get(PointConfig.Color) or self._series.color()
        size = config.get(PointConfig.Size) or self._series.markerSize()
        labelVisibility = (config.get(PointConfig.LabelVisibility)
                           or self._series.pointLabelsVisible())
        customLabel = config.get(PointConfig.LabelFormat) or ""

        combobox_value_list = [
            (self._color_combobox, color.name(), color),
            (self._size_combobox, str(size), size)
        ]
        for box, value_str, value in combobox_value_list:
            if box.findData(value) < 0:
                box.addItem(value_str, value)
            box.setCurrentIndex(box.findData(value))

        self._label_visibility_checkbox.setChecked(labelVisibility)
        self._custom_label_lineedit.setText(customLabel)

    @Slot(int)
    def _set_color(self, index: int):
        spc = self._selectedPointConfig
        spc[PointConfig.Color] = self._color_combobox.currentData()
        self._series.setPointConfiguration(self._selectedPointIndex, spc)

    @Slot(int)
    def _set_size(self, index: int):
        spc = self._selectedPointConfig
        spc[PointConfig.Size] = self._size_combobox.currentData()
        self._series.setPointConfiguration(self._selectedPointIndex, spc)

    @Slot(bool)
    def _set_label_visibility(self, checked: bool):
        spc = self._selectedPointConfig
        spc[PointConfig.LabelVisibility] = checked
        self._series.setPointConfiguration(self._selectedPointIndex, spc)

    @Slot()
    def _set_custom_label(self):
        spc = self._selectedPointConfig
        spc[PointConfig.LabelFormat] = self._custom_label_lineedit.text()
        self._series.setPointConfiguration(self._selectedPointIndex, spc)