C/C++ 信号槽C语言实现

QT中是有信号槽,发现挺好用,秉承着好用就使劲用的原则,肯定要记录下。其实早就有博主实现了轮子。

实现的博主链接:https://mp.weixin.qq.com/s/3BcMHY71lH3WPgcPwxb2LQ,但是测试用例描述的不太清晰,自己写了测试下了。

实验代码:


#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define __PLOOC_CLASS_USE_STRICT_TEMPLATE__

#if     defined(__SIGNALS_SLOTS_CLASS_IMPLEMENT__)
    #define __PLOOC_CLASS_IMPLEMENT__
#elif   defined(__SIGNALS_SLOTS_CLASS_INHERIT__)
    #define __PLOOC_CLASS_INHERIT__
#endif

#include "plooc_class.h"


#define SIG_NAME_MAX 20

#define SIGNAL(x) "sig_"#x

#define SLOT(x) x

#define SIG_SLOT_OBJ  sig_slot_t tObject;


#define  args(...)            ,__VA_ARGS__

#define _args(...)            __VA_ARGS__

#define __RecFun_0(__OBJ)                                     \
            __RecFun((__OBJ))

#define __RecFun_1(__OBJ, __ARG1)                         \
            __RecFun((__OBJ),(__ARG1))

#define __RecFun_2(__OBJ, __ARG1, __ARG2)                         \
            __RecFun((__OBJ),(__ARG1), (__ARG2))

#define __RecFun_3(__OBJ, __ARG1, __ARG2, __ARG3)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3))                         

#define __RecFun_4(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4))    
            
#define __RecFun_5(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5))  

#define __RecFun_6(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6)) 

#define __RecFun_7(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6, __ARG7)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6), (__ARG7)) 

#define __RecFun_8(__OBJ, __ARG1, __ARG2, __ARG3, __ARG4, __ARG5, __ARG6, __ARG7, __ARG8)                 \
            __RecFun((__OBJ),(__ARG1), (__ARG2), (__ARG3), (__ARG4), (__ARG5), (__ARG6), (__ARG7), (__ARG8))  
 
            
#define __signals(__NAME,...)                                    \
             typedef void PLOOC_CONNECT2(__NAME,_fun_t)( __VA_ARGS__);  

#define signals(__NAME,__OBJ,...)               \
          __signals(__NAME,_args(__OBJ __VA_ARGS__))

