Qt Extending my own widget - c++

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

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

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

I would like to use the span slider from Qxt without having to install it. Is this possible?

I stumbled across a widget that provides you with a slider with two handles so you can select a range between an upper and lower limit.
I would like to use it without having to install all of Qxt though, since I am pretty sure this is the only thing that I need.
How can I deal with qxt_p() in order to use this widget as a standalone?
You need to add the following in the main class:
private:
QxtSpanSliderPrivate* d_ptr;
friend class QxtSpanSliderPrivate;
And in the following in the private class:
private:
QxtSpanSlider* q_ptr;
friend class QxtSpanSlider;
Also you should remove Qwt macros usage and replace qxt_d() and qxt_q() with direct access to q_ptr and d_ptr.
Each constructor of the main class should initialize both pointers:
QxtSpanSlider::QxtSpanSlider(Qt::Orientation orientation, QWidget* parent) :
QSlider(orientation, parent),
d_ptr(new QxtSpanSliderPrivate())
{
d_ptr->q_ptr = this;
//...
}
In case I forgot something, here is the gist. This code allowed me to successfully use QxtSpanSlider in Qt5.

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.

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

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