Why does this work and how? Non-static Qt object - c++

I'm a little confused and would like to clear this up.
//QDir()::rmdir is from Qt Creator auto complete.
//It does not work.
//Says no such static function.I looked it up, turns out to be true.
//Fair enough...though I'm not sure why auto-complete suggested it.
bool success = QDir()::rmdir("Y:/dir1/dir2/dir3"); //Does not work.
//Now I could make a QDir object as such.
//I didn;t test this but I'm sure it would work fine.
//However it seems clumsy.
QDir d("Y:/"); //This seems like a waste.
d.rmdir("Y:/dir1/dir2/dir3");
//Lastly, the source of my confusion. QDir().rmdir
//This works, but WHY?
//There is no empty constructor for QDir in Qt Documentation.
//http://doc.qt.nokia.com/4.7/qdir.html
//Yet this empty constructor version works. Why?
bool success = QDir().rmdir("Y:/dir1/dir2/dir3");
My main concern is why does the last examaple [QDir().rmdir] work?
I've noticed this on a number of Qt classes. Is this an anonymous object and if so
what does this mean with regards to object clean up? Is this form safe to use?

One of the QDir constructors is:
QDir ( const QString & path = QString() )
Your QDir().xxx code is calling this constructor, which then uses default to using a QString() as one argument.
This is safe and normal to do.

QDir creates a temporary object. Pretty the same if you callsth. like:
QString s("123");
int answer = 40 + s.left(2).right(1).toInt();
Second line produces 2 temporary objects.

Related

Passing object to a function in QT causes Segmentation Fault

Thanks in advance for your time. I'm still new to the coding world, so excuse me if I ask something silly or obvious.
I'm coding a small program with QT for manipulating data of a data base. To represent the data I'm using QTableViews. I have a few of them with the same configuration, so I made a function to configure them:
QT 5.12
void MainWindow::configureTableView(QSqlTableModel *model, QTableView *table, QString DBTable)
{
//Pacients table.
model = new QSqlTableModel(this);
model->setTable(DBTable);
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
table->setModel(model);
table->setSortingEnabled(true);
table->setCornerButtonEnabled(true);
table->hideColumn(0);
}
I have some QSqlTableModel defined in the mainwindow.h as:
QSqlTableModel *PatientsTable;
...
I call the function with:
configureTableView(PatientsTable, ui->ClientsTabTableView, "Pacientes");
Program starts and shows OK, but as soon as I try to do anything with the view like set a filter
PatientsTable->setFilter(Search)
where Search is a QString configured by other function based on user input, the program crashes and QT tells me it received a signal from the operative system: SIGSEGV (segmentation fault).
Now when is was coding all of this, at some point I had:
void MainWindow::configureTableView(QTableView *table, QString DBTable)
PatientsTable = new QSqlTableModel(this);
PatientsTable->setTable(DBTable);
PatientsTable->setEditStrategy(QSqlTableModel::OnManualSubmit);
PatientsTable->select();
table->setModel(PatientsTable);
table->setSortingEnabled(true);
table->setCornerButtonEnabled(true);
table->hideColumn(0);
which works with no issues at all.
What am I missing? I've been digging for a while now and the code and explanations I found on Internet aren't working.
Thanks again for your time!
The problem is that your function does not modify the PatientsTable variable. Just passing a pointer to a function does not let you modify the pointer itself (only what it's pointing to). Simple solution, pass the pointer by reference.
void MainWindow::configureTableView(QSqlTableModel *&model, QTableView *table, QString DBTable)
The alternative (better in my view) would be to return the pointer from the function
QSqlTableModel *MainWindow::configureTableView(QTableView *table, QString DBTable)
{
QSqlTableModel *model = new QSqlTableModel(this);
...
return model;
}
PatientsTable = configureTableView(ui->ClientsTabTableView, "Pacientes");
It's a very common beginner misunderstanding. Pass pointers to modify what is being pointed to. The pointer itself cannot be modified. In this regard pointers are just like any other kind of variable.

Qt QFileDialog::setDirectory funny behavior in Ubuntu 12.04

I have a class that inherits from QFileDialog. In the constructor, I call setDirectory and pass in the last directory visited (which the class keeps track of; see code below). On Windows, this works fine. And if I show the dialog multiple times, it is internally smart enough to resume at the last location (e.g. where the user saved a file before). This is the desired behavior.
On Ubuntu 12.04 (GCC 4.8 compiler), on the other hand, the system does not automatically resume where last left off if I call showFileDialog multiple times. So I tried adding the setDirectory call within that function as commented below, but that didn't change anything. Furthermore, if I take out setDirectory from the constructor so it is only called in showFileDialog, the file dialog opens to the folder from which the program was run. (i.e. setDirectory didn't work.) Subsequent calls to showFileDialog will open a file dialog starting in the directory requested.
So it seems like the call has a delayed effectiveness. Is this a Qt bug, or mine? Either way, how can I get the setDirectory call to be effective?
Example code:
QString FileDialog::defaultDir = QDir::homePath();
FileDialog::FileDialog(QWidget *parentWindow /*, ...*/)
: QFileDialog(parentWindow)
{
setDirectory(defaultDir);
//...
}
QString FileDialog::showFileDialog()
{
// Adding setDirectory(defaultDir) here doesn't help.
if(!exec())
{
return QString::null;
}
defaultDir = directory().path();
//...
}
It is not clear from the code above how you know that the path was changed. I'm not sure that directory() is responsible for that.
Consider using void QFileDialog::directoryEntered(const QString & directory) signal.
Workaround found:
I happen to set the dialog title (setWindowTitle()) every time I open a FileDialog. If I connect to the QFileDialog::windowTitleChanged signal and call setDirectory within the slot, it is effective.
This is an unintuitive workaround though, so I am open to better answers.

