Handle click on a TGCompositeFrame

Hi,

I would like to create a context menu that pops up when I click on a custom child class of TGCompositeFrame. However, I cannot get the frame to notice that it was clicked. I tried connecting the provided signals “ProcessEvent” and “ProcessConfigure” but to no avail. As far as I could see, only resize events are handled. Also, reimplementing the “HandleSomething(Event*)” methods was not successful.

Any suggestions?

Cheers,
Greg

Hi Greg,

You should add the proper event mask to the frame you want to emit signals. For example:

YourCompositeFrame->AddInput(kButtonPressMask | kButtonReleaseMask); YourCompositeFrame->Connect("ProcessedEvent(Event_t*)", "YourMainFrame", main, "HandleEvent(Event_t*)"); (or do this in your derived class)

Cheers, Bertrand.

Very cool, I do get the menu to pop up now!

Drawback: The frame contains an embedded canvas in which images are displayed. The new menu now also shows up when I click on canvas or image and also e.g. the image zoom doesn’t work anymore.

I tried fEmbCanvas->RemoveInput(kButtonPressMask | kButtonReleaseMask); but it doesn’t change anything.

Is there a way to only pop up the menu when clicking directly on the frame in the background and NOT when clicking on a child frame?

Well. I don’t see how your layout is done, but yes, events might be propagated, so you should maybe create a specific child frame handling your context menu only… Otherwise, please provide a running macro illustrating what you are doing, so I can see if it is possible to implement or not.

Cheers, Bertrand.

Hmm, by creating a test GUI, I accidentally stumbled upon a quite messy solution, but I’m open for something better!

The GUI resizes the embedded canvas when the image is zoomed in order to best fit the zoomed image dimensions - I have my reasons for that… Actually, if there is a way to always center the zoom area of a TImage horizontally and vertically in its TCanvas without changing the image ratio and I have just overlooked it, please let me know and forget about the rest below.

Now, when you zoom a low but long strip with all black pixels in the example (use context menu “Zoom” if visual zoom doesn’t work), you are unable to discern the image from the background frame. Here, I offer the additional context menu to unzoom the image.

The accidental solution I mentioned is commented out in line 27. If I attach the embedded canvas to fMain instead of fFrameCnv, the new context menu is not propagated. But the image is slightly drawn to big in the example. In real life I have a grid of embedded canvases and, believe me, it’s a mess. What I could do is add yet another frame on top of each background frame fFrameCnv[i] in my grid. But if there’s a different way for switching off the propagation from fFrameCnv to its child canvas I’d rather not.
MyGui.zip (104 KB)

Hi Greg,

OK, I’ll check tomorrow, but BTW, do you know you can modify existing context menus (e.g. the one of TASImage) and implement your own methods? See for example the tutorials customContextMenu.C and customTH1Fmenu.C in $ROOTSYS/tutorials/gui

Cheers, Bertrand.

Hi, yes, I’m using that a lot. And I have also been adding menus to TGListBoxes and other GUI elements. That’s why the difficulties with the TGFrame surprised me somewhat…

Hi Greg,

OK, the bad news is that there is a weird behavior with these mouse button events that I will have to investigate, but the good news is that there is also a very simple solution. Simply add:

fEmbCanvas->GetContainer()->AddInput(kButtonPressMask | kButtonReleaseMask); This should solve all your problems. Otherwise just let me know :wink:

[color=#FF0000]EDITED:[/color]
And BTW, you can avoid using ProcessedEvent() signal/slot by simply using HandleButton:

class CanvasBGFrame : public TGCompositeFrame
{
public:
   TContextMenu* fContextMenu;

   CanvasBGFrame(const TGWindow *p=0, UInt_t w=1, UInt_t h=1, UInt_t options=0, 
                 Pixel_t back = GetDefaultFrameBackground()) : 
                 TGCompositeFrame(p,w,h,options,back) {
      AddInput(kButtonPressMask | kButtonReleaseMask);
      fContextMenu = new TContextMenu("CanvasBGFrame");
   };
   virtual ~CanvasBGFrame(){};

   Bool_t HandleButton(Event_t *ev) {
      // only popup context menu if user clicked with the right button
      if (ev->fType == kButtonRelease && ev->fCode == kButton3) {
         Int_t px = 0, py = 0;
         Window_t wtarget;
         // translate coordinates from the event window (the list box container) 
         // to the root (desktop) window
         gVirtualX->TranslateCoordinates(ev->fWindow, 
                                         gClient->GetDefaultRoot()->GetId(), 
                                         ev->fX, ev->fY, px, py, wtarget);
         // popup the context menu, automatically using the TGListBox methods 
         // having // *MENU* as comment
         fContextMenu->Popup(px, py, this);
      }
      return TGFrame::HandleButton(ev);
   };
   virtual void UnZoom() { Emit("UnZoom()"); }; // *MENU* *SIGNAL*

   ClassDef(CanvasBGFrame, 0);
};

[color=#FF0000]EDITED(2):[/color]
And BTW, you should cleanup your code to avoid this kind of mix-up:

[code]class MyMainFrame : public TGMainFrame
{
RQ_OBJECT(“MyMainFrame”)

private:
TGMainFrame *fMain;
[/code]
And only (and simply) use:

class MyMainFrame : public TGMainFramei.e. remove RQ_OBJECT(“MyMainFrame”) and TGMainFrame *fMain;

Cheers, Bertrand.

Thanks for another very helpful reply, Bertrand! It all works now as it should…

@EDIT(2): Thanks for pointing that out, seems to be a relict from years ago that I haven’t even looked at in years… :smiley: