PDA

View Full Version : Question which I don't feel like is quite as silly.



seerofsorrow
29th September 2017, 22:32
So I'm sorry to keep pestering but I could really use the help again and this time it's more of a best way to do this kind of thing.

So I have a main gui I'm calling start it has a layout in it called specificsLayout that has a vertical spacer in it. Inside of this I want to put another ui based off of which click button the user selects.

So I have a class called classy at the top with everything laid out and all of the slots enter correctly. A button called itchySkin that is an object under classy however when it's selected I'd like the new ui I created to poplulate in the specifics Layout.

So I have something similar to the following as far as code:

header.h (For class classy)


#ifndef HEADER_H
#define HEADER_H

#include <QMainWindow>
#include <QLineEdit>
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QString>
#include <QDir>
#include <QDateTime>
#include <QVector>
#include "itchySkin.h"



namespace Ui {class Classy;}

class Classy : public QMainWindow
{
Q_OBJECT

public:
explicit Classy(QWidget *parent = 0);
QDir *dir;
~Classy();

public slots:
on_itchySkin_clicked();

private slots:




private:
Ui::Classy *ui;


class itchySkin
{

};

};

#endif // HEADER_H


As example of above I'm attempted to nest classes here like I would in C++ however the ui isn't visable to classy. How do I go about nesting classes so that Classy can see the objects/ui of itchySkin?

Thank you so much for your time and attention.

d_stranz
30th September 2017, 02:29
As example of above I'm attempted to nest classes here like I would in C++

Umm, Qt -is- C++. Qt adds some "syntactic sugar" (some macros, special keywords like "slots" and "signals") that gets turned into ordinary C++ by the preprocessor, but it's all just C++ under the hood.

There are a few things to remember though. Generally, only one GUI class (i.e. a class derived from QObject with a Q_OBJECT macro in it) to an xyz.h / xyz.cpp file pair. Not that in theory this isn't allowed, but because the MOC processor can't handle it. The MOC processor reads the header file and generates a bunch of "metaobject" code in the moc_xyz.cpp file. Likewise, QWidget-based classes also usually have an associated xyz.ui file which is processed by the UIC compiler to create the ui_xyz.h file. So, every QObject / QWidget - based class to its own declaration and implementations files.

