gpt4 book ai didi

c++ - 使用 QPainter 流畅绘图

转载 作者:行者123 更新时间:2023-11-30 03:44:22 24 4
gpt4 key购买 nike

如何使用 Qt QPainter 平滑地增加一个角度/长度变化的弧?这是我刚刚从 Qt 的 Analog Clock Window Example 创建的最少代码.

代码在 50 毫秒内随机更改 m_value +- 5。这是为了模拟我想要实现的实际行为。圆弧从 12 点钟位置开始并逆时针增长。 m_value 缩放以适应 360 度(12 点到 12 点)。

我的目标是根据给定的(模拟)值实时平滑地改变弧长,而不管输入值抖动如何。

我想完成两件事:

  1. 圆弧的平滑重绘。当前代码直接重绘了当时的值(value)。我什至不使用子角度值。结果在弧线末端视觉上有噪音。
  2. 使用 V-Sync 更新绘图。为了不浪费非显示重绘的计算能力。我不知道怎么办通过 V-Sync 触发 render 事件,所以我设置了 33 毫秒定时器。当 m_value 的变化时间少于 30 毫秒时,这是必需的。

我不想要的

  • QtQuick。我正在寻找 QPainter 的方法来做到这一点。

我使用的平台:

  • Qt 5.x
  • 在 Debian Linux 上(如果重要的话)

#include <QtGui>

#include "rasterwindow.h"

class SmoothArc : public RasterWindow
{
public:
SmoothArc();

protected:
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
void render(QPainter *p) Q_DECL_OVERRIDE;

private:
int m_timerId;
int m_valueTimerId;
int m_value = 50;
};

SmoothArc::SmoothArc()
{
setTitle("Smooth Arc");
resize(200, 200);

m_timerId = startTimer(33);
m_valueTimerId = startTimer(100);
}

void SmoothArc::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_timerId)
renderLater();
if (event->timerId() == m_valueTimerId) {
m_value = m_value + (qrand() % 11 - 5);
if (m_value > 100) m_value = 100;
if (m_value < 0) m_value = 0;
}
}

void SmoothArc::render(QPainter *p)
{
p->setRenderHint(QPainter::Antialiasing);
int side = qMin(width(), height());
p->scale(side / 200.0, side / 200.0);

QRectF rect(10, 10, 180, 180);
QPen pen = p->pen();
pen.setWidth(10);
p->setPen(pen);
p->drawArc(rect, 90*16, (360*(m_value/100.0))*16);
}

int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
SmoothArc arc;
arc.show();
return app.exec();
}

完整代码位于 https://github.com/yashi/smooth-arc .像下面这样的常规构建过程应该可以工作。

git clone https://github.com/yashi/smooth-arc.git
cd smooth-arc
qmake
make
./smooth-arc

最佳答案

我不熟悉仅使用 Qt Gui 的方法来解决这个问题,所以我将展示如何使用 Qt Widgets 来解决这个问题。

  1. Smooth redraw of the arc. The current code directly redraw the value at the time. I does not even use sub angle value. The result is visually noisy at the end of the arc.

您可以使用 Qt 的 animation framework插入属性更改:

#include <QtWidgets>

class SmoothArc : public QWidget
{
Q_OBJECT
Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged)

public:
SmoothArc();

qreal value() const;
void setValue(qreal value);

signals:
void valueChanged();

protected:
void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE;

private:
int m_valueTimerId;
qreal m_value;
QPropertyAnimation m_animation;
};

SmoothArc::SmoothArc()
{
resize(200, 200);

m_valueTimerId = startTimer(100);
m_value = 50;
m_animation.setTargetObject(this);
m_animation.setPropertyName("value");
}

qreal SmoothArc::value() const
{
return m_value;
}

void SmoothArc::setValue(qreal value)
{
if (qFuzzyCompare(value, m_value))
return;

m_value = value;
update();
emit valueChanged();
}

void SmoothArc::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_valueTimerId) {
qreal newValue = m_value + (qrand() % 11 - 5);
if (newValue > 100) newValue = 100;
if (newValue < 0) newValue = 0;

if (m_animation.state() == QPropertyAnimation::Running)
m_animation.stop();
m_animation.setStartValue(m_value);
m_animation.setEndValue(newValue);
m_animation.start();
}
}

void SmoothArc::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
int side = qMin(width(), height());
p.scale(side / 200.0, side / 200.0);

QRectF rect(10, 10, 180, 180);
QPen pen = p.pen();
pen.setWidth(10);
p.setPen(pen);
p.drawArc(rect, 90*16, (360*(m_value/100.0))*16);
}

int main(int argc, char **argv)
{
QApplication app(argc, argv);
SmoothArc arc;
arc.show();
return app.exec();
}

#include "main.moc"

arc animation gif

  1. Update the drawing in along with V-Sync. So that I don't waste computation power for non-displayed redraw. I don't know how to trigger render event by V-Sync, so I've setup 33-millisecond timer. This is needed when m_value changes in less than 30 msec.

如果您使用 update(),我认为 Qt 应该会为您处理这个问题:

Updates the widget unless updates are disabled or the widget is hidden.

This function does not cause an immediate repaint; instead it schedules a paint event for processing when Qt returns to the main event loop. This permits Qt to optimize for more speed and less flicker than a call to repaint() does.

Calling update() several times normally results in just one paintEvent() call.

关于c++ - 使用 QPainter 流畅绘图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35532459/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com