QMetaObject::invokeMethod()使用解决界面卡住问题

本文介绍了如何在Qt应用中避免主界面因耗时操作卡顿,提出了两种解决方案:一是使用QTimer的singleShot进行延时加载,确保界面先显示再执行;二是利用QMetaObject的invokeMethod实现异步加载。详细阐述了函数用法及参数解释,并提醒注意参数限制和数据类型注册。
摘要由CSDN通过智能技术生成

前因:有时在窗体初始化的时候加载一个耗时的操作,很容易卡主界面的显示,要在加载完以后才会显示界面,这就导致了体验很卡不友好的感觉,此时你可以将耗时的加载延时或者异步进行加载,这样就会在界面显示后去执行,而不是卡在主界面。

主界面要执行一些耗时的操作时,不卡主界面的方式:

☺方式一(延时

可以考虑QTimer的单次触发静态函数QTimer::singleShot()

函数原型:void QTimer::singleShot ( int msec, QObject * receiver, const char * member ) [static]

示例1:时间到了之后,只会触发一次

#include <QApplication>
 #include <QTimer>
 
 int main(int argc, char *argv[])
 {
     QApplication app(argc, argv);
     QTimer::singleShot(600000, &app, SLOT(quit()));
     ...
     return app.exec();

}

 示例2:非阻塞方式延时

    
    QEventLoop loop;    
    QTimer::singleShot(msec, &loop, SLOT(quit()));
    loop.exec();
    继续执行代码

    //如果不是QTimer的单次触发事件,是其他的执行代码的话,可以用
    loop.exit();  //退出事件循环

☺方式二(异步加载耗时函数

示例:

QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection);
//load要定义成槽函数,耗时操作放在里面执行即可

补充说明:QMetaObject::invokeMethod静态函数可以同来调用一个Q_OBJECT对象的信号、槽、方法,其原型如下所示:(如果可以调用该成员,则返回True。如果没有这样的成员或参数不匹配,则返回FALSE。)

bool QMetaObject::invokeMethod ( 
    QObject * obj,//被调用对象的指针; 
    const char * member,//参数是方法的名字;
    Qt::ConnectionType type,//参数是连接类型。可以指定连接类型,来决定是同步还是异步调用;
    QGenericReturnArgument ret,//参数接收被调用函数的返回值;注意,如果调用是异步的,则无法计算返回值;
    QGenericArgument val0 = QGenericArgument( 0 ), 
    QGenericArgument val1 = QGenericArgument(), 
    QGenericArgument val2 = QGenericArgument(), 
    QGenericArgument val3 = QGenericArgument(), 
    QGenericArgument val4 = QGenericArgument(), 
    QGenericArgument val5 = QGenericArgument(),
    QGenericArgument val6 = QGenericArgument(),
    QGenericArgument val7 = QGenericArgument(), 
    QGenericArgument val8 = QGenericArgument(),
    QGenericArgument val9 = QGenericArgument() ) [static]

注1:传入的参数是有个数限制的,可以向成员函数传递最多十个参数(val0,val1,val2,val3,val4,val5,val6,val7,val8和val9)。

注2:第三个参数连接类型区别

Qt :: DirectConnection会立即调用该成员
Qt :: QueuedConnection将发送QEvent,并在应用程序进入主事件循环时立即调用该成员(异步)
Qt :: BlockingQueuedConnection将以与Qt :: QueuedConnection相同的方式调用该方法,除了当前线程将阻塞直到事件被传递。使用此连接类型在同一线程中的对象之间进行通信将导致死锁。
Qt :: AutoConnection则如果obj与调用者位于同一个线程中,则会同步调用该成员; 否则它将异步调用该成员。

注3:QGenericArgumentQGenericReturnArgument是内部帮助器类。因为可以动态调用信号和槽,所以必须使用Q_ARG()和Q_RETURN_ARG()宏将参数括起来

对于带参数的槽函数调用示例,槽函数是compute(QString, int, double):

QString sReturnVal;
QMetaObject::invokeMethod(object, "compute", Qt::DirectConnection,
                           Q_RETURN_ARG(QString, sReturnVal),
                           Q_ARG(QString, "sqrt"),
                           Q_ARG(int, 42),
                           Q_ARG(double, 9.7));

☺1、Q_RETURN_ARG()接受类型名非常数引用

☺2、Q_ARG()接受类型名该类型的常量引用; 


对于异步方法调用,参数必须是Qt的元对象系统已知的类型,因为Qt需要复制参数以将它们存储在幕后的事件中。

注:QMetaObject::InvokeMethod:无法处理未注册的数据类型,在调用InvokeMethod()之前,应该调用qRegisterMetaType()注册数据类型,示例:

typedef QString CustomString;
qRegisterMetaType<CustomString>("CustomString");

大佬经验补充:如果要执行private(protected/public)下的函数,需要函数前面加上 Q_INVOKABLE 关键字,private: Q_INVOKABLE void fun_test(int type, double value);

QMetaObject::invokeMethod(this, "fun_test", Q_ARG(int, 99), Q_ARG(double, 99.99)); 

或许你会感兴趣!!!

QT之connect的第五个参数(信号与槽的使用)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼2333号程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值