Using proxy models - c++

I've created Proxy model by subclassing QAbstractProxyModel and connected it as a model to my view. I also set up source model for this proxy model. Unfortunately something is wrong because I'm not getting anything displayed on my listView (it works perfectly when I have my model supplied as a model to view but when I supply this proxy model it just doesn't work). Here are some snippets from my code:
#ifndef FILES_PROXY_MODEL_H
#define FILES_PROXY_MODEL_H
#include <QAbstractProxyModel>
#include "File_List_Model.h"
class File_Proxy_Model: public QAbstractProxyModel
{
public:
explicit File_Proxy_Model(File_List_Model* source_model)
{
setSourceModel(source_model);
}
virtual QModelIndex mapFromSource(const QModelIndex & sourceIndex) const
{
return index(sourceIndex.row(),sourceIndex.column());
}
virtual QModelIndex mapToSource(const QModelIndex & proxyIndex) const
{
return index(proxyIndex.row(),proxyIndex.column());
}
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const
{
return sourceModel()->columnCount();
}
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const
{
return sourceModel()->rowCount();
}
virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex & index) const
{
return QModelIndex();
}
};
#endif // FILES_PROXY_MODEL_H
//and this is a dialog class:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model(this)),
proxy_model_(new File_Proxy_Model(model_)),
sel_model_(new QItemSelectionModel(proxy_model_,this))
{
setupUi(this);
setup_mvc_();
}
void Line_Counter::setup_mvc_()
{
listView->setModel(proxy_model_);
listView->setSelectionModel(sel_model_);
}

mapToSource should return an index from the source model:
virtual QModelIndex mapToSource(const QModelIndex & proxyIndex) const
{
return sourceModel()->index(proxyIndex.row(),proxyIndex.column());
}
I tested with that code:
#include <QtGui>
#include "file_proxy_model.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model model(dir.entryList());
File_Proxy_Model proxy(&model);
QListView listView;
listView.setModel(&proxy);
listView.show();
return a.exec();
}
// In "File_List_Model.h"
class File_List_Model : public QStringListModel
{
public:
explicit File_List_Model(const QStringList & list, QObject *parent = 0)
: QStringListModel(list, parent)
{
}
};

Related

How to use QAbstractItemModel for ComboBox

