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

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/");
}

Related

Referencing QWidget from different class

I'm sorry if this question is duplicate but i am really struggling with finding any answer.
Please take in mind that i am novice in c++ programmming.
My problem is this. I have an GUI made in QtCreator. There are two listeners binding keyReleaseEvent, one on main class (SuperFalcon) , one on QTextEdit ( which is separate and modified class ). I have QFrame which i would like to toggle hide/show on "Ctrl + f" key event. Since that QFrame (object name is findWidget) widget belongs to SuperFalcon->ui, there's no problem, everything works fine, problem starts when i try to make "Ctrl + f" in QTextEdit because it's separate event listener. Basically i tried this.
main class name is "SuperFalcon" so:
in superfalcon.h i've made an public static pointer like this:
public:
static QFrame *fWidget;
then in superfalcon.cpp, i firstly execute
ui->findWidget->hide(); and then
fWidget = ui->findWidget; hoping to get pointer on widget.
Next in my QTextEdit class in keyReleaseEvent function i've tried to get that pointer like SuperFalcon::fWidget->show() but i get undefined reference on it.
So , to make things simpler, i don't know how , if possible, to get reference of QFrame widget which is part of one class (SuperFalcon), from another class (QTextEdit class) in order to execute some commands on QFrame.
If it's not clear enough i can provide some code.
You must have a definition of any static member variable.
This definition has to be in a source file because of the one definition rule.
Simply add the line:
QFrame* SuperFalcon::fWidget;
to "superfalcon.cpp".
You have to initialize your static variable, in superfalcon.cpp:
QFrame* SuperFalcon::fWigdet = nullptr;

Q_PROPERTY with parameterized read and write accessors

I have a Configuration that holds some basic information about file locations like download, install, picture, music, document etc. location.
These are currently exposed to QML using Q_PROPERTY. They all have their own accessors:
Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)
These accessors basically do all the same stuff and I'd like to get rid of all this redundant code I have to write.
My first idea is to have a little nested class FileLocation that provides get, set and validation functions. But then, how would I connect these to the Q_PROPERTY?
Also, if I had something like a static functions which took parameters, (e.g. check_validity( QUrl location )), how would I hand over this parameter from QML side?
I think I'm on the wrong path here, so my question is how to keep redundant code in the context of Q_PROPERTY within reasonable limits, avoiding to write loads and loads of get, set and changed functions for very similar objects?
Here's some more code:
class Configuration : public QObject
{
QObject
Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)
Q_PROPERTY(QUrl music_location READ music_location WRITE set_music_location NOTIFY music_location_changed)
...
signals:
void download_location_changed();
void music_location_changed();
...
public slots:
void set_download_location(QUrl location)
{
download_location = location;
emit download_location_changed(download_location);
}
void set_music_location(QUrl location)
{
music_location = location;
emit music_location_changed(music_location);
}
...
private:
QUrl download_location,
music_location,
...;
}
So as you see there's a lot of recurring code that does the same, and I'd like to damp that down a little. How do I do that? I was thinking about some general functions set, get, changed etc. that get the member to work on was a parameter. But then I didn't know how to hand over which member to work on from qml.
I just found out about the possibility to expose C++ classes to qml via qmlRegisterType(...) - maybe this is the way to go here?
You could go for an evil macro:
#define IMPL(data, name) \
inline decltype(data) name() const { return data; } \
inline void set_##name(decltype(data) value) { if (value != data) { data = value; emit name##Changed();} }
Of course, if you don't need any extra stuff, you can simply use a MEMBER property and have Qt auto generate accessors for you.
This will however not work if you need to do custom things in the accessors, the macro will, just add your stuff to it.
Lastly, when you declare a Q_PROPERTY, you can right-click the property, go to refactoring, and select "generate missing members...", Qt will generate the default stubs for the accessors, and you will only have to add your custom stuff in. The downside to this is it has the nasty habit of putting the generated code in the silliest place possible, so if you want your class to look neat, you have to move it by hand.
qmlRegisterType() is when you want to register a type so it can be created in QML, you generally don't have to do anything to access a QObject derived object from QML - it works for QObject derivatives, you only need to register a metatype for types which do not have meta information generated.
Last but not least - I don't see any point in having your configuration as a C++ object, you can just as well do it in QML, and use Qt.labs.settings to make your settings persistent. C++ is optimal for performance critical parts only. If you do your configuration in QML, you don't need to worry about any of that boilerplate code, as it is all automatic in QML, no need to write accessors, no need to recompile your project on every tiny change.

