رفتن به مطلب
جامعهٔ برنامه‌نویسان مُدرن ایران
کامبیز اسدزاده

نمونه مثال مُدرن از برقراری ارتباط بین ++C و QML در قالب Contact List


پست های پیشنهاد شده

همانطور که می‌دانید یکی از مباحث شاید به ظاهر پیچیده در کیوت برقراری ارتباط بین سی‌پلاس‌پلاس و کیو‌ام‌اِل باشد. در این پست من تصمیم گرفتم مثالی را در قالب لیست تماس‌ها ایجاد کنم که شاید بعد‌ها توسعه آن ادامه داشته باشد.

فرض کنید قرار است لیستی از تماس‌ها یا کاربران را دریافت و در بخش رابط کاربری خود در قالب یک لیست نمایش دهیم. قبل از هرچیز باید بدانید که برای چنین کاری کلاسی را در سمت بک‌اِند ایجاد کنید. نام این کلاس را در این مثال ContactList گذاشته‌ایم.

فایل هدر مرتبط با کلاس تماس‌ها به صورت زیر است:

//
//  File : contactlist.h
//  Class or Function (ContactList)
//
//  Created by Kambiz Asadzadeh on 2018/7/19.
//  Copyright © 2018 Kambiz Asadzadeh. All rights reserved.
//  Official Website : http://kambizasadzadeh.com
//  Powered by : Dotwaves LLC (http://dotwaves.com)
//


#ifndef CONTACTLIST_H
#define CONTACTLIST_H

#include <QObject>

//Namespace Contact
namespace Contact {

  class ContactList;
  class ContactList : public QObject
  {
    Q_OBJECT

    Q_PROPERTY ( QString name    READ name   WRITE setName   NOTIFY nameChanged   )
    Q_PROPERTY ( QString family  READ family WRITE setFamily NOTIFY familyChanged )
    Q_PROPERTY ( QString phone   READ phone  WRITE setPhone  NOTIFY phoneChanged  )
    Q_PROPERTY ( QString device  READ device WRITE setDevice NOTIFY deviceChanged )
    Q_PROPERTY ( QString avatar  READ avatar WRITE setAvatar NOTIFY avatarChanged )
    Q_PROPERTY ( QString color   READ color  WRITE setColor  NOTIFY colorChanged  )
    Q_PROPERTY ( QString url     READ url  WRITE setUrl      NOTIFY urlChanged  )

  public:
    ContactList(QObject *parent=0);
    ContactList(
        const QString &name,
        const QString &family,
        const QString &phone,
        const QString &device,
        const QString &avatar,
        const QString &color,
        const QString &url,
        QObject *parent=0
        );

    ~ContactList();

    QString name    () const;
    QString family  () const;
    QString phone   () const;
    QString device  () const;
    QString url     () const;

    void setName    (const QString &name);
    void setFamily  (const QString &family);
    void setPhone   (const QString &phone);
    void setDevice  (const QString &device);
    void setUrl     (const QString &url);


    //Avatar of user

    QString avatar  () const;
    void setAvatar  (const QString &image);

    //Color of user
    QString color   () const;
    void setColor   (const QString &color);

  signals:
    void nameChanged    ();
    void familyChanged  ();
    void phoneChanged   ();
    void deviceChanged  ();
    void avatarChanged  ();
    void colorChanged   ();
    void urlChanged     ();

  private:
    QString m_name;
    QString m_family;
    QString m_phone;
    QString m_device;
    QString m_avatar;
    QString m_color;
    QString m_url;
  };

}


#endif // CONTACTLIST_H

قبل از هر چیز دقت کنید که برای استفاده و دسترسی به تمامی آبجکت‌های موجود در کیوت نیاز به کلاس QObject خواهیم داشت. بنابراین فایل هدر آن را در فایل خود افزوده‌ایم. فضای نام Contact سپس اعلان کلاس مشتق شده از کلاس QObject مشخص کرده و سپس برای فعال سازی امکان استفاده از سرویس متا آبجکت (به عنوان یک مکانیزم) برای دسترسی به سیگنال‌ها و اسلات‌ها در کیوت از ماکروی Q_OBJECT استفاد می‌کنیم. 

شکل کلی ماکروی Q_PROPERTY

  Q_PROPERTY(type name
             (READ getFunction [WRITE setFunction] |
              MEMBER memberName [(READ getFunction | WRITE setFunction)])
             [RESET resetFunction]
             [NOTIFY notifySignal]
             [REVISION int]
             [DESIGNABLE bool]
             [SCRIPTABLE bool]
             [STORED bool]
             [USER bool]
             [CONSTANT]
             [FINAL])

