Problems with TGCanvas

Hello,
I’m having two issues with TGCanvas that I have been unable to solve:

The first is that the TGCanvas does not seem to resize in the x direction when using kLHintsExpandX. From a class that is a TGTransientFrame window, I’m trying to embed a canvas (so that I’ll have access to scroll bars) and then embed one or more graphs. I create the necessary frames and canvas as so:

void RTDWindow::AddEmbeddedCanvas()
{
    fCanvasWindow = new TGCanvas(this, 900, 400);
    fMainFrame = new TGCompositeFrame(fCanvasWindow->GetViewPort(),
                    900, 400,
                    kLHintsExpandX | kLHintsExpandY | kVerticalFrame);
    fCanvasWindow->SetContainer(fMainFrame);

    // The remaining space I want to be a frame.
    // Inside this frame I will embed a canvas for drawing the profile.
    fGraphicsFrame = new TGCompositeFrame(fMainFrame, 900, 400,
                kLHintsExpandX | kLHintsExpandY | kVerticalFrame);

    fEmbeddedCanvas = new TRootEmbeddedCanvas("ec1", fGraphicsFrame,
                        900, 400);


    fL3 = new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY,
                            2, 2, 0, 0);

    fL4 = new TGLayoutHints(kLHintsTop | kLHintsLeft |
                            kLHintsExpandX | kLHintsExpandY,
                            5, 5, 5, 5);

    fGraphicsFrame->AddFrame(fEmbeddedCanvas, fL4);
    fMainFrame->AddFrame(fGraphicsFrame, fL3);

    TCanvas *c1 = fEmbeddedCanvas->GetCanvas();
    c1->SetBit(kNoContextMenu);
    c1->SetBorderMode(0);
    c1->SetGrid();
    c1->cd();

    this->AddFrame(fCanvasWindow, new TGLayoutHints(kLHintsTop | kLHintsExpandX | kLHintsExpandY,
                       0, 0, 0, 0));

    fMainFrame->Resize();
    fCanvasWindow->Resize();
    fGraphicsFrame->Resize();
    fEmbeddedCanvas->Resize();
}

The graph is able to be drawn correctly and both the vertical and horizontal scrollbars appear as desired. As you can see, I specify both kLHintsExpandX and kLHintsExpandY. When resizing the window and making it larger, the Y direction works fine but the X direction does not (attached no_x_resize.png). There is a white space where the main frame and canvas do not expand.

The second issue comes when trying to remove a frame from the TGCanvas (maybe will be resolved by fix to the first problem?):
Again, I’d like to put several graphs in the TGCanvas and have the scrollbars appear as necessary. This works almost perfectly with the exception of the problem described above (attached multi_panes.png). However, when the user selects from the menu to remove a graph, I have the problem where the TGCanvas does not seem to be re-drawn correctly after the frame and canvas containing the graph are removed. I add a frame and a canvas for an additional graph as follows:

TRootEmbeddedCanvas* RTDWindow::AddNewPane()
{
    TCanvas *c1;
    TGCompositeFrame *newGraphicsFrame;
    TRootEmbeddedCanvas *newEmbeddedCanvas;


    newGraphicsFrame = new TGCompositeFrame(fMainFrame, 900, 400,
                kLHintsExpandX | kLHintsExpandY | kVerticalFrame);
    newEmbeddedCanvas = new TRootEmbeddedCanvas("0", newGraphicsFrame,
                        900, 400);

    newGraphicsFrame->AddFrame(newEmbeddedCanvas, fL4);
    fMainFrame->AddFrame(newGraphicsFrame, fL3);

    c1 = newEmbeddedCanvas->GetCanvas();
    c1->SetBit(kNoContextMenu);
    c1->SetBorderMode(0);
    c1->SetGrid();
    c1->cd();

    newEmbeddedCanvas->Resize();
    newGraphicsFrame->Resize();
    fCanvasWindow->Resize();
    fMainFrame->Resize();

    newEmbeddedCanvas->GetCanvas()->Modified();
    newEmbeddedCanvas->GetCanvas()->Update();

    this->MapSubwindows();
    this->Resize();
    this->MapWindow();

    return newEmbeddedCanvas;
}

When the user wants to remove a graph, I do:

// curPaneData->GetFrame() is the newGraphicsFrame from above
// curPaneData->GetCanvas() is the newEmbeddedCanvas from above
curPaneData->GetFrame()->RemoveFrame(curPaneData->GetCanvas());
fMainFrame->RemoveFrame(curPaneData->GetFrame());

// followed by all sorts of attempts to try to get the window to display correctly
fCanvasWindow->Layout();
fCanvasWindow->MapSubwindows();
fCanvasWindow->Resize();
fCanvasWindow->MapWindow();

fMainFrame->Layout();
fMainFrame->MapSubwindows();
fMainFrame->Resize();
fMainFrame->MapWindow();

this->Layout();
this->MapSubwindows();
this->Resize();
this->MapWindow();

At first glance, this almost works. The vertical scroll bar size decreases, indicating that the frame has been removed, and depending on the position of the vertical scrollbar the window size decreases. However, if I resize the window, or if the vertical scrollbar is somewhere in the middle when removing the frame, the window is not redrawn correctly - the removed frame is still there and covers the top remaining graph (attached bad_remove_frame.png).