Qt Extending my own widget

To put it simply, I want a new class that extends a custom widget that I've made, and thus have full access to it's UI.
I've tried several different methods so far based on how one would normally subclass/extend classes, but I'm somehow failing horribly for so many different reasons.
Additionally, simply using my widget as a member in my new class wouldn't do for this situation.
Can someone illustrate a quick example of how I would do this? I have done a bunch of searching but I can't seem to find any hits relating to exactly what I'm trying to do
If all else fails I will simply copy over the code and make an actual new widget, which technically would have saved me lots time, but it just doesn't feel right doing that.
My first instinct was to do something like this ( Qwe being my new class, Asd being the widget ):
class Qwe : Asd {public: ...}
And I even made the widget's Ui public, but then I just got the error :
use of undefine type Ui::Asd
whenever I tried to access the Ui's elements.
Let's say we have a custom widget named BaseWidget and a child widget named ChildWidget. Declare BaseWidget as usually, but make its ui member protected instead of private, like this:
protected:
Ui::BaseWidget *ui;
Declare ChildWidget as an ordinary widget derived from BaseWidget. Make sure you include ui_BaseWidget.h in the ChildWidget.cpp file, just as you do it in BaseWidget.cpp (this include and the header itself is generated by Qt).
Header:
#include "BaseWidget.h"
class ChildWidget : public BaseWidget {
Q_OBJECT
public:
explicit ChildWidget(QString text, QWidget *parent = 0);
};
Source:
#include "ChildWidget.h"
#include "ui_BaseWidget.h"
ChildWidget::ChildWidget(QString text, QWidget *parent) :
BaseWidget(parent)
{
ui->label->setText(text);
}

Access widgets of a QDockWidget from within the QMainWindow

In my QMainWindow scope I have an instance of a class AgilentSweeper which inherits QDockWindow, and initialize and display it with:
sweeper = new AgilentSweeper(this);
addDockWidget(Qt::RightDockWidgetArea,sweeper);
This class has a Qt Creator-made .ui form which has several widgets in it and the constructor looks like:
AgilentSweeper::AgilentSweeper(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::AgilentSweeper)
{
ui->setupUi(this);
}
where Ui::AgilentSweeper *ui is public.
From other functions in the AgilentSweeper scope I can access the AgilentSweeper widgets and do things like double power = ui->powerSpinBox->value(); normally. However, I can't figure out how to access the AgilentSweeper widgets from within the scope of the main Ui. It seems like this should be possible because sweeper is a member I thought I should be able to do something like double power = sweeper->ui->powerSpinBox->value();, but despite messing around with it for a while I can't figure out how to access anything from sweeper's ui. I can think of several work-arounds, but this seemed like it should be possible.
ui Object is defined as private member of AgilentSweeper by default. So normally, you can't access it.
Some solutions:
very bad: declare QMainWindow as friend
bad: Change in AgilentSweeper.h private: by public: for the Ui::AgilentSweeper
one I would prefer:for each method of your UI-widgets you want to expose, create a public method in AgilentSweeper.h
So you can access the spinbox-value by
//in AgilentSweeper.h
double powerSpinBoxValue()
{
return ui->powerSpinBox->value()
}
//call from outside:
double power = sweeper->powerSpinBoxValue();
EDIT Explanation for 2
The object Ui::AgilentSweeper *ui is defined in AgilentSweeper.h usinf forward declaration. So in a file including AgilentSweeper.h alone, no information is given, how to create an instance of the object and which methods it provides.
This information is provided by autogenerated file ui_AgilentSweeper.h. so in order to use the way 2, include also ui_AgilentSweeper.h.
Why is this solution bad? It looks so flexible right?
In the first line exposing members as public is bad. A user could delete the instances: e.g. delete sweeper->ui->powerSpinBox.
Besides, there is no way to log or lock the access to the member objects.

