Drag and Drop: Difference between revisions
Created page with "Written by Gordon Zeglinski ==Introduction== As my project enters its final stages, the work load associated with it has gone through the roof. Therefore, the column will b..." |
|||
(5 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
Written by [[Gordon Zeglinski]] | ''Written by [[Gordon Zeglinski]]'' | ||
==Introduction== | ==Introduction== | ||
As my project enters its final stages, the work load associated with it has gone through the roof. Therefore, the column will be a tad shorter than usual. | As my project enters its final stages, the work load associated with it has gone through the roof. Therefore, the column will be a tad shorter than usual. | ||
Drag and drop is one of OS/2's nicest features, but probably one of the most feared by new programmers. It's particularly painful, because you can't set breakpoints inside the processing of the DM_DRAG, DM_DRAGOVER, etc. messages. But since this is a C++ column, and drag and drop is a bit complex for a single "tad smaller than usual" article, we'll look at the drop half of drag and drop using the IBM PM class libraries. These class libraries do a lot more than just encapsulate the PM infrastructure; they abstract PM to such an extent, that they could be developed into a cross platform toolkit. | Drag and drop is one of OS/2's nicest features, but probably one of the most feared by new programmers. It's particularly painful, because you can't set breakpoints inside the processing of the DM_DRAG, DM_DRAGOVER, etc. messages. But since this is a C++ column, and drag and drop is a bit complex for a single "tad smaller than usual" article, we'll look at the drop half of drag and drop using the IBM PM class libraries. These class libraries do a lot more than just encapsulate the PM infrastructure; they abstract PM to such an extent, that they could be developed into a cross-platform toolkit. | ||
==Processing Drop== | ==Processing Drop== | ||
===Drop Basics=== | ===Drop Basics=== | ||
Before moving on to looking at the code which processes the drop actions, we will briefly look at the stages involved in processing a drop: | Before moving on to looking at the code which processes the drop actions, we will briefly look at the stages involved in processing a drop: | ||
# The application is notified of a drag occurring. The application checks what is being dragged over it. It then sets the return value to indicate to the OS, whether the dragged object(s) can be dropped. | |||
# The application is notified of a drag occurring. The application checks what is being dragged over it. It then sets the return value to indicate to the OS, whether the dragged object(s) can be dropped. | |||
# When the user drops the dragged objects, the application is notified of the drop. It then performs the actions associated with the drag. | # When the user drops the dragged objects, the application is notified of the drop. It then performs the actions associated with the drag. | ||
Both the initiator and recipient of the drag and drop operation must agree upon the information being exchanged; this is done by using a rendering mechanism and format specifier, both of which are text strings. The OS/2 PM programming reference defines a set of standard rendering and format strings. In addition to these, the programmer can define application-specific rendering and format strings. | |||
===Drop in the ICLUI=== | ===Drop in the ICLUI=== | ||
The ICLUI uses several objects to encapsulate drag and drop. We will look at those classes which we will use in the sample program. | The ICLUI uses several objects to encapsulate drag and drop. We will look at those classes which we will use in the sample program. | ||
Instances of the IDMItem or | Instances of the IDMItem or its ancestors represent the objects being dragged. By subclassing IDMItem, we can create specialized drag items if we choose to implement our own rendering mechanisms. For this example, we create a new class called AFileItem but give it no "special" properties. | ||
<code> | |||
class AFileItem : public IDMItem { | class AFileItem : public IDMItem { | ||
public: | public: | ||
Line 30: | Line 26: | ||
targetDrop ( IDMTargetDropEvent & ); | targetDrop ( IDMTargetDropEvent & ); | ||
}; | }; | ||
</code> | |||
The method targetDrop is called when the dragged objects are dropped. We override this function to handle our application specific processing of the drop event. | The method targetDrop is called when the dragged objects are dropped. We override this function to handle our application specific processing of the drop event. | ||
The template class IDMItemProviderFor is derived from the class IDMItemProvider. We subclass IDMItemProviderFor to control various aspects of the drag and drop process. IDMItemProvider implies that this object creates IDMItem objects. However, it can do a lot more than just that. Below, we subclass the template class IDMItemProviderFor to provide support for drag over type events. | The template class IDMItemProviderFor is derived from the class IDMItemProvider. We subclass IDMItemProviderFor to control various aspects of the drag and drop process. IDMItemProvider implies that this object creates IDMItem objects. However, it can do a lot more than just that. Below, we subclass the template class IDMItemProviderFor to provide support for drag over type events. | ||
<code> | |||
class AFileProvider : public IDMItemProviderFor< AFileItem > { | class AFileProvider : public IDMItemProviderFor< AFileItem > { | ||
Line 42: | Line 37: | ||
provideEnterSupport ( IDMTargetEnterEvent &event ); | provideEnterSupport ( IDMTargetEnterEvent &event ); | ||
}; | }; | ||
</code> | |||
We override the method provideEnterSupport so that when objects are dragged over our main window, we can test them to see if they can be dropped. Both the ICLUI classes we have looked at provide many more member functions that we can override to provide other drag and drop features, but we will not look at these here. | We override the method provideEnterSupport so that when objects are dragged over our main window, we can test them to see if they can be dropped. Both the ICLUI classes we have looked at provide many more member functions that we can override to provide other drag and drop features, but we will not look at these here. | ||
==Building a Simple Test Application== | ==Building a Simple Test Application== | ||
Our simple test application will consist of a frame window and a multi-line edit control. The frame window class will be subclassed by MyFrame. The MLE control will be a member of MyFrame. When a file is dropped on the MLE, the contents of the MLE are discarded and the file is loaded into the control. The following section of code checks the objects being dragged over the MLE. | Our simple test application will consist of a frame window and a multi-line edit control. The frame window class will be subclassed by MyFrame. The MLE control will be a member of MyFrame. When a file is dropped on the MLE, the contents of the MLE are discarded and the file is loaded into the control. The following section of code checks the objects being dragged over the MLE. | ||
<code> | |||
Boolean AFileProvider::provideEnterSupport( IDMTargetEnterEvent &event ){ | Boolean AFileProvider::provideEnterSupport( IDMTargetEnterEvent &event ){ | ||
Line 56: | Line 49: | ||
IDMTargetOperation::Handle targetOp = | IDMTargetOperation::Handle targetOp = | ||
IDMTargetOperation::targetOperation(); | IDMTargetOperation::targetOperation(); | ||
// only want to accept 1 file | // only want to accept 1 file | ||
Line 77: | Line 69: | ||
return(true); | return(true); | ||
} | } | ||
</code> | |||
If there is more than one object being dropped over, or the object isn't identified as "plain text", the application sets the drop indicator to neverOk. This will then prevent the drop from occurring, and change the pointer to indicate that a drop is not permitted. The following code snippet, loads the MLE with the dropped file. | If there is more than one object being dropped over, or the object isn't identified as "plain text", the application sets the drop indicator to neverOk. This will then prevent the drop from occurring, and change the pointer to indicate that a drop is not permitted. The following code snippet, loads the MLE with the dropped file. | ||
<code> | |||
Boolean AFileItem::targetDrop( IDMTargetDropEvent & Event){ | Boolean AFileItem::targetDrop( IDMTargetDropEvent & Event){ | ||
IMultiLineEdit *DropWin=(IMultiLineEdit *) | IMultiLineEdit *DropWin=(IMultiLineEdit *) | ||
this->targetOperation()->targetWindow(); | this->targetOperation()->targetWindow(); | ||
IString | IString | ||
Line 95: | Line 85: | ||
//load the file into the edit window | //load the file into the edit window | ||
DropWin->importFromFile(fname); | DropWin->importFromFile(fname); | ||
return true; | return true; | ||
} | } | ||
</code> | |||
The constructor for the class MyFrame follows. The constructor enables drag and drop for the MLE and attaches an instance of our FileProvider to the MLE. | The constructor for the class MyFrame follows. The constructor enables drag and drop for the MLE and attaches an instance of our FileProvider to the MLE. | ||
<code> | |||
MyFrame::MyFrame(const char *Title): | MyFrame::MyFrame(const char *Title): | ||
IFrameWindow(Title,IResourceId(1), //------------------- | IFrameWindow(Title,IResourceId(1), //------------------- | ||
Line 129: | Line 117: | ||
show(); | show(); | ||
} | } | ||
</code> | |||
The file CPPDD.CPP contains the complete source code for the simple app. To compile the code simply execute the Rexx program GO.CMD. | The file CPPDD.CPP contains the complete source code for the simple app. To compile the code simply execute the Rexx program GO.CMD. | ||
==Summary== | ==Summary== | ||
Drag and drop is one of OS/2's most intuitive user interface features and the ICLUI completely encapsulates the direct manipulation API. However, as with other parts of the ICLUI its encapsulation strategy is not clearly documented. In this article, we have explored how to enable our ICLUI applications to accept dropped files. | Drag and drop is one of OS/2's most intuitive user interface features and the ICLUI completely encapsulates the direct manipulation API. However, as with other parts of the ICLUI its encapsulation strategy is not clearly documented. In this article, we have explored how to enable our ICLUI applications to accept dropped files. | ||
Yet, we still have only barely touched this topic's surface. | Yet, we still have only barely touched this topic's surface. | ||
[[Category:C++ Articles]] | |||
[[Category: |
Latest revision as of 15:12, 22 October 2022
Written by Gordon Zeglinski
Introduction
As my project enters its final stages, the work load associated with it has gone through the roof. Therefore, the column will be a tad shorter than usual.
Drag and drop is one of OS/2's nicest features, but probably one of the most feared by new programmers. It's particularly painful, because you can't set breakpoints inside the processing of the DM_DRAG, DM_DRAGOVER, etc. messages. But since this is a C++ column, and drag and drop is a bit complex for a single "tad smaller than usual" article, we'll look at the drop half of drag and drop using the IBM PM class libraries. These class libraries do a lot more than just encapsulate the PM infrastructure; they abstract PM to such an extent, that they could be developed into a cross-platform toolkit.
Processing Drop
Drop Basics
Before moving on to looking at the code which processes the drop actions, we will briefly look at the stages involved in processing a drop:
- The application is notified of a drag occurring. The application checks what is being dragged over it. It then sets the return value to indicate to the OS, whether the dragged object(s) can be dropped.
- When the user drops the dragged objects, the application is notified of the drop. It then performs the actions associated with the drag.
Both the initiator and recipient of the drag and drop operation must agree upon the information being exchanged; this is done by using a rendering mechanism and format specifier, both of which are text strings. The OS/2 PM programming reference defines a set of standard rendering and format strings. In addition to these, the programmer can define application-specific rendering and format strings.
Drop in the ICLUI
The ICLUI uses several objects to encapsulate drag and drop. We will look at those classes which we will use in the sample program.
Instances of the IDMItem or its ancestors represent the objects being dragged. By subclassing IDMItem, we can create specialized drag items if we choose to implement our own rendering mechanisms. For this example, we create a new class called AFileItem but give it no "special" properties.
class AFileItem : public IDMItem {
public:
AFileItem ( const IDMItem::Handle &item );
virtual Boolean
targetDrop ( IDMTargetDropEvent & );
};
The method targetDrop is called when the dragged objects are dropped. We override this function to handle our application specific processing of the drop event.
The template class IDMItemProviderFor is derived from the class IDMItemProvider. We subclass IDMItemProviderFor to control various aspects of the drag and drop process. IDMItemProvider implies that this object creates IDMItem objects. However, it can do a lot more than just that. Below, we subclass the template class IDMItemProviderFor to provide support for drag over type events.
class AFileProvider : public IDMItemProviderFor< AFileItem > {
public:
virtual Boolean
provideEnterSupport ( IDMTargetEnterEvent &event );
};
We override the method provideEnterSupport so that when objects are dragged over our main window, we can test them to see if they can be dropped. Both the ICLUI classes we have looked at provide many more member functions that we can override to provide other drag and drop features, but we will not look at these here.
Building a Simple Test Application
Our simple test application will consist of a frame window and a multi-line edit control. The frame window class will be subclassed by MyFrame. The MLE control will be a member of MyFrame. When a file is dropped on the MLE, the contents of the MLE are discarded and the file is loaded into the control. The following section of code checks the objects being dragged over the MLE.
Boolean AFileProvider::provideEnterSupport( IDMTargetEnterEvent &event ){
// Get handle to the drag target operation
IDMTargetOperation::Handle targetOp =
IDMTargetOperation::targetOperation();
// only want to accept 1 file
if(targetOp->numberOfItems()!=1){
event.setDropIndicator(IDM::neverOk);
return(true);
}
// Get the types for the drag item.
IString strTypes = targetOp->item(1)->types();
// See if it's marked as a "plain text" file
if ((strTypes.indexOf(IDM::plainText))){
event.setDropIndicator(IDM::ok);
return(true);
}
// Type is not recognized - set the drop indicator to prevent a drop!
event.setDropIndicator(IDM::neverOk);
return(true);
}
If there is more than one object being dropped over, or the object isn't identified as "plain text", the application sets the drop indicator to neverOk. This will then prevent the drop from occurring, and change the pointer to indicate that a drop is not permitted. The following code snippet, loads the MLE with the dropped file.
Boolean AFileItem::targetDrop( IDMTargetDropEvent & Event){
IMultiLineEdit *DropWin=(IMultiLineEdit *)
this->targetOperation()->targetWindow();
IString
fname = this->containerName() + this->sourceName();
//erase the edit window
DropWin->removeAll();
//load the file into the edit window
DropWin->importFromFile(fname);
return true;
}
The constructor for the class MyFrame follows. The constructor enables drag and drop for the MLE and attaches an instance of our FileProvider to the MLE.
MyFrame::MyFrame(const char *Title):
IFrameWindow(Title,IResourceId(1), //-------------------
IFrameWindow::titleBar| //
IFrameWindow::sizingBorder| //
IFrameWindow::minimizeButton| // Create the Frame
IFrameWindow::systemMenu| // Window
IFrameWindow::shellPosition| //
IFrameWindow::minimizeButton| //
IFrameWindow::windowList| //
IFrameWindow::maximizeButton), //--------------------
EditWin(10,this,this){ // Create the Edit Window
// ID=10, use this frame
// window as the parent and
//owner
//---------------------
setIcon(IResourceId(1));
setClient(&EditWin);
//enable default drag and drop handler
IDMHandler::enableDragDropFor(&EditWin);
//attach the provider
EditWin.setItemProvider(&FileProvider);
show();
}
The file CPPDD.CPP contains the complete source code for the simple app. To compile the code simply execute the Rexx program GO.CMD.
Summary
Drag and drop is one of OS/2's most intuitive user interface features and the ICLUI completely encapsulates the direct manipulation API. However, as with other parts of the ICLUI its encapsulation strategy is not clearly documented. In this article, we have explored how to enable our ICLUI applications to accept dropped files.
Yet, we still have only barely touched this topic's surface.