I have implemented QAbstractItemModel as a C++ class and I'm trying to use it as a model for QComboBox. The model is storing QList of QStrings, which are names of project apps INI files. I can print out the list into console, and I'am certainly getting the right list of files. However I'm getting an error Unable to assign [undefined] to QString.
Can you please help me, what am I doing wrong?
LcuModel.cpp
#include "LcuModel.h"
#include "logging/LoggingQtCategories.h"
#include <QCoreApplication>
#include <QSettings>
#include <QFileInfo>
#include <QDir>
LcuModel::LcuModel(QObject *parent)
: QAbstractItemModel(parent)
{
QSettings settings;
QFileInfo fileInfo(settings.fileName());
QDir directory(fileInfo.absolutePath());
iniFiles_ = directory.entryList({"*.ini"},QDir::Files);
if (iniFiles_.empty())
{
qCWarning(lcLcu) << "No ini files were found.";
}
qCInfo(lcLcu) << iniFiles_; //this prints out all the files to console, so the list is certainly not empty
}
QModelIndex LcuModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(parent)
return QModelIndex();
}
QModelIndex LcuModel::parent(const QModelIndex &index) const
{
Q_UNUSED(index)
return QModelIndex();
}
int LcuModel::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent)
return iniFiles_.count();
}
int LcuModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant LcuModel::data(const QModelIndex & index, int role) const
{
Q_UNUSED(role);
int row = index.row();
qCInfo(lcLcu) << QString::number(row) << " ";
if (row < 0 || row >= iniFiles_.count()) {
return QVariant();
}
return QVariant(iniFiles_.at( index.row() ));
}
QHash<int, QByteArray> LcuModel::roleNames() const
{
QHash<int, QByteArray> names;
names[textRole] = "fileName";
return names;
}
LcuModel.h
#ifndef LCUMODEL_H
#define LCUMODEL_H
#include <QAbstractItemModel>
class LcuModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit LcuModel(QObject *parent = nullptr);
enum {
textRole
};
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
protected:
virtual QHash<int, QByteArray> roleNames() const override;
private:
QList<QString> iniFiles_;
};
#endif // LCUMODEL_H
LcuMain.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import project.lcu 1.0
Item {
id: lcuMain
LcuModel{
id:lcuModel
}
Component.onCompleted: {
console.info("Completed "+ comboBox.count + "items")
} //this gives me right number of items from the list
Column{
ComboBox{
id: comboBox
model: lcuModel
delegate: ItemDelegate
{
contentItem: Text {
text: fileName
}
}
onActivated: console.info(comboBox.currentText + comboBox.currentIndex) //it prints out an empty string
}
}
}
console output
18:02:25.543 [ info ] project.lcu: LcuModel::LcuModel - ("first.ini", "second.ini", "third.ini", "fourth.ini", "fifth.ini", "sixth.ini", "seventh.ini", "eight.ini", "nineth.ini")
18:02:25.616 [warning] unknown - ComboBox.qml:47:5: QML Connections: Cannot assign to non-existent property "onCountChanged"
18:02:25.675 [ info ] qml: onCompleted - 9
18:02:25.678 [warning] unknown - qrc:/LcuMain.qml:46:25: Unable to assign [undefined] to QString
It is unnecessary for the model to inherit from QAbstractItemModel, QAbstractListModel is enough so you don't have to implement multiple methods. On the other hand, you must establish the role that you want to show through textRole and in the delegate you must use modelData:
#ifndef LCUMODEL_H
#define LCUMODEL_H
#include <QAbstractListModel>
class LcuModel : public QAbstractListModel
{
Q_OBJECT
public:
enum {
textRole = Qt::UserRole
};
explicit LcuModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QStringList iniFiles_;
};
#endif // LCUMODEL_H
#include "lcumodel.h"
#include <QDir>
#include <QFileInfo>
#include <QSettings>
LcuModel::LcuModel(QObject *parent)
: QAbstractListModel(parent)
{
QSettings settings;
QFileInfo fileInfo(settings.fileName());
QDir directory(fileInfo.absolutePath());
iniFiles_ = directory.entryList({"*.ini"}, QDir::Files);
}
int LcuModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return iniFiles_.length();
}
QVariant LcuModel::data(const QModelIndex &index, int role) const
{
if(!checkIndex(index)){
return QVariant();
}
if(role == textRole){
return iniFiles_.at(index.row());
}
return QVariant();
}
QHash<int, QByteArray> LcuModel::roleNames() const
{
QHash<int, QByteArray> names;
names[textRole] = "fileName";
return names;
}
import QtQuick 2.12
import QtQuick.Controls 2.12
import project.lcu 1.0
Item{
id: lcuMain
LcuModel{
id:lcuModel
}
Column{
ComboBox{
id: comboBox
model: lcuModel
textRole: "fileName"
delegate: ItemDelegate{
text: modelData
width: parent.width
}
}
}
}

QAbstractListModel::Data() method is never called