ماکروی Q_PROPERTY جهت اعلان ویژگی‌های موجود در اشیاء کلاس به کار گرفته شده است که از کلاس QObject ارث بری می‌کند. در نظر داشته باشید که این ویژگی‌های موجود در اصل همانند اعضای موجود در کلاس‌ها رفتار می‌کنند، با این تفاوت که در اینجا امکانات و ویژگی‌های اضافی بر اساس مکانیزم سیستم متا آبجکت کیوت را ارائه می‌دهند.

ویژگی‌های نام، نوع و تابع READ ضروری هستند. نوع می‌تواند هر نوعی را توسط QVariant پشتیبانی کند، یا توسط کاربر نوع مورد نیاز تعریف شود. آیتم‌های دیگر اختیاری هستند، اما یک تابع WRITE رایج است. صفات‌های دیگر به صورت پیشفرض به جز USER که به صورت پیش‌فرض false است همگی true می‌باشند.

برای مثال

Q_PROPERTY(QString title READ title WRITE setTitle USER true)

بر اساس همین روش ما پارامتر‌های کلاس را اعلان و در نهایت توابع، سیگنال‌ها و اعضای خصوصی کلاس را بر اساس نیاز اعلان کرده‌ایم.

تعریف کلاس و توابع آن در ادامه به صورت زیر آمده است:

//
//  File : contactlist.cpp
//  Class or Function (ContactList)
//
//  Created by Kambiz Asadzadeh on 2018/7/19.
//  Copyright © 2018 Kambiz Asadzadeh. All rights reserved.
//  Official Website : http://kambizasadzadeh.com
//  Powered by : Dotwaves LLC (http://dotwaves.com)
//


#include "contactlist.h"

using namespace Contact;

ContactList::ContactList(QObject *parent)
  : QObject(parent)
{
}

ContactList::ContactList(

    const QString &name,
    const QString &family,
    const QString &phone,
    const QString &device,
    const QString &avatar,
    const QString &color,
    const QString &url,
    QObject *parent

    )

  : QObject(parent),

    m_name    (name),
    m_family  (family),
    m_phone   (phone),
    m_device  (device),
    m_avatar  (avatar),
    m_color   (color),
    m_url     (url)
{
}

ContactList::~ContactList() {}

QString ContactList::name() const
{
  return m_name;
}

void ContactList::setName(const QString &name)
{
  if (name != m_name) {
      m_name = name;
      emit nameChanged();
    }
}

QString ContactList::family() const
{
  return m_family;
}

void ContactList::setFamily(const QString &family)
{
  if (family != m_family) {
      m_family = family;
      emit familyChanged();
    }
}

QString ContactList::phone() const
{
  return m_phone;
}

void ContactList::setPhone(const QString &phone)
{
  if (phone != m_phone) {
      m_phone = phone;
      emit phoneChanged();
    }
}

QString ContactList::device() const
{
  return m_device;
}

void ContactList::setDevice(const QString &device)
{
  if (device != m_device) {
      m_device = device;
      emit deviceChanged();
    }
}

QString ContactList::avatar() const
{
  return m_avatar;
}

void ContactList::setAvatar(const QString &avatar)
{
  if (avatar != m_avatar) {
      m_avatar = avatar;
      emit avatarChanged();
    }
}

QString ContactList::color() const
{
  return m_color;
}

void ContactList::setColor(const QString &color)
{
  if (color != m_color) {
      m_color = color;
      emit colorChanged();
    }
}


QString ContactList::url() const
{
  return m_url;
}

void ContactList::setUrl(const QString &url)
{
  if (url != m_url) {
      m_url = url;
      emit urlChanged();
    }
}

توجه داشته باشید که هر یک از توابع مقادیر ورودی را در قالب پارامتر‌های ثابت دریافت و در صورتی که اعضای موجود در کلاس مقداری نداشته باشند برابر با پارامتر ورودی خواهند بود. سپس در صورتی که مقدار آن‌ها تغییر یافت وضعیت تغییر آن‌ها توسط emit به عنوان یک پیش‌پردازندهٔ از قبل تعریف شده کیوت انتشار (ساطع) خواهد شد.

 

بعد از اعلان و تعریف کلاس مربوطه در فایل main.cpp لیستی را به عنوان داده‌های ارسالی ایجاد می‌کنیم که به صورت زیر آمده است:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "contactlist.h"

using namespace Contact;