Second "rule" of Qt (and of C++) is that one class should never be aware of the internals of another class. This is variously known as encapsulation or information hiding. This means no public member variables, minimal (if any) use of friend classes, etc. If a class has a QString member variable that the outside world might need to know the value of, then you write public "getter", "setter", and optional "changed" methods. The "getter" method (like QAbstractSlider::value()) is usually const and provides read-only access. The corresponding "setter" method (QAbstractSlider::setValue()) lets you change the value. In Qt, a convenient way to implement a "changed" notification is via a signal (QAbstractSlider::valueChanged().

Qt takes encapsulation one step further by hiding even the private details of how a class is implemented. If you look at the header file for any Qt class, all you will see is the definition of the public and protected methods and a pointer to some private object. This paradigm is known as the envelope and letter abstraction. All you see is the envelope. Inside the envelope is the letter with all the details but the letter is hidden from your view. This abstraction allows the Qt developers to completely change the internal implementation of a class with no impact on the users of that class, so long as the publicly visible interface remains the same. This was done in the transition from Qt4 to Qt5. Code written for Qt4 that uses QPushButton can be built and run with Qt5 usually with little to no change in the source code.

Third "rule" of Qt is that the majority of communication should be done via the signals and slots of high-level classes derived from QObject or QWidget. This, along with the second rule means that a high-level class (like a QDialog-based class) should not expose any of its implementation details to other classes that use the dialog. So, if you have a parameter-entry dialog that has a bunch of QLabel, QLineEdit, maybe QCombobox, and some QPushButton instances in the UI, no other class should know that. You will never write code where one class refers to "dialog->ui->lineEdit1->text()" or connects directly to a signal or slot of some embedded UI component.

Instead, only the dialog should know how its ui is implemented, and only the dialog class should have internal connections between signals and slots of things in its ui. If whatever the dialog does needs to be made visible to the outside world, then the dialog class itself should provide getter, setter, and changed methods, slots, or signals and those should be as independent as possible from however they are implemented internally. You will not have a "lineEdit1Value()" or "lineEdit1SetValue()" method, you will have a "userName()" or "setUserName()" method instead. In this way, you can completely change how your dialog is implemented without changing how the rest of the program interacts with it.

So with this long-winded preface, the bottom line is that you should design and implement your application in a way that

1 - focuses on the interaction (interface) between different components (ui and other) rather than their internals
2 - creates high level interactions between classes and hides low-level interactions internal to the classes
3 - uses function-related names for methods rather than implementation-related names ("userName", not "lineEdit1").

For the particular case you asked about, a two-part GUI where one part changes depending on something that happens in the other part, a common pattern is to use some type of stacked widget for the variable part, such as QStackedWidget or QTabWidget. These are both designed to show only one of multiple pages at a time. In the case of QTabWidget, there are tabs at one side that allow the user to switch between pages by clicking a tab. QStackedWidget requires some other part of the user interface or the code to trigger page changes.

With either of these container widgets, each page is implemented as a standalone QWidget-based class. You create an instance of each class at startup and add them to the stack or tab widget, connect up the high-level signals and slots of these pages to the appropriate slots / signals in your main window class, then tell the UI to show whichever page should appear first.

With an appropriate design, no page should be aware of any other page or even that they are pages in a stack or tab. All of their interaction is with the main window. If two pages need to communicate, they do it by way of the main window, not by any sort of direct connection between them. In that way, you can completely remove one of the page classes and replace it with a different page class. Only the main window knows about the switch because it has to create an instance of a different class, but otherwise everything else stays the same.

ado130
2nd October 2017, 20:32
Hello,
I know this is not my thread, but I hope it's not problem. First I'd like to thank you d_stranz, your answers are really helpful for me as well. I'd like to ask you if you can help me to understand more "how to think in Qt". I mean, let's say I understand basic (maybe advanced) ways how to write good code, but still it's not as I wish. So if you know any websites(blogs, ..) or whatever... Actually I already wrote two serious project in Qt, but I think it can be better.

d_stranz
3rd October 2017, 19:01
I think the two most important things about "thinking in Qt" as opposed to "thinking in C++" are:

1 - Model communication between classes in your apps using signals and slots rather than pure member functions.

The power of signals and slots is that communication between senders and receivers is completely handled internally to Qt. This means that signals can be emitted by a sender without the having any idea if anyone is listening. The sender doesn't even know what types of objects the receivers are. Likewise on the receiving end, a slot has no idea who sent the signal it is handling. Sure, there is the QObject::sender() method you can use to determine this, but it is rarely necessary.

Connections between senders and receivers can be managed by a third class that is totally unrelated to either the sender or receiver. So a MainWindow can make a connection between two GUI objects. Neither GUI object knows that the other exists, only the MainWIndow does.

This is a very powerful architecture and requires no programming on your part to make it work, other than deriving your classes from some QObject-based class, adding the Q_OBJECT macro, and properly implementing your signals and slots.

This is much different from a traditional C++ callback architecture, where typically a class has the facility to hold only a single pointer to a callback function, and the class itself must do the checking to see if the callback pointer is valid and to call it when needed.

2 - Keep in mind the QObject ownership hierarchy

This hierarchy is important because it means that Qt object hierarchies will "clean up after themselves" when deleted. Parent objects will delete their children and the Qt meta-object system will ensure that connections between instances that are being deleted will be broken properly. Parents own their children and control their lifetimes, and children cannot be shared among multiple parents. Moving a child from one parent to another will also transfer its ownership from the first to the second parent.

The QGraphicsItem and QGraphicsScene classes also take ownership of items added to them and will clean up when they are deleted. They are not part of the QObject hierarchy though.

It is also important to recognize Qt classes that are not part of a hierarchy system. These are classes that are often meant to be shared among multiple class instances. QAbstractItemModel is one example, which can be shared among multiple views. QAction is another, which can be shared among menus, toolbars, and widgets. Each of these classes can be created with an optional QObject owner, and that owner will be responsible for deleting it when the owner is deleted. Any non-owners which are holding a pointer to the instance will be notified that the instance is being deleted so they can remove their internal reference to the pointer.

ado130
3rd October 2017, 21:11
Thank you! What do you think, is possible to find a job in Qt? I mean, do companies use Qt to develop their applications.

d_stranz
3rd October 2017, 23:41
is possible to find a job in Qt? I mean, do companies use Qt to develop their applications.

Yes, and yes. Google is your friend. Looking for "Qt jobs" landed me on this for a start. (https://www.indeed.com/q-Qt-Developer-jobs.html)