Functions cannot access objects defined in the same class .. ! Possibly a bug?

Hey guys .. Well ever since I've started programming in Qt, I've been having problems regarding scope visibility of objects I've defined .. Till now I've managed to find ways to get around these things but now its getting annoying ..
For example, I have this class defined called Canvas:
class Canvas : public QWidget//, public MainWindow
{
Q_OBJECT
public:
void refreshFoldersList(QString inputPath);
void browseFolders();
private:
QListWidget *foldersList;
};
#endif // CANVAS_H
Now even though foldersList is private, refreshFoldersList() should be able to 'see' it, right ? But in my case it can't .. ! I first initialize foldersList in the browseFolders() function and then from within browseFolders(), I call refreshFoldersList() ... Any code inside refreshFoldersList() dealing with foldersList immediately throws a segmentation fault ... I've checked the pointer values for foldersList when the scope is in browseFolders() and refreshFoldersList() .. the values don't match .. its like either I'm trying to access something I'm not supposed to, or that I'm trying to access an object which has not been initialized yet ..
Any clues on this ?
A related issue ... I have another class MainWindow (inherited from QMainWindow) .. In this class I have an instance of the class Canvas .. this instance is named canvas .. I initialize canvas in MainWindow's constructor, and set canvas's parent to the MainWindow instance initializing it .. based on this, I used the following code to access a MainWindow function from within the Canvas class:
((MainWindow*)parent())->someFunctionDefinedInMainWindow();
Before, the above code used to work .. but then like 2-3 days ago it stopped working all of a sudden .. Now it got me to inside the MainWindow function I was calling (namely someFunctionDefinedInMainWindow() ), but from there if I tried to access any variable defined in MainWindow, I got a Segmentation Fault, again with pointer values not matching .. The way I solved this is by defining a variable as:
void * papa;
.. inside Canvas, and then when I initialized canvas, I set:
canvas->papa = this; //this being the MainWindow instance initializing canvas
Now I accessed MainWindow's functions like this:
((MainWindow*)papa)->someFunctionDefinedInMainWindow();
.. which works!
But again, I would like to know the nature of these problems .. Am I doing something wrong or what ?
The bug is here (code from your comment to liaK):
QListWidget *foldersList = new QListWidget();
You are creating a local variable instead of initializing the class member. Change the code to:
foldersList = new QListWidget();
And probably there is no need for foldersList to be a pointer at all, so your class declaration could be:
private:
QListWidget foldersList;
throws a segmentation fault
Probably some error in your initialization.. How you are initializing it?? Showing the code will be helpful.
And you are using --> instead of ->
Check out this link
Sure it is not a bug with Qt.
or that I'm trying to access an object
which has not been initialized yet
Perhaps you are trying to access an object that hasn't been initialised yet? How and where do you initialise folderList?
Now even though foldersList is private, refreshFoldersList() should be able to 'see' it, right ? But in my case it can't .. ! I first initialize foldersList in the browseFolders() function and then from within browseFolders(), I call refreshFoldersList() ... Any code inside refreshFoldersList() dealing with foldersList immediately throws a segmentation fault
If there was any problem with members visibility, your code wouldn't even compile. Your segfault must be related to something else.
I'm afraid you'll have to show more code for us to be able to help you efficiently.
Moreover, you're using C casts while Qt requires you to write C++. That can only make things worse.
So instead of:
((MainWindow*)parent())-->someFunctionDefinedInMainWindow();
You should use either dynamic_cast<> or static_cast<>, depending on what you want to achieve.