If you have a lot of small classes (that are often created and destroyed), and they all depend on the settings, how would you do that?
It would be nice not to have to connect each one to some kind of "settings changed" signal, and even if I did, all the settings will be updated, even those objects whose settings didn't change.
When faced with that myself, I've found it's better to control the save/load settings from a central place. Do you really need to save/load the settings on a regular basis or can you have a master object (likely with a list of the sub-objects) control when savings actually need to be done? Or, worst case, as the objects are created and destroyed have them update an in-memory setting map in the parent collection and save when it thinks it should be saved, rather than child object destruction.
One way of implementing it is given below.
If you wish, the central location for the settings can be a singleton derived from QAbstractItemModel, and you can easily connect the dataChanged(...) signal to various objects as necessary, to receive notifications about changed settings. Those objects can decide whether an applicable setting was changed. By judicious use of helper and shim classes, you can make it very easy to connect your "small classes" with notifications. This would address two issues inherent in the model driven approach to settings.
The possibly large number of subscribers, all receiving notifications about the settings they usually don't care about (the filtering issue).
The extra code needed to connect the subscriber with the item model, and the duplication of information as to what indices of the model are relevant (the selection issue).
Both filtering and selection can be dealt with by a shim class that receives all of the dataChanged notifications, and for each useful index maintains a list of subscribers. Only the slots of the "interested" objects would then be invoked. This class would maintain the list of subscriber-slot pairs on its own, without offering any signals for others to connect to. It'd use invokeMethod or a similar mechanism to invoke the slots.
The selection issue can be dealt with by observing that the subscriber classes will, upon initialization, query the model for initial values of all of the settings that affect their operation - that they are "interested" in. All you need is a temporary proxy model that you create for the duration of the initialization of the subscriber. The proxy model takes the QObject* instance of the caller, and records all of the model indices that were queried (passing them onto the singleton settings model). When the proxy model is finally destroyed at the return from the initialization of the subscriber class, it feeds the information about the model indices for this QObject to the singleton. A single additional call is needed to let the singleton know about the slot to call, but that's just like calling connect().
What I typically do is to create a class handling all my settings, with one instance per thread. To make it quicker to write this class, I implemented a couple of macros that let me define it like this:
L_DECLARE_SETTINGS(LSettingsTest, new QSettings("settings.ini", QSettings::IniFormat))
L_DEFINE_VALUE(QString, string1, QString("string1"))
L_DEFINE_VALUE(QSize, size, QSize(100, 100))
L_DEFINE_VALUE(double, temperature, -1)
L_DEFINE_VALUE(QByteArray, image, QByteArray())
L_END_CLASS
This class can be instantiated once per thread and then used without writing anything to the file. A particular instance of this class, returned from LSettingsTest::notifier(), emits signals when each property changes. If exposed to QML, each property work as regular Qt property and can be assigned, read and used in bindings.
I wrote more info here. This is the GitHub repo where I placed the macros.
Related
I made this post on the Qt Forum as well but I haven't gotten any follow up so I'm hoping to continue the discussion some here. Here is the relevant parts of my post and the response.
My Post:
I have the following design: A main window which has a widget, and
inside that widget different widgets of type "Page" can be loaded. The
first page, let's call it the startup page, allows the user to type in
the serial number of the product. The database is then queried to get
some info about the product itself, and then a concrete child class
representing the type of "Product" is created. All child product
classes inherit from an abstract class, Product.
Basically, when the user selects the product by entering a serial
number, a product factory is called to create the concrete object and
then check if it's physically connected to the system via a bus. This
created product will then be passed to and used by other pages in
somewhat of a wizard like fashion.
Response:
The biggest problem I see [...] is that the ui
is kinda driving your logic. Typically that's a bad idea and down the
line leads to problems that are hard to foresee in the planning stage.
The way I would approach it is that your app is a state machine.
There's user input stage, product lookup stage (which may fail from
what you describe), product view/editing stage etc. Transitions
between those stages would dictate a ui change, for example switching
from product id input to product lookup would switch ui page from
input form to a wait indicator and finishing the query would move
either to success or fail state, which would show an error page or the
product page accordingly. The product object would then be governed by
the state machine state that handles it. Lookup would produce an
object and pass it to the view/edit state and that state would free it
when transitioning to another state. Your logic would be better
encapsulated this way and independent of the ui, which you may want to
change someday or make optional e.g. drive the state machine in a
silent mode, app params or something else. The ui would just send a
signal that would change the machine state e.g. entering a number
would transition the machine from input to lookup, which in turn could
be connected to page change.
The issue I'm having here is I'm not seeing how this actually decouples my application logic from my UI? The QStateMachine would be configured to transition between states based on button clicks which is inherently coupling it to my UI. If I wanted some type of "headless" mode, I'd basically have to reconfigure my entire state machine to attach to signals from different objects. I suppose I could try to abstract this by having a builder type class that configures all the state transitions based on what mode I'm in.
Maybe this indicates I would need some sort of intermediate object which is used whether or not I have a UI, and the state machine connects to signals from that object instead. My different widgets would then contain a reference to this same object and utilize it.
Basically, I am asking how I can decouple my state machine from the UI when it seems it's coupled by design, since what's driving the state machine is the UI itself.
The QStateMachine class and its related classes are not coupled “by design” to the UI. They could be used to implement state machines in any layer of the app.
The response you received just advocates for a better separation of concerns.
Like you already said (about the “headless” mode), you can pack your business logic in a component that drives such a state machine to handle the flow of your process. You can of course have also other state machines, in the UI, to handle model updates, user interaction and page navigation.
I am trying to implement an Validator class in Contract-States library of CordApp, which have several validation methods that are inherited by Model classes in their init() fun, so that each time a Model class is called/initialized the validation happens on the spot.
Now I'm stuck at a point, where I need to validate whether the incoming member name(through a Model class) matches with Organisation name of the node, I need to access the NetworkMap for that. How can I do that?
In Work-Flow library each flow extends FlowLogic class that implements ServiceHub interface and through that we can access the NetworkMap, but how to do that in Contract-States library?
P.S. - I'm trying to avoid any circular dependency (Contract-States lib should not depend on Work-Flow lib)
The short answer, you can't.
The long answer:
The difference between flow validations and contract validation is that the latter (contracts) must be deterministic meaning for the same input they must always give the same output whether it's now or after 100 years, in the current node or any other node.
The reason for that is because any time (even in the future) when a node receives a transaction it must validate that transaction which includes validating the inputs which in return requires validating the transaction that created those inputs and so on, until you get a fully validated graph of all the inputs that lead to the outputs that were used as inputs and so on.
That's why the contract should return the same result any time, and that's why it should be deterministic, and that's why contracts (unlike flows) don't have access to external resources (like HTTP calls, or even the node's database).
Imagine if the contract was relying on the node's database for some validation rule, as you know, states are distributed on a need to know basis (i.e. only to participants of the state); so one node might have the state that you're using as validation source and another node won't, so the contract's output (transaction valid/invalid) will differ between nodes, and that breaks the deterministic concept.
Contracts only have access to the transaction components: inputs, outputs, attachments, signatures, time-windows, reference states.
Good news, there are other ways to implement your requirement:
Using an attachment that has the list of nodes that are allowed to be part of the transaction, this method should be used if the blacklist is not updated frequently and you can see the example here.
Using reference states, where you can create a state that has the allowed parties and require the existence of that reference state in your transaction; this method should be used when the blacklist is more frequently updated. You can read about reference states here.
Using Oracles, this option is in case there is a world organization (or for instance Ministry of Trade of some country) that provides an Oracle which returns the list of blacklisted parties; and you use that Oracle in your transaction. You can read about Oracles here.
So I have this Qt application with a QTreeView with a custom model (derived from QAbstractItemModel) and a custom model proxy for filtering (derived from QSortFilterProxyModel). More or less straightforward (somewhat similar to the and works fine) and works fine in terms of functionality.
The view shows a two-column tree with key-value pairs. The keys are updated very rarely but the values are updated frequently (a lot of entries with several updates every second each). In the proxy model I overload filterAcceptsRow to define visibility based on the key column. But every value change emits a dataChanged signal causing the view to call the proxy (filterAcceptsRow) again and that call is somewhat expensive (evaluate a regex on the element and its children). There is some room for optimization in filterAcceptsRow by caching all the calculations but it would be preferred to limit the calls to that function. Can it somehow be limited what columns trigger the calls to the proxy?
You have any advise for me?
Edit: Thanks for your input. I wasn't aware of dynamicSortFilter. I disabled dynamic sorting and also I connected the dataChanged-signal from the model to see if the key-column was changed and called invalidate in that case. That solved it.
If you look at the code for QSortFilterProxyModel you'll see that most of the work is only done when dynamicSortFilter is enabled. I guess that is the case for your code.
Can you live without it? Maybe call invalidate() once every 100 updates or second, depending on which happens first.
I had the same problem, solved it by emitting dataChanged signal from the proxy model itself, not from the main model. Alternatively, you can disable dynamic sort/filtering (dynamicSortFilter property) and call it manually when you want to filter or sort.
Also, I'm not sure, but maybe simply specifying the column in dataChanged signal will do it for you.
I have a custom UITableViewCell, and when the user clicks a button i make a request to a server and update the cell. I do this with a NSUrlConnection and it all works fine (this is all done inside the cell class) and once it returns it fires a delegate method and the tableivew controller handles this. However when i create the cell in the tableview, i use the dequeue method and reuse my cells. So if a cell has fired a asynchronous nsurlconnection, and the cell gets reused whilst this is still going on, will this in turn erase the current connection? I just want to make sure that if the cell is reused, the actual memory that was assigned to the cell is still there so the connection can fulfil its duty??
You can customize the behavior of a UITableViewCell by subclassing it and overriding the -perpareForReuse method. In this case, I would recommend destroying the connection when the cell is dequeued. If the connection should still keep going, you’ll need to remove the reference to it (set it to nil) and handle its delegate methods elsewhere.
It's never a good idea to keep a reference of a connection or any data that you want to display in a cell, no matter how much of effort you put into it afterward to work around to arising problems. Your approach will never work reliable.
In your case, if the user quickly scrolls the table view up and down, your app will start and possibly cancel dozens of connections and yet never finishes to load something. That will be an awful user experience, and may crash the app.
Better you design your app with MVC in mind: the cell is just a means to display your model data, nothing else. It's the View in this architectural design.
For that purpose the Table View Delegate needs to retrieve the Model's properties which shall to be displayed for a certain row and setup the cell. The model encapsulates the network connection. The Controller will take the role to manage and update change notification and process user inputs.
A couple of Apple samples provide much more details about this topic, and there is a nice introduction about MVC, please go figure! ;)
http://developer.apple.com/library/ios/#documentation/general/conceptual/devpedia-cocoacore/MVC.html
The "Your Second iOS App: Storyboards" also has a step by step explanation to create "Data Controller Classes". Quite useful!
Now, when using NSURLConnection which updates your model, it might become a bit more complex. You are dealing with "lazy initializing models". That is, they may provide some "placeholder" data when the controller accesses the property instead of the "real" data when is not yet available. The model however, starts a network request to load it. When it is eventually loaded, the model must somehow notify the Table View Controller. The tricky part here is to not mess with synchronization issues between model and table view. The model's properties must be updated on the main thread, and while this happens, it must be guaranteed that the table view will not access the model's properties. There are a few samples which demonstrate a few techniques to accomplish this.
I guess it's quite a common problem in databinding scenarios.
What do you usually do, if you are running a batch update and want to avoid that a propertychanged-dependend calculations/actions/whatever are executed for every single update?
The first thing which usually comes to my mind, is to either introduces a new boolean or unhook/hook the eventhandler, ...
What I don't like about this approaches is:
they introduce new complexity (has to be maintained, ...)
they are error prone, because you have to make sure that a suppressed notifications are sent afterwards
I'm wondering if somebody addressed this problem already in a more convenient way that is more easy to handle?
tia
Martin
Edit: not to missunderstand me. I know about the things .NET provides like RaiseListChangedEvents from BindingList, ... They are all addressing the problem in more/less the same way as I described, but I'm searching for a different way which doesn't have to listed drawbacks.
Maybe I'm on the wrong track, but I though I give it a try here...
There isn't a single one-size-fits-all solution, unfortunately. I've applied or seen the following solutions:
There are two singals. One signal is emitted when the change comes from a user action, the other always fires. This allows to distinguish between changes in the UI and updates by code.
A boolean to protect code
The property event framework stops propagating events automatically when a value didn't really change.
A freeze/thaw method on the signal or the signal manager (i.e. the whole framework)
A way to merge signals into a single one. You can do N updates and they get collected into M signals where M <= N. If you change the same property 100 times, you still only get 1 signal.
Queuing of signals (instead of synchronous execution). The queuing code can then merge signals, too. I've used this with great success in an application that doesn't have a "Save" button. All changes are saved to the database as you make them. When you change a text, the changes are merged over a certain time (namely until the previous DB update returns) and then, they are committed as a single change.
An API to set several values at once; only a single signal is emitted.
The signal framework can send signals at different levels of granularity. Say you have a person with a name. When you change the name, you get two signals: One for the name change and one "instance field changed". So if you only care "has something changed", then you can hook into the instance instead of all the fields.
What platform? The post makes me think .NET.
What is the underlying objects? For example, BindingList<T> as a source allows you to disable notifications by setting RaiseListChangedEvents to false while doing the update.
Other than that (or similar); yes, disconnect the binding during big updates
The easiest route to take is to use the BindingSource component for your data binding. Instead of binding your controls to a particular object (or IList), use that object as the DataSource for the BindingSource, then bind the controls to the BindingSource.
The BindingSource class has SuspendBinding() and ResumeBinding() functions.