Reputation:
I'm fairly new to Qt. I started about two months ago with QWidgets applications and things were going smoothly. Now I have a real problem. I need to integrate my c++ logic to my Qml Ui. I will post my source code from my QWidget adreesbook application and my UI written in Qml. What I need to do is to make my application work with an Qml integrated Ui. It works fine with QWidgets but I don't have any idea how to integrate it in Qml. I've been searching the net for 2 days, but I don't seem to grasp the concepts. Given the fact that I'm complete noob regarding Qml, any piece of advice would be greatly appreciated.
Here is my c++/QWidgets version:
Headers: mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
~MainWindow();
};
#endif // MAINWINDOW_H
addressbook.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 files: mainwindow.cpp
#include "mainwindow.h"
#include "addressbook.h"
MainWindow::MainWindow(QMainWindow *parent)
: QMainWindow(parent)
{
AddressBook4 *addressbook4 = new AddressBook4(this);
setCentralWidget(addressbook4);
}
MainWindow::~MainWindow()
{
}
addressbook.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()
{
}
main.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();
}
And now I will post my QtQuick version.
Headers: buttons.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 files: main.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();
}
buttons.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";
}
And my main.qml file
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()
}
}
}
}
}
}
}
Upvotes: 0
Views: 867
Reputation: 1201
In C++ you can define properties which you can use from 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);
};
In QML you can call the slot and read the property
Item {
Button {
onClicked: mySelf.mySlot(mySelf.myProperty);
}
}
Here you can find how to connect a C++ signal to a QML slot:
https://stackoverflow.com/a/8840945/264359
Upvotes: 1