Argus - GUI extension of ROME


  • Introduction.
  • How to design own projects.
  • Introduction.

    ROME has the code generation function also for graphical interface. As empty tasks are generated based on <Task> sections in the definition XML file, graphical panels are generaged based on <Tab> section. The ROMEBuilder will create empty source code where users can write own design of the content in the tabs.
    There are two ways to run the GUI program. The first is to write a combined program for the analysis and the graphics parts. The tabs can fully access the histograms create by tasks and variables stored in the folders. The second is to separate the analysis part and the graphical part. In this case, the program for the graphics connects a ROME-based analysis program (running either on the same host or on a remote host) to obtain histograms for visualize over network.

    If you access a remote host, you need to open the corresponding port (9090 by default) of the host. There is an example program in the "example" directory in the rome package.
    For example, "netfolder" example shows how to draw histograms. Please read "readme" file in the directory.

    How to design own projects.

    How to create graphical objects.

    Each tab in ROME is a class, and Tabs can have several graphical objects in it. A Tab can be created with adding an entry in a project definition xml file.

    Xmonitor.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <ROMEFrameworkDefinition>
      <Experiment>
        <ExperimentName>X</ExperimentName>
        <ExperimentShortCut>X</ExperimentShortCut>
        <ProgramName>monitor</ProgramName>
      </Experiment>
      <Tabs>
        <Tab>
          <TabName>X</TabName>
          <TabTitle>XXX</TabTitle>
        </Tab>
      </Tabs>
    </ROMEFrameworkDefinition>
    

    From this definition file, romebuilder will generates header files and a source file under include/tabs and src/tabs. You will see this window when you run the created executable.

    You can put any ROOT graphical objects such as TGTextButton, TRootEmbeddedCanvas, TGListBox and so on with editing these header and source file. Your change in XTX.h and XTX.cpp will be preserved even if you run romebuilder again, while XTX_Base.h will be over written.

    For example, following change of XTX.h and XTX.cpp will add a canvas in the tab.

    XTX.h
    #include <include/generated/XTX_Base.h>
    #include <TCanvas.h>
    #include <TRootEmbeddedCanvas.h>
    
    class XTX : public XTX_Base
    {
    protected:
       TRootEmbeddedCanvas *fCanvas;
    
    public:
       XTX():XTX_Base(){
          fCanvas = 0;
       }
    
       ~XTX(){
    
          if(fCanvas)
             delete fCanvas;
       }
    
       void Init();
       ClassDef(XTX,1)
    };
    

    XTX.cpp
    #include "include/tabs/XTX.h"
    
    ClassImp(XTX)
    
    void XTX::Init()
    {
    
       fCanvas = new TRootEmbeddedCanvas("XCanvas", this
                     , ((UInt_t)200*gAnalyzer->GetWindowScale())
                     , ((UInt_t)200*gAnalyzer->GetWindowScale()));
    
       AddFrame(fCanvas, new TGLayoutHints( kLHintsExpandX |
       kLHintsExpandY, 10, 10, 4, 4));
    }
    

    How to draw histograms.


    ROME application can draw histograms in tasks defined in the own program. It can also obtain histograms from other ROME application over network. For details, please see files in "netfolder" example. Relevant files are readme, netfolder.xml, include/tabs/NFTHistos.h, src/tabs/NFTHistos.cpp, include/tasks/NFTFillHistoAndFolder.h, src/tasks/NFTFillHistoAndFolder.cpp, separateProcessConfigAnalyzer.xml, separateProcessConfigMonitor.xml and singleProcessConfig.xml.
















    How to create buttons.

    In this example, when the button is pressed. the message (kC_COMMAND, kCM_BUTTON and ButtonID) will be sent to the function ProcessMessage. You can call any function from ProcessMessage.

    In addition to ProcessMessage, ROME provide a special function ProcessMessageThread. If you rename ProcessMessage to ProcessMessageThread in XTX.h and XTX.cpp, All functions called from ProcessMessageThread will be executed in new thread. It means you can do other operation even if the called function is not finished.

    It is possible to use both ProcessMessage and ProcessMessageThread. In this case ProcessMessageThread needs to be called from ProcessMessage. There is an example project in rome/argus/examples/processMessage. Please note that multi thread application might not safe (especially on multi processor computer). For instance, usually Xlib is not thread safe.

    XTX.h
    #include <include/generated/XTX_Base.h>
    #include <TGButton.h>
    
    class XTX : public XTX_Base
    {
    protected:
    
       TGTextButton  *fButton;
       enum CommandIdentifiers {
          ButtonID
       };
    
    public:
       XTX():XTX_Base(){
          fButton = 0;
       }
    
       ~XTX(){
          delete fButton;
       }
    
       void Init();
    
       Bool_t ProcessMessage(Long_t msg, Long_t param1, Long_t param2);
       
       ClassDef(XTX,1)
    };
    

    XTX.cpp
    #include "include/tabs/XTX.h"
    
    ClassImp(XTX)
    
    void XTX::Init()
    {
    
       fButton = new TGTextButton(this, "Button", ButtonID);
       fButton->Associate(this);
       AddFrame(fButton, new TGLayoutHints( kLHintsCenterX |
                             kLHintsCenterY, 10, 10, 4, 4));
    }
    
    
    Bool_t XTX::ProcessMessage(Long_t msg, Long_t param1, Long_t param2)
    {
       switch (GET_MSG(msg)) {
       case kC_COMMAND:    
          switch (GET_SUBMSG(msg)) {
          case kCM_BUTTON:
             switch (param1){
             case ButtonID:
                cout<<"Button is clicked."<<endl;
                break;
             }
             break;
          }
          break;    
       }
       return true;
    }
    

    How to create menus.

    Menus can be added with adding entries in a project definition XML file. Menus belong to a tab, and they appear when the tab is front. Every menu item has MenuItemID. This number will be sent to a special function MenuClicked. You can implement any function in MenuClicked. Please note that MenuItemID needs to be between 0 and maxNumberOfTabMenuItems. maxNumberOfTabMenuItems is defined in rome/builder/include/ROMEBuilder.h, and the default value is 20.


    Xmonitor.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <ROMEFrameworkDefinition>
      <Experiment>
        <ExperimentName>X</ExperimentName>
        <ExperimentShortCut>X</ExperimentShortCut>
        <ProgramName>monitor</ProgramName>
      </Experiment>
      <Tabs>
        <Tab>
          <TabName>X</TabName>
          <TabTitle>XXX</TabTitle>
    
          <Menus>
            <Menu>
              <MenuTitle>Y</MenuTitle>
              <MenuItems>
                <MenuItem>
                  <MenuItemTitle>YYY</MenuItemTitle>
                  <MenuItemID>1</MenuItemID>
                </MenuItem>
              </MenuItems>
            </Menu>
          </Menus>
        </Tab>
      </Tabs>
    </ROMEFrameworkDefinition>
    

    XTX.h
    #include <include/generated/XTX_Base.h>
    
    class XTX : public XTX_Base
    {
    protected:
    
    public:
       XTX():XTX_Base(){
       }
    
       ~XTX(){
       }
    
       void Init();
    
       void MenuClicked(Long_t param);
       
       ClassDef(XTX,1)
    };
    

    XTX.cpp
    #include "include/tabs/XTX.h"
    
    ClassImp(XTX)
    
    void XTX::Init()
    {
    }
    
    
    void XTX::MenuClicked(Long_t param){
       cout<<"Menu is clicked.("<<param<<")"<<endl;
    }
    

    How to show message in status bar.

    gWindow->GetStatusBar() returns a pointer of TGStatusBar. You can split status bar and set text. Please note that the first part may be used by framework.

    XTX.cpp
    #include "include/monitor/XWindow.h"
    
    ClassImp(XTX)
    
    void XTX::Init()
    {
    
       gWindow->GetStatusBar()->SetText("status bar");
    }
    

    How to execute functions in background.

    There are two ways to execute functions in background. One is executing functions in a new thread, and the other is using TTimer.

    With creating thread, you can execute functions in parallel with the main thread. It uses effectively (maybe less) CPU power than TTimer. On the other hand, you have to carefully write code, because two threads can access the same memory space really at the same time. It is known that Xlib is not thread safe.

    If the calculation time of the functions is rather short or you want to use safer way. You may use TTimer. It executes functions periodically within the main thread.


    R.Sawada