Qt. Integrating C++ and Qml

Qt. Integrating C++ and Qml

本文关键字:Qml and C++ Integrating Qt      更新时间:2023-10-16

我对Qt相当陌生。大约两个月前,我开始使用QWidgets应用程序,事情进展顺利。现在我有一个真正的问题。我需要将我的 c++ 逻辑集成到我的 Qml UI 中。我将发布我的QWidget adreesbook应用程序和用Qml编写的UI的源代码。我需要做的是让我的应用程序与 Qml 集成的 UI 一起工作。它与QWidgets一起工作,但我不知道如何将它集成到Qml中。我已经在网上搜索了 2 天,但我似乎没有掌握这些概念。鉴于我对 Qml 完全是菜鸟,任何建议都将不胜感激。

这是我的c ++/QWidgets版本:

头:主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
    {
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H

地址簿.h

#ifndef ADDRESSBOOK_H
#define ADDRESSBOOK_H
#include <QMainWindow>
#include <QWidget>
#include <QTextEdit>
#include <QPushButton>
#include <QObject>
#include <QLineEdit>
#include <QLabel>
#include <QListWidget>
#include <QFrame>
#include <QList>
#include <QGridLayout>
#include <QString>
#include <QStringList>
#include <QKeyEvent>
#include <QCoreApplication>
class AddressBook4 : public QWidget
{
    Q_OBJECT
public:
    explicit AddressBook4(QWidget *parent = 0);
    ~AddressBook4();
    struct Details
    {
        QString name;
        QString street;
        QString number;
        QString notes;
    };
signals:
public slots:
private slots:
    void add(bool);
    void onListWidgetItemClicked(const QModelIndex &index);
    void importSql (bool);
    void exportSql (bool);
private:
    QTextEdit *m_pNotesTextEdit;
    QTextEdit *m_pDetailsTextEdit;
    QLineEdit *m_pNameLineEdit;
    QLineEdit *m_pStreetLineEdit;
    QLineEdit *m_pNumberLineEdit;
    QListWidget *m_pListWidget;
    QPushButton *m_pAddbutton;
    QPushButton *m_pImportbutton;
    QPushButton *m_pExportbutton;
    QFrame *m_pFrame;
    QLabel *m_pAddAdress;
    QLabel *m_pName;
    QLabel *m_pStreet;
    QLabel *m_pNumber;
    QLabel *m_pDetails;
    QLabel *m_pNotes;
    QLabel *m_pAddresses;
    QGridLayout *m_pGrid;
    QString *line;
    QListWidgetItem *item;
    QList<Details> m_detailsList;
};
#endif // ADDRESSBOOK_H

CPP 文件:主窗口.cpp

#include "mainwindow.h"
#include "addressbook.h"
MainWindow::MainWindow(QMainWindow *parent)
    : QMainWindow(parent)
{
    AddressBook4 *addressbook4 = new AddressBook4(this);
    setCentralWidget(addressbook4);
}
MainWindow::~MainWindow()
{
}

地址簿.cpp

#include "addressbook.h"
#include "mainwindow.h"
#include <QMainWindow>
#include <QWidget>
#include <QMessageBox>
#include <QTextEdit>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QGridLayout>
#include <QFrame>
#include <QPushButton>
#include <QTextStream>
#include <QtCore>
#include <QString>
#include <QTextStream>
#include <QFile>
#include <QStringList>
#include <QtSql>
#include <QCoreApplication>
#include <QApplication>
#define FISIER_ADRESE "C:\Users\max\Documents\workspace\AddressBook5\Addresses.db"
AddressBook4::AddressBook4(QWidget *parent)
    : QWidget(parent)
{
    m_pGrid = new QGridLayout(this);
    m_pFrame = new QFrame(this);
    m_pGrid->addWidget(m_pFrame,1,0,8,4);
    m_pFrame->setFrameShape(QFrame::StyledPanel);
    m_pAddAdress = new QLabel("Add address", this);
    m_pGrid->addWidget(m_pAddAdress,1,2);
    m_pAddAdress->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    m_pName = new QLabel("Name:", this);
    m_pGrid->addWidget(m_pName,2,1);
    m_pName->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_pNameLineEdit = new QLineEdit(this);
    m_pGrid->addWidget(m_pNameLineEdit,2,2);
    m_pStreet = new QLabel("Street:", this);
    m_pGrid->addWidget(m_pStreet,3,1);
    m_pStreet->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_pStreetLineEdit = new QLineEdit(this);
    m_pGrid->addWidget(m_pStreetLineEdit,3,2);
    m_pNumber = new QLabel("Number:", this);
    m_pGrid->addWidget(m_pNumber,4,1);
    m_pNumber->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_pNumberLineEdit = new QLineEdit(this);
    m_pGrid->addWidget(m_pNumberLineEdit,4,2);
    m_pNumberLineEdit->setFixedWidth(50);
    m_pNotes = new QLabel("Notes:", this);
    m_pGrid->addWidget(m_pNotes,6,1);
    m_pNotes->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    m_pNotesTextEdit = new QTextEdit(this);
    m_pGrid->addWidget(m_pNotesTextEdit,6,2);
    m_pAddbutton= new QPushButton ("Add",this);
    m_pGrid->addWidget(m_pAddbutton, 7,2,Qt::AlignBaseline);
    m_pImportbutton= new QPushButton ("ImportSql",this);
    m_pGrid->addWidget(m_pImportbutton, 7,4,Qt::AlignBaseline | Qt::AlignLeft);
    m_pImportbutton->setFixedWidth(80);
    m_pImportbutton->setShortcut(QKeySequence(Qt::Key_Insert));
    m_pExportbutton= new QPushButton ("ExportSql",this);
    m_pGrid->addWidget(m_pExportbutton, 7,4,Qt::AlignBaseline | Qt::AlignRight);
    m_pExportbutton->setFixedWidth(80);
    m_pAddresses = new QLabel("Addresses", this);
    m_pGrid->addWidget(m_pAddresses,1,4);
    m_pAddresses->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    m_pListWidget = new QListWidget(this);
    m_pGrid->addWidget(m_pListWidget,2,4,3,1);
    m_pDetails = new QLabel("Details", this);
    m_pGrid->addWidget(m_pDetails,5,4);
    m_pDetails->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    m_pDetailsTextEdit = new QTextEdit(this);
    m_pGrid->addWidget(m_pDetailsTextEdit,6,4);
    m_pDetailsTextEdit->setReadOnly(true);
    setLayout(m_pGrid);
    connect(m_pAddbutton, SIGNAL(clicked(bool)),
            this, SLOT(add(bool)));
    connect(m_pListWidget, SIGNAL(clicked(QModelIndex)),
            this, SLOT(onListWidgetItemClicked(const QModelIndex)));
    connect(m_pImportbutton, SIGNAL(clicked(bool)),
            this, SLOT(importSql(bool)));
    connect(m_pExportbutton, SIGNAL(clicked(bool)),
            this, SLOT(exportSql(bool)));
}
//Reads the user imput data from m_pNameLineEdit, m_pStreetLineEdit, m_pNumberLineEdit,
//m_pNotesiTextEdit and creates a new QListWidget item every time when clicked.
void AddressBook4::add(bool)
{
    if ((m_pNameLineEdit->text().isEmpty()) || (m_pStreetLineEdit->text().isEmpty())
       || (m_pNumberLineEdit->text().isEmpty()) || (m_pNotesTextEdit->toPlainText().isEmpty()))
    {
         QMessageBox::warning(this, "Warning", "You need to complete all the fields");
    } else {
         int index = m_pListWidget->count();
         m_pListWidget->addItem("address " + QString::number(index));
         Details detail;
         detail.name = m_pNameLineEdit->text();
         detail.street = m_pStreetLineEdit->text();
         detail.number = m_pNumberLineEdit->text();
         detail.notes = m_pNotesTextEdit->toPlainText();
         m_detailsList.append(detail);
    }
}
//Prints the data from every QListWidgetItem in the m_pDetailsTextEdit when clicked
void AddressBook4::onListWidgetItemClicked(const QModelIndex &index)
{
    m_pDetailsTextEdit->clear();
    m_pDetailsTextEdit->append("Name: " + m_detailsList.at(index.row()).name);
    m_pDetailsTextEdit->append("Street: " + m_detailsList.at(index.row()).street);
    m_pDetailsTextEdit->append("Nr.: " + m_detailsList.at(index.row()).number);
    m_pDetailsTextEdit->append("Notes: " + m_detailsList.at(index.row()).notes);
}
//Imports data from the Sql database and attributes it to QListWidget items
void AddressBook4::importSql(bool)
{
    QSqlDatabase my_db = QSqlDatabase::addDatabase("QSQLITE");
    my_db.setDatabaseName(FISIER_ADRESE);
    my_db.open();
    qDebug() << "Connected to database..." ;
    QSqlQuery my_qry("SELECT * FROM Addresses");
    int idx_Name = my_qry.record().indexOf("Name");
    int idx_Street = my_qry.record().indexOf("Street");
    int idx_Number = my_qry.record().indexOf("Number");
    int idx_Notes = my_qry.record().indexOf("Notes");
    while (my_qry.next()) {
        Details detail;
        detail.name = my_qry.value(idx_Name).toString();
        //qDebug() << detail.name;
        detail.street = my_qry.value(idx_Street).toString();
        //qDebug() << detail.street;
        detail.number = my_qry.value(idx_Number).toString();
        //qDebug() << detail.number;
        detail.notes = my_qry.value(idx_Notes).toString();
        //qDebug() << detail.notes <<"n";
        m_detailsList.append(detail);
        int index = m_pListWidget->count();
        m_pListWidget->addItem("address " + QString::number(index));
    }
}
//Reads through every QlistWidget item and inserts the containing data into the Sql database
void AddressBook4::exportSql(bool)
{
    QSqlDatabase my_db = QSqlDatabase::addDatabase("QSQLITE");
    my_db.setDatabaseName(FISIER_ADRESE);
    if (!my_db.open()) {
        QMessageBox::warning(this, "Warning", "Cannot connect to the database");
    } else {
        qDebug() << "Connected to database...";
        QSqlQuery my_qry;
        my_qry.prepare( "CREATE TABLE IF NOT EXISTS Addresses (Name QSTRING, "
                        "Street QSTRING, Number QSTRING, Notes QSTRING)" );
          if( !my_qry.exec() )
            qDebug() << my_qry.lastError();
          else
            qDebug() << "Table created!";
          for (int row = 0; row < m_pListWidget->count(); ++row) {
              item = m_pListWidget->item(row);
              Details detail = m_detailsList.at(row);
          my_qry.prepare( "INSERT INTO Addresses ( Name, Street, Number, Notes) "
                          "VALUES (:Name, :Street, :Number, :Notes)");
          my_qry.bindValue(":Name", detail.name);
          my_qry.bindValue(":Street", detail.street);
          my_qry.bindValue(":Number", detail.number);
          my_qry.bindValue(":Notes", detail.notes);
            if( !my_qry.exec() )
              qDebug() << my_qry.lastError();
            else
              qDebug() << "Inserted!";
        }
    }
}
AddressBook4::~AddressBook4()
{
}

主.cpp

#include <QApplication>
#include "addressbook.h"
#include "mainwindow.h"
#include <QMainWindow>
#include <QWidget>
#include <QTextStream>
#include <QString>
#include <QTextStream>
#include <QFile>
#include <QStringList>
#include <QtCore>
#define STYLE_SHEET "C:\Users\max\Documents\workspace\AddressBook4\stylesheet.css"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.setWindowTitle("AddressBook4");
    w.show();
    //QFile file (STYLE_SHEET);
    //if (file.open(QFile::ReadOnly | QFile::Text)) {
       // QTextStream in(&file);
        //QString styleStr = in.readAll();
        //qDebug() << styleStr;
        //file.close();
        //a.setStyleSheet(styleStr);
    //}
    return a.exec();
}