Child access parent variable / Define variable once, use it in entire application

Consider the following code:
class.h
public:
QString dataDirectory;
class.cpp
dataDirectory = QApplication::applicationDirPath();
dataDirectory.append("/../data");
child.h
class Child : public QDialog
child.cpp
QString dataFile = parent()->dataDirectory; // Fails
dataFile.append("myfile.txt");
Of course I tried to cast it with an qobject_cast, like so:
ParentClass *myParent = qobject_cast<class *>(parent());
QString dataFile = myParent->dataDirectory; // Fails (I even get a segfault);
No success. I also tried to change the constructor of the child, but I get a few dozen error messages of what is not defined. Although I used forward declaration and avoided to include the header files.
All I want is to have one place where I define the directory path and access it in my whole application. In another language I know better that would be really, really simple, but in C++ I can't get it to work :/
The problem is a really basic one and I'm kinda embarrassed not to find a solution, but my Parent and Child are both QWidgets and I can't find any way to access the parents variable in the child.
Use a private data member and a public and static getter function, returning const QString & made from the data member.
"My" solution (thanks to dom0)
QString parent::dir()
{
return QGuiApplication::applicationDirPath().append("/../data/");
}

Qt QScriptEngine and default conversions from Qt Script to C++

I'm trying to convert a QVariantMap to Qt Script object. If I understood correctly it should go something like this:
QScriptEngine* engine = new QScriptEngine();
QVariantMap* test = new QVariantMap();
test.insert("testkey", QString("testvalue"));
QScriptValue testqs = engine->toScriptValue(test);
QString value = testqs.property("testkey").toString();
I'm not sure if that is the right way to event try to ask for the value from the ScriptValue. But the root problem is that the Script object I get, doesn't seem the have any of the properties that were in the map to begin with.
So, what am I missing?
Ok, so I figured out my problem. If I would have read the specs correctly I would have noticed that the toScriptValue() method won't take a pointer. So the fix was:
QScriptValue testqs = engine->toScriptValue(*test);

Showing two windows in Qt4

My friend and I have each created parts of a GUI using Qt 4. They both work independently and I am trying to integrate his form with the my main window. As of now this is the code I am using to try and load his form:
//connect buttons and such
connect(exitbtn, SIGNAL(triggered()),this,SLOT(terminated()));
connect(add, SIGNAL(triggered()),this,SLOT(add_rec()));
void MainWindowImpl::add_rec()
{
//form quits as soon as it loads...?
DialogImpl dia;//name of his form
dia.show();
}
I have included his header file. The program compiles but when I hit the trigger his form loads up for maybe half a second and then closes. Does anyone know what I am doing wrong?
You have almost get it right. This is because the RAII of C++. If you allocate the Dialog on stack, it would be destructed as soon as the function return.
Assuming MainWindowImpl inherits publically from QWidget, you're looking for this:
void MainWindowImpl::add_rec()
{
// passing "this" to the constructor makes sure dialog will be cleaned up.
// Note that DialogImpl will need a constructor that takes a
// QObject* parent parameter.
DialogImpl* dialog = new DialogImpl(this);
dialog->show();
}
Look at the Qt documentation for examples of how the constructors should look.
Apparently QT4 only allows one instance of an object at a time, however pointers are another matter. Change both the main.cpp and what ever your main window to look something like this:
DialogImpl *dia=new DialogImpl;
dia->show();