I am trying to view a list of c++ models in qml by subclassing QAbstractListModel following this tutorial Models and Views: AbstractItemModel Example
Here is my implementation:
Item model class
class User
{
private:
QString m_macAddr;
QString m_firstName;
QString m_lastName;
public:
User();
User(const QString &mac);
QString macAddr() const;
void setMacAddr(QString &mac);
};
User::User()
{}
User::User(const QString &mac){
m_macAddr = mac;
}
QString User::macAddr() const{
return m_macAddr;
}
void User::setMacAddr(QString &mac){
if(mac == m_macAddr)
return;
m_macAddr = mac;
// emit macAddrChanged();
}
QAbstractListModel subclass
class UserListModel : public QAbstractListModel
{
Q_OBJECT
public:
// User model roles
enum roles{
macRole = Qt::UserRole + 1
};
UserListModel(QObject *parent = nullptr);
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QModelIndex getIndex(int r, int c, void *p);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void addUser(const User &user);
private:
QList<User> m_users;
protected:
QHash<int, QByteArray> rolesNames() const;
};
// Class inplementation.
UserListModel::UserListModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void UserListModel::addUser(const User &user){
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_users << user;
endInsertRows();
}
int UserListModel::rowCount(const QModelIndex &parent) const
{
return m_users.count();
}
QVariant UserListModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= rowCount())
return QVariant();
const User &user = m_users[index.row()];
if(role == macRole){
return user.macAddr();
}
return QVariant();
}
QModelIndex UserListModel::index(int row, int column, const QModelIndex &parent) const
{
return parent;
}
QModelIndex UserListModel::parent(const QModelIndex &index) const
{
return index;
}
QModelIndex UserListModel::getIndex(int r, int c, void *p) {
return this->createIndex(r, c, p);
}
QHash<int, QByteArray> UserListModel::rolesNames() const {
QHash<int, QByteArray> roles;
roles[macRole] = "mac";
return roles;
}
main.cpp
QQmlApplicationEngine engine;
QString mac = "12:3e:3w:4r:33";
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
engine.rootContext()->setContextProperty("usersModel", userlistModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QModelIndex id = userlistModel->getIndex(1, 0, 0);
QVariant v1 = userlistModel->data(id, Qt::UserRole + 1);
qDebug() << "===========" << v1.toString();
controller::DatabaseService<SqliteDB> *sqliteDb = new controller::DatabaseService<SqliteDB>();
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
QML
ListView{
id: listView
anchors.fill: parent
model:usersModel
delegate: Component { HorizontalListItem{mac: mac}}
}
The Problem is :
In main function I am adding 4 models to the list model but, They are shown in qml without data. althought, I am trying to view mac role.
what I tried
I tried to add a breakpoint inside methodes rolesNames() and data()
but, It seems that the compiler is not getting inside anyone of them.
I tried to invoke data() method in main function and it returns the desired data.
It is not necessary that you override the index, or parent methods, nor do you create the getIndex method. In your case you need to implement the roleNames method:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QAbstractListModel>
#include <QDebug>
class User
{
QString m_macAddr;
public:
User(){}
User(const QString &mac): m_macAddr(mac){}
QString macAddr() const{return m_macAddr;}
void setMacAddr(QString &mac){m_macAddr = mac;}
};
class UserListModel : public QAbstractListModel
{
public:
enum roles{
macRole = Qt::UserRole + 1
};
explicit UserListModel(QObject *parent = nullptr)
: QAbstractListModel(parent){}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
if (parent.isValid())
return 0;
return m_users.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid())
return QVariant();
if (index.row() < 0 || index.row() >= rowCount())
return QVariant();
const User &user = m_users[index.row()];
if(role == macRole)
return user.macAddr();
return QVariant();
}
QHash<int, QByteArray> roleNames() const override{
QHash<int, QByteArray> roles;
roles[macRole] = "mac";
return roles;
}
void addUser(const User &user){
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_users << user;
endInsertRows();
}
private:
QList<User> m_users;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
UserListModel userlistModel;
QString mac = "12:3e:3w:4r:33";
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
QModelIndex ix = userlistModel.index(1, 0);
QVariant v = userlistModel.data(ix, UserListModel::macRole);
qDebug() << "===========" << v.toString();
engine.rootContext()->setContextProperty("usersModel", &userlistModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListView{
anchors.fill: parent
model:usersModel
delegate: Component
{
Text{
text: model.mac
}
}
}
}

Qt: QListView with QAbstractItemModel and QStyledItemDelegate takes long for adding items

