I have several different classes derived from QGraphicsItem or its children (like QGraphicsRectItem). I am at the point when I need to copy selected objects of those classes while not knowing exactly which one I copy.
Since QGraphicsScene::selectedItems() return a list of selected items I decided to use it, however I cannot copy the QGraphicsItem since its an abstract class. To address this I am trying to copy the object using malloc and memcpy.
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene();
item = new QGraphicsRectItem(50,50,50,50);
item->setFlag(QGraphicsItem::ItemIsSelectable);
scene->addItem(item);
item->setSelected(true);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
for(QGraphicsItem *item : scene->selectedItems())
{
QGraphicsItem *copiedItem=(QGraphicsItem *)malloc(sizeof(*item));
memcpy(copiedItem, item, sizeof(*copiedItem));
copiedItem->moveBy(50, 50);
scene->addItem(copiedItem);
qDebug() << item;
qDebug() << copiedItem;
}
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QGraphicsScene *scene;
QGraphicsRectItem *item;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
GUI consisting of QGraphicsView and QPushButton is sufficient for this example.
This code seem to work, item and copiedItem have different addresses but the same properties as qDebug() returns.
The scene however return the following error:
QGraphicsScene::addItem: item has already been added to this scene
I don't quite understand why the scene thinks the items are the same while they have different addresses. Is there any way to solve this issue?
EDIT:
If possible I would like to do this without modifying the code of classes derived from QGraphicsItem, since this is a group work and I would not like to bug other functionalities.
If you look at the class definition inside qgraphicsitem.h, you'll see the following:
private:
Q_DISABLE_COPY(QGraphicsItem)
Q_DECLARE_PRIVATE(QGraphicsItem)
What this means is that, by design, you are not supposed to copy a QGraphicsItem, each object is supposed to be unique.
EDIT:
I would imagine that the reason that you are denied the copying ability is because QGraphicsItem follows the Composite Design Pattern. Creating a copy of a single object that has child items would result in child items having more than one parent. To get round that, you'd have to not only copy the item you're interested in but every child in the child hierarchy as well. For very large hierarchies, this can become a very time-consuming operation.
If you really feel that you need to make copies, you can create a cloning factory function/class that creates a clone of the QGraphicsItem and all it's children by going through all the object's properties and transferring them to a newly created QGraphicsItem.
If this is not feasible, perhaps think about accomplishing your goal in a different way.
You really want to be using the copy constructor or the assignment operator, not malloc and memcpy. This is how you copy objects in C++:
QGraphicsItem copiedItem = *item;
The problem of copying a class by block copying its memory with malloc is that if the class contains pointers to objects or arrays, then only a shallow copy will occur.
In your case of getting pointers to a QGraphicsItem, you'll need to identify the type of item you're copying (its actual child class, not base class) and use the copy constructor. QGraphicsItem includes a function called type(), which returns an int that indicates which item it is. You can also add to this in your own derived classes by implementing the type() function. For example, from the Qt docs: -
class CustomItem : public QGraphicsItem
{
...
enum { Type = UserType + 1 };
int type() const
{
// Enable the use of qgraphicsitem_cast with this item.
return Type;
}
...
};
Alternatively, if all the classes are your own type, you could use your own system.
Once you know the type, you can then copy the item with its copy constructor: -
// Example, assuming type denotes a QGraphicsItemRect
QGraphicsItemRect rect = (*originalRect);
Note that if you have inherited from QGraphicsItem and added members that are pointers, you'll need to add your own copy constructor to ensure a deep copy occurs, instead of a shallow copy.
Related
The title of the question is not very clear, I'll try to explain better.
I'm using Qt and the windows I'm working with derive (directly or indirectly) from QWidget. My windows has to be treat uniformly, so that I can take a pointer to the currently active window and invoke methods on it not knowing the actual window class, for this reason all my windows derive from another class, let's call it "myScreen". So far so good.
Now I would like to handle in "myScreen" also the hiding and showing of a window, so that it's uniform. For example passing from a window to another may imply calling "hide()" on the current window and "show()" on the new window. Since "myScreen" and QWidget don't have any relationship, I must use dynamic_cast to cast the windows that I know derive from "myScreen" and "QWidget" inside "myScreen" methods, in order to call the functions of QWidget just mentioned.
I know that probably the best way could be having "myScreen" derive from QWidget and all of other windows derive from that, but my goal is to change as little as possible the existing code. I also tried using virtual inheritance, but this approach can't work because of the files generated automatically by the moc (see this link Cannot convert from pointer to base class to pointer to derived class).
By now I managed to ensure that a constructor of "myScreen" is called by a class that derives from QWidget:
struct isQWidget{
class QWidgetType{
QWidgetType(){}
friend struct isQWidget;
};
template<class T>
static QWidgetType isQwidgetType(const T&){
static_assert (std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
return QWidgetType();
}
};
Constructor declaration:
myScreen(myScreen& parentScreen, isQWidget::QWidgetType);
Constructor definition:
sigin::sigin(QWidget *parent, myScreen& si) :
QWidget(parent),
myScreen(si, isQWidget::isQwidgetType(*this)),
ui(new Ui::sigin)
{
ui->setupUi(this);
}
I would like to treat a pointer to myScreen as a pointer to QWidget inside "myScreen" compile-time, since I know I will always use something that derives from QWidget.
Any idea on how I can manage this problem?
I had something like this in mind
template <typename T>
myScreen::myScreen(T &parent)
{
static_assert(std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
QWidget &parentQt = dynamic_cast<QWidget&>(parent); // guaranteed to succeed in runtime by the above
...
}
So for parent which does not inherit from QWidget that would be a compilation error, and which does would always cast successfully.
I know that, in Qt, parent object takes ownership of its child objects. However, if I have my own class deriving from a Qt class, do I need to control memory in my derived-class' destructor or does Qt do it for me? Below is an example:
#include <QWidget>
#include <QPushButton>
class MyWidget: public QWidget{
public:
MyWidget(QWidget* parent = 0): QWidget(parent) {
this->setAttribute(Qt::WA_DeleteOnClose);
m_button = new QPushButton(this);
}
~MyWidget() { delete m_button; } // do I need this to prevent leaks?
private:
QPushButton* m_button;
}
So my question is, do I need ~MyWidget() to prevent memory leaks? Or would QWidget somehow manage the memory for me?
No you don't, QObject handles that. Everything derived will be collected as long as it is in a parent-children tree. QWidget inherits QObject and you inherit QWidget. So you are all set.
Note that there are still many Qt types which do not inherit QObject. Better look at the doc to be sure.
The MainWindow code generated by QtCreator says:
namespace Ui {
class MainWindow; // forward-declare Ui::MainWindow (?)
}
class MainWindow : public QMainWindow // Declare MainWindow class (Ui::MainWindow?)
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0 );
/**/ ~MainWindow( void );
// ...
private:
Ui::MainWindow *ui;
// ...
};
main() does:
MainWindow w;
w.show( );
MainWindow::MainWindow( QWidget *parent ) does:
ui( new Ui::MainWindow ) // Initialization
I don't understand why a MainWindow instance has a pointer to another/a different/a new MainWindow in its ui instance variable. I instrumented the MainWindow::MainWindow constructor, and I can see it's only being called once. So presumably that's the automatic variable on the stack in main(). But what about the ui( new Ui::MainWindow ) that happens in the constructor? That's creating a MainWindow on the heap, isn't it? How is it being initialized?
Maybe the subsequent ui->setupUi( this ) in the constructor is doing some magic? Otherwise, it seems like this would recurse to stack crash, as each new MainWindow creates a new MainWindow to populate its ui instance variable.
The Ui::MainWindow class is code generated by uic from the respective QtDesigner file.
It is not a widget but a helper that contains code to populate a widget.
So in your case it is code that is used to populate a QMainWindow derived class named MainWindow.
Ui::MainWindow is held as a pointer to allow forward declaration and avoid build dependencies of code including MainWindow's header to the generate code (which will change everytime you change something in QtDesigner)
There are two different classes in play here:
::MainWindow
::Ui::MainWindow
I wouldn't go so far as to say they are not related - but they are not the same class.
For several graphic objects I inherit from QGraphicsLineItem, QGraphicsRectItem and so on.
class CustomLine : public QGraphicsLineItem{};
class CustomRect : public QGraphicsRectItem{};
Those objects are added to a container, a custom subclass of a QGraphicsScene "scene" that is meant for displaying and interacting with those items. this->scene->items() returns a list of QGraphicItem's: QList<QGraphicsItem* >
What I want to do is each custom object class to have the same custom interface methods, for example setModeX(). Then I could do stuff like:
Foreach (BaseItem *item, this->scene->items()){
item->setModeX(...);
}
But how do I achieve that?
If I make an interface like
class BaseItem{
public: setModeX(); [...]
private: Mode mode_;
}
and inherit
class CustomLine : public QGraphicsLineItem, BaseItem {};
So while the scene should only contain items based on BaseItem (not sure if this is really needed for this task), I first retrieve a list of objects of one of its 2 base classes, namely QGraphicsItem, and need to cast it to its other base class BaseItem to use the interface methods.
I will probably not be able to cast a CustomLine-item to BaseItem in the loop above, because it does not know about the other base class.
EDIT:
I use MinGW 4.8 32 bit (g++).
I noticed that when I start the foreach-loop, the items in my scene disappear (yet don't see the reason why)
Since scene is a QGraphicsScene, it only consists of QGraphicsItems. So you cannot directly iterate over scene as BaseItems as you show in your code. You have to iterate over each QGraphicsItem. You describe that you could downcast to your CustomLine and then upcast back to a BaseItem, but this only works if you know that all the items in the scene are lines. If scene contains other types of items, your technique would require you to iterate of each kind of item until you found a downcast that worked, and then cast it back to BaseItem.
QGraphicsItem
\ BaseItem
QGraphicsLineItem /
\ /
CustomLine
A simple solution would have been available to you if the Qt library had used virtual inheritance on QGraphicsItem. Then, you would simply need to use virtual inheritance on QGraphicsItem from BaseItem, and then down casting would have worked.
QGraphicsItem
/ \
QGraphicsLineItem BaseItem
\ /
CustomLineItem
Since Qt does not do so, you would either need to make custom changes to the Qt library, or code in your own conversion mechanism.
Assuming you are unwilling to make custom modifications to the Qt library itself, then one approach is to create a mapping between Qt's QGraphicsItem and your BaseItem. The mapping can be done within the constructor of your BaseItem, and undone from BaseItems destructor. To make undoing the mapping more efficient, you can also create a link from the BaseItem to the QGraphicsItem.
class BaseItem {
static std::unordered_map<QGraphicsItem *, BaseItem *> map;
QGraphicsItem *link_;
public:
BaseItem (QGraphicsItem *q) : link_(q) {
//...
map[q] = this;
}
virtual ~BaseItem () {
map.erase(link_);
//...
}
static BaseItem * getBaseItem (QGraphicsItem *q) {
std::unordered_map<QGraphicsItem *, BaseItem *>::iterator i;
if ((i = map.find(q)) == map.end()) return NULL;
return i->second;
}
//...
};
//...
std::unordered_map<QGraphicsItem *, BaseItem *> BaseItem::map;
In your derived classes, you would simply need to pass this to the BaseItem constructor.
class CustomLine : public QGraphicsLineItem, public BaseItem {
public:
CustomLine () : BaseItem(this) {
//...
};
//...
};
And then your loop would use the static BaseItem::getBaseItem() function to convert from a QGraphicsItem pointer to a BaseItem pointer. Thus, since there is no way to create a useable inheritance relationship between QGraphicsItem and BaseItem, their relationship is recorded in a table.
QGraphicsItem <-----------------. link
\ BaseItem <--' map
QGraphicsLineItem /
\ /
CustomLine
Should work just fine, but remember to declare the interface methods virtual in the base class, at least if you want polymorphic behavior.
Declare the functions that you want to exist in every derived class as virtual in the base class. A function that is defined as virtual in the base class can give a default implementation, but derived classes are free to override that implementation and provide their own. You can also declare that function "purely virtual" which means derived classes MUST provide an implementation for that particular function.
In either case, when calling that function on an instantiated object pointed to by a pointer of the base class, it will notice that the base class declared the function to be virtual and use a virtual table (vtable) to find which function to call (As in the base class' definition of the function, if it exists, or the derived classes version of the function).
It seems like there are some constraints on your problem that make this more of an issue than it should be. If you can't control the underlying pointers in your scene, but you know that each of those items inherits from BaseItem, then you can do a cast inside your for loop.
For instance, using the structure you have above:
Foreach (QGraphicsItem *item, this->scene){
((BaseItem*) item)->setModeX(...);
}
Of course, this is only if you can guarantee that the objects in your scene are derived from BaseItem.
CRTP to the rescue:
template <class D> class Base {
D& m_d;
public:
Base(D& derived) : m_d(d) { ... }
...
};
class CustomLine : public QGraphicsLine, Base<CustomLine> {
...
CustomLine() : Base(*this) { ... }
};
I'm fighting with Qt. Cannot find out reliable solution for my specific problem.
We have custom class MyWidget that must:
be derived from QWidget to override closeEvent method
have fields that must be initialzed in constructor
Problems:
QWidget's guts initialized with QUiLoader from .ui file. So I have only QWidget* pointer
QWidget is non-copyable.
QWidget has no move constructor
The code (error checking and memory management are omitted for simplicity):
class MyWidget : public QWidget
{
bool m_Closed;
public:
MyWidget(QWidget* qw) :
QWidget(*qw), // error: copy constructor is private
m_Closed(false)
{}
bool IsClosed() const { return m_Closed; }
virtual void closeEvent(QCloseEvent *) override { m_Closed = true; }
};
QFile file("main.ui");
QUiLoader uiLoader;
MyWidget* uiMain = new MyWidget(uiLoader.load(&file));
uiMain->show();
Questions:
How can I workaround this? I feel that solution is very simple.
Can I use move semantics here somehow?
Note that:
I cannot make QWidget member, as I need to override its method.
Probably, I can make some MyWidget::Init() method, to init those bool flag, which must be called after each instantiation. But I find this solution unreliable.
In the end, I must just have QWidget, that I can check if it was closed or not (maybe you know another, simple way)
I use MSVC 2013 RC and GCC 4.8.1, so C++11 solution would be great
Do not hesitate, I appreciate any suggestions and criticism.
.ui files can use custom classes that derive from QWidget, so you can use your class in the Designer - even without writing any Designer plugins (it won't be shown). Right-click on a widget and select "Promote".
You need to create your own derived version of QUiLoader, and provide an implementation of the factory method QUiLoader::createWidget that can create your widgets. See this answer for a complete example.
Then you put your initialization code in the derived widget.