I'm seeing a strange segmentation fault when accessing a QString type struct member from GET_STATION_MODEL_PARAMS_t. The execution is stopped at **:
code:
#include <QDebug>
#include "hradcontroller.h"
#include "hradAPI.h"
#define TAG "HRAD_CONTROLLER:\0"
#define HRAD_API_VERSION "2"
#define MANUFACTURER_KEY "abcde12345"
typedef struct registerDeviceParams{
QString brand;
QString device;
QString manufacturer;
QString model;
QString serial;
QString ibd;
QString ibkey;
QString version;
QString track;
registerDeviceCB_t cbFn;
}REGISTER_DEVICE_PARAMS_t;
typedef struct getStationModelParams{
int stationID;
QString ibd;
QString ibkey;
QString version;
QString track;
getStationModelCB_t cbFn;
GET_STATION_MODEL_RESPONSE_t* resp;
}GET_STATION_MODEL_PARAMS_t;
HRAD *hbr = new HRAD();
void registerDevice(){
REGISTER_DEVICE_PARAMS_t params;
params.brand = "brand";
params.device = "TI-J6";
params.manufacturer = "manuf";
params.model = "EVK";
params.ibkey = MANUFACTURER_KEY;
params.serial = "abcde12345";
params.version = HRAD_API_VERSION;
params.track = "true";
params.cbFn = deviceRegisteredCB;
hbr->registerDevice(¶ms);
}
void getStationModel(int id){
GET_STATION_MODEL_PARAMS_t params;
params.stationID = id;
params.ibd = hbr->getId();
params.ibkey = "abdef";
params.version = "2";
** params.track = "false"; //SIGSEGV segmantation fault here
params.cbFn = stationModelAvailableCB;
params.resp = &g_StationModel;
}
void deviceRegisteredCB(QString ibd){
qDebug() << TAG << "Device Registered: ibd = " << ibd;
getStationModel(currentPublicStationID);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* Register ourselves to HRAD Server */
registerDevice();
}
Values just before the seg. fault:
If you notice "track" is "not accessible" while debugging and this causes crash.
I modified GET_STATION_MODEL_PARAMS_t like this:
typedef struct getStationModelParams{
int stationID;
QString foo; //dummy variable.
QString ibd;
QString ibkey;
QString version; //seg. fault here now
QString track;
getStationModelCB_t cbFn;
GET_STATION_MODEL_RESPONSE_t* resp;
}GET_STATION_MODEL_PARAMS_t;
And values became like this:
Now "version" is also "not accessible".
Any idea why is this happening?
Thanks.
Update 1:
Tools:
Qt Creator 3.4.1 (ubuntu 14.04)
Qt 5.4.2 (GCC 4.6.1, 64 bit)
TL;DR: This is why you really need to post all the code needed to reproduce the crash.
Your code works - no crashes. Your question is thus answered, even if the answer is completely useless to you, and everyone else too. Don't ask questions that can only be answered in a way that can't help you.
The only thing that stands out in your code, besides it being a horrible C abomination with no place in modern C++, is that the HRAD instance is created before main starts executing. Depending on what HRAD's constructor is doing, this might be a bad thing.
But let's see if we can fix your code up some, to guide you to write safer code.
Old Code
First, let's start with your code verbatim, with some additions at the beginning and end to get it to compile and execute.
You should have provided all that in your question - with enough of "other stuff" to crash. The below, assuming that it crashed or otherwise reproduced your problem, would be considered an sscce and make your question valuable to the community.
#include <QString>
#include <QDebug>
typedef void (*registerDeviceCB_t)(QString);
typedef void (*getStationModelCB_t)();
typedef struct getStationModelResponse {} GET_STATION_MODEL_RESPONSE_t;
void deviceRegisteredCB(QString);
void stationModelAvailableCB() {}
typedef struct registerDeviceParams REGISTER_DEVICE_PARAMS_t;
struct HRAD {
void registerDevice(REGISTER_DEVICE_PARAMS_t*);
QString getId() { return QString(); }
};
GET_STATION_MODEL_RESPONSE_t g_StationModel;
int currentPublicStationID = 1;
void registerDevice();
void getStationModel(int);
int main()
{
registerDevice();
getStationModel(0);
return 0;
}
// Your code verbatim beyond this point
Your code, copy-pasted for reference (with apparently irrelevant MainWindow removed):
#define TAG "HRAD_CONTROLLER:\0"
#define HRAD_API_VERSION "2"
#define MANUFACTURER_KEY "abcde12345"
typedef struct registerDeviceParams{
QString brand;
QString device;
QString manufacturer;
QString model;
QString serial;
QString ibd;
QString ibkey;
QString version;
QString track;
registerDeviceCB_t cbFn;
}REGISTER_DEVICE_PARAMS_t;
typedef struct getStationModelParams{
int stationID;
QString ibd;
QString ibkey;
QString version;
QString track;
getStationModelCB_t cbFn;
GET_STATION_MODEL_RESPONSE_t* resp;
}GET_STATION_MODEL_PARAMS_t;
HRAD *hbr = new HRAD();
void registerDevice(){
REGISTER_DEVICE_PARAMS_t params;
params.brand = "brand";
params.device = "TI-J6";
params.manufacturer = "manuf";
params.model = "EVK";
params.ibkey = MANUFACTURER_KEY;
params.serial = "abcde12345";
params.version = HRAD_API_VERSION;
params.track = "true";
params.cbFn = deviceRegisteredCB;
hbr->registerDevice(¶ms);
}
void getStationModel(int id){
GET_STATION_MODEL_PARAMS_t params;
params.stationID = id;
params.ibd = hbr->getId();
params.ibkey = "abdef";
params.version = "2";
params.track = "false"; //SIGSEGV segmantation fault here
params.cbFn = stationModelAvailableCB;
params.resp = &g_StationModel;
}
void deviceRegisteredCB(QString ibd){
qDebug() << TAG << "Device Registered: ibd = " << ibd;
getStationModel(currentPublicStationID);
}
// End of verbatim code
And, finally, the implementation of registerDevice:
void HRAD::registerDevice(REGISTER_DEVICE_PARAMS_t* params) {
params->cbFn("some ibd");
}
These three pieces, when put into a main.cpp, will compile, run, and properly invoke the callback. To wit:
Starting bad-c-aargh-31542746...
HRAD_CONTROLLER: Device Registered: ibd = "some ibd"
bad-c-aargh-31542746 exited with code 0
Rework
It seems that you're using callbacks and passing values via pointers, as you would in C. We'll get rid of the C typedefs that are unnecessary in C++, and we will leverage C++11's features to make the callbacks much more usable.
As above, the code below is merely interspersed with the commentary. You could copy-paste it to a main.cpp, remove the commentary, compile it and run. It is complete.
First, let's include the functional header to bring in std::function, and we shall get rid of C-style macros:
#include <QString>
#include <QDebug>
#include <functional>
const QString TAG = QStringLiteral("HRAD_CONTROLLER:");
const QString HRAD_API_VERSION = QStringLiteral("2");
const QString MANUFACTURER_KEY = QStringLiteral("abcde12345");
Then we shall define the structures used to pass parameters to HRAD methods, and to obtain the responses from these methods:
struct RegisterDeviceParams {
QString brand;
QString device;
QString manufacturer;
QString model;
QString serial;
QString ibd;
QString ibkey;
QString version;
QString track;
};
struct GetStationModelParams {
int stationID;
QString ibd;
QString ibkey;
QString version;
QString track;
};
struct GetStationModelReponse {};
We can then implement a skeleton HRAD class. The parameters are passed as const references. The optional callbacks can be compatible lambdas, functor instances, function pointers, etc. The provision of default-constructed values makes them optional. You can leave them out from a call, the compiler will use the defaults instead. The currentPublicStationID, presumably a global variable, belongs in HRAD, too.
class HRAD {
public:
void registerDevice(const RegisterDeviceParams &,
const std::function<void(const QString & ibd)> & cb
= std::function<void(const QString&)>()) {
cb("some ibd");
}
void getStationModel(const GetStationModelParams &,
const std::function<void(const GetStationModelReponse &)> & cb
= std::function<void(const GetStationModelReponse&)>()) {
GetStationModelReponse response;
cb(response);
}
QString getId() { return "some id"; }
int currentPublicStationID;
HRAD() : currentPublicStationID(1) {}
};
The global instance of HRAD is defined using the Q_GLOBAL_STATIC macro. It will be instantiated, thread-safely, upon first use. It acts as a pointer - to get the global instance, you should use the -> operator.
Q_GLOBAL_STATIC(HRAD, hbr) // no semicolon needed
The getStationModel and registerDevice functions will use lambda syntax to instantiate the callbacks on the spot. Of course if the callbacks were more complex, you could put them in stand-alone functions or methods.
void getStationModel(int id){
GetStationModelParams params;
params.stationID = id;
params.ibd = hbr->getId();
params.ibkey = "abdef";
params.version = "2";
params.track = "false";
hbr->getStationModel(params, [](const GetStationModelReponse&){
qDebug() << "got station model";
});
}
void registerDevice(){
RegisterDeviceParams params;
params.brand = "brand";
params.device = "TI-J6";
params.manufacturer = "manuf";
params.model = "EVK";
params.ibkey = MANUFACTURER_KEY;
params.serial = "abcde12345";
params.version = HRAD_API_VERSION;
params.track = "true";
hbr->registerDevice(params, [](const QString & ibd){
qDebug() << TAG << "Device Registered: ibd = " << ibd;
getStationModel(hbr->currentPublicStationID);
});
}
Finally, we call registerDevice from main:
int main()
{
registerDevice();
return 0;
}
This code works, and produces the following output:
Starting bad-c-aargh-31542746...
"HRAD_CONTROLLER:" Device Registered: ibd = "some ibd"
got station model
bad-c-aargh-31542746 exited with code 0
Note the absence of any manual memory management. Raw pointers aren't used either - neither as parameters, nor as members.
Related
I have a GUI composed of:
N.1 GraphicsView
N.1 QTableView
N.1 dialog that opens up as needed by the user after doubleclicking on each row of the QTableView
I can capture features on the QGraphicsView with the mouse click. After the feature is drawn I right click and open up a dialog like the one in the figure:
After hitting accept: I register the feature as the row index of the QTableView as shown below:
If I doubleclick on each row I am able to open again the same dialog with the information previously saved. I do that because I may need to change the name of the image and call it differently.
The problem I currently have is that I ma receiving a weird Parameter count mismatch from the compiler and I don't understand why and it should be due to QSQLITE
Below is what I am trying to do along with the most important part of the code:
parameters.h
typedef struct Param
{
int mId;
QString mName;
QByteArray mSave;
} Param;
class Parameters
{
public:
Parameters() = default;
Parameters(Param newdata);
Parameters(int id, const QString &name, const QByteArray &save);
int id() const { return data.mId; }
QString name() const {return data.mName; }
QByteArray save() const {return data.mSave; }
Param getData() const { return data; }
void setData(Param ndat) { data = ndat; }
private:
Param data;
};
parameters.cpp
#include "parameters.h"
Parameters::Parameters(Param newdata) {
data = newdata;
}
Parameters::Parameters(int id, const QString &name,
const QByteArray &save) {
data.mId = id;
data.mSave = save;
data.mName = name;
}
the database is set in the following dataleftcamera.h part:
public:
explicit dataLeftCamera(QObject *parent = nullptr);
bool addItem(Parameters* mParameters);
bool updateItem(int itemId, Parameters* mParameters);
QSqlDatabase getDatabase();
private:
QString mError;
QSqlDatabase mDatabaseLeft;
The table is initiated here on dataleftcamera.cpp and here is where the compiler is giving the Parameter count mismatch error specifically on the function updateItem
#define CREATE_TABLE \
" CREATE TABLE IF NOT EXISTS leftCamTable" \
" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL" \
", name TEXT NOT NULL" \
", save BLOB NOT NULL)"
dataLeftCamera::dataLeftCamera(QObject *parent) : QObject (parent)
{}
bool dataLeftCamera::addItem(Parameters *mParameters)
{
QSqlQuery qry;
qry.prepare("INSERT INTO leftCamTable (name, save)"\
" VALUES (?,?)");
qry.addBindValue(mParameters->name());
qry.addBindValue(mParameters->save());
bool ok = qry.exec();
if(!ok) {
mError = qry.lastError().text();
qDebug() << mError;
}
}
bool dataLeftCamera::updateItem(int itemId, Parameters *mParameters)
{
QSqlQuery qry;
qry.prepare(" UPDATE lefCamTable SET " \
" name = ?," \
" save = ?" \
" WHERE id = ?");
qry.addBindValue(mParameters->name());
qry.addBindValue(mParameters->save());
qry.addBindValue(itemId);
bool ok = qry.exec();
if(!ok) {
mError = qry.lastError().text();
qDebug() << mError;
}
}
On the mainwindow.cpp is the part where I update the item after I doubleclick on the row to change the name of the image and accept again the modification:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mDatabaseLeftCamera = new dataLeftCamera(this);
mModelLeftCamera = nullptr;
mModelLeftCamera = new QSqlTableModel(this);
ui->tableView->setModel(mModelLeftCamera);
connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)),
this, SLOT(onTableClick(QModelIndex)));
// temporary folder
temporaryFolder = "/home/name/Desktop/tempDBFolder/tmp.db";
QFile dbRem(temporaryFolder);
dbRem.remove();
mDatabaseLeftCamera->inizializationDatabaseLeftCamera(temporaryFolder);
mDatabaseLeftCamera->configurationDatabaseLeftCamera();
mModelLeftCamera = new QSqlTableModel(this, mDatabaseLeftCamera->getDatabase());
mModelLeftCamera->setTable("leftCamTable");
mModelLeftCamera->select();
ui->tableView->setModel(mModelLeftCamera);
ui->tableView->showColumn(true);
}
// opening the dialog for the first time after capturing the image
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
// operations
Param result = d.getData();
Parameters* param = new Parameters(result);
mDatabaseLeftCamera->addItem(param);
mModelLeftCamera->select();
ui->tableView->show();
}
// This is the doubleclick that re-opens the small dialog to change the name of the feature
void MainWindow::onTableClick(const QModelIndex &index)
{
int row = index.row();
Param currentData;
int ItemId = index.sibling(row, 0).data().toInt();
currentData.mName = index.sibling(row, 1).data().toString();
currentData.mSave = index.sibling(row, 2).data().toByteArray();
QPixmap iconPix;
if(!iconPix.loadFromData(index.sibling(row, 2).data().toByteArray())) {
}
clipSceneDialog d(this);
d.show();
d.setData(currentData);
d.setImage(iconPix.toImage());
if(d.exec() == QDialog::Rejected) {
return;
} else {
//
}
Param result = d.getData();
Parameters* param = new Parameters(result);
mDatabaseLeftCamera->updateItem(ItemId,param);
mModelLeftCamera->select();
ui->tableView->show();
}
For completeness see the error the compiler is giving if that helps:
I am sorry if this is trivial but I checked the updateItem(ItemId,param)
and thanks for shedding light on this.
Try and add some debug printing. Especially for the parameters that you add to the prepared statement. qry.addBindValue converts your value to a QVariant. Based on the documentation QVariants become NULL when they contain no data:
QVariant x(QString());
// x.isNull() == true
In case there is a problem retrieving your parameters, this could explain the violation of the NOT NULL constraints.
I'm creating a QList<> in C++ using a QML ListView to display it. The application runs without errors but the ListView stubbornly remains empty.
The QML will show a rectangle for the presence of each list item.
I checked the UI code by creating a list in QML.
It displays correctly for the QML created list.
Here's my QML:
import Processes 1.0
...
ListView {
id: qInterfaceList
height: parent.height;
width: parent.width;
model: myModel
orientation: ListView.Vertical
delegate:
Rectangle {
height: 30;
width: 120;
border.color: "red"
border.width: 3
}
The C++ code that creates and registers the list object:
// Register C++ classes as a QML type named Processes (version 1.0)
qmlRegisterType<Process>("Processes", 1, 0, "Process");
QQmlApplicationEngine engine;
// read the configuration file
Config conf;
if ( conf.read() )
{
QQmlContext* ctxt = engine.rootContext();
if ( ctxt )
{
qDebug()
<< "--- conf.Interfaces: "
<< conf.Interfaces.length()
;
ConfigInterface c;
QVariant v = QVariant::fromValue( conf.Interfaces );
qDebug()
<< "--- ConfigInterface: "
<< v
<< "--- typeName: "
<< v.typeName()
;
ctxt->setContextProperty("myModel", QVariant::fromValue( conf.Interfaces ));
}
}
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
To debug I output information about list from C++ and QML:
In C++ the count of list items is correct.
In C++ the conversion to QVariant is working.
In QML it sees the defined list.
The debugging output:
Debugging starts
--- conf.Interfaces: 65
--- ConfigInterface: QVariant(QList<ConfigInterface*>, ) --- typeName: QList<ConfigInterface*>
qml: myModel: QVariant(QList<ConfigInterface*>)
Debugging has finished
Any ideas what's wrong or how to debug this?
Thanks
EDIT: Here's the class being used as a list item
Class declaration:
class ConfigInterface : public QObject
{
Q_OBJECT
Q_PROPERTY(QString sql READ getTag WRITE setTag NOTIFY tagChanged)
Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged)
public:
/*explicit*/ ConfigInterface();
/*explicit*/ ConfigInterface(QObject *parent);
~ConfigInterface();
// Copy constructor needed because these are copied when added to a QList
ConfigInterface(const ConfigInterface &p2) {_tag = p2._tag; _description = p2._description; }
QString getDescription() const;
void setDescription(QString&);
QString getTag() const;
void setTag(QString&);
signals:
void tagChanged(QString);
void descriptionChanged(QString);
public:
QString _tag;
QString _description;
QString QueryTemplate;
QString ConnectString;
QString MinimumId;
};
Q_DECLARE_METATYPE(ConfigInterface*)
C++ code:
ConfigInterface::ConfigInterface()
: QObject( nullptr )
{
}
ConfigInterface::ConfigInterface(QObject* parent)
: QObject(parent)
{
}
ConfigInterface::~ConfigInterface()
{
}
QString ConfigInterface::getTag() const
{
return _tag;
}
void ConfigInterface::setTag(QString& str)
{
_tag = str;
emit tagChanged(_tag);
}
The main problem is caused because it has a list of ConfigInterface *, according to the examples provided in the documentation should be a list of QObject *:
class Config{
[...]
public:
QList<QObject *> Interfaces;
[...]
};
In addition to this you should get the following warning:
/..../configinterface.h:17: warning: base class ‘class QObject’ should be explicitly initialized in the copy constructor [-Wextra]
ConfigInterface(const ConfigInterface &p2) {_tag = p2._tag; _description = p2._description; }
^~~~~~~~~~~~~~~
This is caused because QObject and its derived classes must not have a copy constructor or assignment operator, For more information read the following:
http://doc.qt.io/qt-5/qobject.html#no-copy-constructor-or-assignment-operator
Another improvement is that both constructors can be united in only one, in the end their class could have the following structure:
configinterface.h
#ifndef CONFIGINTERFACE_H
#define CONFIGINTERFACE_H
#include <QObject>
class ConfigInterface : public QObject
{
Q_OBJECT
Q_PROPERTY(QString sql READ getTag WRITE setTag NOTIFY tagChanged)
Q_PROPERTY(QString description READ getDescription WRITE setDescription NOTIFY descriptionChanged)
public:
ConfigInterface(QObject *parent=Q_NULLPTR);
~ConfigInterface();
QString getTag() const;
void setTag(const QString &tag);
QString getDescription() const;
void setDescription(const QString &description);
signals:
void tagChanged(QString);
void descriptionChanged(QString);
private:
QString _tag;
QString _description;
QString QueryTemplate;
QString ConnectString;
QString MinimumId;
};
#endif // CONFIGINTERFACE_H
configinterface.cpp
#include "configinterface.h"
ConfigInterface::ConfigInterface(QObject* parent)
: QObject(parent)
{
}
ConfigInterface::~ConfigInterface()
{
}
QString ConfigInterface::getDescription() const
{
return _description;
}
void ConfigInterface::setDescription(const QString &description)
{
if(_description == description)
return;
emit descriptionChanged(description);
_description = description;
}
QString ConfigInterface::getTag() const
{
return _tag;
}
void ConfigInterface::setTag(const QString &tag)
{
if(tag == _tag)
return;
emit tagChanged(tag);
_tag = tag;
}
I would like to build up dialog same as Qt Creator "Options" tab that left side page titles with scroll bar and detailed page on the right side.
It would be really helpful if there were code samples or sample applications for reference.
Qt Creator Source Code
Qt Creator has it source code both in Gitorious and in GitHub. But because Qt Creator is such a large and complex project, it can be overwhelming finding its sub parts.
The Github version is very searchable. It ends up that the source related to the nice options page in Qt Creator uses the IOptionsPage as the base class for any of the pages that show up in the Options dialog.
https://github.com/qtproject/qt-creator/search?utf8=%E2%9C%93&q=ioptionspage&type=Code
The ioptionspage.cpp has all the comments explaining the purpose of the different slots.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.cpp
Basically for Qt Creators options page, it has an interface that is used by several different sub modules.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.h
#ifndef IOPTIONSPAGE_H
#define IOPTIONSPAGE_H
#include <coreplugin/id.h>
#include <QIcon>
#include <QObject>
#include <QStringList>
namespace Core {
class CORE_EXPORT IOptionsPage : public QObject
{
Q_OBJECT
public:
IOptionsPage(QObject *parent = 0);
virtual ~IOptionsPage();
Id id() const { return m_id; }
QString displayName() const { return m_displayName; }
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual bool matches(const QString &searchKeyWord) const;
virtual QWidget *widget() = 0;
virtual void apply() = 0;
virtual void finish() = 0;
protected:
void setId(Id id) { m_id = id; }
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_id;
Id m_category;
QString m_displayName;
QString m_displayCategory;
QString m_categoryIcon;
mutable bool m_keywordsInitialized;
mutable QStringList m_keywords;
};
/*
Alternative way for providing option pages instead of adding IOptionsPage
objects into the plugin manager pool. Should only be used if creation of the
actual option pages is not possible or too expensive at Qt Creator startup.
(Like the designer integration, which needs to initialize designer plugins
before the options pages get available.)
*/
class CORE_EXPORT IOptionsPageProvider : public QObject
{
Q_OBJECT
public:
IOptionsPageProvider(QObject *parent = 0) : QObject(parent) {}
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual QList<IOptionsPage *> pages() const = 0;
virtual bool matches(const QString & /* searchKeyWord*/) const = 0;
protected:
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_category;
QString m_displayCategory;
QString m_categoryIcon;
};
} // namespace Core
#endif // IOPTIONSPAGE_H
The search box uses an index the all the titles/labels of the children of each options page that gets added.
bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
{
if (!m_keywordsInitialized) {
IOptionsPage *that = const_cast<IOptionsPage *>(this);
QWidget *widget = that->widget();
if (!widget)
return false;
// find common subwidgets
foreach (const QLabel *label, widget->findChildren<QLabel *>())
m_keywords << label->text();
foreach (const QCheckBox *checkbox, widget->findChildren<QCheckBox *>())
m_keywords << checkbox->text();
foreach (const QPushButton *pushButton, widget->findChildren<QPushButton *>())
m_keywords << pushButton->text();
foreach (const QGroupBox *groupBox, widget->findChildren<QGroupBox *>())
m_keywords << groupBox->title();
// clean up accelerators
QMutableStringListIterator it(m_keywords);
while (it.hasNext())
it.next().remove(QLatin1Char('&'));
m_keywordsInitialized = true;
}
foreach (const QString &keyword, m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
return true;
return false;
}
Finding the rest of the components of the original dialog may take some time, but it is doable.
Included Example
When in Qt Creator > Welcome (tab) > Examples, the best one for a complex settings dialog is probably:
Tab Dialog Example
http://doc.qt.io/qt-5/qtwidgets-dialogs-tabdialog-example.html
Persistent Settings
QSettings is probably the best bet for storing settings. Other options include XML, and JSON. Qt 5 has a great implementation of JSON.
Hope that helps.
I'm making a program that uses lots of timer and, at intervals of 4 seconds, does an online post to a php script.
I'm coding in QtCreator 5.1. I use classes just like the ones below.
The one below just populates a task list, but throughout the course of 8 to 12 hours, the memory that the program takes up just keep rising and rising gradually.
What am I doing wrong while using this class?
I have to be able to keep posting online like I already am, about every 4 to 8 seconds.
Here's a simple class for taking care of one of my processes:
Header file: tasklistprocess.h
#ifndef TASKLISTPROCESS_H
#define TASKLISTPROCESS_H
#include <QThread>
#include <QtCore>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QListWidget>
#include <QTabWidget>
#include "globalhelper.h"
#include "securityinfo.h"
class TaskListProcess : public QThread
{
Q_OBJECT
public:
explicit TaskListProcess(QListWidget *obj_main, QTabWidget *tabs_main, QString user, QObject *parent = 0);
signals:
void upTaskStorage(int key,QHash<QString,QString> item);
private:
GlobalHelper gh;
Securityinfo sci;
QNetworkAccessManager *nam;
QNetworkRequest request;
QByteArray data;
// this is the disposable params for reusage through out the class
QUrlQuery params;
QString post_data;
QString user_name;
QTimer *tasklist_tmr;
bool get_task_list;
QListWidget *obj;
QTabWidget *tabs;
private slots:
void setTaskList();
void replyFinished(QNetworkReply *reply);
void sendPost(QString file_name, QUrlQuery params);
};
#endif // TASKLISTPROCESS_H`
Source file: tasklistprocess.cpp
#include "tasklistprocess.h"
TaskListProcess::TaskListProcess(QListWidget *obj_main, QTabWidget *tabs_main, QString user, QObject *parent) :
QThread(parent)
{
user_name = user;
get_task_list = false;
obj = obj_main;
tabs = tabs_main;
tasklist_tmr = new QTimer(this);
connect(this,SIGNAL(started()),this,SLOT(setTaskList()));
connect(tasklist_tmr,SIGNAL(timeout()),this,SLOT(setTaskList()));
nam = new QNetworkAccessManager(this);
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
request.setRawHeader( "User-Agent" , "Mozilla Firefox" );
// here we connect up the data stream and data reply signals
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
}
void TaskListProcess::setTaskList()
{
qDebug() << "Your task list was set";
bool in = false;
if(!(tasklist_tmr->isActive()))
{
tasklist_tmr->start(10000);
in = true;
}
if(!(get_task_list))
{
params.clear();
params.addQueryItem("user_name", user_name);
params.addQueryItem("logged_in", "1");
sendPost("getTaskList.php",params);
get_task_list = true;
}
else
{
if(post_data.contains("|*|"))
{
//here i retrieve a piece of information from a php script which is stored in a custom string format
// here we clear the list for the new data to be put in
if(obj->count()>0)
{
obj->clear();
}
int key = 0;
foreach(QString inner_task,post_data.split("|*|"))
{
QHash<QString,QString> task_cont;
//qDebug() << " ";
if(inner_task.contains("*,*"))
{
foreach(QString task_val,inner_task.split("*,*"))
{
if(task_val.contains("*=*"))
{
QStringList key_pairs = task_val.split("*=*");
task_cont.insert(key_pairs[0],key_pairs[1]);
if(key_pairs[0] == "tt")
{
QString val_in;
if(key_pairs[1].length()>10)
{
// this sets the title to the shortened version
// if the string length is too long
val_in = key_pairs[1].left(10) + "....";
}
else
{
val_in = key_pairs[1];
}
obj->addItem("Task :" + QString::fromUtf8(key_pairs[1].toStdString().c_str()));
}
}
}
}
//task_storage.insert(key,task_cont);
emit upTaskStorage(key,task_cont);
key ++;
}
}
get_task_list = false;
}
// here we're checking to see if they are looking at the task tab so it doesn't keep changing
// back and forth between the tabs
bool change = true;
if(tabs->currentIndex() != 0)
{
change = false;
}
if(change)
{
tabs->setCurrentIndex(0);
}else if(in)
{
tabs->setCurrentIndex(0);
}
}
void TaskListProcess::replyFinished(QNetworkReply *reply)
{
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error in" << reply->url() << ":" << reply->errorString();
return;
}
QString data = reply->readAll().trimmed();
post_data = data;
if(get_task_list)
{
setTaskList();
}
}
void TaskListProcess::sendPost(QString file_name, QUrlQuery params)
{
post_data = "";
QUrl url(sci.getHost() + file_name);
url.setQuery(params);
data.clear();
data.append(params.toString().toUtf8());
request.setUrl(url);
nam->post(request, data);
}
From the Qt docs http://qt-project.org/doc/qt-5.1/qtnetwork/qnetworkaccessmanager.html
Note: After the request has finished, it is the responsibility of the
user to delete the QNetworkReply object at an appropriate time. Do not
directly delete it inside the slot connected to finished(). You can
use the deleteLater() function.
I would suggest calling reply->deleteLater() in your replyFinished() method.
You should call deleteLater() for an QNetworkReply object after use.
Note: After the request has finished, it is the responsibility of the user to delete the QNetworkReply object at an appropriate time. Do not directly delete it inside the slot connected to finished(). You can use the deleteLater() function.
More information here: http://harmattan-dev.nokia.com/docs/library/html/qt4/qnetworkaccessmanager.html
Thank you everyone for the hel.
It was very simply the "deleteLater()" on the reply in the
void replyFinished(QNetworkReply *reply)
{
}
and it should have looked like this
void replyFinished(QNetworkReply *reply)
{
// after all of your processing
reply->deleteLater();
}
it was such a small problem but one that drove me crazy for a long time so i hope this helps
I need to validate that the text entered in a qlineedit has the form of the regexp, I tried to use this:
void MainWindow::checkReg( QLineEdit& mail, const QCheckBox& skip, string type )
{
if(type == "mail")
{
if( skip.checkState() != 2)
{
QRegExp mailREX("\\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\\b");
mailREX.setCaseSensitivity(Qt::CaseInsensitive);
mailREX.setPatternSyntax(QRegExp::Wildcard);
bool regMat = mailREX.exactMatch(mail.text());
if(regMat == false)
{
QMessageBox *message = new QMessageBox(this);
message->setWindowModality(Qt::NonModal);
message->setText("Inserte los datos en el formato correcto");
message->setStandardButtons(QMessageBox::Ok);
message->setWindowTitle("MainWindow");
message->setIcon(QMessageBox::Information);
message->exec();
this->ok = 0;
mail.clear();
}
else
this->ok = 1;
}
}
}
but every mail mail I entered like me#me.com, the error message appear. I also tried using
int regMat = mailREX.indexIn(mail.text());
and it didnt work.
Thanks in advance
Why did you set pattern syntax to wildcard? Your code works (assuming you understand, that your regexp itself is simplified) with RegExp pattern syntax:
QRegExp mailREX("\\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\\b");
mailREX.setCaseSensitivity(Qt::CaseInsensitive);
mailREX.setPatternSyntax(QRegExp::RegExp);
qDebug() << mailREX.exactMatch("me#me.com");
prints true
If you want to create a real QValidator for reusing in e.g. QLineEdits, you also have to check for Intermediate email adress strings, else nothing will be accepted unless you COPY&PASTE an email address into the edit.
Here is an example for an EmailValidator:
The emailvalidator.h file:
#ifndef EMAILVALIDATOR_H
#define EMAILVALIDATOR_H
#include <QValidator>
QT_BEGIN_NAMESPACE
class QRegExp;
QT_END_NAMESPACE
class EmailValidator : public QValidator
{
Q_OBJECT
public:
explicit EmailValidator(QObject *parent = 0);
State validate(QString &text, int &pos) const;
void fixup(QString &text) const;
private:
const QRegExp m_validMailRegExp;
const QRegExp m_intermediateMailRegExp;
};
#endif // EMAILVALIDATOR_H
And the emailvalidator.cpp file:
#include "emailvalidator.h"
EmailValidator::EmailValidator(QObject *parent) :
QValidator(parent),
m_validMailRegExp("[a-z0-9._%+-]+#[a-z0-9.-]+\\.[a-z]{2,4}"),
m_intermediateMailRegExp("[a-z0-9._%+-]*#?[a-z0-9.-]*\\.?[a-z]*")
{
}
QValidator::State EmailValidator::validate(QString &text, int &pos) const
{
Q_UNUSED(pos)
fixup(text);
if (m_validMailRegExp.exactMatch(text))
return Acceptable;
if (m_intermediateMailRegExp.exactMatch(text))
return Intermediate;
return Invalid;
}
void EmailValidator::fixup(QString &text) const
{
text = text.trimmed().toLower();
}