int main(int argc, char *argv[])
{
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

  QGuiApplication app(argc, argv);

  QList<QObject*> dataList;
     dataList.append(new ContactList("کامبیز",
                                    "اسدزاده",
                                    "09140000000",
                                    "Apple iPhone",
                                    "https://avatars0.githubusercontent.com/u/4066299?s=460&v=4",
                                    "#00D397",
                                    "https://github.com/Kambiz-Asadzadeh"));

     dataList.append(new ContactList("حامد",
                                    "مصافی",
                                    "09350000000",
                                    "Samsung Galaxy",
                                    "https://avatars2.githubusercontent.com/u/13809362?s=460&v=4",
                                    "#E83B0B",
                                    "https://github.com/HamedMasafi"));

     dataList.append(new ContactList("بهنام",
                                    "صباغی",
                                    "09190000000",
                                    "Google Nexus",
                                    "https://avatars3.githubusercontent.com/u/17690495?s=460&v=4",
                                    "#E15504",
                                    "https://github.com/FONQRI"));

     dataList.append(new ContactList("آرش",
                                    "میلانی",
                                    "09140000000",
                                    "Apple iPhone",
                                    "https://avatars3.githubusercontent.com/u/586816?s=460&v=4",
                                    "#3650F7",
                                    "https://github.com/arashmilani"));

     dataList.append(new ContactList("سروش",
                                    "ربیعی",
                                    "09190000000",
                                    "Google Nexus",
                                    "https://avatars0.githubusercontent.com/u/920670?s=460&v=4",
                                    "#8C56EA",
                                    "https://github.com/soroush"));


  QQmlApplicationEngine engine;
  QQmlContext *ctxt = engine.rootContext();

  qmlRegisterType<ContactList>("api.dotwaves.qml", 1, 0, "Data");

  ctxt->setContextProperty("contactModel", QVariant::fromValue(dataList));
  engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

  if (engine.rootObjects().isEmpty())
    return -1;

  return app.exec();
}

تحت کلاس QList اشیاء را به کلاس ساخته شده سفارشی خود به عنوان داده‌های جدید معرفی می‌کنیم. جهت رجیستر (ثبت) کردن کلاس و داده‌های سمت بک‌اِند به سمت فرانت اِند در QML توسط تابع qmlRegisterType به عنوان یک تابع سربار گذاری شده اقدام می‌کنیم که ساختار آن به صورت زیر است:

qmlRegisterType<MyClass>("com.mycompany.qmlcomponents", 1, 0, "CppClass");

این کار باعث می‌شود شما به کلاس‌ها و توابع کلاس سفارشی خود در سمت فرانت اند دسترسی داشته باشید. این روش در این پروژه اختیاری بوده است و فعلاً آنچنان مهم نیست اما برای اینکه روش آن را بدانید آورده شده است.

در ادامه با نمونه گیری کلاس QQmlContext تابع setContextProperty که به عنوان ریشه‌ای از محتوا مجموعه‌ای از خواص‌های موجود از مُدل کلاس را بر می‌گرداند را تنظیم می‌کند که نام ویژگی را در قالب QVariant برمی‌گرداند.

در نهایت قرار است با استفاده از نوع ListView در سمت QML مقادیر ارسالی از سمت سی‌پلاس‌پلاس را دریافت کنیم. به عنوان مثال دریافت نام به صورت زیر خواهد بود:

ListView {
id:listview
model : contactModel

delegate: Rectangle {

....
.......

Text {
    id: nameTitle
    text: model.modelData.name
  }
}

نمونه خروجی این مثال به صورت زیر است:

Contact-01.png

برای دسترسی به منبع این مثال می‌توانید به گیت‌هاب من در این لینک مراجعه کنید.

نقل قول

دقت کنید که به خاطر آدرس دهی https در تصاویر آواتار نیاز خواهد بود تا فایل‌های libeay32.dll و ssleay32.dll را در کنار فایل اجرایی برنامهٔ خود داشته باشید. در غیر اینصورت تصاویر مرتبط با پروتکل https بارگذاری نخواهند شد.

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

سلام ممنون از مطلب مفیدتون
من نیاز دارم که بتونم یک Qimage رو از داخل cpp به سمت qml بفرستم و نمایش بدم امکانش هست یک مثال خیلی ساده در این مورد درون سایت قرار بدین؟

ویرایش شده در توسط سعید معصومی

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
در هم اکنون، سعید معصومی گفته است :

سلام ممنون از مطلب مفیدتون
من نیاز دارم که بتونم یک Qimage رو از داخل cpp به سمت qml بفرستم و نمایش بدم امکانش هست یک مثال خیلی ساده در این مورد درون سایت قرار بدین؟

چرا از نوع Image در QML استفاده نمی‌کنید؟ در این صورت فقط نیاز دارین آدرس تصاویر رو بهش انتقال بدین.

مثال:

Image {
    source: "pic/avatar.png"
}

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

به گفتگو ملحق شوید

شما همین الآن می‌توانید مطلبی را ارسال و بعداً ثبت‌نام کنید. اگر حساب کاربری دارید، و با حساب کاربری خود مطلب ارسال کنید.
نکته: مطلب شما قبل از انتشار نیاز به بازبینی توسط میانجی‌گر‌ها دارد.

مهمان
ارسال پاسخ به این موضوع ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از ۷۵ اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


  • کاربران آنلاین در این صفحه   0 کاربر

    هیچ کاربر عضوی،در حال مشاهده این صفحه نیست.

×
×
  • جدید...