牛骨文教育服务平台(让学习变的简单)

【Qt编程】基于Qt的词典开发系列调用讲述人

我们知道,win7系统自带有讲述人,即可以机器读出当前内容,具体可以将电脑锁定,然后点击左下角的按钮即可。之前在用Matlab写扫雷游戏的时候,也曾经调用过讲述人来进行游戏的语音提示。具体的Matlab脚本文件如下:

sp=actxserver("SAPI.SpVoice");sp.Speak("你好,欢迎来到西安电子科技大学!Hello,Welcome to XD University!")  

Qt调用讲述人,需要使用专门的类,具体可以参考http://lynxline.com/qtspeech-say-hello-world    一文,文中大致介绍了该类的使用方法。下面我就通过使用该类来实现讲述人的调用。

首先建立一个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)  
}  
/***************************/  
//}  

程序结果如下: