Interactive TApplication

Hi rooters,

I am trying to make a simple executable that displays a canvas with a certain plot (in interactive mode, so that the user zoom in/out and do other things), and then asks the user whether or not to save a file.

I know I can open the canvas and “stop” the executable from exiting with TApplication, but how can I do input/output (even the simplest cin) while the application is running?

here’s a sample of my code:

int main(int argv, char** argc){

    /*
     Here I create and fill a TH2F "h"
    */

    TApplication* app = new TApplication("app",0,0);
    // Draw and save TH2F
    TCanvas* c = new TCanvas("c","c",800,600);
    TRootCanvas* rc = (TRootCanvas*)c->GetCanvasImp();
    h->Draw("colz");

    app->Run();

    // Ask user if they want to save 2d binning file
    std::cout<<"Do you want to save the 2d binning file? (y/n)\n";
    std::string answer;
    std::cin>>answer;
    if(answer=="y"){
        //Saving binning file...
    }

    return 0;
}

I would like the part “ask the user if they want to save the binning file” to be within the TApplication.

Another solution I thought of would be to use Connect and terminate the Application when the canvas is closed, addingrc->Connect("CloseWindow()", "TApplication", gApplication, "Terminate()"); after app->Run(), but this closes my executable entirely, and does not go to the following code where I ask the input to the user.

Any suggestions?

_ROOT Version: 6.26
_Platform: mac
_Compiler:c++14


You can try something like this:

int main(int argv, char** argc)
{
    /*
     Here I create and fill a TH2F "h"
    */
    TApplication* app = new TApplication("app",0,0);
    // Draw and save TH2F
    TCanvas* c = new TCanvas("c","c",800,600);
    TRootCanvas* rc = (TRootCanvas*)c->GetCanvasImp();
    h->Draw("colz");
    // Ask user if they want to save 2d binning file
    Int_t retval;
    new TGMsgBox(gClient->GetRoot(), gClient->GetRoot(),
                 "Question", "Do you want to save the 2d binning file?",
                 kMBIconQuestion, kMBYes | kMBNo | kMBCancel, &retval);
    if (retval == kMBYes)
       std::cout << "Saving binning file..." << std::endl;
    app->Run();
    return 0;
}

unfortunately I have a problem while linking this.
I get the following error message in my compiler/linker:

Undefined symbols for architecture arm64:
  "TGClient::Instance()", referenced from:
      _main in FitterBinningBuilder-ffe4ce.o
  "TGMsgBox::TGMsgBox(TGWindow const*, TGWindow const*, char const*, char const*, EMsgBoxIcon, int, int*, unsigned int, int)", referenced from:
      _main in FitterBinningBuilder-ffe4ce.o
  "TGClient::GetRoot() const", referenced from:
      _main in FitterBinningBuilder-ffe4ce.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [FitterBinningBuilder] Error 1

I included both:

#include "TGMsgBox.h"
#include "TGClient.h"

Make you can help with that?

You must link with libGui

Ok, now the compilation works but:

THis solution is ot ideal for me as:

  1. the Root canvas is not shown anymore, only the message box
  2. I would like it to work with a terminal I/O rather than a message box

Is it possible?

Weird, it works fine on Windows…

This is blocking the event loo. There might be other solutions, but it is maybe a conceptual issue. I’ll check tomorrow

    // Ask user if they want to save 2d binning file
    std::cout<<"Do you want to save the 2d binning file? (y/n)\n";
    std::string answer;
    while (1) {
       if (_kbhit()) {
          std::cin>>answer;
          if(answer=="y"){
              std::cout << "Saving binning file..." << std::endl;
              //Saving binning file...
          }
       }
       gSystem->ProcessEvents();
       gSystem->Sleep(20);
    }

I found a workaround:


    while(!returned){
        c->Update();
        gSystem->ProcessEvents();
        std::string answer = "";
        std::cout<<"\rDo you want to save the 2d binning file? (y/n)";
        std::cin>>answer;
        if (answer=="y" || answer=="Y" || answer=="yes" || answer=="Yes" || answer=="YES") {
            returned=true;
           // Saving binning file
            theApp.Terminate();
        }else{
            returned=true;
            std::cout<<"Binning file not saved.\n";
            theApp.Terminate();
        }
    }

it is a bit ugly, and it works only partially: the only annoying thing is that I lose the interactivity of the canvas (zooming in/out)…

As I said, std::cin>>answer; is blocking the event loop. But up to you if you want to keep the input from the console…