#define __emit(__OBJ,...) \
              __PLOOC_EVAL(__RecFun_,##__VA_ARGS__)             \
                   ((__OBJ)->ptRecObj,__VA_ARGS__); 

#define emit(__NAME,__OBJ,...)                     \
           do {sig_slot_t *ptObj = &((__OBJ)->tObject);                \
               do{if(__OBJ == NULL || ptObj == NULL ) break;              \
                   PLOOC_CONNECT2(__NAME,_fun_t) *__RecFun = ptObj->ptRecFun;   \
                   if(__RecFun != NULL) __emit(ptObj __VA_ARGS__);                           \
                   ptObj = ptObj->ptNext;             \
               }while(ptObj != NULL);              \
           }while(0)

#define __slots(__NAME,...)             \
            void __NAME(__VA_ARGS__);
            
#define slots(__NAME,__OBJ,...)  \
            __slots(__NAME,_args(__OBJ,##__VA_ARGS__))

#define connect(__SIG_OBJ,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)    \
            direct_connect(__SIG_OBJ.tObject,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)
            
#define connectptr(__SIG_OBJ,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)    \
            direct_connect(&__SIG_OBJ->tObject,__SIG_NAME,__SLOT_OBJ,__SLOT_FUN)                        

#define disconnect(__SIG_OBJ,__SIG_NAME)    \
            auto_disconnect(__SIG_OBJ.tObject,__SIG_NAME)
            
#define disconnectptr(__SIG_OBJ,__SIG_NAME)    \
            auto_disconnect(&__SIG_OBJ->tObject,__SIG_NAME)            


typedef struct sig_slot_t sig_slot_t;
typedef struct sig_slot_t{
    char   chSenderName[SIG_NAME_MAX];
    void * ptSenderObj;  
    void * ptRecObj;
    void * ptRecFun;
    sig_slot_t *ptNext;
    sig_slot_t *ptPrev;
}sig_slot_t;

void direct_connect(sig_slot_t *ptSenderObj, const char *ptSender,void *ptRecObj,void *ptRecFun);
void auto_disconnect(sig_slot_t *ptSenderObj, const char *ptSender);

#undef __SIGNALS_SLOTS_CLASS_INHERIT__
#undef __SIGNALS_SLOTS_CLASS_IMPLEMENT__

void direct_connect(sig_slot_t *SenderObj, const char *ptSender,void *RecObj,void *RecFun)
{
    if(SenderObj == NULL || ptSender == NULL || RecObj == NULL || RecFun == NULL){
        return;
    }
    sig_slot_t * ptMetaObj = SenderObj;
    do{
        if(strstr(RecFun,"sig_")){
            memcpy(ptMetaObj->chSenderName,ptSender,strlen(ptSender)); 
            while(ptMetaObj->ptNext != NULL){
                ptMetaObj = ptMetaObj->ptNext;
            }
            ptMetaObj->ptNext = RecObj; 
            ptMetaObj->ptNext->ptPrev = ptMetaObj;          
            ptMetaObj = ptMetaObj->ptNext;
            memcpy(ptMetaObj->chSenderName,RecFun,strlen(RecFun));  
            break;            
        }
        
        if(strcmp(ptMetaObj->chSenderName,ptSender) == 0){
           sig_slot_t * ptSenderObj = malloc(sizeof(sig_slot_t));
           while(ptMetaObj->ptNext != NULL){
               ptMetaObj = ptMetaObj->ptNext;
           }
           ptMetaObj->ptNext = ptSenderObj;
           ptMetaObj->ptNext->ptPrev = ptMetaObj;  
           ptMetaObj = ptMetaObj->ptNext;
        }
        ptMetaObj->ptRecFun = RecFun;
        ptMetaObj->ptRecObj = RecObj;
        memcpy(ptMetaObj->chSenderName,ptSender,strlen(ptSender));  
        
    }while(0);
    
}

void auto_disconnect(sig_slot_t *ptSenderObj, const char *ptSender)
{
    if(ptSenderObj == NULL || ptSender == NULL){
        return;
    }
    sig_slot_t * ptMetaObj = ptSenderObj;
    if(strcmp(ptMetaObj->chSenderName,ptSender) == 0){
       while(ptMetaObj->ptNext != NULL){
           ptMetaObj = ptMetaObj->ptNext;
       }
 
       while(ptMetaObj != NULL){
           ptMetaObj->ptNext = NULL;
           memset(ptMetaObj->chSenderName,0,sizeof(ptMetaObj->chSenderName));
           if(ptMetaObj->ptRecFun != NULL){
               ptMetaObj->ptRecObj = NULL;
               ptMetaObj->ptRecFun = NULL;
               sig_slot_t * ptObj = ptMetaObj;
               free(ptObj);
           }
           ptMetaObj = ptMetaObj->ptPrev;
       }
    }
}

typedef struct 
{
SIG_SLOT_OBJ 
  int a;
  int b;
  int c;     
}test;

test m_test;

//signals(send_sig,test* this,args(unsigned char* p,int len));

typedef struct
{
  int c;    
}rslot;

rslot m_slot;

void func(void *this, unsigned char* p,int len)
{
   printf("----%p\n",this);
   printf("p is %s c is %d\n",p,len);
   return;   
}    

signals(send_sig,test* this,args(unsigned char* p,int len));

int main(int argc, char* argv[])
{
   m_test.a =1;
   m_test.b =2;
   m_test.c =3;
   
  
   rslot* cc_slot = &m_slot;
   test* cc_test = (test*) malloc(sizeof(test));
   printf("func %p\n",func);
   printf("cc_test addr %p\n",cc_test);
   connectptr(cc_test,SIGNAL(send_sig),&m_slot,SLOT(func));
   printf("----%p\n",&m_slot);
   unsigned char cc[30] = {"hello"};
   emit(send_sig,cc_test,args(cc,m_test.b)); 
   disconnectptr(cc_test,SIGNAL(send_sig)); 

   return 0;    
}

运行结果:

潜在的隐患:

若信号槽传入的参数是malloc分配的,需要在168行进行free释放

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以通过以下步骤在QT中实现QTableWidget的点击表头排序: 1. 在QT Designer中将QTableWidget添加到窗口中。 2. 在代码中为QTableWidget设置表头,并设置表头的单击信号连接到函数中。 ```c++ QTableWidget *tableWidget = new QTableWidget(this); tableWidget->setColumnCount(3); tableWidget->setHorizontalHeaderLabels(QStringList() << "Name" << "Age" << "City"); connect(tableWidget->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(sortTable(int))); ``` 3. 编写函数sortTable(),该函数根据点击的表头排序QTableWidget中的数据。 ```c++ void MainWindow::sortTable(int column) { tableWidget->sortByColumn(column); } ``` 4. 运行程序,单击表头即可按照点击的列排序。 完整的代码如下: ```c++ #include <QtWidgets/QMainWindow> #include <QtWidgets/QTableWidget> #include <QtWidgets/QHeaderView> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { QTableWidget *tableWidget = new QTableWidget(this); tableWidget->setColumnCount(3); tableWidget->setHorizontalHeaderLabels(QStringList() << "Name" << "Age" << "City"); connect(tableWidget->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(sortTable(int))); QStringList names = {"Alice", "Bob", "Charlie", "David", "Eva"}; QStringList ages = {"25", "30", "20", "35", "28"}; QStringList cities = {"New York", "London", "Paris", "Tokyo", "Sydney"}; for (int i = 0; i < 5; i++) { QTableWidgetItem *nameItem = new QTableWidgetItem(names[i]); QTableWidgetItem *ageItem = new QTableWidgetItem(ages[i]); QTableWidgetItem *cityItem = new QTableWidgetItem(cities[i]); tableWidget->setItem(i, 0, nameItem); tableWidget->setItem(i, 1, ageItem); tableWidget->setItem(i, 2, cityItem); } setCentralWidget(tableWidget); } private slots: void sortTable(int column) { tableWidget->sortByColumn(column); } private: QTableWidget *tableWidget; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow mainWindow; mainWindow.show(); return app.exec(); } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

水火汪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值