QT5笔记:7. 自定义类、自定义信号及类的元对象信息

  • 自定义的QPerson类,需要继承 QObject类

    • qperson.h头文件

      #ifndef QPERSON_H
      #define QPERSON_H
      
      #include <QObject>
      
      class QPerson : public QObject
      {
          Q_OBJECT
          Q_CLASSINFO("author", "……");
          Q_CLASSINFO("company", "……");
          Q_CLASSINFO("version", "1.0");
          Q_PROPERTY(unsigned int age READ age WRITE setAge NOTIFY ageChanged);
          Q_PROPERTY(QString name MEMBER m_name);
          Q_PROPERTY(int score MEMBER m_score);
      
      public:
          explicit QPerson(QString name, QObject *parent = nullptr);
          unsigned int age();
          void setAge(unsigned int val);
          void increaseAge();
      
      private:
          unsigned int m_age = 10;
          QString m_name;
          int m_score = 80;
      
      signals:
          void ageChanged(int age);//自定义的信号
      };
      
      #endif // QPERSON_H
      
    • qperson.cpp 类文件

      #include "qperson.h"
      
      QPerson::QPerson(QString name, QObject *parent) : QObject(parent)
      {
          m_name = name;
      }
      
      unsigned int QPerson::age()
      {
          return m_age;
      }
      
      void QPerson::setAge(unsigned int val)
      {
          if (val != m_age)//当变化时设置值并发射信号
          {
              m_age = val;
              emit(ageChanged(m_age));//发射信号
          }
      }
      
      void QPerson::increaseAge()
      {
          m_age++;
          emit(ageChanged(m_age));//发射信号
      }
      
      
    • widget.h 界面的头文件

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include "qperson.h" //自己创建的类,用双引号引入
    
    QT_BEGIN_NAMESPACE
    namespace Ui
    {
        class Widget;
    }
    QT_END_NAMESPACE
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = nullptr);
        ~Widget();
    
    private slots: //信号&槽不同于方法,需要写在头文件的这里 private slots
        void on_btnAddBoyAge_clicked();
    
        void on_btnAddGirlAge_clicked();
    
        void on_btnMetaInfo_clicked();
    
        void on_spin_valueChanged(int val);
    
        void on_ageChanged(int age);
    
    private:
        Ui::Widget *ui;
        QPerson *boy;
        QPerson *girl;
    };
    #endif // WIDGET_H
    
    • widget.cpp 界面的类文件
    #include "widget.h"
    #include "ui_widget.h"
    #include <QMetaProperty>
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent), ui(new Ui::Widget)
    {
        ui->setupUi(this);
        ui->spinBoxBoyAge->setProperty("isBoy", true);// 类似于WinForm 的Tag,但是比Tag强大,键值对类型
        ui->spinBoxGirlAge->setProperty("isBoy", false);
    
        boy = new QPerson("张三");
        boy->setAge(12);
        boy->setProperty("score", 99);
        boy->setProperty("sex", "boy"); //动态属性
    //    connect(boy, &QPerson::ageChanged, this, &Widget::on_ageChanged);
        connect(boy, SIGNAL(ageChanged(int)), this, SLOT(on_ageChanged(int)));//链接自定义函数
    
        girl = new QPerson("蕾欧娜");
        girl->setAge(15);
        girl->setProperty("score", 120);
        girl->setProperty("sex", "girl"); //动态属性
        connect(girl, SIGNAL(ageChanged(int)), this, SLOT(on_ageChanged(int)));
    
        connect(ui->spinBoxBoyAge, SIGNAL(valueChanged(int)), this, SLOT(on_spin_valueChanged(int)));
        connect(ui->spinBoxGirlAge, SIGNAL(valueChanged(int)), this, SLOT(on_spin_valueChanged(int)));
    }
    
    Widget::~Widget()
    {
        delete ui;
    }
    
    void Widget::on_btnAddBoyAge_clicked()
    {
        boy->increaseAge();
    }
    
    void Widget::on_btnAddGirlAge_clicked()
    {
        girl->increaseAge();
    }
    
    /**
     * @brief Widget::on_btnMetaInfo_clicked 元对象信息:对象信息和类的信息
     */
    void Widget::on_btnMetaInfo_clicked()
    {
        ui->textBoxInfo->clear();
        const QMetaObject *metaGirl = girl->metaObject();
        ui->textBoxInfo->appendPlainText("【对象信息】");
        ui->textBoxInfo->appendPlainText(QString("类名称:%1").arg(metaGirl->className()));
        QString text = QString::Null();
        for (int i = metaGirl->propertyOffset(); i < metaGirl->propertyCount(); i++)//属性的获取方式
        {
            QMetaProperty property = metaGirl->property(i);
            const char *name = property.name();
            QString value = girl->property(name).toString();
            text += QString("属性名:%1").arg(name) + "\t值:" + value + "\n";//字符串的拼接
        }
        ui->textBoxInfo->appendPlainText(text);
        ui->textBoxInfo->appendPlainText("【类信息】");
        QString classInfo = QString::Null();
        for (int i = metaGirl->classInfoOffset(); i < metaGirl->classInfoCount(); i++)
        {
            QMetaClassInfo classInf = metaGirl->classInfo(i);
            const char *name = classInf.name();
            const char *value = classInf.value();
            classInfo += QString("属性名:%1\t值:%2\n").arg(name).arg(value);//格式化字符串拼接函数
        }
        ui->textBoxInfo->appendPlainText(classInfo);
    }
    
    void Widget::on_spin_valueChanged(int val)
    {
        Q_UNUSED(val);//标明这个变量unused
        QSpinBox *box = qobject_cast<QSpinBox *>(sender());//类似于WinForm 的事件里的sender,一样需要类型转换,并且类型不匹配时返回null
        if (box->property("isBoy").toBool())
            boy->setAge(box->value());
        else
            girl->setAge(box->value());
    }
    
    void Widget::on_ageChanged(int age)
    {
        Q_UNUSED(age);//标明这个变量unused
        QPerson *person = qobject_cast<QPerson *>(sender());
        QString name = person->property("name").toString();
        QString sex = person->property("sex").toString();
        unsigned int p_age = person->age();
        ui->textBoxInfo->appendPlainText("姓名:" + name + " ,性别:" + sex + ", 年龄:" + QString::asprintf("%d", p_age));//格式化输出
    
        if (person->property("sex").toString() == "boy")
            ui->spinBoxBoyAge->setValue(p_age);
        else
            ui->spinBoxGirlAge->setValue(p_age);
    }
    
    
    • 最终界面样式
      image
posted @ 2023-03-15 17:11  echo_lovely  阅读(183)  评论(0编辑  收藏  举报