信号槽模式分析

一、信号槽的基本概念

通过信号槽机制,QT使对象间的通信变得非常简单:A对象声明信号(signal)B对象实现与之参数相匹配的槽(slot),通过调用connect进行连接,合适的时机A对象使用emit把信号带上参数发射出去,B对象的槽会就接收到响应。

信号槽机制有一些特点:

1.   类型安全:只有参数匹配的信号与槽才可以连接成功(信号的参数可以更多,槽会忽略多余的参数)。

2.   线程安全:通过借助QT自已的事件机制,信号槽支持跨线程并且可以保证线程安全。

3.   松耦合:信号不关心有哪些或者多少个对象与之连接;槽不关心自己连接了哪些对象的哪些信号。这些都不会影响何时发出信号或者信号如何处理。

4.   信号与槽是多对多的关系:一个信号可以连接多个槽,一个槽也可以用来接收多个信号。

二、信号与槽的定义

槽:用来接收信号,可以被看作是普通成员函数,可以被直接调用。支持publicprotectedprivate修饰,用来定义可以调用连接到此槽的范围。

public slots:  

void testslot(const QString& strSeqId);  

信号:只需要声明信号名与参数列表即可,就像是一个只有声明没有实现的成员函数。

signals:  

void testsignal(const QString&); 

QT会在moccpp文件中实现它(参考下面代码)。下面代码中调用activate的第三个参数是类中信号的序列号。

 // SIGNAL 0  

 void CTestObject:: testsignal (const QString & _t1)  

 {  

     void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };  

     QMetaObject::activate(this, &staticMetaObject, 0, _a);  

 }  

三、信号槽的连接与触发

通过调用connect()函数建立连接,会把连接信息保存在sender对象中;调用desconnect()函数来取消。

connect函数的最后一个参数来用指定连接类型(因为有默认,我们一般不填写)

 static bool connect(const QObject *sender, const QMetaMethod &signal,  

 const QObject *receiver, const QMetaMethod &method,  

Qt::ConnectionType type = Qt::AutoConnection);  

sender对象中调用:

 emit testsignal(“test”);  

 # define emit  

上面代码可以看到emit被定义为空,这样在发射信号时就相当于直接调用QT为我们moc出来的函数testsignal(constQString & _t1)

具体的操作由QMetaObject::activate()来处理:遍历所有receiver并触发它们的slots。针对不同的连接类型,这里的派发逻辑会有不同。

QProgressDialog类提供了慢操作的进度的反馈。

 、QProgressDialog类的描述

进度对话框用于给用户这个操作还要有多长时间的指示,并且证明这个应用程序还没有冻结。它也给用于一个中止这个操作运行的机会。

进度对话框的一个常见问题是很难知道什么时候使用它们,操作在不同的硬件会占用不同的时间。QProgessDialog提供了对这个问题的解决方案:它估计操作将占用的时间(基于没步的时间),并且如果它超过minimumDuration()(默认为4秒)才显示自己。

使用setTotalSteps()(或者在构造函数中)设置操作中的“步”数并且调用setProgress()作为操作进度。步值的选择是任意的。它可以是复制的文件数,接收的字节数,在你的算法的主循环中的反复次数,或者一些其它的适合单元。进度从0开始,并且当你把totalSteps()作为参数调用setProgress(),这个进度对话框会显示这个操作已经完成。

对话框会在操作结束的时候自动重置并且隐藏自己。使用setAutoReset()setAutoClose()可以改变这个行为。

你需要拥有一个正在运行的时间循环,把cancelled()信号和停止这个操作的槽连接起来,并且在间隔中调用setProgress()。例如:

Operation::Operation( QObject*parent = 0 )

    : QObject(parent ), steps( 0 )

{

    pd = newQProgressDialog( "Operation in progress.", "Cancel", 100 );

    connect( pd, SIGNAL(cancelled()), this, SLOT(cancel()) );

    t = new QTimer(this );

    connect( t, SIGNAL(timeout()), this, SLOT(perform()) );

    t->start( 0 );

}

 

void Operation::perform()

{

    pd->setProgress( steps );

    //……执行操作的一个半分比

    steps++;

    if ( steps> pd->totalSteps() )

        t->stop();

}

 

void Operation::cancel()

{

    t->stop();

    //……清除

}

你可以通过使用setLabel()setBar()setCancelButton()用自定制的窗口部件来替换子窗口部件来定制这两种进度对话框。

 

使用QProgressDialog的两种方法:模式和非模式。

使用模式QProgressDialog是更简单的,但是必须调用qApp->processEvents()来保持事件循环的运行来确保应用程序没有冻结。在循环中执行这个操作,在间隔中调用setProgress(),并且检查wasCancelled()的取消。例如:

QProgressDialog progress( "Copyingfiles...", "Abort Copy", numFiles,

                          this,"progress", TRUE );

for ( int i = 0; i < numFiles; i++ ) {

    progress.setProgress(i );

    qApp->processEvents();

 

    if (progress.wasCancelled() )

        break;

    //……复制文件

}

progress.setProgress( numFiles );

非模式进度对话框适合发生在后台的操作,用户还可以和应用程序进行交互。这样的操作通常是基于QTimer(或者QObject::timerEvent())、QSocketNotifierQUrlOperator,或者在一个独立的进度中执行。你的主窗口的状态条中的QProgressBar常常可以做为模式进度对话框的替代。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值