I'm looking for an easy way (I think there isn't) to serialize a QGraphicsView or QGraphicsScene into XML or JSON.
I don't know if I'm supposed to save the View or the Scene. XML or JSON are fine I only need one of them. I just want to save a scene in a file to save it/load it
I found few stuff on other websites but it's seems quite complicated, or not really functional.
First of all, check out this very useful tutorial for working with json. Secondly, I think I've read you're working with a model-view based project?
If so, all model info should be saved and then there are two possibilities (depending on your design). Let's say you have created a model class PlayerList and you are showing all players using a PlayerListLayout or PlayerListView, a derived class from QVBoxLayout. Now there are two possibilities:
In each of the view classes, you have a direct reference to the model class. Well, all you need is to ask the model using getters (these getters would exist already, else you don't want to visualize the information). You don't need the json file, as long as you initialize your model first. So, for the PlayerListLayout, all you need to do is ask each Player* of that PlayerList-member and call PlayerLayout::read(Player* player) on all PlayerLayout members of PlayerListLayout. PlayerLayout will initialize it's new player-reference and ask the name, the capital, etc. to visualize it.
In one of the view class, you have no reference to any model class. Then you shall have to pass either the model or the json file to that view class, so you can get/read the information (again). This is a less clean way, which I don't prefer. It happened to me that I was creating large functions to read; that's when I found out something had to change. Reading and writing should be easy (if you divide the responsibilities in multiple classes).
I've had a Monopoly project, where I used this serialization as well, and the tutorial was really helpful. Secondly, I opened the .json file outside the model class (so in the view class), which you might want to consider as well. The disadvantage is that "when you want wo re-use the model classes, but not the view classes", you shall have to reimplement the opening and closing of a file in your new gui.
However, this way you create parallelism throughout your code, because returning true/false will happen in the view class of the main model (MonopolyLayout in my case), so the methods Monopoly::read(...), Board::read(...) all behave in a similar way.
Related
i read the documentation http://docs.wxwidgets.org/3.0/classwx_data_view_model.html several times but it hardly answers any questions. Maybe i'm confused as to the function of this class?
so i riddle you this:
Is this a View Model as we know from MVVM?
How do you implement a derivative?
How do you set data in the containing wxDataViewListCtrl?
Is this the right/recommended way to make a table?
As its name subtly hints, wxDataViewModel is indeed the model in the usual MVC design (while wxDataViewCtrl is both the view and the controller).
You can see a couple of examples of custom models in the dataview sample.
Notice that wxDataViewListCtrl is mostly a compatibility class made for transitioning the code using wxListCtrl to wxDataViewCtrl and it already defines its own trivial list model. I don't recommend using it unless this is exactly what you need.
I may be bordering on a discussion type question here so I apologise if the question is not specific enough.
I would like to know if I my current application design is inherently weak/flawed. My background is C so I am not using clever c++ patterns to their fullest extent, of this I am sure.
My application is similar to a 3D modelling package, without geometry creation (e.g setting up animations using existing models). The user imports a geometry and can set various parameters on pre existing geometry, and there are time dependent values that relate to the whole system. The output is a text file to be processed by another application.
I am using a QTreeview to render a QStandardItemModel. I simply store pointers to my core classes in the model's items. These have specific UI for each class type, and are all descended from a common base class. They all have a QWidget which is their "mainwidget"
When the user clicks on part of the treeview, the stored class is retrieved and its mainwidget is displayed on a pane on the UI. So - treeview on the left, pane to the right with the current item's contents, and a 3D view showing the geometry.
Most of my data is stored in the classes UI elements themselves; I don't have a central database which stores anything, and when it's time to save the project, I traverse the tree and let every item write itself to a QSettings file. This feels quite naive but it does work, and the reverse happens on project load. The project class generates new classes based on the type information in the settings file and they then read the contents out of the file themselves.
Similarly when writing the output file, each item knows how to write itself and does so. Where other classes can influence the output of others (for example, start and end times), higher level classes process the children and will set start and end times based on the order and duration of each child.
Should I be storing more data in the QStandardItemModel itself, or defining my own model perhaps? Does it sound like I have set myself up for future problems?
At the moment I have modified this system a couple of times to provide customised applications, but I am about to try and make it more generic. I welcome suggestions for improving my design. Go easy, please!
You should try to avoid creating god objects. Split your tasks and duties into smaller chunks. It makes it much easier to maintain and also much easier to extend if you need to.
Your specific use-case would benefit a lot from a more complete use of the Model-View-Controller pattern.
What doesn't make sense in your design is that your data objects hold a UI element. Since only one item can be shown in the right pane, this seems like a waste of resources. It makes more sense to have a single object that then gets passed a data object to display.
What I suggest for your program is the following:
Splitting your data into classes that only have functions for reporting and modifying values. There should be no knowledge of how to display data or store to a file.
Create separate class that handles the reading and writing from a file. If your model is very simple, you could just use single functions to do this using the method shown in the documentation for QDataStream or QTextStream.
Use your QTreeView and QStandardItemModel as Adaptor class between your data objects and the left pannel.
Create a controller class that gets informed by the QTreeView if data needs to be displayed in the right panel. The controller will then retrieve the data item and pass it to the right panel in order to be displayed.
The right panel should act like another View class with the sole responsibility of graphically displaying the data passed in from the controller class.
One advantage of doing it this way is that, if there are different categories of data that get displayed differently in the right panel, the controller could examine the selected data item, determine what the category is, create a view widget to put in the right panel, and then pass it the data to display.
This pattern is open-ended as far as extendability is concerned because you do not need to change your data classes if you need a new display, you merely need to create a new right-panel widget, and then teach your controller class how to determine when the new view should be used.
Another advantage of this pattern is that you only ever need to have a single widget created to display data in your right panel. If you change your selected item, you can just pass it to the view class that already exists and get it to refresh its display with the newly selected data. You only need to distroy the right-panel view widget if a different category of data object is selected and its data needs to be drawn in a different way. The controller class can determine whether a right-panel view widget can be re-used or whether it needs to be swapped out for a different widget.
i'm need your help again.
I have an document viewer application what can read two different kinds of documents:
Special one (based on PDF, with custom header)
Standart one ("raw" PDF).
With raw PDF viewer should acts like any other one.
With custom - execute some additional actions during it's opening, which are not available to raw PDF.
These actions should be available later in the application's menu only. And only for custom document.
Project OOP architecture (designed by other man) looks like this:
class GenericDocument
class PdfLibDocument
class CustomDocumentHighLevel
class CustomDocumentLowLevel
I.e. each higher-level class contains the lower-level one as member:
class GenericDocument
{
SmartPointer< PdfLibDocument > m_document;
...
};
and so on.
Custom document has much specific functionaly:
class CustomDocumentLowLevel
{
public:
void DoSomeBlackMagic();
...
// Another black magic
};
The problem occurs then i need to "pull" some low-level method from CustomDocumentLowLevel to GenericDocument (to show in app menu) - because i need to add this method to ALL FOUR classes!
And probably in the future i need to "pull" more methods from custom document.
Looks like this software architecture is bad choice in such case, isn't it?
So i need find a way to refactor this code. Should i replace aggregating with inheritance? Introduce interfaces?
Usually composition is preferred over inheritance, but it doesn't seem applicable to your case. Why not to inherit Viewers from one another? Make a base viewer with a simple functionality, available all over and then inherit specialised one from it adding new functionality.
As for menu and actions, connected with it, they should be represented as a separate objects. Check Command pattern for that.
UI can request available command list from your Viewers. Each viewer can fill its internal command list on initialization or construction or whatever you choose.
In Qt, I'm writing my own tree model (by subclassing QAbstractItemModel) which wraps around an existing data structure. It should be possible to update the data structure internally (not via the model) as well as via the model (so views can change it). In order to imagine it better: it's a scene graph which should be possible to edit using a scene view (without going via the Qt model) but also using an outliner (QTreeView which uses a Qt model as a proxy around the scene graph).
To avoid confusion we should consider two different scenarios (in the following, I use the "remove" operation as an example):
The user uses the Qt view to remove a node. The view wants to remove a row from the model using QAbstractItemModel::removeRow. This should in turn remove a corresponding node from the underlying data structure, the scene graph.
The user uses the scene view to remove a node. The scene view wants to remove a node from the scene graph. The model which wraps around the scene graph gets notified and in turn wants to notify connected views that a row has just been removed.
While I think I know how to implement 1., I don't know how to implement the notifying part in 2. There is the signal QAbstractItemModel::rowsAboutToBeRemoved() as well as rowsRemoved() which sound like they're my friends. But they are private signals (they say in the header source code: "can only be emitted by QAbstractItemModel"). There also is beginRemoveRows() and endRemoveRows() but according to their documentation, they should be called when the updates happens from the view, i.e. when removeRow has been called. Also, when I tried to use them, the view was screwed up totally.
According to the documentation it seems like it's not intended that the model class can model self-modifying data. Let's take a file system as another example. When using file system watching, which can detect changes in directories, a model should notify a view so the changes in the directory can be displayed live, even if the view was not used to modify the file system. Are such models even possible in Qt?
You're reading it wrong. The model must signal to its users when it's about to start changing its "geometry". So, no matter what is removing the rows from the model, it must tell the outside world that it happened. The sequence of events when a view removes rows from the model is such:
The view calls model->removeRows().
The model calls beginRemoveRows()
The model actually removes the rows from the internal data.
The model calls endRemoveRows().
If you implement some other interface that will remove the rows without calling model->removeRows(), you have to do exactly the same thing. It doesn't matter if it's a view or some other code that removes rows from the model, the model's behavior must be the same or else nothing will work.
You can architect an adapter class that's inserted between your SceneGraph and the Model. It should hold a pointer to the scenegraph and the model, and translate the operations between the two.
Background
We use the Model-View-Presenter design pattern along with the abstract factory pattern and the "signal/slot" pattern in our application, to fullfill 2 main requirements
Enhance testability (very lightweight GUI, every action can be simulated in unit tests)
Make the "view" totally independant from the rest, so we can change the actual view implementation, without changing anything else
In order to do so our code is divided in 4 layers :
Core : which holds the model
Presenter : which manages interactions between the view interfaces (see bellow) and the core
View Interfaces : they define the signals and slots for a View, but not the implementation
Views : the actual implementation of the views
When the presenter creates or deals with views, it uses an abstract factory and only knows about the view interfaces.
It does the signal/slot binding between views interfaces. It doesn't care about the actual implementation. In the "views" layer, we have a concrete factory which deals with implementations.
The signal/slot mechanism is implemented using a custom framework built upon boost::function.
Really, what we have is something like that : http://martinfowler.com/eaaDev/PassiveScreen.html
Everything works fine.
The problem
However, there's a problem I don't know how to solve.
Let's take for example a very simple drag and drop example.
I have two ContainersViews (ContainerView1, ContainerView2). ContainerView1 has an ItemView1. I drag the ItemView1 from ContainerView1 to ContainerView2.
ContainerView2 must create an ItemView2, of a different type, but which "points" to the same model object as ItemView1.
So the ContainerView2 gets a callback called for the drop action with ItemView1 as a parameter. It calls ContainerPresenterB passing it ItemViewB
In this case we are only dealing with views. In MVP-PV, views aren't supposed to know anything about the presenter nor the model, right ?
How can I create the ItemView2 from the ItemView1, not knowing which model object is ItemView1 representing ?
I thought about adding an "itemId" to every view, this id being the id of the core object the view represents.
So in pseudo code, ContainerPresenter2 would do something like
itemView2=abstractWidgetFactory.createItemView2();
this.add(itemView2,itemView1.getCoreObjectId())
I don't get too much into details. That just work. The problem I have here is that those itemIds are just like pointers. And pointers can be dangling. Imagine that by mistake, I delete itemView1, and this deletes coreObject1. The itemView2 will have a coreObjectId which represents an invalid coreObject.
Isn't there a more elegant and "bulletproof" solution ?
Even though I never did ObjectiveC or macOSX programming, I couldn't help but notice that our framework is very similar to Cocoa framework. How do they deal with this kind of problem ? Couldn't find more in-depth information about that on google. If someone could shed some light on this.
I hope this question isn't too confusing ...
Ok the technique I found is actually coming from Cocoa, so it's objective-C but you can definitely do the same in C++.
The solution is simply to use a PasteBoard (developer.apple.com documentation).
In the hope it helps someone ...