How to extend QDockWidget functions in Qt? - c++

I'm new to Qt, tried several widgets and found that QDockWidget is the most modern/interactive one to work with
But I've found a little limitation "about where to dock the widget only in the 4 sides, left/right/top/bottom"
I want to do one of the two following things and any one should work.
Add more areas to dock widget "for example it can recognize separators between widgets and get its data from there , then resize itself depending on that"
Reimplement the whole functions of QDockWidget into QWidget and do
it like option 1
Thanks in advance

In Qt you can pretty much inherit any class into a new class of your own and extend it yourself. for example:
// New class that inherits QDockWidget and extends its functionality
ExtendedQDockWidget : public QDockWidget
{
public:
ExtendedQDockWidget(QWidget * parent = 0) :
QDockWidget(parent)
{
// ... do any extra initialisations here
}
ExtendedFunc(/* some params */)
{
// code here
}
}
You can also re-implement or overload existing functions to do exactly what you want.

Related

How to restrict access to the most direct base class, while still exposing the base-base classes?

I have a class hierarchy similar to this:
class Widget {
// a lot of virtual members
};
class Button : public Widget {
// new stuff + overrides
};
class MySuperButton : public Button {
// ...
};
And I would like to hide the fact that MySuperButton inherit from Button, but not from Widget. Basically making the inheritance from Button private while keeping all its base classes public.
Why?
I have a complicated widget build on Button, which needs to maintain some invariant with its button state. Exposing it has a Button might allow something to
modify the button directly breaking these invariants.
Example:
MySuperButton button;
button.setText("Click me!") // calls Button::setText
// Oh no, MySuperButton set some special text which has now been overriden =(
What doesn't work
Making MySuperButton inherit from Button privately also hides Widget, preventing me from doing Widget things with my button.
Using access specifiers does not prevent MySuperButton to be converted into a Button.
So void doButtonStuff(Button& b); will accept a MySuperButton& just fine.
Using compositon forces me to reimplement a bunch of stuff that Button already reinmplements, just to forward it which is a PITA. Especially since the actual hierarchy is rather deep and these are big classes.
Virtual inheritance doesn't seem to work as the base isn't visible (not sure why that would be a problem though). See Godbolt
I can not modify the Button or Widget classes as they are from an external library (Qt in this case). Also the actual code is somewhat more complicated, the provided hierarchy is for illustration.
Is there any way to do this, or do I need to accept that my widget can be broken if I am not careful ?
What you are asking is not really possible.
A possible Qt-specific solution is the following:
class MySuperButton : public Widget {
public:
MySuperButton () {
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(button = new Button());
setLayout(layout);
}
private:
Button *button;
}

Creating custom buttons in QT

I have my class, which should represent buttons (pads, if I need to be specific). Right now I am wondering if it's possible to draw them in my QMainWindow class.
In first version of app I created buttons in QtCreators designer. But right now I Would like to create them by code. As said before, already got class Pad, where I want to have position, text and other behaviors. Right now my class is pretty poor:
#include <QObject>
class Pad
{
public:
Pad(int x, int y);
private:
int m_xPosition;
int m_yPosition;
};
And here is how I create them (where m_pads is std::vector )
void PadsWindow::createPads(const int &numberOfPads)
{
enablePadsWindow();
for (int index = 0; index < numberOfPads; ++index)
{
m_Pads.push_back(new Pad(10, 100));
}
}
Exactly here I would like to draw buttons in my QMainWindow and have it like normal QPushButton.
Could you help guys ?
To use a custom class as UI widget it must inherit from QWidget, which provides the necessary interface and already a lot of implementations (which you can override to customize the behaviour).
To make a widget behave like a button it is recommandable to use QAbstractButton or one of its derivations as base class, because these already provide much of the behaviour, and customizing is easier than adding all functionality to a plain QWidget.
This class can be added as custom widget to Qt Designer, so you can use it like any original Qt widget in dialogs and layouts.
You can find a lot of tutorials and FAQs regarding custom widgets on the net and here, so getting started should be easy enough for anyone who's got a grasp of the basics of Qt and C++.

Accessing widgets inside QStackedWidget

