🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 【Qt编程】基于Qt的词典开发系列调用讲述人 我们知道,win7系统自带有讲述人,即可以机器读出当前内容,具体可以将电脑锁定,然后点击左下角的按钮即可。之前在用Matlab写扫雷游戏的时候,也曾经调用过讲述人来进行游戏的语音提示。**具体的Matlab脚本文件如下:** ` sp=actxserver('SAPI.SpVoice');sp.Speak('你好,欢迎来到西安电子科技大学!Hello,Welcome to XD University!')  ` Qt调用讲述人,需要使用专门的类,具体可以参考[http://lynxline.com/qtspeech-say-hello-world  ](http://lynxline.com/qtspeech-say-hello-world%E4%B8%80%E6%96%87%EF%BC%8C%E6%96%87%E4%B8%AD%E5%A4%A7%E8%87%B4%E4%BB%8B%E7%BB%8D%E4%BA%86%E8%AF%A5%E7%B1%BB%E7%9A%84%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%E3%80%82%E4%B8%8B%E9%9D%A2%E6%88%91%E5%B0%B1%E9%80%9A%E8%BF%87%E4%BD%BF%E7%94%A8%E8%AF%A5%E7%B1%BB%E6%9D%A5%E5%AE%9E%E7%8E%B0%E8%AE%B2%E8%BF%B0%E4%BA%BA%E7%9A%84%E8%B0%83%E7%94%A8%E3%80%82)  一文,文中大致介绍了该类的使用方法。下面我就通过使用该类来实现讲述人的调用。 首先建立一个dialog类型的gui项目,将上面所说的类QtSpeech类的头文件speech.h和源文件speech.cpp添加到工程中,**这样项目中就有5个文件**:dialog.h、speech.h、main.cpp、dialog.cpp、speech.cpp。当然还有界面文件dialog.ui。在界面文件中**添加QTextEdit控件**用于输入你要读取的文字,然后在其槽函数中添加QtSpeech的发音功能,**添加QPushButton控件**来控制发音。**具体的各个文件源代码如下:** **1、dialog.h** ~~~ #ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include"speech.h" namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); ~Dialog(); private slots: void on_pushButton_clicked(); private: Ui::Dialog *ui; }; #endif // DIALOG_H ~~~ **2、speech.h** ~~~ #ifndef SPEECH_H #define SPEECH_H #include <QObject> class QtSpeech : public QObject { Q_OBJECT public: // 处理异常情况 struct Error { QString msg; Error(QString s):msg(s) {} }; struct InitError : Error { InitError(QString s):Error(s) {} }; struct LogicError : Error { LogicError(QString s):Error(s) {} }; struct CloseError : Error { CloseError(QString s):Error(s) {} }; //定义数据类型 struct VoiceName { QString id; QString name; }; typedef QList<VoiceName> VoiceNames; //定义构造函数 QtSpeech(QObject * parent); QtSpeech(VoiceName n = VoiceName(), QObject * parent =0L); virtual ~QtSpeech(); const VoiceName & name() const; //要读的内容 static VoiceNames voices(); //要读的内容 void say(QString) const; //同步发音 void tell(QString) const; //异步发音 void tell(QString, QObject * obj, const char * slot) const; //发音结束时,有停顿 /*******************/ void pause(void) const;//暂停 void resume(void) const;//从暂停中恢复 void stop(void) const;//停止发音 /******************/ signals: void finished(); protected: virtual void timerEvent(QTimerEvent *); private: class Private; Private * d; }; //} #endif // SPEECH_H ~~~ **3、main.cpp** ~~~ #include <QApplication> #include"dialog.h" int main(int argc, char *argv[]){ QApplication app(argc, argv); Dialog dlg; dlg.show(); return app.exec(); } ~~~ **4、dialog.cpp** ~~~ #include "dialog.h" #include "ui_dialog.h" Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); } Dialog::~Dialog() { delete ui; } void Dialog::on_pushButton_clicked() { QtSpeech *speaker = new QtSpeech(this); speaker->tell(ui->textEdit->toPlainText(),speaker,SLOT(onSpeechFinished())); // speaker.stop(); } ~~~ **5、speech.cpp** ~~~ #include "speech.h" #include <QString> #include <QPointer> #include <QList> #include <QTimerEvent> #undef UNICODE #include <sapi.h> #include <sphelper.h> #include <comdef.h> #define UNICODE #include <windows.h> #include <windowsx.h> #include <commctrl.h> // some defines for throwing exceptions #define Where QString("%1:%2:").arg(__FILE__).arg(__LINE__) #define SysCall(x,e) {\ HRESULT hr = x;\ if (FAILED(hr)) {\ QString msg = #e;\ msg += ":"+QString(__FILE__);\ msg += ":"+QString::number(__LINE__)+":"+#x+":";\ msg += _com_error(hr).ErrorMessage();\ throw e(msg);\ }\ } // internal data class QtSpeech::Private { public: Private() :onFinishSlot(0L),waitingFinish(false) {} VoiceName name; static const QString VoiceId; typedef QPointer<QtSpeech> Ptr; static QList<Ptr> ptrs; CComPtr<ISpVoice> voice; const char * onFinishSlot; QPointer<QObject> onFinishObj; bool waitingFinish; class WCHAR_Holder { public: WCHAR * w; WCHAR_Holder(QString s) :w(0) { w = new WCHAR[s.length()+1]; s.toWCharArray(w); w[s.length()] =0; } ~WCHAR_Holder() { delete[] w; } }; }; const QString QtSpeech::Private::VoiceId = QString("win:%1"); QList<QtSpeech::Private::Ptr> QtSpeech::Private::ptrs = QList<QtSpeech::Private::Ptr>(); //类的定义 QtSpeech::QtSpeech(QObject * parent) :QObject(parent), d(new Private) { CoInitialize(NULL); SysCall( d->voice.CoCreateInstance( CLSID_SpVoice ), InitError); VoiceName n; WCHAR * w_id = 0L; WCHAR * w_name = 0L; CComPtr<ISpObjectToken> voice; SysCall( d->voice->GetVoice(&voice), InitError); SysCall( SpGetDescription(voice, &w_name), InitError); SysCall( voice->GetId(&w_id), InitError); n.name = QString::fromWCharArray(w_name); n.id = QString::fromWCharArray(w_id); voice.Release(); if (n.id.isEmpty()) throw InitError(Where+"No default voice in system"); d->name = n; d->ptrs << this; } QtSpeech::QtSpeech(VoiceName n, QObject * parent) :QObject(parent), d(new Private) { ULONG count = 0; CComPtr<IEnumSpObjectTokens> voices; CoInitialize(NULL); SysCall( d->voice.CoCreateInstance( CLSID_SpVoice ), InitError); if (n.id.isEmpty()) { WCHAR * w_id = 0L; WCHAR * w_name = 0L; CComPtr<ISpObjectToken> voice; SysCall( d->voice->GetVoice(&voice), InitError); SysCall( SpGetDescription(voice, &w_name), InitError); SysCall( voice->GetId(&w_id), InitError); n.name = QString::fromWCharArray(w_name); n.id = QString::fromWCharArray(w_id); voice.Release(); } else { SysCall( SpEnumTokens(SPCAT_VOICES, NULL, NULL, &voices), InitError); SysCall( voices->GetCount(&count), InitError); for (int i =0; i< count; ++i) { WCHAR * w_id = 0L; CComPtr<ISpObjectToken> voice; SysCall( voices->Next( 1, &voice, NULL ), InitError); SysCall( voice->GetId(&w_id), InitError); QString id = QString::fromWCharArray(w_id); if (id == n.id) d->voice->SetVoice(voice); voice.Release(); } } if (n.id.isEmpty()) throw InitError(Where+"No default voice in system"); d->name = n; d->ptrs << this; } QtSpeech::~QtSpeech() { d->ptrs.removeAll(this); delete d; } const QtSpeech::VoiceName & QtSpeech::name() const { return d->name; } QtSpeech::VoiceNames QtSpeech::voices() { VoiceNames vs; ULONG count = 0; CComPtr<IEnumSpObjectTokens> voices; CoInitialize(NULL); SysCall( SpEnumTokens(SPCAT_VOICES, NULL, NULL, &voices), LogicError); SysCall( voices->GetCount(&count), LogicError); for(int i=0; i< count; ++i) { WCHAR * w_id = 0L; WCHAR * w_name = 0L; CComPtr<ISpObjectToken> voice; SysCall( voices->Next( 1, &voice, NULL ), LogicError); SysCall( SpGetDescription(voice, &w_name), LogicError); SysCall( voice->GetId(&w_id), LogicError); QString id = QString::fromWCharArray(w_id); QString name = QString::fromWCharArray(w_name); VoiceName n = { id, name }; vs << n; voice.Release(); } return vs; } void QtSpeech::tell(QString text) const { tell(text, 0L,0L); } void QtSpeech::tell(QString text, QObject * obj, const char * slot) const { if (d->waitingFinish) throw LogicError(Where+"Already waiting to finish speech"); d->onFinishObj = obj; d->onFinishSlot = slot; if (obj && slot) connect(const_cast<QtSpeech *>(this), SIGNAL(finished()), obj, slot); d->waitingFinish = true; const_cast<QtSpeech *>(this)->startTimer(100); Private::WCHAR_Holder w_text(text); SysCall( d->voice->Speak( w_text.w, SPF_ASYNC | SPF_IS_NOT_XML, 0), LogicError); } void QtSpeech::say(QString text) const { Private::WCHAR_Holder w_text(text); SysCall( d->voice->Speak( w_text.w, SPF_IS_NOT_XML, 0), LogicError); } void QtSpeech::timerEvent(QTimerEvent * te) { QObject::timerEvent(te); if (d->waitingFinish) { SPVOICESTATUS es; d->voice->GetStatus( &es, NULL ); if (es.dwRunningState == SPRS_DONE) { d->waitingFinish = false; killTimer(te->timerId()); finished(); } } } /************************/ void QtSpeech::pause(void) const{//暂停 SysCall( d->voice->Pause(), LogicError); } void QtSpeech::resume() const{//恢复 SysCall(d->voice->Resume(), LogicError); } void QtSpeech::stop() const{//停止 SysCall(d->voice->Speak(NULL, SPF_PURGEBEFORESPEAK, 0), LogicError) } /***************************/ //} ~~~ **程序结果如下:** ![](https://box.kancloud.cn/2016-01-15_5698c1c93fc22.jpg)