Qt Widgets and derived classes - c++

I am wondering if there is a way to do this.
I create a Qt Application (using Creator 3.6.1, Qt 5.6.0).
I add a widget to the main window. For example a QGraphicsView called myView.
I create a C++ class derived from QGraphicsView (called DerivedView)
code of DerivedView class:
class DerivedView : public QGraphicsView {
...
I would like my new DerivedView class to control this widget. I can access a pointer to the object through ui->myView. Is there any way to do get my derived class to work with the already instantiated QGraphicsView?
DerivedView * dView = ui->myView;
Or do I need to not derive my class from QGraphicsView and just add a pointer as a data member?
class DerivedView {
QGraphicsView * gv;
...

You should promote your QGraphicsView to DerivedView, for this follows the following steps.
Right click on QGraphicsView and select promote to ..:
And add the name of the class and header
And press add.
And then press on promote.
After this, ui->myView is already a member of the DerivedView class

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

Using Interface class in form, in order to use the derived class desired

I would like to use different custom widgets on the same area (that depends on the situation). For that I created an Interface class and some derived custom classes widgets (because they have same methods and for the cleanliness).
My Interface is :
IDial
Derived Classes :
FirstDial, SecondDial
These derived classes inherit from IDial, so they have common functions from IDial.
When I start my program, I would like to chose which dial I will display, it depends of macros or parameters (it's not important).
In order to be able to display the derived class (widget) that I want, I have no other choices than put the Interface class name (IDial) as "objectName" of my widget area in the form (design mode).
The problem is that Qt is trying to instantiate this Interface... (it's impossible and normal because of pure virtual functions).
I would like to indicate that the area can contain different widgets, which all inherit from this Interface.
Instead of class IDial, add QFrame to the place where you want. In your header file:
#include "firstdial.h"
#include <QHBoxLayout>
...
QHBoxLayout* layout;
FirstDial* firstDial;
In source file create new layout and object of your class:
ui->frame->setFrameShape(QFrame::NoFrame); // a frame you've created
layout = new QHBoxLayout(ui->frame);
firstDial = new FirstDial;
Add your widget to layout:
layout->addWidget(firstDial);

C++ Qt Derived Classes

I'm trying to learn Qt and C++ and having some trouble understanding the C++ this keywork. I've seen examples where a class is derived from QMainWindow and then within the class member functions, a QMenu is added. One example is the "Simple menu" program described on this page:
http://www.zetcode.com/gui/qt4/menusandtoolbars/
In that example, a quit action is created with
QAction *quit = new QAction("&Quit", this);
However, imagine I want to also derive a class from QMenu and use that to create my menu.
mymenu.h
class MainWindow; // forward declaration
class MyMenu : QMenuBar
{
public:
MyMenu(MainWindow *main_window);
};
mymenu.cpp
#include "mymenu.hpp"
MyMenu::MyMenu(MainWindow *main_window) : QMenuBar()
{
QAction *quit = new QAction("&Quit", main_window); // Notice here I replaced
// 'this' with 'main_window'
QMenu = *file;
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
Unfortunately this doesn't work because QAction expects a QObject as a parent. All that being said, there are a couple things that don't make sense to me:
If the class MainWindow inherits from QMainWindow, doesn't that make 'MainWindow' a QObject?
What is the difference between passing 'this' to QAction from within the class MainWindow, as opposed to passing 'main_window' which is (as far as I can tell) also a pointer to the instance from within the MyMenu class?
I apologize for such a long winded question, but if any of you have made it to the end with me, I would love any suggestions as to what I am missing here. The end goal here is just to create a derived class of QMenu (MyMenu here) and add it to the QMainWindow derived class (MainWindow here) existing in a separate class. Thank you for your time.
If the class MainWindow inherits from QMainWindow, doesn't that make 'MainWindow' a QObject?
Yes, MainWindow is a QMainWindow which is a QObject (you can see this by browsing the inheritance tree on the API docs).
You have only forward declared MainWindow. Since the compiler does not have a definition for the class MainWindow it can only do miminal things with a pointer to MainWindow. In order for the compiler to "know" that MainWindow is a QMainWindow which is a QObject, you must provide a class definition for MainWindow. You can solve your compiler error with:
#include "MainWindow.h"
No dynamic cast is needed
Also, in Qt land to make something "really" a QObject you should put the Q_OBJECT macro on the object:
class MyMenu : QMenuBar
{
Q_OBJECT
public:
MyMenu(MainWindow *main_window);
};
It might save you a few headaches later on if you ever plan to use the object for signal/slots or other Qt stuff.
What is the difference between passing 'this' to QAction from within the class MainWindow, as opposed to passing 'main_window' which
is (as far as I can tell) also a pointer to the instance from within
the MyMenu class?
this is a pointer to your custom MyMenu class which is also a QMenuBar. main_window is a pointer to your custom MainMenu class which is also a a QMainMenu. So, two different objects in memory. The second argument of the QAction constructor takes a pointer to a parent widget. The parent widget is responsible for managing the memory of its children. Since it takes a QObject its reasonable to pass in either this or main_menu.
Also you should probably pass a parent to the QMenu constructor.
MyMenu::MyMenu(MainWindow *main_window) : QMenuBar(main_window)
This way MyMenu is correctly deleted when the MainWindow is deleted.
The usual Qt paradigm is:
MyMenu::MyMenu(<arg1>, <arg2>, ... QObject * parent) : QMenuBar(parent)
But in this case forwarding along main_window is good enough.

Subclassing QGraphicsItemGroup

I have system that has classes derived from QGraphicsWidget. I manage derived class objects in layouts on QGraphicsScene. Now I need a compound item that contain two or more QGraphicsWidget in it and also I need to put that item inside my layout. So I choose QGraphicsItemGroup and write I class like this.
class CompositeItem : public QGraphicsItemGroup,public QGraphicsLayoutItem
{
...
};
I only implemented sizeHint function again.
When add CompositeItem instance to layout it does not shown.
What may cause this? Where I made wrong?
Call show() on either the QGraphicsItemGroup or QGraphicsWidgets after adding to the layout.
Add setGraphicsItem( this ) to your constructor.