How to call gSystem->ProcessEvents() to avoid frozen canvas

Dear rooters,

I am writing a histogram display program. It fetches histograms from a server and display them locally. The canvas where the histogram is drawn should respond to user mouse events. Here is a simplified version:

{
  TTimer *timer = new TTimer(0);
  timer->SetCommand("gSystem->ProcessEvents();");
  timer->Start();

  TH1F h1("h1", "histo from a gaussian", 100, -3, 3);

  while(1) {
    h1.FillRandom("gaus", 10000);
    h1.Draw();

    getchar();

    // break in some condition
  }

  timer->Stop();
  delete timer;
}

I thought I have the gSystem->ProcessEvents() running independently on the while loop. But obviously this is not the case. Could someone tell me where I did wrong?

Thank you,

Jing

Hi

You should put gSystem->ProcessEvents() in the while loop (timers are processed by gSystem->ProcessEvents()…) Or create several threads if you need to handle several events in parallel

Cheers, Bertrand.

1 Like

[quote=“bellenot”]Hi

You should put gSystem->ProcessEvents() in the while loop (timers are processed by gSystem->ProcessEvents()…) Or create several threads if you need to handle several events in parallel

Cheers, Bertrand.[/quote]

Thank you, Bertrand,

here is another version:

{
   TH1F h1("h1", "histo from a gaussian", 100, -3, 3);

   while(1) {
      h1.FillRandom("gaus", 10000);
      h1.Draw();

      gSystem->ProcessEvents();
      getchar();
   }
}

“gSystem->ProcessEvents()” will be executed once after the draw command. When the terminal is waiting for the input, the canvas is frozen because gSystem is not processing events constantly (for example, every 1 second).

Sorry that I am not familiar with thread. If there is no easy solution I may then try thread…

Cheers, Jing

Hi Jing,

Why do you need getchar()? You could use another solution, like WaitPrimitive(), or use the TApplication::ReturnPressed() signal, as shown in this very simple example:

[code]TH1F *h1 = 0;

void NextHisto()
{
if (h1) {
h1->FillRandom(“gaus”, 10000);
h1->Draw();
}
}

void UserInput()
{
h1 = new TH1F(“h1”, “histo from a gaussian”, 100, -3, 3);
h1->FillRandom(“gaus”, 10000);
h1->Draw();
gApplication->Connect(“ReturnPressed(const char*)”, 0, 0, “NextHisto()”);
}
[/code]

Cheers, Bertrand.

Hi, Bertrand,

thank you for the example! I did not know ReturnPressed() signal can be used this way :stuck_out_tongue:

what I really did is to make a prompt for the user:

       cout<<"Please type a command to continue: "<<endl;
       cout<<" q : quit this program"<<endl;
       cout<<" s : save histogram"<<endl;
       cout<<" 0 : draw hit map"<<endl;
       cout<<" a number from 1 to 720 : draw ADC[number]"<<endl;
       cout<<" a number from -1 to -720 : draw TDC[-number]"<<endl;
       cout<<" unrecognized : update current histogram"<<endl;
       cout<<"Command ["<<loop<<"]: ";
       gets(command);
       if (command[0]=='q') break;
       else if (command[0] == '0') hist = "fHIDHitMap";
       else if (atoi(command) > 0 && atoi(command)<=720)
          hist = Form("fHIDADC[%d]",atoi(command));
       else if (atoi(command) < 0 && atoi(command)>=-720)
          hist = Form("fHIDTDC[%d]",-atoi(command));
       else if (command[0]=='s') {
          TFile fout(hist+".root","recreate");
          fout.cd();
          h1->Write();
          fout.Close();
          cout<<hist<<" saved to "<<hist+".root"<<endl;
       }

I’d like users to do something on the current canvas (for example zoom-in and out) and then type in the terminal a command to continue. I will see if I can use your way to make this kind of prompt.

Thanks a lot, Jing

You’re welcome! And you can use the “const char*” signal parameter:

void NextHisto(const char *command)
{
   cout<<command<<endl;
   if (command[0]=='q') gApplication->Terminate(0);
   [...]
}
void UserInput()
{
   [...]
   gApplication->Connect("ReturnPressed(const char*)", 0, 0, "NextHisto(const char*)");
   [...]

– Bertrand.

This is very nice. But the script won’t stop after the above code. It will keep running to the end and give back the ROOT prompt. And now the ROOT prompt will respond to both my commands defined in the script and the normal ROOT commands. If I type in a command, which can be recognized by my script but not by ROOT, ROOT will give out error message:

Error: Symbol kjsafdsaf is not defined in current scope (tmpfile):1:
*** Interpreter error recovered ***

If I tell the script to wait for user input rather than keep running to the end, then I freeze the canvas again, because there is still only one thread in our simple solution. Don’t know if there is a easy way to solve this…

Thanks again, Jing

Hi Jing,

Here is another possible solution, using a dialog to enter a command:

void UserInput() { char command[80]; h1 = new TH1F("h1", "histo from a gaussian", 100, -3, 3); h1->FillRandom("gaus", 10000); h1->Draw(); printf("\nDouble click in the bottom right corner of the pad to continue\n"); while (1) { h1->FillRandom("gaus", 10000); gPad->Modified(); gPad->Update(); gPad->WaitPrimitive(); new TGInputDialog(gClient->GetDefaultRoot(), gClient->GetDefaultRoot(), "Please type a command:", "q", command); cout<<command<<endl; if (command[0]=='q') gApplication->Terminate(0); } }
Cheers, Bertrand.

Dear Bertrand,

you always have solutions :slight_smile: Thank you very much again! Meanwhile, I found an old post through Google:

root.cern.ch/root/roottalk/roottalk02/0530.html

It was the solution I looked for originally. But now I kind of like your solution (the ReturnPressed one) more, because a ROOT prompt is better than a simple getline, for example, I can now use arrow keys to bring back old commands. (Of course, I will have to live with some warning messages.)

Could you please shortly explain what an “asynchronous” timer is?

And is there any comprehensive explanation about TApplication, TSystem, TClient, etc. (instead of the class documentation pages)?

Cheers, Jing

Dear Jing,

You’re right, sorry, I forgot about asynchronous timers… :blush:
According to the class documentation:

[quote]1. synchronous timer is registered into TSystem and is processed
within the standard ROOT event-loop.
2. asynchronous timer is passed to the operating system which sends
an external signal to ROOT and thus interrupts its event-loop.[/quote]
And you can find some information in the user’s guide, but not very extensive about TApplication, TSystem, and TGClient…

Cheers, Bertrand.

Dear Bertrand,

nice talking to you. I’ve learned a lot.

Thank you!

Jing

You’re welcome! Glad to be able to help a bit. :smiley:

Cheers, Bertrand.