Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

CatchCulator

4.97/5 (71 votes)
18 Oct 2005CPOL7 min read 1   2K  
A tool used to catch and combine values output by different applications.

Application screen-shot

Introduction

Have you had a requirement to run more than one application in parallel on the same machine while needing to watch their numerical outputs and sometimes to combine the results in order to draw some important conclusion? Well, it happened to me a couple of weeks ago. I was actually running two independent applications that were acquiring data and each displaying "tones" of values all over the screen, when I realized I was needing some small computation involving only a few of the values displayed by the two applications. Working with the MS Calculator was not much of a deal, as the displayed values were continuously changing, and stopping the applications from time to time so that I could get my computations, resulted in a big waste of time.

I then asked myself: how could I get the results I want without stopping and restarting the applications all the time, without being necessary to key down the same operations on the calculator again and again (boring, you know?) and even without having to look at the values displayed by those applications? (sometimes, engineers do enjoy screens full of data).

And here is the solution: the CatchCulator. A small tool, with great potential for improvement, helping me get the job done fast and clean.

Working with the CatchCulator

I wrote a small dialog based application displaying two values within two edit controls in order to present my idea, and running two or more instances of it. In real life, you will use whatever applications you need, with one observation: the output values must come out through CEdit and / or CStatic derived objects.

The pointer

Assuming now that you already started the applications, the data of which you need to observe, you must start the CatchCulator. It comes up on the screen accompanied by an "arrow" toolbox which you are going to use in pin-pointing the displayed values you are interested in. Simply drag the arrow (the blue arrow is actually the visible part of dialog's title bar) over the value you are interested in and click the Try button. The value captured by the CatchCulator will be displayed under that button. It may happen that the CEdit or the CStatic object, which you are pointing to, could have been created over a CStatic frame for example, and actually you are catching the caption belonging to the frame. In that case, click the Hide button and the unwanted object will be hidden (do not worry, nothing bad will happen to the application containing that control). Click again the Try button (you may need to repeat the operation in certain cases). If the shown value is what you need, then click the Catch button, so that the CatchCalculator becomes aware of your choice.

Try and hide

After catching the value, the visibility status of the previously hidden item(s) is restored automatically. Once you have caught a value, the CatchCulator assigns a name to it, so that you can refer it later as a variable.

Catch

It's up to you to keep the default name or rename it to be more related to the meaning of the monitored value. To rename the variable, select its name with a mouse click and after a short while, click it again (this is the normal behaviour of a CTreeCtrl object, which is actually used by CatchCulator's code). Once you have finished with catching the variables, you can proceed to telling the CatchCulator what to do with those variables. This means you have to provide some scripts describing the calculation. As you may have already observed, the CatchCulator is endowed with three displays. Each display has a calculation script assigned. To edit the script, right-click the desired display while keeping the CTRL key pressed. The scripting rules are very simple and only simple checks are performed for the syntax. Mainly, you must keep in mind that every line of script mast have a name closed in angular brackets and two operands separated by an operation symbol. For the current version of the CatchCulator, only the basic four operations are supported: *, /, +, -. Depending on the interest on this tool, I will provide future support for other operations and functions. The name assigned to a calculation result can be used further as a variable. Click the Update script button whenever you alter your script in order for the modification to become effective.

The Script

By default, the result of any calculation is displayed as a number with 5 digits after the decimal point. You can specify your own display format by using a syntax similar to the one used by the sprintf() function, with the observation that only the %f or %lf specification makes sense in the case of this tool.

To change the display format, right-click the desired display while keeping the SHIFT key pressed. By including an explanation string within your format specification, you can make the displayed result more clear. To display integer numbers, choose the %.0lf specification.

The Script

The variable names assigned to the caught values can be modified at any time, even after the scripts have been edited. Any change in those names will be automatically reflected in the scripts. If you leave a name as an empty string, it will be reflected as NoName in the scripts. Keep in mind that you don't have to use duplicates for the variable names, as only the first appearance of the name in that case will be considered.

The Script

Two modes are available for showing the results of the calculations: the manual mode and the timer mode. In the manual mode, each display is updated when you click the corresponding D button. The D buttons are enabled only in the manual mode. To toggle the modes, click the clock button. In the timer mode, the displays are periodically updated with no intervention from your side. The default update time is 100 milliseconds. To change this value, click the the clock button with a question mark (?), which is enabled only in the timer mode.

The Script

Other available commands are:

  • right click a display - clear the display
  • click the blue arrow button - show the catcher (if previously closed)
  • click the red X button - remove all the catches
  • click the barred X button - remove the selected catch

Once you have defined the scripts, you can send the monitored application to the task bar so that you keep only the information shown by the CatchCulator on the display of your computer.

The code behind

Catching the value

When the catching process starts, the catcher is positioned with the point of its arrow over the desired value on the screen. The handle of the window containing that point is obtained by a call to WindowFromPoint(ptAt) where ptAt is a CPoint object storing the position of the point of the arrow in screen coordinates. This handle (hParent) is then used to get the text of the pointed window:

HWND  hParent;
char  chText[256];

::GetWindowText(hParent, chText, 255);

If the returned text is a null string, there is the possibility that the window be of CEdit class (or derived). Therefore, the CatchCulator attempts to read the first line of such a control (as it may be a multi-line one):

CEdit  *pEdit;
int    N;

pEdit = (CEdit *)FromHandle(hParent);
N = pEdit->GetLine(0, chText, 255);
chText[N] = 0; // null termination

The resulting text (if any) is displayed under the Try button of the catcher.

Calculating according to the scripts

Each line of the script describes a calculation unit, implemented through the Calculation class:

class Calculation
{
  public:
    Calculation() { result = 0; opL = ""; opR = ""; }
    ~Calculation() {}
    CString  resultName;
    CString  operation;
    CString  opL; // 1-opName, 2-opName (1 for caught var, 2 for computed value)
    CString  opR; // or 3-value (for constant value)
    double   result;
};

The name assigned to the calculation result is stored in resultName, while the operation is stored as it is (*, /, + ,-) in operation. Depending on the operands (left and right), one of the following three cases is to be considered:

  1. the operand is a name of a caught (monitored variable)
  2. the operand is the name of a previously computed value in the script
  3. the operand is a constant value (a number)

Each operation result is stored in result which is initialized to 0. The calculation units are stored within a CList object:

CList  <Calculation, Calculation> m_listToDo;

The whole computation is performed within the CCatchCulatorDlg::ProcessScript(CStaticDisplay *pDisplay) function, which takes a pointer to the related display as parameter. The values for the operands are obtained as follows: if the operand is the name of a monitored value, the CCatchCulatorDlg::ValueOf(char *varName) is invoked with that name as parameter; if the name was assigned to a computed value, the CStaticDisplay::ComputedValue(char *varName) is invoked with that name passed as parameter; or if the operand is the string representation of a number, the sscanf() function is invoked. The resulting values are used as operands for the indicated operation. The result of the operation is stored in the result member of the current Calculation unit. The units are processed one after the other by going through the m_listToDo list. The last unit holds the final result in its result data member, which is actually shown by the related display.

History

  • Created: October, 2005.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)