【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)
}
/***************************/
//}
程序结果如下:
【Qt编程】基于Qt的词典开发系列<十二>调用讲述人

基于Qt的词典开发系列

  1. 词典框架设计及成品展示
  2. 本地词典的设计
  3. 开始菜单的设计
  4. 无边框窗口的缩放与拖动
  5. 无边框窗口的拖动
  6. 界面美化设计
  7. 调用网络API
  8. 用户登录及API调用的实现
  9. JSON数据解析
  10. 国际音标的显示
  11. 系统托盘的显示
  12. 调用讲述人
  13. 音频播放
  14. 自动补全功能
  15. HTML特殊字符及正则表达式
  16. 后序
作品下载地址(发布版):http://download.csdn.net/detail/tengweitw/8548767
作品下载地址(绿色版):http://download.csdn.net/detail/tengweitw/8830495
源码下载地址:http://download.csdn.net/detail/tengweitw/8830503

原文:http://blog.csdn.net/tengweitw/article/details/38306803

作者:nineheadedbird

上一篇:[转载]Matlab中fft与fftshift命令的小结与分析


下一篇:【传输协议】发送https请求,由于客户端jdk版本过高,服务端版本低。导致异常:javax.net.ssl.SSLHandshakeException: Server chose SSLv3, but that protocol version is not enabled or not supported by the client.