my question is about Qt and its QAbstractItemModel.
I have a map of strings and doubles (std::map<stringclass, double>) which I would like to present in a Qt widget. While I could use QTableView for that, I would like to exploit the fact that the keys of the map are of form "abc.def.ghi" where there can be multiple strings that can start with "abc.def" and even more that start with "abc".
So I would like to setup a tree data model to present the items in a QTreeView like
(-) abc
|--(-)def
|--ghi 3.1415
|--jkl 42.0815
|--(+)pqr
|--(+)xyz
The keys of my std::map are the leaves of the tree, where all other nodes would be temporary and auxillary constructs to support the folding for user convenience.
Unfortunately, the methods rowCount, index, columnCount, and data have const-modifiers, so I cannot simply setup a auxillary data structure for the headers inside my QAbstractItemModel derivate and change that data structure in there.
What would be the best practice for that? Should I setup another class layer between my std::map and the QAbstractItemModel or is there a smarter way to do this?
Edit 1: The std::map can change while the QTreeView is shown and used, so the auxillary nodes might be thrown away and reconstructed. My assumption is that the best way to handle this is to restructure the QAbstractItemModel - or should I simply throw that model away and assign a newly constructred one to the QTreeView? In that case I could set-up all nodes within the constructor without being bothered by the const-ness of the methods, I guess.
I would parse the map and create a tree data structure based on it. Make sure you sync the model when you change the map.
If this sync step gets too complicated you might want to hold your data in a tree structure from the start and convert to a map when necessary.
Parsing the map on the fly in the model functions seems like a bad idea to me, you'd want these functions to be as fast as possible.
I don't see how const-modifiers would really be an issue.
What members of your QAbstractItemModel derivate would you want to modify when rowCount, index, columnCount and data methods are called ? You may very well store a reference to your map, and compute everything from it. No need to modify the map itself to extract the needed information (as far as i can tell !).
EDIT after EDIT1 and comments :
If your map is bound to be modified, use it as your base structure in your own class.
If you can't keep a reference to your map because the model's lifetime might exceed the map's, use smart pointers to make sure it does not happen.
Related
I’m trying to cut down on the amount of network queries in my c++ program (to increase speed), and when displaying search results, I don’t want each (of the sometimes thousands) of objects found in the search to initialize themselves completely from the database when I only need to display part of this information.
It is much faster to perform one bigger query where I get all the information I want to display about the objects at once in the query (for example, for each object/row I select the id, the name and the location), passing them to a bigger constructor, and letting all other members be default values. Previously, and in other cases where I need the complete object, I just pass the ID to the object, then call initializeFromDatabase() directly to set all the other values.
//current solution (problem is, I might need many constructors like this for different purposes)
auto *myobject = new MyObject(345, "ObjectName", "Europe");
//no further (costly) initialization since I only need the following 2 values for my search results.
myobject->getName();
myobject->getLocationName();
//prevous solution (resulting in too many queries)
auto *myobject = new MyObject(345);
myobject->initializeFromDatabase();
myobject->getName();
myobject->getLocationName();
//I could also query the other 30 or so members here, everything is set.
This doesn’t feel like good practice though, I would need other custom constructors for say, another search window displaying other kinds of data about the objects.
Are there any general best practices / a suitable design pattern to solve this sort of problem? Should I create a “Search object” that is its own class and that can then be used to create the complete object when needed? Or always initialize with only the database ID (setting a flag that the object is not initialized yet) and use the setters I need?
I found that a solution to this would be to use some sort of Lazy Loading, since I want to quickly load part of the object for the list, then load all of it if a user clicks on one of the objects. For example, a Virtual Proxy or the Ghost Design pattern would be suitable. I simply create a proxy object for displaying the search results (and for other lists in the program) that can create the full object on demand. Every proxy object has one constructor so I avoid the problem of using lots of different constructors for different purposes.
See Chapter 11 of Patterns of Enterprise Application Architecture by Martin Fowler (published by Addison-Wesley Professional, 2002)
I have to access my objects (multiple instances from one class) via several different identifiers and don't know which is the best way to store the mapping from identifier to object.
I act as a kind of "connector" between two worlds and each has its own identifiers I have to use / support.
If possible I'd like to prevent using pointers.
The first idea was to put the objects in a List/Vector and then create a map for each type of identifier. Soon I had to realize that the std-containers doesn't support storing references.
The next idea was to keep the objects inside the vector and just put the index in the map. The problem here is that I didn't find an index_of for vector and storing the index inside the object only works as long as nobody uses insert or erase.
The only identifer I have when creating the objects is a string and for performance I don't want to use this string as identifer for a map.
Is this a problem solved best with pointers or does anybody have an idea how to deal with it?
Thanks
Using pointers seems reasonable. Here's a suggested API that you could implement:
class WidgetDatabase {
public:
// Returns true if widget was inserted.
// If there is a Widget in *this with the same name and/or id,
// widget is not inserted.
bool Insert(const std::string& name, int id, const Widget& widget);
// Caller does NOT own returned pointer (do not delete it!).
// null is returned if there is no such Widget.
const Widget* GetByName(const string& name) const;
const Widget* GetById(int id) const;
private:
std::set<Widget> widgets_;
std::map<std::string, Widget*> widgets_by_name_;
std::map<int, Widget*> widgets_by_id_;
};
I think this should be pretty straightforward to implement. You just need to make sure to maintain the following invariant:
w is in widgets_ iff a pointer to it is in widgets_by_*
I think the main pitfall that you'll encounter is making sure is that name and id are not already in widgets_by_* when Insert is called.
It should be easy to make this thread safe; just throw in a mutex member variable, and some local lock_guards. Optionally, use shared_lock_guard in the Get* methods to avoid contention; this will be especially helpful if your use-case involves more reading than writing.
Have you considered an in-memory SQLite database? SQL gives you many ways of accessing the same data. For example, your schema might look like this:
CREATE TABLE Widgets {
-- Different ways of referring to the same thing.
name STRING,
id INTEGER,
-- Non-identifying characteristics.
mass_kg FLOAT,
length_m FLOAT,
cost_cents INTEGER,
hue INTEGER;
}
Then you can query using different identifiers:
SELECT mass_kg from Widgets where name = $name
or
SELECT mass_kg from Widgets where id = $id
Of course, SQL allows you to do much more than this. This will allow you to easily extend your library's functionality in the future.
Another advantage is that SQL is declarative, which usually makes it more concise and readable.
In recent versions, SQLite supports concurrent access to the same database. The concurrency model has gotten stronger over time, so you'll have to make sure you understand the model that is offered by the version that you're using. The latest version of the docs can be found on sqlite's website.
I recently worked on a small game project where the player would be granted a random item at a certain point. The items (about 50 or so) were implemented as sub-classes of a virtual Item interface. We needed a way to select one of those items randomly and give an instance of the specific class to the player.
Our solution was to create some container (e.g. std::list) and insert an instance of each item we implemented. The item implementations had to provide a copy constructor, so that we could just create a copy for the player who gets the item. Voilà!
The downside is clear: it's very easy to forget inserting an item, and being careless with the copy constructors can lead to bugs that are not so easy to track. Since it was prototype code we didn't bother too much, but I wonder if there is a prettier way. An ideal solution would include:
Automatic "registering" of items, somewhere.
A way to choose one item at random and instantiate it.
No need for writing copy constructors for each item.
Thanks for your hints and suggestions!
Daerst
You can create a factory to create items. The factory will then also register the create item in the container. I'd like to use shared pointer for players! But that'd be up to you.
This way you can ensure that items will be created through a single interface. And also the common logic for inserting items etc. is implemented at a single place.
There are details that are not clear in your question. For example, based on my interpretation of your question it would seem that you are hard coding the specifics of your items? Based on the assumption that you're current prototype is hard coding the details of your items for your game I would:
Separate the content from the code - This is important because changing content values will require you to recompile, or more importantly, expansion of the total number of items will soon become burdensome and error prone.
Create a generic class that represents an item with all of the appropriate fields necessary to populate this item class with the relevant details of the item.
2A. If your items do not have similar properties, you could use some sort of self-describing array of the custom aspects of the item. For example, Item A is unique and has a flavour property. You would have a a two dimensional array [1][2] with it's values being [1][1] = flavour [1][2] = blueberry.
Create a class that acts as a container for items.
In the container class, implement a method to instance a random item (pulling the details about the item from the database or other storage mechanism), and adding it to the containers collection of "loaded items" - effectively "registering" it. The two obvious benefits to having this container class is that once an item is loaded, and if you then choose another random item that happens to be one already loaded, you don't have to load it again and secondly, you are using less memory until the entire item set has been loaded.
In the container class, implement a method to copy an instanced item to the player class. - OR - create an interface in the container class that your player class implements to request a new random item - which would then call upon the method to instance a random item.
Hope this helps in your brainstorming!
Add the items to the vector right inside the constructor of the Item class. That way you won't need to add every single item "by hand", they'll be added upon creation.
Instead of copying the items, make them singleton classes and instead of 'giving' the user an item, just use a pointer to a place inside your vector.
That being said, your problem is strictly connected with the bad design of the game. Items shouldn't be derived classes, but instances of a generic item class. But since other people already mentionned it, I don't think typing it once more would be any help to you :)
I'm currently migrating my project from QTreeWidget to QtreeView, and have a lot of problems caused by poor understanding of the Qt model-view design. So far I couldn't find answers even in Qt examples.
I've implemented my QAbstractItemModel. I'm returning strings to be viewed in the QTreeView through data method. Now, the underlying data will change in runtime. To handle this my model is subscribed to a notification that does emit dataChanged(index(0,0), index(rowCount() - 1, LastColumn));. The question is: how to create and cleanup QModelIndex objects? One of the Qt examples reimplements index method, so I did the same:
QModelIndex CFileListModel::index(int row, int column, const QModelIndex &/*parent*/) const
{
QModelIndex index = createIndex(row, column);
return index;
}
However, data is static in that example and in my case it changes at runtime. Is my index implemetation correct? What if index is called more than once for the same coordinates? Do I need to somehow cleanup old indexes before emitting dataChanged?
Your question about "deletion" of indices makes no sense in the light of the semantics of C++. There is simply no way for you to destroy an object that you returned by value from inside of a function - at least not without resorting to purposeful dirty hacks. So let's forget about it.
The dataChanged signal and the lifetime of indices are not really related. When your index() method returns an index, you are not the one who can "delete" it; whoever called your model's index() method is responsible for destructing the index. Never mind that the index you give out is not allocated in the free store anyway, so the notion of deletion doesn't apply at all.
The QModelIndex is what it says on the box: an index. When it comes to how it might be used, it's very much like a C++ iterator. It comes with a few caveats that mirror iterator caveats:
It must be created by the model using a factory method index(). Internally you use the createIndex() factory to create it for you within the model. Think of iterator-returning methods of C++ containers do (begin(), end(), etc.).
It must be used at once and then discarded. It won't remain valid if you make changes to the model. The same general limitation applies to C++ container iterators.
If you need to keep a model index over time use a QPersistentModelIndex. The C++ standard library doesn't offer this.
The lifetime of an index is out of your control. You create it, you give it out with an expectation that it will be used according to this protocol. The user (the view, for example) is supposed to use it subject to the limitations listed above. If a view, for example, holds on to an index for too long (through intervening modifications), it's entirely OK that it will result in undefined behavior (say, a crash).
When you emit (or receive, if you're a view or a proxy model) dataChanged, you shouldn't expect any indices given out prior to that point to remain usable. The persistent indices of course should still work, but it's ok to invalidate those if, say, the pointed-to index was removed (think of a cell being removed from a spreadsheet, not the cell's data being changed!).
If you gave out an index, then emit dataChanged, and any of your model's methods get called with that old index, you're free to crash, assert, abort, whatever.
Let's also be clear about how you use dataChanged: you're supposed to emit it whenever an item of data at a given index changes. You should be as specific as possible: it is not a good idea at all to simply tell your views that everything has changed if, in fact, it hasn't. If one index has changed, emit the signal with topLeft and bottomRight set to the same index. If a small rectangular area has changed, emit the corners of this rectangle. If multiple unrelated items have changed that are too far away to be meaningfully bundled in a small enclosing index rectangle, you should indicate such changes separately for each changed item.
You should definitely use modeltest to verify that your model behaves sanely.
This can be done by adding the modeltest.cpp and modeltest.h to your project, and instantiating the tester for each model instance. You can do it directly within your model:
#include "modeltest.h"
MyModel(QObject * parent) : ... {
new ModelTest(this, parent);
...
}
You also need to handle persistent indices for your model, and that's a separate issue. The documentation says:
Models that provide interfaces to resizable data structures can provide implementations of insertRows(), removeRows(), insertColumns(),and removeColumns(). When implementing these functions, it is important to notify any connected views about changes to the model's dimensions both before and after they occur:
An insertRows() implementation must call beginInsertRows() before inserting new rows into the data structure, and endInsertRows() immediately afterwards.
An insertColumns() implementation must call beginInsertColumns() before inserting new columns into the data structure, and endInsertColumns() immediately afterwards.
A removeRows() implementation must call beginRemoveRows() before the rows are removed from the data structure, and endRemoveRows() immediately afterwards.
A removeColumns() implementation must call beginRemoveColumns() before the columns are removed from the data structure, and endRemoveColumns() immediately afterwards.
The private signals that these functions emit give attached components the chance to take action before any data becomes unavailable. The encapsulation of the insert and remove operations with these begin and end functions also enables the model to manage persistent model indexes correctly. If you want selections to be handled properly, you must ensure that you call these functions. If you insert or remove an item with children, you do not need to call these functions for the child items. In other words, the parent item will take care of its child items.
I have a data structure that stores ... well, data. Now, I need to access various pieces of data in slightly different manner, so I'm essentially building an in-memory index. But I'm wondering: should the index hold pointers or copies?
To elaborate, say I have
class Widget
{
// Ways to access the list of gears...
private:
std::list<Gears> m_gears;
};
Now, I have two Widgets, and there exists between these two a mapping between their Gears. Currently, this is
boost::unordered_map<Gear, Gear>
but Gear is a fairly hefty class, and I feel like making so many copies is poor design. I could store a pointer, but then the mapping is only valid for the lifetime of the corresponding Widgets, and you start getting ->s... (And if that std::list ever changes to a std::vector, it gets more complex...)
Pertaining to the copies, it's actually slightly worse: There's two boost::unordered_maps, one for each direction. So, for each Gear, I'm making up to 2 copies of it.
Alternatively, I could put the index inside the Widget class, but I feel like this violates the responsibilities of the Widget class.
You might try Boost Pointer Container Library: http://www.boost.org/doc/libs/1_43_0/libs/ptr_container/doc/ptr_container.html
I think it addresses exactly the problem you are facing.
Could you store all gears in one place, like statically in the gears class, and then have each mapping AND widget store only the reference/index to it?
You would have to keep track of references to each gear so you know when you can dispose them, but that should be easy enough.