I have a qt-application with QListView, a custom model and a class inherited from QStyledItemDelegate to show custom items. Unfortunately it takes to long (5 seconds) when I add approximately 6000 items. Do you have a hint/solution for my problem?
Below you see my implementation:
The Model:
class AddressItemData : public QObject {
Q_OBJECT
public:
AddressItemData (QObject * parent = 0) : QObject(parent) {}
QString address;
QString name;
bool inserted;
};
class AddressModel : public QAbstractListModel
{
Q_OBJECT
public:
AddressModel (QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const {
return addressItems.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const {
if (!index.isValid())
return QVariant();
if (index.row() >= addressItems.size() || index.row() < 0)
return QVariant();
if (Qt::DisplayRole == role) {
return QVariant::fromValue<AddressItemData*>(addressItems.at(index.row()));
}
return QVariant();
}
void addAddressItem(AddressItemData* addressItem){
beginInsertRows(QModelIndex(), rowCount(), rowCount());
addressItems.append(addressItem);
endInsertRows();
}
void addAddressItems(QList<AddressItemData*> addressItems){
beginInsertRows(QModelIndex(), rowCount(), rowCount() + addressItems.size() - 1);
this->addressItems.append(addressItems);
endInsertRows();
}
void removeAddressItem(AddressItemData* addressItem);
void deleteAllAddressItems(void){
beginRemoveRows(QModelIndex(), rowCount(), rowCount());
for (int i = 0; i < addressItems.size(); ++i) {
delete addressItems.at(i);
}
addressItems.clear();
endRemoveRows();
}
private:
QList<AddressItemData*> addressItems;
};
For the model I created a custom add and delete method, which will be called from the delegate.
The ItemViewDelegate:
class AddressViewDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
AddressViewDelegate (QWidget *parent = 0) : QStyledItemDelegate(parent) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const {
if(!index.isValid())
return;
painter->save();
QStyleOptionViewItemV4 opt = option;
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
QRect addressRect = opt.rect;
AddressItemData* d = index.data().value<AddressItemData*>();
painter->setPen(Qt::black);
painter->drawText(QRect(addressRect.left(), addressRect.top(), addressRect.width(), addressRect.height()/2),
opt.displayAlignment, d->address);
}
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const {
if(!index.isValid())
return QSize();
QSize result = QStyledItemDelegate::sizeHint(option, index);
result.setHeight(result.height()*2);
return result;
}
};
For test purposes, the application displays only the address. I want to show also the other information next to address in one line. Later I also want to add signal/slot-behavior for each row, but that's still a long way off.
The main:
AddressModel* model = new AddressModel;
AddressViewDelegate* viewDelegate = new AddressViewDelegate;
ui->listView->setItemDelegate(viewDelegate);
ui->listView->setModel(model);
ui->listView->setUniformItemSizes(true);
ui->listView->setLayoutMode(QListView::Batched);
QList<AddressItemData *> addressItems;
... for loop to add AddressItemData:
AddressItemData* data = new AddressItemData;
data->address = anotherTable.at(index);
addressItems.append(data);
// ...
model->addAddressItems(addressItems);
In the main, I call addAddressItems but also with the single-call-variant it is slow. I hope my code is clear enough and I can help others as well.
Do you have an idea, why the adding-procedure is so slow?

My simple QTableView code crashes

I wrote a simple code to try and learn about QTableView. When I build my project it doesnt give any errors but when I try to run it says:
C:\Users\Eren\Documents\build-QTableViewUygulama-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\debug\QTableViewUygulama.exe exited with code 255
or
The program has unexpectedly finished.
C:\Users\Eren\Documents\build-QTableViewUygulama-Desktop_Qt_5_8_0_MSVC2015_64bit-Debug\debug\QTableViewUygulama.exe crashed.
I have some knowledge about C++ but I dont know much about Qt. I have no idea why I keep getting this error. Here is my code
//Class Model(aracmodel.cpp)
#include "aracmodel.h"
AracModel::AracModel(QObject* parent = 0) : QAbstractTableModel(parent) {
}
int AracModel::rowCount(const QModelIndex &) const {
return 3;
}
int AracModel::columnCount(const QModelIndex &) const {
return Araclar.size();
}
QVariant AracModel::data(const QModelIndex &index, int role) const {
if(role != Qt::DisplayRole && role != Qt::EditRole) return 0;
const Arac& arac = Araclar[index.row()];
switch(index.column()){
case 0 : return arac.id;
case 1 : return QString::fromStdString(arac.marka);
case 2 : return QString::fromStdString(arac.model);
default : return 0;
}
return QVariant();
}
QVariant AracModel::headerData(int section, Qt::Orientation orientation, int
role){
if(orientation != Qt::Horizontal || role != Qt::DisplayRole) return 0;
switch(section){
case 0 : return "ID";
case 1 : return "Marka";
case 2 : return "Model";
default : return 0;
}
return QVariant();
}
//Class Model (aracmodel.h)
#ifndef ARACMODEL_H
#define ARACMODEL_H
#include <QAbstractTableModel>
#include "arac.h"
class Arac;
class AracModel : public QAbstractTableModel
{
public:
QList<Arac> Araclar;
AracModel(QObject*);
int rowCount(const QModelIndex&) const override;
int columnCount(const QModelIndex&) const override;
QVariant data(const QModelIndex& index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role);
};
#endif // ARACMODEL_H
//Class Header arac.h
#ifndef ARAC_H
#define ARAC_H
#include <string>
class Arac
{
public:
int id;
std::string marka;
std::string model;
Arac(int, std::string, std::string);
};
#endif // ARAC_H
Arac::Arac(int i, std::string ma, std::string mo) : id(i), marka(ma), model(mo){} //This constructor is in arac.cpp
//MainWindow.cpp (only copying the parts i've changed)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableView->setModel(model);
}
//MainWindow.hh(only copying the parts i've changed
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
AracModel* model;
~MainWindow();
private:
Ui::MainWindow *ui;
};
Instantiate model pointer using :
model = new AracModel(this);
before setting this model to tableView.
Have a look at this simple example:
http://www.thedazzlersinc.com/source/2012/06/04/qt-qtableview-example-short-and-quick/