现在我将发布我的QtQuick版本。

头:按钮.h

#ifndef BUTTONS_H
#define BUTTONS_H
#include <QObject>
#include <QDebug>
class Buttons : public QObject
{
    Q_OBJECT
public:
    explicit Buttons(QObject *parent = 0);
public slots:
    void addClicked(const QStringList &in);
    void exportClicked();
    void importClicked();
};
#endif // BUTTONS_H

CPP 文件:主.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include "buttons.h"
#include <QQmlContext>
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    Buttons buttons;
    engine.rootContext()->setContextProperty("buttons", &buttons);
    return app.exec();
}

按钮.cpp

#include "buttons.h"
#include <QApplication>
#include <QObject>
#include <QString>
#include <QDebug>
Buttons::Buttons(QObject *parent) :
    QObject(parent)
{
}
void Buttons::addClicked(const QStringList &in)
{
    qDebug() << in;
}
void Buttons::exportClicked()
{
    qDebug() << "Works";
}
void Buttons::importClicked()
{
    qDebug() << "Works";
}

和我的主.qml文件

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.3
ApplicationWindow {
    visible: true
    title: "AddressBookQml"
    property int margin: 11

    GridLayout {
        id: mainLayout
        anchors.fill: parent
        anchors.margins: margin

        GroupBox {
            id: gridBox
            title: "Add address"
            Layout.fillWidth: true
            Layout.fillHeight: true
            GridLayout {
                id: gridLayout
                rows: 5
                columns: 2
                flow: GridLayout.TopToBottom
                anchors.fill: parent
                Label { text: "Name" }
                Label { text: "Street" }
                Label { text: "Number" }
                Label { text: "Notes"}
                Button {
                    text: "Add "
                    onClicked: buttons.addClicked("Name:" + textfield_1.text + "Street:" +
                                                      textfield_2.text + "Number:" +
                                                      textfield_3.text + "Notes:" + textArea_1.text)
                }
                TextField {
                    id: textfield_1
                    Layout.fillWidth: true
                }
                TextField {
                    id: textfield_2
                    Layout.fillWidth: true
                }
                TextField {
                    id: textfield_3
                }
                TextArea {
                    id: textArea_1
                    Layout.rowSpan: 1
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                }
            }
        }
        GroupBox {
            id: gridBox2
            Layout.fillWidth: true
            Layout.fillHeight: true
            GridLayout {
                id: gridLayout2
                rows: 5
                flow: GridLayout.TopToBottom
                anchors.fill: parent
                GridLayout {
                    id: gridLayout4
                    rows: 2
                    flow: GridLayout.TopToBottom
                    anchors.fill: parent
                    Label { text: "Addresses" }
                    ListModel {
                        id: model
                        ListElement {
                            name: 'Address 1'
                        }
                        ListElement {
                            name: 'Address 2'
                        }
                    }
                    ScrollView {
                        ListView {
                            id: list
                            anchors.fill: parent
                            model: model

                            Layout.rowSpan: 1
                            Layout.fillHeight: true
                            Layout.fillWidth: true
                            delegate: Component {
                                Item {
                                    width: parent.width
                                    height: 15
                                    Column {
                                        Text { text: name }
                                        //Text { text: 'Number:' + number }
                                    }
                                    MouseArea {
                                        anchors.fill: parent
                                        onClicked: list.currentIndex = index
                                    }
                                }
                            }
                            highlight: Rectangle {
                                color: "white"
                                Text {
                                    anchors.centerIn: parent
                                }
                            }
                            focus: true
                            onCurrentItemChanged: console.log(model.get(list.currentIndex).name + ' selected')
                        }
                    }
                }
                Label { text: "Detalii" }
                TextArea {
                    Layout.rowSpan: 2
                    Layout.fillHeight: true
                    Layout.fillWidth: true
                    readOnly: true
                }
                GroupBox {
                    id: gridBox3
                    Layout.fillWidth:  true
                    GridLayout {
                        id: gridLayout3
                        rows: 1
                        flow: GridLayout.LeftToRight
                        Button {
                            text: "ExportSql "
                            onClicked: buttons.exportClicked()
                        }
                        Button {
                            text: "ImportSql "
                            onClicked: buttons.importClicked()
                        }
                    }
                }
            }
        }
    }
}

在C++中,您可以定义可以从 QML 使用的属性

class MyQuickView : public QQuickView {
  MyQuickView (){
    rootContext()->setContextProperty('mySelf',     this);
    rootContext()->setContextProperty('myProperty', 5);
    setSource(QUrl.fromLocalFile(myQmlFile.qml));
    mySignal.connect
  }
  public slots:
    void mySlot(int i);
};

在 QML 中,您可以调用插槽并读取属性

Item {
  Button {
    onClicked: mySelf.mySlot(mySelf.myProperty);
  }
}

在这里,您可以找到如何将C++信号连接到 QML 插槽:

https://stackoverflow.com/a/8840945/264359