选择点配置示例#

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

Line chart with controls for configuring selected points

展示的功能#

在这款应用中,您将学习如何

  • 在点击时选择一系列点

  • 覆盖以下特定点的配置

    • 颜色

    • 大小

    • 标签可见性

    • 标签文本格式

子类化QMainWindow#

创建一个QMainWindow的子类,用于包含图表和控制功能。

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

创建一个折线序列#

创建一个包含点的折线序列以进行绘制。给它一个名称并使点可见。

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: Union[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,调整其大小,显示它,并启动事件循环。

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

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

使用方法#

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

您可以使用三个特殊的格式化字符串用于标签:@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

"""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

"""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
from typing import Union


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: Union[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)