Spanning horizontal header in Qt

I want to merge(span) horizontal headers in QTableWidget. I tried googling for the same, but no luck and hence posting it. Please guide me.
You can subclass QHeaderView and create one section for each of the groups of columns/rows you would like to span and connect signals and slots to have them react to the different columns/rows.
The following example is for spanning the horizontal header:
#include <QtGui>
class MyHeaderModel : public QAbstractItemModel
{
public:
MyHeaderModel(QObject *parent = 0) : QAbstractItemModel(parent) {}
int columnCount(const QModelIndex &parent = QModelIndex()) const { return 2; }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return QVariant(); }
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const { return QModelIndex(); }
QModelIndex parent(const QModelIndex &index) const { return QModelIndex(); }
int rowCount(const QModelIndex &parent = QModelIndex()) const { return 0; }
};
class MyHeader : public QHeaderView
{
Q_OBJECT
public:
MyHeader(QHeaderView *header, QWidget *parent = 0) : QHeaderView(Qt::Horizontal, header), mainHeader(header)
{
setModel(new MyHeaderModel(this));
// This example uses hardcoded groups, you can extend
// this yourself to save the groups
// Group 1 is 0-2 and Group 2 is 3-4
resizeSection(0, getSectionSizes(0, 2));
resizeSection(1, getSectionSizes(3, 4));
connect(this, SIGNAL(sectionResized(int,int,int)), this, SLOT(updateSizes()));
connect(((QTableWidget *)(mainHeader->parentWidget()))->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateOffset()));
setGeometry(0, 0, header->width(), header->height());
updateOffset();
mainHeader->installEventFilter(this);
}
public slots:
void updateSizes()
{
setOffset(mainHeader->offset());
mainHeader->resizeSection(2, mainHeader->sectionSize(2) + (sectionSize(0) - getSectionSizes(0, 2)));
mainHeader->resizeSection(4, mainHeader->sectionSize(4) + (sectionSize(1) - getSectionSizes(3, 4)));
}
void updateOffset()
{
setOffset(mainHeader->offset());
}
protected:
bool eventFilter(QObject *o, QEvent *e)
{
if (o == mainHeader) {
if (e->type() == QEvent::Resize) {
setOffset(mainHeader->offset());
setGeometry(0, 0, mainHeader->width(), mainHeader->height());
}
return false;
}
return QHeaderView::eventFilter(o, e);
}
private:
int getSectionSizes(int first, int second)
{
int size = 0;
for (int a=first;a<=second;++a)
size += mainHeader->sectionSize(a);
return size;
}
QHeaderView *mainHeader;
};
#include "main.moc"
int main(int argc, char **argv)
{
QApplication a(argc, argv);
QWidget w;
QVBoxLayout *vbox = new QVBoxLayout;
QTableWidget *tw = new QTableWidget(5, 5);
MyHeader *h = new MyHeader(tw->horizontalHeader());
vbox->addWidget(tw);
w.setLayout(vbox);
w.show();
return a.exec();
}