如何使用Qt QPainter平滑地生长角度/长度变化的弧?这是我刚从Qt的Analog Clock Window Example创建的最小代码。
代码在50毫秒内随机更改m_value
+ - 5。这是为了模拟我想要实现的实际行为。弧开始于12点钟位置并逆时针方向增长。 m_value
缩放到360度(12点到12点)。
我的目标是实时平滑地改变弧的长度,以响应给定的(模拟)值,而不管输入值是否抖动。
我想完成两件事:
render
事件,所以我设置了33毫秒
计时器。当m_value
在不到30毫秒内发生变化时,需要这样做。我不想要的东西
我正在使用的平台:
#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
答案 0 :(得分:2)
我不熟悉仅针对此问题的Qt Gui方法,因此我将展示如何使用Qt Widgets来实现。
- 平滑重绘圆弧。当前代码直接重绘当时的值。我甚至不使用子角度值。结果在弧的末端有视觉上的噪音。
醇>
您可以使用Qt&#39; 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"
- 将图形与V-Sync一起更新。这样我就不会浪费计算能力来进行不显示的重绘。我不知道如何通过V-Sync触发渲染事件,所以我设置了33毫秒的计时器。当m_value变化小于30毫秒时,这是必需的。
醇>
如果您使用update()
:
更新小部件,除非禁用更新或隐藏小部件。
此功能不会立即重绘;相反,当Qt返回主事件循环时,它会调度一个paint事件进行处理。这允许Qt优化以获得比调用repaint()更快的速度和更少的闪烁。
多次调用update()通常只会导致一次paintEvent()调用。