来自QThread 上的 Qt 文档:-
默认情况下,run() 通过调用 exec() 启动事件循环
由于您从 QThread 继承,您现在有一个不调用 exec() 的运行函数。因此,事件循环没有运行,很可能是播放音效所必需的。
调用 exec() 应该替换 while(true){} 因为 exec() 将等到 exit() 被调用。
基于“如何真正真正使用 QThreads...” ,正确地执行此操作,将对象移动到线程
class Worker : public QObject
{
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void PlaySoundEffect();
signals:
void finished();
void error(QString err);
private:
// store the sound effect, so we can reuse it multiple times
QSoundEffect* m_pAlarmSound;
private slots:
};
Worker::Worker()
{
m_pAlarmSound = new QSoundEffect;
m_pAlarmSound.setSource(QUrl::fromLocalFile(":/sound"));
}
Worker::~Worker()
{
delete m_pAlarmSound;
m_pAlarmSound = nullptr; // C++ 11
}
void Worker::PlaySoundEffect()
{
m_pAlarmSound->play();
}
// setup the worker and move it to another thread...
MainWindow::MainWindow
{
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(PlaySoundEffect()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
// We can also connect a signal of an object in the main thread to the PlaySoundEffect slot
// Assuming MainWindow has declared a signal void Alert();
connect(this, &MainWindow::Alert, worker, &Worker::PlaySoundEffect);
// Then play the sound when we want: -
emit Alert();
}
虽然这看起来需要付出很多努力,但这样做有很多好处。例如,如果您有很多音效,那么继承 QThread 的方法意味着您正在为每个音效创建一个线程,这并不理想。
通过将枚举传递到 PlaySoundEffect 插槽,我们可以轻松地扩展上述 Worker 对象以保存声音效果列表并播放我们想要的效果。由于该线程一直在运行,因此播放声音会产生较少的延迟;在运行时创建线程需要时间和资源。