Qt4: The best way to access parent class (1 level up, 2 levels up .... ) - c++

I'm wondering how to access parent class in my Qt application.
Lets say my project has following structure:
mainWindow: MainWindow
tabWidget: QTabWidget
tab1: MySubClass1
tab2: MySubClass2
tabWidget: QTabWidget
xtab1: MySubSubClass1
xtab2: MySubSubClass2
It is a little simplified.
What I want to do is to access mainWindows object from one of xtab2 slot functions.
(1) What would be the best method ?
I tried to pass the pointer to mainWindow along the tree but I get runtime errors.
(2) Should I include mainwindow.h in xtab.h file or should I do it in xtab.cpp file ?
Thanks for help :)

If you really need the mainwindow, passing the MainWindow pointer is the best way to do it. A static method has the drawback that it will stop working with more than one mainwindow.
I would suggest to avoid accessing the mainwindow from the contained widgets though and use signals instead. E.g.:
class MainWindow {
public:
explicit MainWindow( QWidget* parent=0 ) {
tab = new TabWidget;
...
MySubSubClass1* ssw1 = new MySubSubClass;
connect( ssw1, SIGNAL(textChanged(QString)), this, SLOT(page1TextChanged(QString));
tab->addWidget( ssw1 );
}
private Q_SLOTS:
void page1TextChanged( const QString& ) {
//do something...
}
};
MySubSubClass1 then emits textChanged(), addresseeChanged() (e.g. in Addressbook), or whatever level of abstraction or detail makes sense on the higher level. That way MySubSubClass is generic and doesn't have to know about MainWindow at all. It can be reused in any other context. If MySubSubClass itself contains other widgets, it can again connect to their signals.

You could create a static method and object inside MainWindow that would return mainwindow object.
Something like this:
private:
static MainWindow* _windowInstance
public:
static MainWindow* windowInstance()
{
return _windowInstance;
}
This seems to be the simples solution in most cases. Now you just have to include mainwindow.h whenever you need to access this object.
And don't forget to initialize _windowInstance in the contructor, like this;
_windowInstance = this;

By parent class, I assume you mean parent widget?
If you want to find the top level widget, QWidget::window() will point you to it. Use dynamic_cast or qobject_cast to turn it into your MainWindow object.
If you want to go up some arbitrary level, use paerntWidget().

There are a variety of different solutions to this problem, the one you chose as the answer is in terms of object orientation and encapsulation one of the worse ones. Some thoughts
Encapsulation: if you find yourself having to provide access accross a large distance in relation (down a long chain of containers or subclasses) you might want to look at the functionality that you are trying to distribute. I might be that it should be encapsulated in a class by itself that can passed around easier than where it is currently located (the main window in your case).
Abstraction: Unless it is actually functionality of QMainWindow that you need to access don't pass a pointer to your MainWindow class, create an interface for the functionality that you need, have your MainWindow implement that interface and pass around and object of the interface type instead of your MainWindow type.
Signals and Slots: As Frank noted, implement the appropriate functionality using Qt's signalling mechanism, this makes the connection between the caller and callee into a dynamic one, again separating it from the actual MainWindow class
QApplication: If you absolutely have to have global information restrict the entry point, you already have one singleton the QApplication object, make it the maintainer of all the other objects that need to be globally accessible, derive your own QApplication class and maintain global references in there. Your QApplication class can then create or destroy the needed global objects.
With more information about what you need to do with the MainWindow instance or what needs to be communicated you will also get better answers

QWidget* parent = this ;
while (parent -> parentWidget()) parent = parent -> parentWidget() ;

Related

Qt5 ui, multiple windows: how can I access the Ui objects in Window 2 from Window 1

I know this is very clunky and I'm probably doing a lot of wrong things but so far everything I saw on the net gives back the same errors: invalid use of non-static data member ui.
So in the MainWindow, I have a comboBox named hometeam, and I want to display the currentText on a Qlabel named label which is on another Form Class called Dialog
I figured they're both private members so I added friend class MainWindow and friend class dialog in the respective headers (I know this is pretty wrong but it's the last thing I tried), I included the "ui_mainwindow" and "ui_dialog" in the .cpp files, and here's the bit of code I'm trying:
ui->label->setText(MainWindow::ui->hometeam->currentTex());
Keep in mind that I don't want a QDialog, the second window will do a lot more than a display, I just want to access the objects from a different window. Slots and signals give the same error.
Thanks !
I think the proper way to do that, is to add a function to your MainWindow class:
QString hometeamText() const
{
return ui->hometeam->currentTex();
}
This way you can access the information you need without violating encapsulation rules, but you need an instance of MainWindow to do it, and sure must keep a pointer to it in your Dialog class:
class Dialog
{
private:
MainWindow * mainwindow;
public:
void setMainWindow(MainWindow * w) { mainWindow = w; }
then somewhere (e.g. in main) you can do something like:
MainWindow mainwindow;
Dialog dialog;
dialog.setMainWindow(&mainWindow);
and from inside your Dialog class, wherever you need it:
ui->label->setText(window->hometeamText());

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

Why do we pass "this" pointer to setupUi function?

I'm fairly new in QT. Taking below fairly simply explain from qt docs :
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
private:
Ui::CalculatorForm ui;
};
and implementation of constructor
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this); // <-- Question below
}
Q: I was wondering why do we pass this pointer to setupUi function?, what does it do ?
So that the dialog will have the caller as parent, so that eg when the parent is closed the dialog can be closed automatically. Generally all gui elements have a pointer to their parent.
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
These are auto generated slots which exactly match the naming of the gui elments in QtDesigner. They are only meant to do the direct hookup to those gui elements and so should be dealt with in this class. If these signals were extended to other classes then any change in the gui would require changing a lot of other code which doesn't need to know details of the gui.
In the handler slot for the specific gui element you can then emit another more general signal to the rest of the app.
The only widget that setupUi doesn't create is the widget at the top of the hierarchy in the ui file, and as the Ui::CalculatorForm class instance doesn't know the widget it has to fill, it (this) has to be passed explicitly to the class at some point.
this or any other widget you would pass to it, is used as the parent to all other subwidgets. For example, you could fill a widget without inheritance like this:
QWidget *widget = new QWidget;
Ui::CalculatorForm *ui = new Ui::CalculatorForm;
ui->setupUi(widget);
widget->show();
But really, it would be easier to understand if you read the content of the uic generated file (probably named ui_calculatorform.h).
setupUi creates the instances of widgets (QLabel, QTextEdit and so on). The [user interface compiler] (http://qt-project.org/doc/qt-4.8/uic.html) gets information for you from the .UI form and generates widget-creation code in the generated moc source files.
The manual way of creating widgets without using the Qt Designer or a UI file would be like so:
QWidget* pWidget = new QWidget(this);
I think it is to add the caller widget to the layout of this UI.
This widget will be the toplevel widget.
Martin Beckett answer might be correct as well, as what he described is a common behavior in Qt (cf the 'parent' argument in most of widget's derived class constructor)
Note that you have alternative ways how designer can auto-generate code.
In this case you have a separate 'UI' class for this code which is not QObject so it also is not a QWidget.
Auto generated code needs information about parent widget and to make auto-conections of slots and signals so this is why you have to pass this.
This pater is less intrusive then other pasterns (that is why it is default). You can also try alternative patters (check Qt Creator Designer options), but I recommend you to see what is generated by designer tools in default settings.

Qt problem when working over classes GUI access

I got 2 classes:
- MainWindow (Was the default class)
- ExtraClass (That i created myself)
Inside the class MainWindow i've made a public function called "logger". This function looks like this:
// Takes in a QString and appends it to a QTextEdit.
void MainWindow::logger(QString Log_MSG)
{
ui->Logg->append(Log_MSG);
}
This logger functions works out as expected inside its own Class MainWindow but when i try to pass in a MSG into logger from the class ExtraClass, it suddenly doesn't work.
My approach to accessing logger from MainWindow to ExtraClass:
MainWindow Con;
Con.logger("The Message the will get appended to ui->logg");
So the question, what have i missed? I don't get any errors and the text "Log_MSG" that should be appended to the QTextEdit Log don't execute.
Sorry for the style, i just don't understand how to get it to look good.
EDIT:
I've already tried to access other functions from "MainWindow class"
and that works but when i try to pass a string this particuallry function "logger"
from another class nothing happens.
For an instance:
MainWindow MainWindow;
int ANumber = MainWindow.GiveMeAValue(); // This works
But when i'm doing this:
MainWindow MainWindow;
MainWindow.logger("Log MSG"); // This dosen't work
My guess is that the problem lies in the appendment of
a QString passed in into the main class that was automatically created by Qt (have stuff like ui->abc) from another class. But in my current
level of understandment of Qt i don't really know where to
troubleshoot beocuse i don't even get an error.
Your code to access the logger is wrong (it shouldn't even compile).
First, everytime you call the function where this code resides, you create a new local MainWindow object (Con). And then you try to call the method on the class and not on an object. If it is a static method (which I doubt, due to the use of ui), you would have to write MainWindow::logger(). If it is not a static method, then you need to call it on a specific MainWindow instance. But instead of creating a local MainWindow everytime, you should provide the correct application's MainWindow instance to your ExtraClass object.
If all this sounds alien to you, you should first look a bit deeper into fundamental C++ programming before delving into Qt.

qt GUI connecting

I am just starting out with QT. I have read through some tutorials, and I think I have an understanding of signals and slots. I am writing a GUI that has various buttons that change the state of my main program. So for example in a drawing app, you would pick different drawing tools (using various buttons).
What is the best way to go about this? My first thought was to try to connect the clicked signal of the PushButton to some function that sets a current_tool variable. I did some searching and couldn't find a way to connect a QObject signal to a regular function.
This leads me to believe that there is probably a different approach. One where I create a new QObject (my own extension that is) that has various GUI properties. I would then define my slots here for the various buttons.
What is the best way to do this in QT. I am new and do not know of the preferred practice.
Any info would be useful,
thanks
You can define these "normal functions" as slots. Slots are just normal functions that can also be called by signals:
class ToolSelector : public QObject {
Q_OBJECT
public:
Tool *selected;
public slots:
void selectBrush();
void selectPen();
void selectFill();
};
ToolSelector::selectBrush() {
delete selected;
selected = new Brush();
}
ToolSelector::selectPen() {
// ...
}
// ...
toolsel = new ToolSelector();
brushButton = new QPushButton();
connect(brushButton, SIGNAL(clicked()), toolsel, SLOT(selectBrush()));
Inherit from the class that uic generates, creating, say, a MyAppWindow class. Provide extra METHODs in that class, as well as a Document or Drawing object. Connect these methods to the signals you're interested in, and them alter a member variable that contains the drawing state.