QChartView 和 QScatterSeries 覆盖了 QPointF 的标签
QChartView and QScatterSeries overrdide the label of a QPointF
我有一个 QChartView,它显示一些 2D 点,每个点代表一个特定的项目我想用项目名称标记每个点,而不是用它的 x、y 坐标作为默认行为
有什么方法可以实现覆盖创建或渲染标签的功能吗?
为什么在不更改 Qt 源代码的情况下很难实现
QXYSeries::setPointLabelsFormat对你帮助不大。它确实允许您更改标签的格式,但它唯一可变的部分是点的坐标。
所有绘图都在Qt classes的私有部分完成。这是整个故事:
标签绘制在QXYSeries的private part(painter->drawText(position, pointLabel);
):
void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points,
const int offset)
{
if (points.size() == 0)
return;
static const QString xPointTag(QLatin1String("@xPoint"));
static const QString yPointTag(QLatin1String("@yPoint"));
const int labelOffset = offset + 2;
painter->setFont(m_pointLabelsFont);
painter->setPen(QPen(m_pointLabelsColor));
QFontMetrics fm(painter->font());
// m_points is used for the label here as it has the series point information
// points variable passed is used for positioning because it has the coordinates
const int pointCount = qMin(points.size(), m_points.size());
for (int i(0); i < pointCount; i++) {
QString pointLabel = m_pointLabelsFormat;
pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x()));
pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y()));
// Position text in relation to the point
int pointLabelWidth = fm.width(pointLabel);
QPointF position(points.at(i));
position.setX(position.x() - pointLabelWidth / 2);
position.setY(position.y() - labelOffset);
painter->drawText(position, pointLabel);
}
}
drawSeriesPointLabels是从ScatterChartItem的paint method中调用的(这个class官方没有包含文档):
void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (m_series->useOpenGL())
return;
QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
painter->save();
painter->setClipRect(clipRect);
if (m_pointLabelsVisible) {
if (m_pointLabelsClipping)
painter->setClipping(true);
else
painter->setClipping(false);
m_series->d_func()->drawSeriesPointLabels(painter, m_points,
m_series->markerSize() / 2
+ m_series->pen().width());
}
painter->restore();
}
ScatterChartItem 又在 QScatterSeries 的 private part 中创建,不能用自定义 class:
void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
{
Q_Q(QScatterSeries);
ScatterChartItem *scatter = new ScatterChartItem(q,parent);
m_item.reset(scatter);
QAbstractSeriesPrivate::initializeGraphics(parent);
}
你可能想尝试什么
用setPointLabelsVisible(false);
隐藏原来的labels 后面会单独绘制labels
Subclass QChartView 并重新实现 paintEvent
,首先调用 QChartView::paintEvent
,然后调用自定义函数 (比方说 drawCustomLabels
),它是 QXYSeriesPrivate::drawSeriesPointLabels
的修改版本。通过调用 drawCustomLabels
pass:
- 当地画家在 MyChartView,
的视口上作画
QXYSeries::points
、 返回的点数
- 所需的偏移量。
下面是 drawCustomLabels
的示例:
void MyChartView::drawCustomLabels(QPainter *painter, const QVector<QPointF> &points, const int offset)
{
if (points.count() == 0)
return;
QFontMetrics fm(painter->font());
const int labelOffset = offset + 2;
painter->setFont(m_pointLabelsFont); // Use QXYSeries::pointLabelsFont() to access m_pointLabelsFont
painter->setPen(QPen(m_pointLabelsColor)); // Use QXYSeries::pointLabelsColor() to access m_pointLabelsColor
for (int n(0); n < points.count(); n++) {
QString pointLabel = "..."; // Set the desired label for the n-th point of the series
// Position text in relation to the point
int pointLabelWidth = fm.width(pointLabel);
QPointF position(points.at(n));
position.setX(position.x() - pointLabelWidth / 2);
position.setY(position.y() - labelOffset);
painter->drawText(position, pointLabel);
}
}
我有一个 QChartView,它显示一些 2D 点,每个点代表一个特定的项目我想用项目名称标记每个点,而不是用它的 x、y 坐标作为默认行为
有什么方法可以实现覆盖创建或渲染标签的功能吗?
为什么在不更改 Qt 源代码的情况下很难实现
QXYSeries::setPointLabelsFormat对你帮助不大。它确实允许您更改标签的格式,但它唯一可变的部分是点的坐标。
所有绘图都在Qt classes的私有部分完成。这是整个故事:
标签绘制在QXYSeries的private part(painter->drawText(position, pointLabel);
):
void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QVector<QPointF> &points,
const int offset)
{
if (points.size() == 0)
return;
static const QString xPointTag(QLatin1String("@xPoint"));
static const QString yPointTag(QLatin1String("@yPoint"));
const int labelOffset = offset + 2;
painter->setFont(m_pointLabelsFont);
painter->setPen(QPen(m_pointLabelsColor));
QFontMetrics fm(painter->font());
// m_points is used for the label here as it has the series point information
// points variable passed is used for positioning because it has the coordinates
const int pointCount = qMin(points.size(), m_points.size());
for (int i(0); i < pointCount; i++) {
QString pointLabel = m_pointLabelsFormat;
pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x()));
pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y()));
// Position text in relation to the point
int pointLabelWidth = fm.width(pointLabel);
QPointF position(points.at(i));
position.setX(position.x() - pointLabelWidth / 2);
position.setY(position.y() - labelOffset);
painter->drawText(position, pointLabel);
}
}
drawSeriesPointLabels是从ScatterChartItem的paint method中调用的(这个class官方没有包含文档):
void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (m_series->useOpenGL())
return;
QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
painter->save();
painter->setClipRect(clipRect);
if (m_pointLabelsVisible) {
if (m_pointLabelsClipping)
painter->setClipping(true);
else
painter->setClipping(false);
m_series->d_func()->drawSeriesPointLabels(painter, m_points,
m_series->markerSize() / 2
+ m_series->pen().width());
}
painter->restore();
}
ScatterChartItem 又在 QScatterSeries 的 private part 中创建,不能用自定义 class:
void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
{
Q_Q(QScatterSeries);
ScatterChartItem *scatter = new ScatterChartItem(q,parent);
m_item.reset(scatter);
QAbstractSeriesPrivate::initializeGraphics(parent);
}
你可能想尝试什么
用
setPointLabelsVisible(false);
隐藏原来的labels 后面会单独绘制labelsSubclass QChartView 并重新实现
paintEvent
,首先调用QChartView::paintEvent
,然后调用自定义函数 (比方说drawCustomLabels
),它是QXYSeriesPrivate::drawSeriesPointLabels
的修改版本。通过调用drawCustomLabels
pass:- 当地画家在 MyChartView, 的视口上作画
QXYSeries::points
、 返回的点数
- 所需的偏移量。
下面是 drawCustomLabels
的示例:
void MyChartView::drawCustomLabels(QPainter *painter, const QVector<QPointF> &points, const int offset)
{
if (points.count() == 0)
return;
QFontMetrics fm(painter->font());
const int labelOffset = offset + 2;
painter->setFont(m_pointLabelsFont); // Use QXYSeries::pointLabelsFont() to access m_pointLabelsFont
painter->setPen(QPen(m_pointLabelsColor)); // Use QXYSeries::pointLabelsColor() to access m_pointLabelsColor
for (int n(0); n < points.count(); n++) {
QString pointLabel = "..."; // Set the desired label for the n-th point of the series
// Position text in relation to the point
int pointLabelWidth = fm.width(pointLabel);
QPointF position(points.at(n));
position.setX(position.x() - pointLabelWidth / 2);
position.setY(position.y() - labelOffset);
painter->drawText(position, pointLabel);
}
}