Logo ROOT   6.07/09
Reference Guide
drag_and_drop.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_gui
3 /// This tutorial illustrates how to use drag and drop within ROOT.
4 /// Select a list tree item with a mouse press, drag it (move the mouse while keeping the mouse button pressed)
5 /// and release the mouse button in any pad inside the canvas or in the top list tree item ("Base").
6 /// When the button is released, the selected data is "dropped" at that location,
7 /// displaying the object in the canvas or adding (copying) it in the list tree.
8 ///
9 /// \macro_code
10 ///
11 /// \author Bertrand Bellenot
12 
13 #include "TROOT.h"
14 #include "TApplication.h"
15 #include "TSystem.h"
16 #include "TGFrame.h"
17 #include "TGButton.h"
18 #include "TGLabel.h"
19 #include "TGMenu.h"
20 #include "TGFileDialog.h"
21 #include "TBrowser.h"
22 #include "TRootEmbeddedCanvas.h"
23 #include "TRootHelpDialog.h"
24 #include "TCanvas.h"
25 #include "TH1F.h"
26 #include "TH2F.h"
27 #include "TF2.h"
28 #include "TGraph.h"
29 #include "TImage.h"
30 #include "TRandom.h"
31 #include "TGMsgBox.h"
32 #include "TGPicture.h"
33 #include "TGListTree.h"
34 #include "TObjString.h"
35 #include "TMessage.h"
36 #include "TTimer.h"
37 #include "TGDNDManager.h"
38 #include <cmath>
39 
40 const char gHelpDND[] = "\
41  Drag & Drop (DnD)\n\
42 Drag and Drop support is implemented on Linux via Xdnd, the\n\
43 drag and drop protocol for X window system, and on Windows\n\
44 via the Clipboard.\n\
45 Users can selects something in ROOT with a mouse press, drags\n\
46 it (moves the mouse while keeping the mouse button pressed) and\n\
47 releases the mouse button somewhere else. When the button is\n\
48 released the selected data is \"dropped\" at that location. This\n\
49 way, a histogram from an opened ROOT file in the browser can be\n\
50 dragged to any TCanvas. A script file from the browser can be\n\
51 dropped to a TGTextView or TGTextEdit widget in TGTextEditor.\n\
52 On Linux, it is possible to drag objects between ROOT and an\n\
53 external application. For example to drag a macro file from the\n\
54 ROOT browser to the Kate editor. On Windows, drag and drop works\n\
55 only within a single ROOT application, but it is possible to drag\n\
56 from the Windows Explorer to ROOT (e.g. a picture file to a canvas\n\
57 or a text file to a text editor).\n\
58 ";
59 
60 const char gReadyMsg[] = "Ready. You can drag list tree items to any \
61 pad in the canvas, or to the \"Base\" folder of the list tree itself...";
62 
63 //----------------------------------------------------------------------
64 
65 class DNDMainFrame : public TGMainFrame {
66 
67 protected:
68  TRootEmbeddedCanvas *fEc; // embedded canvas
69  TGTextButton *fButtonExit; // "Exit" text button
70  TGMenuBar *fMenuBar; // main menu bar
71  TGPopupMenu *fMenuFile; // "File" popup menu entry
72  TGPopupMenu *fMenuHelp; // "Help" popup menu entry
73  TCanvas *fCanvas; // canvas
74  TGListTree *fListTree; // left list tree
75  TGListTreeItem *fBaseLTI; // base (root) list tree item
76  TGLabel *fStatus; // label used to display status
77  TGraph *fGraph; // TGraph object
78  TH1F *fHist1D; // 1D histogram
79  TH2F *fHist2D; // 2D histogram
80 
81 public:
82  DNDMainFrame(const TGWindow *p, int w, int h);
83  virtual ~DNDMainFrame();
84 
85  void DoCloseWindow();
86  void HandleMenu(Int_t);
87  TObject *GetObject(const char *obj);
88  void DataDropped(TGListTreeItem* item, TDNDData* data);
89  void ResetStatus();
90 
91  //ClassDef(DNDMainFrame, 0); // Mainframe for Drag and Drop demo
92 };
93 
94 enum EMyMessageTypes {
96  M_FILE_BROWSE,
97  M_FILE_NEWCANVAS,
98  M_FILE_CLOSEWIN,
101 };
102 
103 const char *dnd_types[] = {
104  "ROOT files", "*.root",
105  "ROOT macros", "*.C",
106  "All files", "*",
107  0, 0
108 };
109 
110 static Atom_t gRootObj = kNone;
111 
112 //______________________________________________________________________________
113 DNDMainFrame::DNDMainFrame(const TGWindow *p, int w, int h) :
114  TGMainFrame(p, w, h), fGraph(0), fHist1D(0), fHist2D(0)
115 
116 {
117  // Constructor.
118 
119  SetCleanup(kDeepCleanup);
120  const TGPicture *pic = 0;
121  TGListTreeItem *item;
122  fMenuBar = new TGMenuBar(this, 35, 50, kHorizontalFrame);
123 
124  fMenuFile = new TGPopupMenu(gClient->GetRoot());
125  fMenuFile->AddEntry(" &Open...\tCtrl+O", M_FILE_OPEN, 0,
126  gClient->GetPicture("bld_open.png"));
127  fMenuFile->AddEntry(" &Browse...\tCtrl+B", M_FILE_BROWSE);
128  fMenuFile->AddEntry(" &New Canvas\tCtrl+N", M_FILE_NEWCANVAS);
129  fMenuFile->AddEntry(" &Close Window\tCtrl+W", M_FILE_CLOSEWIN);
130  fMenuFile->AddSeparator();
131  fMenuFile->AddEntry(" E&xit\tCtrl+Q", M_FILE_EXIT, 0,
132  gClient->GetPicture("bld_exit.png"));
133  fMenuFile->Connect("Activated(Int_t)", "DNDMainFrame", this,
134  "HandleMenu(Int_t)");
135 
136  fMenuHelp = new TGPopupMenu(gClient->GetRoot());
137  fMenuHelp->AddEntry(" &About...", M_HELP_ABOUT, 0,
138  gClient->GetPicture("about.xpm"));
139  fMenuHelp->Connect("Activated(Int_t)", "DNDMainFrame", this,
140  "HandleMenu(Int_t)");
141 
142  fMenuBar->AddPopup("&File", fMenuFile, new TGLayoutHints(kLHintsTop|kLHintsLeft,
143  0, 4, 0, 0));
144 
145  fMenuBar->AddPopup("&Help", fMenuHelp, new TGLayoutHints(kLHintsTop|kLHintsRight));
146 
147  AddFrame(fMenuBar, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 2, 2, 2, 5));
148 
149  TGHorizontalFrame *hfrm = new TGHorizontalFrame(this, 10, 10);
150  TGCanvas *canvas = new TGCanvas(hfrm, 150, 100);
151  fListTree = new TGListTree(canvas, kHorizontalFrame);
152  fListTree->Associate(this);
153  fEc = new TRootEmbeddedCanvas("glec", hfrm, 550, 350);
154  hfrm->AddFrame(canvas, new TGLayoutHints(kLHintsLeft | kLHintsExpandY, 5, 5));
156  AddFrame(hfrm, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
157  fEc->SetDNDTarget(kTRUE);
158  fCanvas = fEc->GetCanvas();
159  fCanvas->Divide(3, 2);
160  fCanvas->SetBorderMode(0);
161  fBaseLTI = fListTree->AddItem(0, "Base");
162 
163  TGHorizontalFrame *hf = new TGHorizontalFrame(this, 10, 10);
164 
165  fStatus = new TGLabel(hf, new TGHotString(gReadyMsg));
166  fStatus->SetTextJustify(kTextLeft);
167  fStatus->SetTextColor(0x0000ff);
169  10, 10, 10, 10));
170 
171  fButtonExit = new TGTextButton(hf, " &Exit... ", 3);
172  fButtonExit->Resize(fButtonExit->GetDefaultSize());
173  fButtonExit->SetToolTipText("Exit Application (ROOT)");
174  fButtonExit->Connect("Clicked()" , "TApplication", gApplication,
175  "Terminate()");
176  hf->AddFrame(fButtonExit, new TGLayoutHints(kLHintsCenterY | kLHintsRight,
177  10, 10, 10, 10));
178 
179  AddFrame(hf, new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5));
180 
181  gRootObj = gVirtualX->InternAtom("application/root", kFALSE);
182 
183  TGraph *gr = (TGraph *)GetObject("Graph");
184  pic = gClient->GetPicture("f1_t.xpm");
185  item = fListTree->AddItem(fBaseLTI, gr->GetName(), gr, pic, pic);
186  fListTree->SetToolTipItem(item, "Simple Graph");
187  item->SetDNDSource(kTRUE);
188 
189  TH1F *hpx = (TH1F *)GetObject("1D Hist");
190  pic = gClient->GetPicture("h1_t.xpm");
191  item = fListTree->AddItem(fBaseLTI, hpx->GetName(), hpx, pic, pic);
192  fListTree->SetToolTipItem(item, "1D Histogram");
193  item->SetDNDSource(kTRUE);
194 
195  TH2F *h2 = (TH2F *)GetObject("2D Hist");
196  pic = gClient->GetPicture("h2_t.xpm");
197  item = fListTree->AddItem(fBaseLTI, h2->GetName(), h2, pic, pic);
198  fListTree->SetToolTipItem(item, "2D Histogram");
199  item->SetDNDSource(kTRUE);
200 
201  TString rootsys(gSystem->UnixPathName(gSystem->Getenv("ROOTSYS")));
202 #ifdef G__WIN32
203  // remove the drive letter (e.g. "C:/") from $ROOTSYS, if any
204  if (rootsys[1] == ':' && rootsys[2] == '/')
205  rootsys.Remove(0, 3);
206 #endif
207  TString link = TString::Format("/%s/tutorials/image/rose512.jpg",
208  rootsys.Data());
209  if (!gSystem->AccessPathName(link.Data(), kReadPermission)) {
210  TImage *img = TImage::Open(link.Data());
211  if (img) {
212  // create a 16x16 icon from the original picture
213  img->Scale(16, 16);
214  pic = gClient->GetPicturePool()->GetPicture("rose512", img->GetPixmap(),
215  img->GetMask());
216  delete img;
217  }
218  else pic = gClient->GetPicture("psp_t.xpm");
219  link.Prepend("file://");
220  TObjString *ostr = new TObjString(link.Data());
221  item = fListTree->AddItem(fBaseLTI, "Rose", ostr, pic, pic);
222  fListTree->SetToolTipItem(item, link.Data());
223  item->SetDNDSource(kTRUE);
224  }
225 
226  // open the base list tree item and allow to drop into it
227  fListTree->OpenItem(fBaseLTI);
228  fListTree->GetFirstItem()->SetDNDTarget(kTRUE);
229 
230  // connect the DataDropped signal to be able to handle it
231  fListTree->Connect("DataDropped(TGListTreeItem*, TDNDData*)", "DNDMainFrame",
232  this, "DataDropped(TGListTreeItem*,TDNDData*)");
233 
234  SetWindowName("ROOT DND Demo Application");
235  MapSubwindows();
236  Resize(GetDefaultSize());
237  Connect("CloseWindow()", "DNDMainFrame", this, "DoCloseWindow()");
238  DontCallClose(); // to avoid double deletions.
239 }
240 
241 //______________________________________________________________________________
242 DNDMainFrame::~DNDMainFrame()
243 {
244  // Destructor. Doesnt't do much here.
245 }
246 
247 //______________________________________________________________________________
248 void DNDMainFrame::DoCloseWindow()
249 {
250  // Do some cleanup, disconnect signals and then really close the main window.
251 
252  if (fGraph) { delete fGraph; fGraph = 0; }
253  if (fHist1D) { delete fHist1D; fHist1D = 0; }
254  if (fHist2D) { delete fHist2D; fHist2D = 0; }
255  fMenuFile->Disconnect("Activated(Int_t)", this, "HandleMenu(Int_t)");
256  fMenuHelp->Disconnect("Activated(Int_t)", this, "HandleMenu(Int_t)");
257  fButtonExit->Disconnect("Clicked()" , this, "CloseWindow()");
258  fListTree->Disconnect("DataDropped(TGListTreeItem*, TDNDData*)", this,
259  "DataDropped(TGListTreeItem*,TDNDData*)");
260  delete fListTree;
261  CloseWindow();
262 }
263 
264 //______________________________________________________________________________
265 void DNDMainFrame::DataDropped(TGListTreeItem *, TDNDData *data)
266 {
267  // Handle the drop event in the TGListTree. This will just create a new
268  // list tree item and copy the received data into it.
269 
270  fStatus->SetTextColor(0xff0000);
271  fStatus->ChangeText("I received data!!!");
272  if (data) {
273  const TGPicture *pic = 0;
274  TGListTreeItem *itm = 0;
275  char tmp[1000];
276  if (data->fDataType == gRootObj) {
277  TBufferFile buf(TBuffer::kRead, data->fDataLength, (void *)data->fData);
278  buf.SetReadMode();
279  TObject *obj = (TObject *)buf.ReadObjectAny(TObject::Class());
280  sprintf(tmp, "Received DND data : Type = \"%s\"; Length = %d bytes;",
281  obj->ClassName(), data->fDataLength);
282  if (obj->InheritsFrom("TGraph"))
283  pic = gClient->GetPicture("f1_t.xpm");
284  else if (obj->InheritsFrom("TH2F"))
285  pic = gClient->GetPicture("h2_t.xpm");
286  else if (obj->InheritsFrom("TH1F"))
287  pic = gClient->GetPicture("h1_t.xpm");
288  itm = fListTree->AddItem(fBaseLTI, obj->GetName(), obj, pic, pic);
289  fListTree->SetToolTipItem(itm, obj->GetName());
290  }
291  else {
292  sprintf(tmp, "Received DND data: \"%s\"", (char *)data->fData);
293  TObjString *ostr = new TObjString((char *)data->fData);
294  TImage *img1 = TImage::Open("doc_t.xpm");
295  TImage *img2 = TImage::Open("slink_t.xpm");
296  if (img1 && img2) {
297  img1->Merge(img2);
298  pic = gClient->GetPicturePool()->GetPicture("doc_lnk", img1->GetPixmap(),
299  img1->GetMask());
300  delete img2;
301  delete img1;
302  }
303  else pic = gClient->GetPicture("doc_t.xpm");
304  itm = fListTree->AddItem(fBaseLTI, "Link...", ostr, pic, pic);
305  fListTree->SetToolTipItem(itm, (const char *)data->fData);
306  }
307  if (itm) itm->SetDNDSource(kTRUE);
308  fStatus->ChangeText(tmp);
309  }
310  TTimer::SingleShot(3000, "DNDMainFrame", this, "ResetStatus()");
311 }
312 
313 //______________________________________________________________________________
314 TObject *DNDMainFrame::GetObject(const char *obj)
315 {
316  // Return the object specified in argument. If the object doesn't exist yet,
317  // it is firt created.
318 
319  if (!strcmp(obj, "Graph")) {
320  if (fGraph == 0) {
321  const Int_t n = 20;
322  Double_t x[n], y[n];
323  for (Int_t i=0;i<n;i++) {
324  x[i] = i*0.1;
325  y[i] = 10*sin(x[i]+0.2);
326  }
327  fGraph = new TGraph(n, x, y);
328  }
329  return fGraph;
330  }
331  else if (!strcmp(obj, "1D Hist")) {
332  if (fHist1D == 0) {
333  fHist1D = new TH1F("1D Hist","This is the px distribution",100,-4,4);
334  Float_t px, py;
335  for ( Int_t i=0; i<10000; i++) {
336  gRandom->Rannor(px, py);
337  fHist1D->Fill(px);
338  }
339  }
340  return fHist1D;
341  }
342  else if (!strcmp(obj, "2D Hist")) {
343  if (fHist2D == 0) {
344  Double_t params[] = {
345  130,-1.4,1.8,1.5,1, 150,2,0.5,-2,0.5, 3600,-2,0.7,-3,0.3
346  };
347  TF2 *f2 = new TF2("f2","xygaus + xygaus(5) + xylandau(10)",
348  -4, 4, -4, 4);
349  f2->SetParameters(params);
350  fHist2D = new TH2F("2D Hist","xygaus+xygaus(5)+xylandau(10)",
351  20, -4, 4, 20, -4, 4);
352  fHist2D->FillRandom("f2",40000);
353  }
354  return fHist2D;
355  }
356  return 0;
357 }
358 
359 //______________________________________________________________________________
360 void DNDMainFrame::HandleMenu(Int_t menu_id)
361 {
362  // Handle menu events.
363 
364  TRootHelpDialog *hd;
365  static TString dir(".");
366  TGFileInfo fi;
367  fi.fFileTypes = dnd_types;
368  fi.fIniDir = StrDup(dir);
369 
370  switch (menu_id) {
371  case M_FILE_EXIT:
372  // close the window and quit application
373  DoCloseWindow();
375  break;
376  case M_FILE_OPEN:
377  new TGFileDialog(gClient->GetRoot(), this, kFDOpen, &fi);
378  dir = fi.fIniDir;
379  // doesn't do much, but can be used to open a root file...
380  break;
381  case M_FILE_BROWSE:
382  // start a root object browser
383  new TBrowser();
384  break;
385  case M_FILE_NEWCANVAS:
386  // open a root canvas
387  gROOT->MakeDefCanvas();
388  break;
389  case M_FILE_CLOSEWIN:
390  DoCloseWindow();
391  break;
392  case M_HELP_ABOUT:
393  hd = new TRootHelpDialog(this, "About Drag and Drop...", 550, 250);
394  hd->SetText(gHelpDND);
395  hd->Popup();
396  break;
397  }
398 }
399 
400 //______________________________________________________________________________
401 void DNDMainFrame::ResetStatus()
402 {
403  // Restore the original text of the status label and its original color.
404 
405  fStatus->SetTextColor(0x0000ff);
406  fStatus->ChangeText(gReadyMsg);
407 }
408 
409 //------------------------------------------------------------------------------
410 void drag_and_drop()
411 {
412  // Main function (entry point)
413 
414  DNDMainFrame *mainWindow = new DNDMainFrame(gClient->GetRoot(), 700, 400);
415  mainWindow->MapWindow();
416 }
417 
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition: TSystem.cxx:1265
virtual void SetParameters(const Double_t *params)
Definition: TF1.h:439
virtual void Rannor(Float_t &a, Float_t &b)
Return 2 numbers distributed following a gaussian with mean=0 and sigma=1.
Definition: TRandom.cxx:460
Int_t fDataLength
Definition: TGDNDManager.h:80
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:51
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:488
Collectable string class.
Definition: TObjString.h:32
float Float_t
Definition: RtypesCore.h:53
EMyMessageTypes
THist< 1, float, THistStatContent, THistStatUncertainty > TH1F
Definition: THist.hxx:302
TH1 * h
Definition: legend2.C:5
#define gROOT
Definition: TROOT.h:364
Basic string class.
Definition: TString.h:137
tomato 1-D histogram with a float per channel (see TH1 documentation)}
Definition: TH1.h:575
#define gClient
Definition: TGClient.h:174
static void SingleShot(Int_t milliSec, const char *receiver_class, void *receiver, const char *method)
This static function calls a slot after a given time interval.
Definition: TTimer.cxx:256
int Int_t
Definition: RtypesCore.h:41
const Bool_t kFALSE
Definition: Rtypes.h:92
virtual void AddEntry(TGHotString *s, Int_t id, void *ud=0, const TGPicture *p=0, TGMenuEntry *before=0)
Add a menu entry.
Definition: TGMenu.cxx:987
An abstract interface to image processing library.
Definition: TImage.h:37
virtual void Terminate(Int_t status=0)
Terminate the application by call TSystem::Exit() unless application has been told to return from Run...
virtual void Merge(const TImage *, const char *="alphablend", Int_t=0, Int_t=0)
Definition: TImage.h:180
TString & Prepend(const char *cs)
Definition: TString.h:604
R__EXTERN TApplication * gApplication
Definition: TApplication.h:171
const char * Class
Definition: TXMLSetup.cxx:64
virtual Pixmap_t GetPixmap()
Definition: TImage.h:243
virtual const char * UnixPathName(const char *unixpathname)
Convert from a Unix pathname to a local pathname.
Definition: TSystem.cxx:1037
virtual void Scale(UInt_t, UInt_t)
Definition: TImage.h:149
const char * Data() const
Definition: TString.h:349
void SetText(const char *helpText)
Set help text from helpText buffer in TGTextView.
Double_t x[n]
Definition: legend1.C:17
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2335
const char ** fFileTypes
Definition: TGFileDialog.h:65
Handle_t Atom_t
Definition: GuiTypes.h:38
virtual const char * Getenv(const char *env)
Get environment variable.
Definition: TSystem.cxx:1627
void * fData
Definition: TGDNDManager.h:79
double sin(double)
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:41
R__EXTERN TSystem * gSystem
Definition: TSystem.h:549
void Popup()
Show help dialog.
tomato 2-D histogram with a float per channel (see TH1 documentation)}
Definition: TH2.h:255
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition: TObject.cxx:188
const Handle_t kNone
Definition: GuiTypes.h:89
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
A 2-Dim function with parameters.
Definition: TF2.h:33
Atom_t fDataType
Definition: TGDNDManager.h:77
R__EXTERN TRandom * gRandom
Definition: TRandom.h:66
TGraphErrors * gr
Definition: legend1.C:25
#define gVirtualX
Definition: TVirtualX.h:362
char * StrDup(const char *str)
Duplicate the string str.
Definition: TString.cxx:2514
The Canvas class.
Definition: TCanvas.h:41
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:416
virtual Pixmap_t GetMask()
Definition: TImage.h:244
double Double_t
Definition: RtypesCore.h:55
Double_t y[n]
Definition: legend1.C:17
virtual void AddFrame(TGFrame *f, TGLayoutHints *l=0)
Add frame to the composite frame using the specified layout hints.
Definition: TGFrame.cxx:1099
Mother of all ROOT objects.
Definition: TObject.h:44
double f2(const double *x)
A Graph is a graphics object made of two arrays X and Y with npoints each.
Definition: TGraph.h:53
void SetDNDSource(Bool_t onoff)
Definition: TGListTree.h:129
static TImage * Open(const char *file, EImageFileTypes type=kUnknown)
Open a specified image file.
Definition: TImage.cxx:110
const Bool_t kTRUE
Definition: Rtypes.h:91
THist< 2, float, THistStatContent, THistStatUncertainty > TH2F
Definition: THist.hxx:308
const Int_t n
Definition: legend1.C:16
char * fIniDir
Definition: TGFileDialog.h:64