I am developing a Qt app with QtDesigner.
Previously it was quite easy to access specific widgets to do something with them like connecting signals. After I added QStackedWidget I can no longer access specific widgets with something like ui->stack->page1->widget.
Is there a way to do it somehow? Or should I always call findChild method? Or maybe it is possible to at least assign some of the nested widgets in stack widget to properties of the main windwo class?
QStackedWidget provides a method to get child widgets by index, as well as the current widget.
A quick example is as follows:
MOCed Header
class MyWidget: QWidget
{
Q_OBJECT
public:
using QWidget::QWidget
QWidget *ptr;
};
Source File
QStackedWidget *stackedWidget = new QStackedWidget;
stackedWidget->addWidget(new MyWidget); // index 0
stackedWidget->addWidget(new QWidget); // index 1
stackedWidget->addWidget(new MyWidget); // index 2
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget);
setLayout(layout);
// do something specific with the first widget's ptr element
auto* widget = stackedWidget->widget(0);
auto* mywidget = qobject_cast<MyWidget*>(widget);
if (mywidget) {
mywidget->ptr->setObjectName("FirstPage");
}
Now, Qt uses virtual interfaces by default, so if you have a custom subwidget you need to extract, you can use qobject_cast. qobject_cast is basically a fast dynamic_cast, and works even without RTTI. In template-driven code, dynamic_cast is a bit of a code-smell: it means you lost useful type information too early. With virtual interfaces, the exact opposite is true: you should use qobject_cast as needed.
Why you get the widget layer by layer, if your widgets are added in Qt designer, you can get it by ui->widget directly.

How to provide user options with expanding layouts QVBoxLayout in QT

I currently have 3 Vertical Layouts in my form. I want to provide the user the option of resizing them to their liking by stretching them. Can this be achieved with Vertical layouts ?
You can use QSplitter as said before. Even being not possible to add it by Designer, there is a way to solve. Create those frames in your widget (which have no layout), and in your cpp and h file you will do that:
in header, write
class YourClass : public QSplitter
instead
class YourClass : public QWidget
and replace in your cpp these declaration on constructor
QWidget(parent)
for
QSplitter(parent)
I guess it does (or almost, perhaps some other changes will be necessary, as add include files).
EDIT: at this time usin code in a QMainWindow class:
QSpliter *splitter = new QSplitter(this) //or declare 'splitter' in .h file.
splitter->setOrientation(Qt::Vertical);
splitter->addWidget(widget1);
splitter->addWidget(widget2);
splitter->addWidget(widget3);
setCentralWidget(splitter);
As of 4.8.6, it's possible to add a QSplitter in Qt Designer by using the Lay out [horizontally/vertically] in splitter layout option. It's somewhat surprising that it's not listed in the widget box, but you can use it.

How to specialize a widget according to a file type?

I'm looking for a way to specialize a widget at runtime. I have a form created with Qt Designer. In this form there is a widget that displays user data, like name, age and so on. Then the user chooses a file and according to the type the widget shall display additional information (like to OO example person -> student, teacher).
I tried to put an empty QWidget on my form, assigned a person widget to it and if the user clicks a button I call deleteLater() on person and assign a new Student(). This works but the new widget then doesn't follow the layout.
I also found QStackedWidget. This seems to work but because all possible widgets are created when the form is shown, even if they are never used, this way doesn't feel right.
What would be the way to accomplish this?
Edit: I feel that my question is a bit unclear. What Qt mechanism should be utilized if one wants to replace a QWidget with a specialized (inherited) version of the original widget? I'm looking for the Qt way to do this.
You need to add a widget dynamically to the widget you have drawn in the designer.
// in UI file
QWidget *wdgFromForm;
// in cpp file
QHBoxLayout *const layout(new QHBoxLayout(wdgFromForm));
SpecializedWidget * specializedWidget( new SpecializedWidget(wdgFromForm));
layout->addWidget(specializedWidget);
Maybe the problem is not that the widget is not suitable, but simply that you're not giving time for the widget to update.
You could take a look at processEvents:
http://web.mit.edu/qt-dynamic/www/qapplication.html#details
This looks like a use case for the factory pattern.
#include <map>
#include <string>
struct Whatever;
struct QWidget;
typedef QWidget*(*WidgetCtor)(Whatever*);
typedef std::map<std::string, WidgetCtor> FileFactory;
QWidget* createFoo(Whatever*);
QWidget* createBar(Whatever*);
QWidget* createDefault(Whatever*);
void factory_init(FileFactory& ff)
{
ff["foo"] = createFoo;
ff["bar"] = createBar;
}
QWidget* create_by_factory(const FileFactory& ff, const std::string t, Whatever* w)
{
FileFactory::const_iterator it(ff.find(t));
if(it != ff.end())
{
return it->second(w);
}
else
{
return createDefault(w);
}
}
Adding widgets dynamically to a layout is not a problem.
You might need to call updateGeometry on the containing widget though.