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

前言

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

博客转载至:https://blog.csdn.net/ligare/article/details/124406743

延时:可以考虑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();  //退出事件循环

异步进行load函数:QMetaObject::invokeMethod(this, "load", Qt::QueuedConnection);

让耗时操作可以异步进行,不至于卡界面

使用方法,都是把耗时的操作放在对应的槽函数里执行。

补充说明: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]

参数说明:

☺第一个参数是被调用对象的指针;
☺第二个参数是方法的名字;
☺第三个参数是连接类型。可以指定连接类型,来决定是同步还是异步调用。
☺第四个参数接收被调用函数的返回值;注意,如果调用是异步的,则无法计算返回值。
注意:传入的参数是有个数限制的,可以向成员函数传递最多十个参数(val0,val1,val2,val3,val4,val5,val6,val7,val8和val9)。

第三个参数类型区别:

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

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

Q_ARG()接受类型名和该类型的常量引用;

Q_RETURN_ARG()接受类型名和非常数引用。您只需要将信号或槽的名称传递给此函数,而不是整个签名。例如,若要异步调用QPushButton上的AnimateClick()槽,请使用以下代码:
QMetaObject::InvokeMethod(pushButton,“AnimateClick”,Qt::QueuedConnection);

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

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

常用的形式

QMetaObject::invokeMethod(object, "methodName", Qt::QueuedConnection, 
    Q_ARG(type1, arg1),   
    Q_ARG(type2, arg2));


还有一种是没有第三个参数,也就是不指明信号与槽的连接方式。

注:因为上面所示的参数需要被在构建事件时进行硬拷贝,参数的自定义型别所对应的类需要提供一个共有的构造函数、析构函数以及拷贝构造函数。而且必须使用注册Qt型别系统所提供的qRegisterMetaType() 方法来注册这一自定义型别。

对于异步方法调用,参数必须是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)); 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值