Changing the size of TCanvas on the go (Run Time)


Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Linux
Compiler: Not Provided


Hi,

I am building a QT application which wraps over Root. I managed to successfully display all sorts of histograms in a TCanvas but I cannot get the TCanvas resize to work. The TCanvas when created is the size of the window in which it displays but It seems that it cannot be resized in Run Time of the program. I tried using SetCanvasSize followed by an Update. My guess is that I’m missing something essential. Should I maybe use TGCanvas or TRootEmbeddedCanvas instead?

Window before resizing:
Screenshot_12
After Resizing:

The QWidgets within QT resize just fine but TCanvas does not change after calling the before mentioned functions.

I guess @bellenot can help you.

Try with those options:

   setAttribute(Qt::WA_PaintOnScreen, false);
   setAttribute(Qt::WA_OpaquePaintEvent, true);
   setAttribute(Qt::WA_NativeWindow, true);
   setUpdatesEnabled(kFALSE);

You can also try to play with those options to see which one could fix this issue…

Thank you for your input,

I already had that in my code. What I managed to observe is that somehow when I resize the physical window the following class instances do resize as well: QMainWindow, QWidget on top of which the TCanvas is based and here comes a tricky part. The TPad inside of that TCanvas changes it’s size just as expected but the TCanvas itself does not :face_with_monocle:. I tried inspecting that and all I managed to find out was that somehow a new instance of TCanvas was created ?

I am just leaving a small snippet of my code(maybe that will be enough to showcase the problem until I come up with a proper example code):

class TCanvasContainer: public QWidget{
    //My main pointer that (was supposed) to hold the histograms 
    TCanvas* m_canvas = nullptr;
    ...
}
//CTOR:
int wid = gVirtualX->AddWindow((ULong_t)winId(), width(), height());
m_canvas = new TCanvas("Root Canvas", width(), height(), wid);

// I handle resizing in the resizeEvent() method within the MainWindow class.
virtual void resizeEvent( QResizeEvent * event) override;

// It basically takes the size of the window and passes it further on to the class with the m_canvas where I attempt the following:
void TCanvasContainer::ResizeCanvas(const QSize & p_size) {
    std::cout << "m_canvas size: " << m_canvas->GetWw() << ", "
              << m_canvas->GetWh() << std::endl;
    std::cout << "MainWindow size: " << p_size.width() << "," << p_size.height() << std::endl;
    m_canvas->SetCanvasSize(p_size.width(), p_size.height());
    //retrieving the TPad from the m_canvas:
    auto pad = static_cast<TPad *>(m_canvas->cd());
    std::cout << "TPad size: " << pad->GetWw() << ", " << pad->GetWh() << std::endl;

    //retrieving the TCanvas back
    auto canv = pad->GetCanvas();

    //For some reason this one resizes just fine...
    std::cout << "canv size: " << canv->GetWw() << ", " << canv->GetWh() << std::endl;

    getEmbeddedCanvas()->displayAddressOfCanvas();
    std::cout << "&canv: " << &canv << ", canv: " << canv << std::endl;

    gPad->SetCanvasSize(p_size.width(), p_size.height());
    pad->SetCanvasSize(p_size.width(), p_size.height());

    m_canvas->Update();
}

What gets displayed to the console when I resize the window:

As you can tell the canv resizes just fine and the m_canvas stays the same (except for these moments when it changes for a split second and goes back to the original value).

When It comes to how the actual window behaves:
When resizing it seems as if the actual TCanvas received the singal telling it to resize and the actual plot rescales for a split second and then immediately resets itself back to the original form. (size of the plot stays the same just like in the original post)

That’s the way the plot looks like for that split second:
Screenshot_15

Edit:
I’m guessing blindly that maybe somehow it has to do something with TCanvasImp?

Edit2:
I have spent some extra time with the code and I managed to notice that when constructing the m_canvas in this way (without the Window ID):

m_canvas = new TCanvas("Root Canvas", "test",  width(), height());

A new window pops up instead of the previously build in TCanvas. And interestingly all the dependencies are still here - resizing the Main QT window causes the TCanvas within the second window to rescale/resize (it makes it so that it does not fit within the window anymore at some point)

Here is the way I do it, and AFAIK, it works (at least it used to work)

//______________________________________________________________________________
void QRootCanvas::resizeEvent( QResizeEvent *event )
{
   // Handle resize events.

   if (fCanvas) {
      fCanvas->SetCanvasSize(event->size().width(), event->size().height()); 
      fCanvas->Resize();
      fCanvas->Update();
   }
}

QRootCanvas being a QWidget

Yes, that’s the trick. Passing the window ID tells the window manager that the parent of the canvas is the window with this ID…

I don’t think so

I will try that and report back as soon as I know anything. Btw, did you use any extra resizeEvent handlers in your app for QMainWindow or just this one for the QRootCanvas class itself?

You can find the complete source code here: Root canvas in Qt5 revisited

I had a little bit of time to analize the example from you and so far my only big discovery is that the main class being used in the source code you have supplied is a QWidget whereas I use QMainWindow which has a QWidget inside. I suppose I could switch to the QWidget approach since I already know that it works… but for now I want to make sure that using QMainWindow is for sure impossible to implement. Do you maybe know anything about that?

Sorry, but I have no real experience with Qt…

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.