I am trying to use the drag & drop functionality on a QTreeView with an underlying QStandardModelItem. The default behavior of the widget is perfect for me until it gets to the drop part where I need to perform some operation. Hence, I am going to override the dropEvent(QDropEvent *event) method of my TreeView where I would like to decode the dropped mime data.
The formats of the data I find in the mime object are "application/x-qabstractitemmodeldatalist" and "application/x-qstandarditemmodeldatalist". Does anyone know how to decode the associated data (or where to find some documentation on it) ?
That mime type is the default type for item views. The qt already handles this when drop is made; To enable drag'n drop do:
itemView->setSelectionMode(QAbstractItemView::SingleSelection);
itemView->setDragEnabled(true);
itemView->viewport()->setAcceptDrops(true);
itemView->setDropIndicatorShown(true);
itemView->setDragDropMode(QAbstractItemView::InternalMove);
To change default behavior take a look at:
http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views
Related
I have a container x, with a Link item y set as display.
How can I access programmatically y if I know x?
I tried: getattr(x, 'default_page', None), but it returns None all the time.
By using getattr you may override plone default behavior regarding how to determinate the default page of an object (item or container).
Content objects in Plone inherit BrowserDefaultMixin, which provides the functionality of getting the default page of a object
The mixin, respectively a utility used by the mixin provides the desired method called getDefaultPage
>>> x = b.getObject()
>>> x.getDefaultPage()
...
This will return the right content object or view depending on the configuration on the object, on the FTI and on the View itself and more.
Have a look at get_default_page for more details.
And even better...
This canonical way of getting the default page, would also have helped finding the issue in your case pretty fast, since the method does certain checks to make sure the passed object provides the right "features". A string would not pass those checks.
default_page = getattr(x, 'default_page', None) is the answer. But make sure you have an object for x.
My mistake was I tried b.getObject().absolute_url() in my query instead of b.getObject().
Can one subclass INObject?
I ask because I have an Intents Handler Extension for Siri Shortcuts. I attempted to create a subclass for INObject because I want to add an extra property. Seems like it works just fine here.
However, I also have an Intents Handler UI Extension. When my response object gets to this point, I have a handle on the INObject and its identifier and display string. But, when I try to cast it to my custom INObject sublcassed type, the result is nil and therefore I cannot access my custom property.
Does anyone know how to pass custom properties from the Intents Extension to the Intents UI Extension using the custom INObject?
Apple Engineering got back to me that this is not supported.
I have some problem with drag and drop in QTreeView:
I set flag to Qt::MoveAction and reimplemented removeRows(), dropMimeData() and etc in my model. The Model inherits QAbstractItemModel.
When I drag and drop, mimeData(), dropMimeData() are called automatically,
and also dropMimeData() calls insertRows() automatcally. But removeRows() is not called, so the dragged item is still alive. I googled, but they said their removeRows() was called automatically.
Why isn't my removeRows() called after dropMimeData()?
Shoud I call removeRows() manually in dropMimeData()?
If so, how can I know the previous QModelIndex of start of drag?
When starting drag, in mimeData(), I can save index in private member, but it looks like not good.
Any advice would be appreciated.
Short answer
If everything is correctly configured, the target should not remove the source item, the initiator of the drag should remove the source item if a Qt::MoveAction is performed.
Configuration of the view
QAbstractItemView (which is the base class of QTreeView, QListView, QTableView, ...) implements the initiation and finishing of the QDrag operation in startDrag:
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction)
d->clearOrRemove();
So, when the requested drop action (returned by QDrag::exec) is a Qt::MoveAction, the item is automatically removed (or cleared as specified by setDragDropOverwriteMode).
Important configuration options of the view are:
setDragDropMode: specifies if the view should accept drag and/or drop items from external or only internal items. This function calls setDragEnabled and setAcceptDrops accordingly.
setDragEnabled: enables the builtin drag mechanism
setAcceptDrops: enables the builtin drop mechanism
setDragDropOverwriteMode: specifies if the source item should be removed (typical in a tree view) or cleared (typical in a table view)
setDefaultDropAction: the default drop action specified when initiating the QDrag operation.
Configuration of the model
Besides the configuration of the view, you should configure your model correctly.
You should implement the editing interface of your model, i.e. removeRows, insertRows, moveRows and setData. Although it may not be necessary to implement all of them depending on your specific situation, it is a good approach to implement them anyway for an editable model.
supportedDropActions: Reimplement this function to return the support drop actions (Qt::CopyAction by default). Note that the user may switch between the different supported actions by pressing some keys. (shift for Qt::MoveAction and control for Qt::CopyAction)
supportedDragActions: Reimplement this function if the supported drag actions are different from the supported drop actions.
Examples
Good examples are the source code of Qt itself. The corresponding Q*Widget classes (ex. QTreeWidget for QTreeView) are provides concrete implementations of the view and a corresponding model.
I had the same issue with my custom model. Setting dragDropOverwriteMode=false for view resolved my problem.
I think yes, you have to call removeRows() from the dropMimeData() if the Qt::DropAction is Qt::MoveAction, i.e. you completely move your tree node from one place to another.
WRT your second question, you can create your custom mime data in QAbstractItemModel::mimeData() and encode your dragged nodes initial information there. So, in dropMimeData() function you can decode and use it.
I'm using XtraGrid of DevExpress 2.9.5 to display a blotter of dynamic set of lines. The blotter is integrated into another application, this is why it has to be based on UserControl class and also implement a couple of custom interfaces.
public partial class BlotterForm : UserControl, ISMMdiEmbeddable, ISMAssociatedMFCWindow
{
private BindingList<BlotterTrade> fDeals;
....
}
As the data is binded to control using BindedList, any change should be reflected in the form automatically. And if I try to add new line to fDeals like follows:
public void AddDeal()
{
fDeals.Add(new BlotterTrade(1,2,3));
}
... i can see the line, but it's content is rubbish.
I tried to do the same in a small test application. It works ok with only difference that the blotter in test application is based on DevExpress.XtraEditors.XtraForm. To me it looks now that the form of original blotter doesn't overload some method or miss some event. But I cannot find out what exactly is missed.
Can somebody tell me what I do wrong or don't do?
Thanks.
A couple of things:
BindingList doesn't always work too well with DevExpress, and it's suggested to use XPCollection instead.
Do you have any more info about how you setup your columns in the xtragrid? If you use incorrect field names in the column, then they won't show what you're looking for.
If the params you're using (1, 2, 3) are ids stored as fkeys to other objects (not sure if you're using xpo or not) then they won't show up correctly either (there'll likely be a '+' in the cell instead of any values).
[aside] be sure that blottertrade implements INotifyPropertyChanged for better interaction with the grid.
Thanks to everybody for the answers and comments. I think I sorted out the problem. It was actually related to interaction between native C++ and C# layers in my application. The object that was supposed to be displayed in XtraGrid was created in C++ layer, the grid was displayed asynchronously with object construction/deconstruction, that's why at the moment when the grid was ready to display it, the object itself didn't exist. Hence the rubbish. It's good the grid itself was not crashing or firing exceptions.
I'm re-writing an MXML item renderer in pure AS. A problem I can't seem to get past is how to have each item renderer react to a change on a static property on the item renderer class. In the MXML version, I have the following binding set up on the item renderer:
instanceProperty={callInstanceFunction(ItemRenderer.staticProperty)}
What would be the equivalent way of setting this up in AS (using BindingUtils, I assume)?
UPDATE:
So I thought the following wasn't working, but it appears as if Flex is suppressing errors thrown in the instanceFunction, making it appear as if the binding itself is bad.
BindingUtils.bindSetter(instanceFunction, ItemRenderer, "staticProperty");
However, when instanceFunction is called, already initialized variables on the given instance are all null, which was the cause of the errors referenced above. Any ideas why this is?
You have 2 options that I am aware of:
Option 1
You can dig into the code that the flex compiler builds based on your MXML to see how it handles binding to static properties. There is a compiler directive called -keep-generated-actionscript that will cause generated files to stick around. Sleuthing through these can give you an idea what happens. This option will involve instantiating Binding objects and StaticPropertyWatcher objects.
Option 2
There is staticEventDispatcher object that gets added at build time to classes containing static variables see this post http://thecomcor.blogspot.com/2008/07/adobe-flex-undocumented-buildin.html. According to the post, this object only gets added based on the presence of static variables and not getter functions.
Example of Option 2
Say we have a class named MyClassContainingStaticVariable with a static variable named MyStaticVariable and another variable someobject.somearrayproperty that we want to get updated whenever MyStaticVariable changes.
Class(MyClassContainingStaticVariable).staticEventDispatcher.addEventListener(
PropertyChangeEvent.PROPERTY_CHANGE,
function(event:PropertyChangeEvent):void
{
if(event.property == "MyStaticVariable")
{
someobject.somearrayproperty = event.newValue as Array;
}
});
I think you need to respond to the "PropertyChanged" event.
If you're going to do that, use a singleton instead of static. I don't think it will work on a static. (If you have to do it that way at all, there are probably a couple ways you could reapproach this that would be better).
var instance:ItemRenderer = ItemRenderer.getInstance();
BindingUtils.bindProperty(this, "myProperty", instance, "theirProperty");
After fiddling with this for a while, I have concluded that this currently isn't possible in ActionScript, not even with bindSetter. It seems there are some MXML-only features of data bindings judging by the following excerpt from the Adobe docs (though isn't it all compiled to AS code anyways)?
You cannot include functions or array
elements in property chains in a data
binding expression defined by the
bindProperty() or bindSetter() method.
For more information on property
chains, see Working with bindable
property chains.
Source: http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_7.html
You can create a HostProxy class to stand in for the funciton call. Sort of like a HostFunctionProxy class which extends from proxy, and has a getProperty("functionInvokeStringWithParameters") which will invoke the function remotely from the host, and dispatch a "change" event to trigger the binding in typical [Bindable("change")] Proxy class.
You than let the HostProxy class act as the host, and use the property to remotely trigger the function call. Of course, it'd be cooler to have some TypeHelperUtil to allow converting raw string values to serialized type values at runtime for method parameters (splitted by commas usually).
Example:
eg.
var standInHost:Object = new HostFunctionProxy(someModelClassWithMethod, "theMethodToCall(20,11)");
// With BindingUtils.....
// bind host: standInHost
// bind property: "theMethodToCall(20,11)"
Of course, you nee to create such a utlity to help support such functionality beyond the basic Flex prescription. It seems many of such (more advanced) Flex bindings are usually done at compile time, but now you have to create code to do this at runtime in a completely cross-platform Actionscript manner without relying on the Flex framework.