我有一个简单的启动画面扩展,在用户等待主窗口时应该显示一些动画(动画gif)。问题是,只显示第一帧而不是全部:
class SplashScreen : public QSplashScreen
{
Q_OBJECT
public:
explicit SplashScreen(const QPixmap& pixmap, const QString& animation, Qt::WindowFlags flags = 0);
protected:
void paintEvent(QPaintEvent* event);
signals:
void frameChanged();
private slots:
void convertFrameChanged(int)
{
repaint();
}
private:
QMovie movie;
};
SplashScreen::SplashScreen(const QPixmap& pixmap, const QString& animation, Qt::WindowFlags flags)
: QSplashScreen(pixmap, flags),
movie(animation)
{
movie.start();
connect(&(movie), SIGNAL(frameChanged(int)), this, SLOT(convertFrameChanged(int)));
}
void SplashScreen::paintEvent(QPaintEvent* event)
{
QSplashScreen::paintEvent(event);
QPixmap frame = movie.currentPixmap();
QRect rect = frame.rect();
rect.moveCenter(this->rect().center());
if (rect.intersects(event->rect()))
{
QPainter painter(this);
painter.drawPixmap(rect.left(), rect.top(), frame);
}
}
编辑:
试图在SplashScreen构造函数中使用QTimer调用重绘:
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(doRefresh()));
timer->start(1000);
在Splashscreen中添加了插槽:
void doRefresh()
{
repaint();
}
但这也行不通。不调用doRefresh。似乎QTimer还需要一个已读的现有事件循环。
答案 0 :(得分:1)
假设在调用QApplication :: exec()函数之前显示启动画面,则可能没有处理事件,因此您需要在QApplication对象上调用processEvents。
请注意帮助示例: -
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QPixmap pixmap(":/splash.png");
QSplashScreen splash(pixmap);
splash.show();
app.processEvents(); // need to process events manually
...
QMainWindow window;
window.show();
splash.finish(&window);
return app.exec();
}
在这种情况下,它讨论了在启动画面上调用raise(),使用QTimer确保它保持在最顶层,但需要processEvents调用才能使QTimer运行。
正如Qt帮助在点击鼠标按钮时解除闪屏一样: -
由于启动画面通常在事件循环开始运行之前显示,因此需要定期调用QApplication :: processEvents()来接收鼠标点击。
同样可能适用于GIF动画。
答案 1 :(得分:1)
问题非常深刻。要使动画正常工作,您必须在主线程中允许进程事件。另一方面,也在主线程上执行初始化过程
第一种方法是尽可能频繁地添加app.processEvents()
,但这会严重限制帧速率,使其无用。
要正确修复它,您可以回答两个重要问题:
一旦我有应用程序,在初始化期间构建大索引。这花费了大约40秒钟。我已经使用QtConcurrent::run(this, &MyClass::MyMethodToBuildIndex)
将构建索引移动到单独的线程,并通过MyClass::MyMethodToBuildIndex
定期发出信号来显示一些进展(默认自动连接完成了整个技巧)。
如果您有类似的日志时间初始化,此解决方案将启用您的QMovie
开箱即用的动画,问题将只是信号和插槽的智能连接,因此窗口将以适当的时序显示和隐藏。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SplashScreen splash();
splash.show();
app.processEvents(); // need to process events manually
QMainWindow window;
SomeLogicClass data;
window.setData(&data);
connect(&data, SIGNAL(initializationProgressChanged(int)),
&spash, SLOT(setProgress(int)));
// show main window when initialization is finished
connect(&data, SIGNAL(initializationFinished()),
&window, SLOT(show()));
// close splash when initialization is finished
connect(&data, SIGNAL(initializationFinished()),
&spash, SLOT(close()));
// this line I usually hide behind some method like: startBackgroundInitialization
QtCuncurent::run(&data, &SomeLogicClass::heavyInitialization);
return app.exec();
}
如果您需要使用QSplashScreen::finish
代替close
,那么QSignalMapper
可以提供帮助
请注意,connect的最后一个参数是默认值Qt::AutoConnection
,它将强制在主线程中运行插槽。