Any help to get my window to function better would be greatly appreciated as I have run out of ideas to try.
Thanks very much!
Tim






Hi,

At the first glance I see in your code a mixture of frame option and layout hints when you create fMainFrame, fGraphicsFrame and newGraphicsFrame objects. When you create them, you have to provide frame options as a parameter of their constructors. Please have a look at ftp://root.cern.ch/root/doc/chapter26.pdf (page 387). The layout hints have to be specified when you add those objects to the parent frame (that is done fine in your code).

Please fix the creation of fMainFrame, fGraphicsFrame and newGraphicsFrame in your code and let us know if you have still problems. A small running example could help in this case for reproducing the problem.

Cheers, Ilka

Ilka,
Thanks so much for your help. Putting the correct options in the constructor for the frames did indeed fix my problem with the frame not scaling in the x direction. I had to simply replace kLHintsExpandX with kFitWidth and it worked correctly.

My second problem still remains, however. I’ve attached a very simple guitest.cxx to illustrate. Select ‘Select Data’ from the File menu to create a new pane. Then select ‘Remove Graph’ from the file menu. The vertical scroll bar changes correctly. Now resize the window, making it larger. You can see that the second frame is still remaining underneath. It also doesn’t work correctly if you add a pane, make the window larger and then try removing the pane.

Thanks!
Tim
guitest.cxx (7.87 KB)

Hi Tim,

Thank you for provided example - I can reproduce the problem and will investigate the reasons. As a temporary workaround you could make your application window not resizable.

Cheers, Ilka

Ilka,
I’m sure you’re very busy with many ROOT projects, but any success with finding a solution for this problem? Unfortunately, even making the window a fixed size does not provide a good solution. Depending on the location of the scroll bar the window might not display correctly even with a fixed size, so I’d really like to be able to get this working correctly.
Thanks!
Tim Sorrentino

Hi Tim,

You are right - I was busy with my tasks for the last ROOT release and after that with the User’s Guide update according to it. I had some time to investigate your case before the Christmas holidays but have not found a solution yet. We will be back at work on Monday and I will continue my investigation. I will keep you informed.

Cheers, Ilka

Hi Tim,

Please find attached guitest_1.cxx as a solution of your problem. I spent some time looking for bugs on the TGCanvas level, but it was not the case. In fact, the method RemoveFrame should not be used when removing an object from the container of TGCanvas. Please have a look into the changes I made in DoUnLoad method. Also, I have simplified your code by removing some extra container frames. Please let me know if this example works for you.

Thank you, Ilka
guitest_1.cxx (6.33 KB)

Ilka,
As always, thank you for your time and help! Your solution works great and has solved my problem with removing a pane.

During the time that I asked the original question, the application has evolved somewhat to use splitter bars. I’ve used the solution you provided in my new version with splitters and it still works great. I do have two questions, however, to make sure that I am doing things properly (perhaps this belongs in a separate post on splitters).

1.) When you first start the application there is one pane only. I’d like the canvas to take up the entire window. When another pane is added, a splitter bar is added as well. From the documentation on splitters, I’ve figure out that the original pane needs to change from using kLHintsExpand X and Y to only kLHintsExpandX. You also need to change the original pane to use kFixedSize. There is a method to set the kFixedSize bit but the only way I could figure out to change the layout hints was to remove the frame and then add it again using different layout hints. It seems to work just fine, but should I be doing this a different way?

2.) When removing a pane, I’ve called DestroySubwindows() to delete all the frames and canvases in the pane. Does this take care of properly removing the frames and canvases? Is it even necessary or would one call to DestroyWindow() take care of everything?

I’ve attached some simplified code to illustrate what I’m trying to do as well as a screenshot to illustrate the overall application and how the example has been extended to multiple panes.

Thanks!
Tim



guitest.cxx (10.9 KB)

Hi Tim,

There are disadvantages to use splitters in your case: the way the drawing in the canvas area is modified; the way to add/remove a new canvas, etc. May I propose you to use TGTab instead? This class provide a flexibility to add/remove tabs with embedded canvases keeping the same size. As an example you can see RootShower application in $ROOTSYS/test/RootShower directory. In case you need to compare the data visually, you can divide the canvas in several pads for different drawing. But this is only a proposal from my point of understanding of your application. Of course, I will have a look in your code and will try to find a solution if you are waiting for it.

Cheers, Ilka

I do like the TGTab effect demonstarted in RootShower and I agree that it would be much easier to implement. Unfortunately, I’m replacing an older software component and the customer would like the application to look like the old application as much as possible, just with additional functionality. I’m pretty limited as to how I design the GUI, so I’m trying to use all of ROOT’s features the best way I can to fulfill the design requirements. My application is now working correctly, the way I need it to, or at least it appears that way. I just wanted to check on those two items to make sure that I wasn’t adding or removing splitters improperly and it just happened to work.
Thanks!
Tim

Hi Tim,

I understand very well and will check the way your code works as soon as I can. Unfortunately no time for that right now.

Cheers, Ilka