Copyright © 2007 Albert Graef
QCalc is a spreadsheet program with the Q programming language under its hood. It lets you run all Q functions, no strings attached, and you can define your own functions in a script and use these in the spreadsheet, too. As such, it should be useful as an educational tool, or if you simply want to play around with the Q interpreter in a more convenient graphical and interactive environment.
QCalc is a spreadsheet program with Q as its underlying programming language. The present version is more a replacement frontend to the Q interpreter rather than a full-blown spreadsheet, so some functionality you know from other spreadsheets may still be missing or be implemented in a slightly different way. But if you've ever worked with MS Excel or its OpenOffice and KOffice equivalents, you should feel right at home. The only major difference is that each cell may hold either text, a number or any Q value.
Also note that there's only one spreadsheet and one script per file in the current implementation. But the spreadsheet can get as large as you want and each cell may hold an arbitrarily complex Q value. The user script may import other source files as necessary, using Q's import/include statements, so the single script page doesn't really limit what you can do either.
If you have ever used another spreadsheet program then the basic paradigm should be familiar and using QCalc should be rather straightforward. In the following we discuss the most important aspects of QCalc's operation, which will hopefully provide you with enough information to get started.
After installing the program, you can simply fire it up using the command qcalc or qcalc mysheet.qcalc. To exit the program, use theoption of the menu or just press Ctrl-Q; you will be warned and get a chance to abort the operation if the current file hasn't be saved yet.
The following screenshot shows QCalc in action:
QCalc is a standard Qt application with menu, toolbar, main area (showing the spreadsheet by default) and a status bar which displays helpful status information like the current cell index and the line number in the script editor. The spreadsheet takes the form of a table with columns numbered A, B, etc., and rows 1, 2, etc. The table is browsed with the usual mouse and keyboard operations.
Online help is available with the F1 key or any of the options in the Q language manual is included, too, to assist you on your journey into the "land of Q". Just press Shift-F1 to show the manual in the help browser.menu. These options invoke the Qt "assistant" program, which is Qt's HTML help browser. (As you're reading the online manual right now, you probably discovered this already.) The full
Themenu provides the necessary operations to create new spreadsheets and load, save and print them. QCalc saves its spreadsheets in a text format which is in fact valid Q script syntax, but uses the .qcalc extension by default. (The contents of the spreadsheet are stored as comments at the beginning of the script; it goes without saying that you shouldn't remove or alter these lines if you edit the file with a text editor, unless you know what you are doing.) QCalc also provides some locale support, in that the encoding of a spreadsheet file is recorded in the first line of the file when it is saved. When the file is loaded again, the encoding tag is read and the contents of the file are converted to the current system encoding on the fly.
It is also possible to open any plain Q script in QCalc, which then becomes an empty spreadsheet with the given Q source as the user script. (This only works properly if the file actually contains a valid Q script.)
As in other spreadsheets, rows are numbered starting at 1, while columns are denoted using the letters A through Z. Beyond the 26th column the indices are denoted AA, AB, ..., BA, BB, etc. In formulas, cell indices are always written with the column letters first. (These are also valid Q variable identifiers, thus you cannot use a global Q variable in formulas if it looks like a cell index.)
In difference to other spreadsheets, a table cell in QCalc may contain arbitrary Q values and thus cell values may in fact be complex data structures, not just strings and numbers. It is also possible to populate cells with special GUI elements, including various types of widgets for numerical and symbolic data entry, as well as graphical plots of spreadsheet data using the gnuplot program, see Chapter 3 for details.
Each spreadsheet initially starts out with 128x26 cells, i.e. rows 1 thru 128 and columns A thru Z. (This is currently hardcoded in the program, but you can change the default size by editing the qcalc.ui file accordingly.) A spreadsheet grows and shrinks as necessary with certain editing operations (see Section 2.3), but QCalc always keeps it at a minimum size of 128x26.
Row and column sizes can be changed by dragging the borders in the row and column headers, and you can also quickly adjust the size by double-clicking on the border. The sizes will be remembered on a per-file basis when the spreadsheet is saved and then reloaded.
Q expressions to be evaluated are written in the customary "=
expr" format. (Note that the = symbol must be the first character, the formula won't be recognized as such if it is preceded by whitespace). Thus, e.g., if you have the literal values 6 and 7 in cells A1 and B1, and A2 contains "= A1*B2", then you will get the value 42 there. The cell will also show a little arrow symbol to indicate that there is a computed value there, so it will actually look like " 42".
In your formulas you can also use relative and absolute cell references like A1, B$2, $C5 or $E$9 just like in any other spreadsheet. These work exactly the same, as far as evaluation is concerned, but behave differently when they are copied or filled (see Section 2.3 below). You can also employ ranges of the form A1:A10, which are mapped to Q lists (or lists of lists, if they span multiple rows and columns, as in B5:C12).
You can also do calculations with strings, of course, using Q's string operators and functions, but note that to get an empty string value you'll have to use the formula '= ""'. That's because the value of an empty cell defaults to the integer 0 (rather than the empty string) in calculations.
In fact, this spreadsheet is much more powerful than others in that cells can hold any Q value and you can do calculations with any kind of Q data, including "infinite" values such as streams (lazy lists). And, because of Q's term rewriting heritage, you can do symbolic calculations, too!
Also note that if an expression doesn't evaluate because some arguments don't match, this is not an error in Q – the expression is then considered a normal form and will be printed "as is". So, if the computed value in a cell looks "weird", take a second look at the computed formula; you will always find that there's something in there which "doesn't compute", as they say. Actually, this feature is quite useful, as it really shows you where your computation went wrong, instead of just giving you some silly error message.
On the other hand, it is an error if an expression doesn't have a value, either because it is not valid Q syntax, or because it raises an exception (e.g., by calling halt or throw) when evaluated. In the former case, the cell will just show the formula as literal text (without the arrow symbol). The latter kind of error is flagged (quite literally) with a little red flag instead of the arrow symbol, showing the offending formula as the contents of the cell: " = halt". (Currently QCalc doesn't show you the actual exception raised by an expression, but you can easily find out about these by making judicious use of Q's built-in catch function.)
When you enter a new or edit an existing cell value, the evaluation algorithm used by QCalc will only reevaluate the cells affected by this change. Cyclic computations (e.g., if cell A1 is computed using A1 itself, or if there is a cyclic chain of cell dependencies, such as A1=A2+1 and A2=2*A1) are permitted, but are executed in a "depth-first" order which breaks cycles in an apparently random way. The only thing that you can count on in such cases is that if you edit a given cell, then the change will propagate to other cells from there and each dependent cell will be recomputed at most once using the most recent values of all its requisite cells.
The entire spreadsheet is reevaluated each time it is loaded, or when you recompile the script of the spreadsheet (see Section 2.4 below).
Note that QCalc doesn't limit your spreadsheet to operations which always terminate. If a computation (indicated by the wait cursor) takes longer than expected, or just loops indefinitely, you can abort it with Ctrl-G (this is the only operation active while an evaluation is in progress), and correct the offending spreadsheet cells and/or definitions in the script. In the latter case you can then force a reevaluation of the entire spreadsheet by recompiling the script with F9 (see Section 2.4 below).
Also note that all computations are actually executed in a secondary process running your script in a separate instance of the Q interpreter, so it shouldn't be possible to mess up QCalc no matter how badly your script behaves. In the worst case, if your script just "hangs" or "dies", so that QCalc cannot perform further calculations, you should still be able to correct your script in the editor and then just restart it with F9.
The editing operations provided by QCalc are rather straightforward. You can find these in the Edit toolbar and the context menu which pops up when you right-click on a table cell.menu, as well as the
There are also many useful keyboard and mouse shortcuts. You can browse through your spreadsheet with the mouse or the cursor keys, including the Tab and Backtab keys which traverse to the next and previous table cell (in row-major order), respectively. F3 or Shift-F3 edits a cell (the former edits the cell "in-place", while the latter invokes a separate multiline editor which is often more convenient for complicated formulas), Esc aborts the edit (reverting the cell to its previous value), and F2 or Return stores the edited value (and does any necessary computations). You can force reevaluation of a cell by pressing F2 while the cell is selected, and a double click opens a cell for editing. You can also just start typing when a cell is selected, to overwrite its current value. Cell indices and formulas are shown in the status line when you click on them.
NOTE: Browsing the table and selecting ranges of cells with the mouse or the keyboard can be hard to do if the cells contain editable GUI elements like comboboxes and spinboxes (see Section 3.3), since these will grab the focus when they are selected. As a remedy, if you are not currently editing a cell, the Esc key allows you to switch the table from the default mode of operation to a special "browse" mode which is indicated by a tiny lock symbol in the status line. While the table is in browse mode, editing operations on ranges of cells still work normally, but GUI elements are not activated when selected any more. This makes it much easier to browse the table and make selections with the mouse or the cursor keys. To leave browse mode, either just press Esc again, or double-click on a cell or press F3 to open a cell for editing.
Rectangular ranges of spreadsheet cells can be selected by sweeping the mouse over them as usual, or by using the cursor keys while holding down the Shift key. You can also click a row or column header to select the entire row or column. Selected ranges of cells can be deleted, cut, copied and pasted as usual. Using cut/copy and paste you can also transfer ranges between different instances of QCalc. Moreover, QCalc performs automatic adjustment of relative column and row indices in formulas. Thus, if you copy a cell containing the formula "= foo A1" to a position at an offset of, say, 2 rows and 3 columns from the original position, it will become "= foo D3". As usual, you can use the $ symbol to indicate absolute row or column indices (or both) which will not be adjusted.
Theoperation always copies formulas for computed cells, but there is also a second " " operation to just copy the literal cell contents (without the formulas). QCalc can also exchange data with other programs, using the customary textual "tab-separated values" format to store the selection in the clipboard, which can readily be pasted into almost any other application, including text editors and other spreadsheet programs. On X11, the global mouse selection is also supported; just select a range of cells, and you can paste their contents in tab-separated format into any other application with the middle mouse button.
There's also a special both rows and columns in a single step. To use this, select the desired target range, with the value to be copied in the "principal" (upper-left) cell of the selected range, and then just push the button (the one with the magic wand symbol on it), or press Ctrl-L. This will copy the formula in the principal cell to the adjacent cells, adjusting it across the range as usual. The same operation also allows you to fill a range of cells with arithmetic sequences. For this purpose, the principal cell value is the starting value of the sequence, and the cells immediately below and to the right of the principal cell (more precisely, the differences between these values and the principal cell value) determine the increment in the vertical and horizontal direction, respectively. If one or both of the adjacent cells are empty or non-numeric then the corresponding increment defaults to 0 (meaning that the principal value will just be copied). Thus, when the operation has finished, each row or column will be an arithmetic sequence for the indicated horizontal or vertical increment, respectively. (This sounds more complicated than it actually is. Just try it out and see what happens.)operation which basically works like dragging the little fill handle in other spreadsheets to copy a value or formula to adjacent cells. In fact, this operation is even more flexible than the fill handle, since it allows you to fill
Theoption (F6) in the menu allows you to merge adjacent cells into one bigger cell which may span multiple rows and columns; the (Shift-F6) option splits them up into their constituents again. You can also insert and delete entire rows and columns by selecting a cell (a single cell will do, although you can also select a range, in which case the upper left cell of the range determines where the operation is to be performed) and choose the corresponding option. The corresponding keyboard shortcuts are F7 and Shift-F7 to insert and delete a row, and F8 and Shift-F8 to insert and delete a column, respectively. Each of the these operations only inserts or deletes a single row or column, so you have to invoke the command repeatedly if you want more. Also note that the other editing operations will enlarge the table if needed, e.g., when you paste a range of cells near the edges of the spreadsheet. Thus it is not necessary to explicitly insert table rows and columns in such cases.
QCalc also has an unlimited undo/redo facility, so if you mess up your spreadsheet you can always go back and forth in time as needed. These operations also adjust the table size as needed. They may also shrink the table if there is unused extra space; this also happens when you load a spreadsheet from a file. However, as already mentioned, QCalc always keeps the spreadsheet at a minimum table size of 128x26.
You get to the script page by switching to the corresponding tab located right below the menu and toolbar, or by pressing F11 which toggles between the spreadsheet and the script view. After selecting the script view you see the following:
In the upper pane of the script page, there is a full-featured text editor with syntax highlighting for Q scripts. In the editor you can enter any Q script, which is submitted to the Q compiler when you invoke the Compile operation (F9). The script can also be empty if your spreadsheet only uses the built-in and prelude types and functions of the Q language. Or it may just consist of the appropriate import declarations for the additional modules containing the needed operations. But in most cases it will just include any additional definitions required for the operation of your spreadsheet.
If there are any errors or warning messages during compilation of the script, they will be shown in the lower "log" pane of the script page. The log pane is also used to show output produced by Q's I/O operations like puts or printf. But note that the log is just that, a log of everything that is printed either by the Q compiler or the operations in your spreadsheet; it's not an interactive kind of terminal window, so it isn't possible to interact with the interpreter or enter any input to operations like gets and scanf there. Also note that the log is cleared automatically whenever you recompile your script or load a new spreadsheet.
You must correct all errors in your script before you can evaluate anything. As soon as your script is error-free, after pressing F9 the entire spreadsheet will be reevaluated, using the definitions from your script.
For instance, if you want to use a function square in your spreadsheet, which isn't provided by the Q library, you can define it yourself as follows:
square X = X*X;
Enter this definition in the script editor and press F9. Voila, the new function is now available and you can use it in your spreadsheet just like any other function. E.g., you can now type the formula "= square 9" into a cell and it will evaluate to 81.
Some special support operations for use in QCalc scripts can be found in the calclib.q module which is to be installed on the Q path. These are described in some detail in Chapter 3.
The script editor has two additional editing operations provided for your convenience, thedialog (Ctrl-F) which lets you, well, find text and replace it, and the "Goto line" (F5) operation to locate the given line number, which comes in handy to find the lines listed in compiler error messages.
Thedialog looks as follows:
Just enter the text to be searched and, if applicable, the replacement text in the corresponding fields and hit the and search for the next occurrence. Backward searches and replacements work analogously, using the button instead of . (You can switch the search direction at any time.) There are also various options which determine whether the search is case-sensitive and/or for whole words only, and whether to preserve the case of replaced text (which works as in Emacs).button to search for the first occurrence behind the cursor, or press the Return key. Keep on pushing or Return to search for further occurrences, or push to perform a replacement
NOTE: With the Qt3 highlighting engine, the syntax highlighting of the script editor can slow things down quite a bit with large scripts. As a remedy, if the highlighting makes the editor unresponsive and sluggish, you can disable it with thetoggle (Ctrl-H).
There are a few options which allow you to change the visual appearance of the spreadsheet and the script display. These settings are global and are remembered across invocations of the program.
You can change the font of the spreadsheet or the text editor by selecting the corresponding tab and invoking theoperation. Fixed width fonts seem to work best for most purposes, although YMMV. The configured fonts are also used for printing, see below.
Theand (Ctrl-+ and Ctrl--) commands allow you to quickly change the font size on either the sheet or the script page.
Theand (Alt-+ and Alt--) commands let you to change the precision of floating point values in computed cells. (This affects the display of floating point values only; internally, these values are always stored at full precision.)
As already mentioned, thetoggle (Ctrl-H) switches syntax highlighting in the script editor on and off.
You can print a spreadsheet with the Section 3.5). After invoking this operation, QCalc shows Qt's standard printer setup dialog:(Ctrl-P) command in the menu. This isn't very sophisticated right now, and it isn't "WYSIWYG" either, but at least it does simple pagination, adds some formatting, and renders plots created with gnuplot (cf.
This lets you choose the target printer or file, paper format and the range of pages to be printed. If you selected a cell range before the operation, you also have the option to just print the selection.
There is a second "" dialog, also available in the menu:
Here you can choose which parts of the document should be printed (spreadsheet, script, or both) and whether to print just the cell contents, just the formulas, or both. There are also configurable headers and footers which can show the spreadsheet filename and running page numbers, and for the script printout you can enable or disable the line numbering. These options are remembered across invocations, whereas the printer setup only sticks for the duration of the QCalc session.
QCalc comes with a little library of support functions to be used in spreadsheets. You can find these in the calclib.q script which must be installed somewhere on the Q library path. These operations allow you to show messages in the QCalc status line while a computation is in progress, and to change spreadsheet cells programmatically. Convenience functions to insert a vector or matrix given as a Q list into a corresponding range of table cells are also provided. Last but not least, there are a number of operations to populate cells with GUI elements like buttons, comboboxes, spinboxes and sliders, which provide a convenient means to enter values into your spreadsheet. Some special GUI elements allow you to execute custom actions and background tasks in your spreadsheet. Using these facilities, QCalc also provides special support for the gnuplot program which enables you to draw graphical plots of your data in table cells.
Examples for the usage of most support functions can be found in the sample spreadsheets in the examples subdirectory of the QCalc distribution. To use any of these functions in your spreadsheet script, an appropriate import declaration is needed:
Place this somewhere near the beginning of your script. (No explicit import is needed if you just want to use the operations in formulas.)
The following functions allow you to retrieve information about the spreadsheet cell currently being worked on, and provide feedback about ongoing operations in the QCalc status line.
public index, row, column;
These functions are used inside formulas to access the row and column indices of the cell currently being computed. The index function returns both indices as a pair (I,J) where I and J are the zero-based row and column indices, respectively. Thus A1 will be returned as (0,0), A2 as (1,0), B1 as (0,1), etc. The row and column functions return only the row and column number, respectively.
public cellindex X, cellstr KEY, cellname KEY;
These functions can be used to convert between numeric cell indices like (0,0) and symbolic ones, either in string form ("A1") or as a quoted symbol ('A1). The cellindex function converts from a string or a quoted symbol to the numeric index of the form (I,J), whereas cellstr and cellname convert a numeric index back to a string or a quoted symbol, respectively. In the string and quoted symbol form, the $ symbol is permitted as well. Note that constructs like '(A$4) aren't really symbols in Q, but applications of the built-in $ operator, so they have to be surrounded with parentheses, as indicated. Also note that, when converting from a numeric index back to its symbolic form, the $ indicators are lost since they aren't included in the numeric representation.
The most useful routine among these probably is the cellindex function which can be used with a quoted cell symbol to embed symbolic cell names into formulas, where they are adjusted automatically when copied or filled (this conversion is already built into setval et al, see Section 3.2, so you do not have to use cellindex explicitly for these).
public message S;
This function sends a status message. The message will be shown in the QCalc status line. This can be used to provide some feedback during longer computations.
The following functions are provided to change spreadsheet cells programmatically. They also work when executed asynchronously, i.e., from a Q thread executing in the background.
public setval KEY X;
This operation changes a cell value. It also returns that value, so that it can be applied to several cells in sequence. The given cell index KEY can be a pair of numbers as returned by the index function, or it may be specified in any of the symbolic formats supported by the cellindex routine (see Section 3.1). The X parameter may be any Q expression. If the given cell is an ordinary cell (no GUI element), then the current cell value is overwritten, so you should make sure that you do not have important data there. For GUI elements (see Section 3.3), the value of the element is changed accordingly, instead of overwriting the cell. In both cases, after changing the cell value QCalc will update its display and trigger updates in dependent cells as usual. Note, however, that the triggered changes will not take effect immediately, rather they are processed by QCalc when the current computation is finished.
public clearval KEY X;
This function works like setval, but clears the cell before setting the new value. This is useful if you want to overwrite a cell already populated with a GUI element.
public matrix KEY Xs, rowvect KEY Xs, colvect KEY Xs;
These are convenience functions implemented in terms of setval to store a list in a matrix or a row or column vector of table cells. They return the given list value. For the matrix function, Xs must be a list of lists which are all of the same size; the component lists become the rows of the matrix. The rowvect and colvect routines create matrices with just one row or column for a given list of values, respectively. In any case the matrix or vector is inserted into the table starting at the given index KEY (given in any of the formats supported by setval). NOTE: For updating a large number of cells, these operations work much faster than calling setval individually on each cell.
QCalc provides a fairly comprehensive set of functions which allow you to populate spreadsheet cells with various useful GUI elements:
public label ARGS, pixmap ARGS, checkbox ARGS, combobox ARGS, comboedit ARGS, spinbox ARGS, hslider ARGS, vslider ARGS, pushbutton ARGS, togglebutton ARGS;
The currently supported widget types are text labels, pixmaps, checkboxes, comboboxes (both non-editable and editable), spinboxes, horizontal and vertical sliders, push buttons and toggle buttons. The argument tuple ARGS depends on the specific kind of widget, as detailed below.
NOTE: These functions will not work if they are run asynchronously (i.e., in a secondary Q thread of the user script). They must be executed, either directly or indirectly, from a formula in a spreadsheet cell.
The following GUI elements are used to display formatted text and pixmaps in a cell:
label S or label (S,A), where S is the text (a string) to be shown, and A (optionally) denotes the alignment of the text within the cell. The text is actually a Qt "rich text" element, which may contain a limited set of html tags as described on the QStyleSheet page in the Qt manual. Hence this element allows you to have formatted text in a cell, as well as embedded images.
The alignment is specified as a string of at most two characters specifying the horizontal and/or vertical alignment, respectively. The known horizontal alignments are "a" ("auto", which may be either "left" or "right" depending on the current locale), "c" (center), "l" (left) and "r" (right), the vertical alignments are "c" (center), "t" (top) and "b" (bottom). A singleton "c" denotes both horizontal and vertical alignment. The horizontal alignment defaults to "a", the vertical alignment to "c".
pixmap S or pixmap (S,A,B), where S is the name of a pixmap file to be shown, A denotes the alignment (specified in the same fashion as with labels, see above), and B is a numeric value indicating the desired rendering of the pixmap. The possible values for the B parameter are 1 ("scaled", i.e., the pixmap is scaled to fill all the available space in the cell), 2 ("animated", which can be used to animate a pixmap in mng or gif format consisting of multiple images), and 0 (no scaling or animation, which is also the default). Both the A and B parameters are optional.
Note that label elements can also have embedded pixmaps (employing the <img> tag) and thus offer pretty much the same functionality, minus the animation feature. On the other hand, labels are much more versatile in that you can combine text and images and that they also give you more options for the placement and scaling of images. Dedicated pixmap elements are most useful for showing animated mng and gif images.
Here is a screenshot showing the label and pixmap elements in a spreadsheet:
Text label and pixmap elements are normally used for display purposes only, but the corresponding cells do have a value which can be queried in other formulas, which is the text of the element or the name of the pixmap as a string, respectively. The S, A and B parameters can also be computed values, and in addition the text or filename can be changed with setval and friends, to update the cell contents dynamically, as described in further detail below.
The remaining GUI elements are typically used for value input in various forms:
checkbox S or checkbox (S,INIT), where S is the label (a string) to be shown, and INIT (optionally) is the initial value (true or false, default is false).
The value of a checkbox is the current status of the checkbox, a Q boolean: true if checked, false otherwise.
pushbutton S or pushbutton (S,ICON), where S is the text of the button and ICON is the filename of a pixmap to be shown on the button. Both arguments are strings.
The value of a push button is true as long as the button is pressed and false otherwise.
togglebutton S, togglebutton (S,ICON) or togglebutton (S,ICON,INIT): Analogous to push buttons, but toggle buttons are switched on and off by clicking them, and have an optional INIT argument which indicates the initial state (true or false, the default is false).
The value of a toggle button is true if it is currently on and false otherwise. (Note that a toggle button changes its state after being clicked, whereas a push button changes its state when it is pressed or released. Also note that a toggle button provides essentially the same functionality as a checkbox, using a different visual appearance.)
combobox L or combobox (L,INIT), where L denotes the list of items (strings) to choose, and INIT (optionally) is the initial item.
The value of a combobox is the currently selected item (a string).
comboedit L or comboedit (L,INIT): This works like combobox, except that the combobox is editable, i.e., the user can enter new items which become part of the combobox.
spinbox (MIN,MAX,STEP,INIT,SPECIAL,PREF,SUFF), where MIN and MAX are the minimum and maximum value, STEP is the stepsize, INIT the initial value, SPECIAL a special string used to display the minimum value (commonly used for defaults) and PREF and SUFF are strings used as prefixes and suffixes in the value display (commonly used for currency symbols and units), respectively. See the QSpinBox page in the Qt manual for details. All arguments except MIN and MAX are optional. The numeric arguments MIN, MAX, STEP and INIT may be integers or floating point values; other Q Real values are coerced to Float if possible.
The value of a spinbox is the numeric value (any prefixes and suffixes are stripped from the value). If a SPECIAL value has been set, the corresponding string is returned for the minimum value of the spinbox.
hslider (MIN,MAX,STEP,INIT), where MIN and MAX are the minimum and maximum value, STEP is the page stepsize and INIT the initial value (which is "clamped" to the given bounds). This creates a horizontal slider. See the QSlider page in the Qt manual for details. All arguments must be integer. The STEP and INIT parameters are optional.
The value of a slider is the numeric value of the current slider position, an integer between MIN and MAX.
vslider (MIN,MAX,STEP,INIT): Like hslider, but creates a vertical slider instead.
By placing a formula with a call to any of the widget functions into a cell, the cell becomes populated with the GUI element and the initial value of the GUI element becomes the new cell value. You can then change the value of the GUI element through GUI interactions, triggering reevaluations of dependent cells as if you typed the corresponding value directly into the cell.
The following screenshot shows some of these GUI elements in action:
The parameters of all GUI elements can be computed values which may also depend on other cell values (including other GUI elements). In this case the GUI element will be updated automatically whenever any of the requisite cells changes. In particular, you can also use GUI elements to display values from other cells by specifying the corresponding cell as the INIT parameter of the widget, or you can define "buddies" which always change values in concert, like a slider and an associated spinbox.
Moreover, the values of all GUI elements except the push button (which is a read-only element) can also be set with setval (see Section 3.2). This is useful, in particular, if the GUI element displays some value which is updated asynchronously.
You can find examples for all types of widgets in the guiexamples.qcalc spreadsheet included in the QCalc distribution.
QCalc also provides a number of advanced GUI elements to deal with custom actions to be executed in a spreadsheet. Currently supported are action buttons, task buttons and task windows. We will describe each of these in turn.
public special actionbutton ~ARGS X;
The action button is a special push button with a slightly different visual appearance, which has an associated Q expression (special argument) to be evaluated whenever the button is clicked. The ARGS parameter has the same format as for toggle buttons (the INIT parameter specifies the initial value of the button, 0 by default). The result returned by the action expression (which can be any Q value) becomes the value of the button when it is clicked.
public special taskbutton ~ARGS X;
The task button works in a similar fashion, but instead of a direct action it has an associated background task (a Q thread) to be executed, and the button is operated as a toggle button which enables the user to "start" and "stop" the task. The ARGS parameter is the same as for togglebutton, without the ICON parameter (instead, the icon on the button is set and animated automatically in response to the current activation status of the thread). The special X parameter is the Q expression to be evaluated by the task.
Inside the background task, the index, row and column functions work as usual and provide you with the cell index of the task. (Note that these values are in fact only available in the original background task started by the taskbutton function; if your task in turn creates other threads which need to access these values, you have to pass them on to the secondary threads.)
The task_input function equips you with a Q semaphore queue used to communicate values to the executing task in response to GUI actions inside QCalc. Usually these are either true or false, and are sent when the button state changes (true = button is switched on, i.e. the task was "started" by the user; false = button is off, the task was "stopped" or "paused"). The background task can respond to these by taking some appropriate action, e.g., pause operation (or terminate altogether) if the false value is sent, or resume operation (if still active) when true is sent. Note that it is completely up to the task how it actually responds to these messages, if at all. However, it is a good idea to have the task at least empty the semaphore in regular time intervals to prevent the semaphore from being flooded with useless messages. In any case the semaphore queue will initially contain just the "startup" message (true if the task is initially started, false otherwise) when the tread is kicked off.
The task_input semaphore may also yield a quoted taskbutton call of the form '(taskbutton (S,INIT) X) to indicate that the task button itself was updated while the task is still running. This happens when a triggered update of the button is caused by some requisite cells of the task button formula changing values. In such a case, rather than reexecuting the taskbutton function and restarting the task from scratch, the taskbutton expression with the new parameters is sent via the semaphore. Again, it is completely up to the task how it handles such a message; it may completely ignore it, or it may just evaluate the (unquoted) taskbutton call to replace itself with the new task (to support this, the taskbutton function, unlike the other GUI elements, may also be executed asynchronously). Alternatively, the task may also extract the needed data from the quoted taskbutton call and update its own internal state accordingly. To help with this, the following task_params special form is provided, which, when applied to a quoted expression of the form '(taskbutton (S,INIT) (F X1 ... Xn)), where F X1 ... Xn is the new task expression, returns the parameter tuple (S,INIT,X1,...,Xn):
public special task_params X;
At any time, the background task can also send values back to the hosting QCalc process, using the setval function (see Section 3.2) with index as the KEY argument. For instance, you can invoke setval index false to indicate that processing has finished and the task is stopped (this is also done automatically when the thread terminates). Currently, the recognized values to be sent back are false (the task is stopped), true (the task has been started, maybe in response to an asynchronous event), and arbitrary string values (which change the text label shown on the task button). QCalc will update the button in response to these messages and also change the cell value of the task button accordingly, which may trigger updates in other, dependent cells, see the description of the setval function for further details.
Note that, no matter what the purported "started/stopped" status of the button is, the user can always check whether the task associated with the button is currently up and running by taking a look at the arrow symbol shown on the button. If the task is currently executing (even if it hasn't been "started" by pushing down the button yet), the arrow symbol will be "lit" in green, otherwise it will be greyed out. Also note that in the latter case, if the thread has exited when the user starts it by pressing the button, the task will be restarted automatically and will initially be fed with the message true to indicate that it should now go ahead with its business.
Examples for the use of action and task buttons can be found in the guiexamples.qcalc spreadsheet included in the QCalc distribution. The screenshot below shows these elements in action.
public special taskwindow X;
The task window works pretty much like a task button, minus the toggle button functionality. Instead, it provides an empty parent window inside the task's cell which can be operated directly by the task in the inferior Q process. The id of the parent window is available inside the task with the task_winid function:
Moreover, the index, row, column and task_input functions work in the same fashion as with task buttons. Messages of the form (W,H), where W and H are integers denoting the width and height of the task window, are delivered via task_input at initialization time and whenever the size of the parent window changes, and quoted taskwindow calls are sent when the task window is to be updated due to changes in requisite cells while its task is still up and running.
The initial value of the task window cell is the id of the parent window. It is up to the task to change this value using setval when appropriate. It is also up to the task to draw the contents of the window, using either some external program or Q's own GUI and graphics operations. In the simplest case, you can invoke taskwindow with a trivial task (e.g., taskwindow ()) and use the supplied window id to do the actual drawing elsewhere (e.g., using a task button), or you can provide an expression which takes care of drawing the contents of the cell in the window task itself. An example for the use of task windows can be found in the mplayer.qcalc spreadsheet included in the QCalc distribution; see the screenshot below.
The following convenience function is provided to set up a task window running gnuplot.
public gnuplot CMD DATA;
The gnuplot function allows you to embed graphical plots of your data in a spreadsheet. Gnuplot is a very comprehensive plotting software with which you can produce most common kinds of 2D and 3D diagrams quite easily. NOTE: Currently this feature only works under X11 and it also requires a fairly recent gnuplot version which supports the 'x11-external' option (at the time of this writing, this is only available with the CVS version of gnuplot as of Dec 4 2007 or later). Also note that by default, the gnuplot function assumes that your installed gnuplot program is named gnuplot. If necessary, you can set the GNUPLOT string variable to a different name for the executable.
The CMD parameter of gnuplot is a string containing the gnuplot command used to produce the plot, and DATA is the data to be plotted, usually a range of cell values. DATA can also be () if no additional data is required, or a tuple of lists if multiple datasets are to be plotted. Each dataset must either be a list of integer or floating point values, or a list of lists of such values, which will be translated to inline data in ASCII format as described in Section 61 of the gnuplot manual. Each element of the dataset becomes one line in the ASCII format. Blank lines (which are required by some plotting commands) can be produced using an empty list inside your dataset. You then use '-' to specify each dataset inside the gnuplot command as usual. Alternatively, you can also specify the data yourself inside the gnuplot command string, employing any of gnuplot's supported data formats, and use () as the DATA argument.
You can use pretty much any gnuplot command in the command string; multiple gnuplot commands are separated with a semicolon or a newline character. However, your command shouldn't specify any output terminal or file (as set with the set term and set output commands) since these will be set up by QCalc when rendering the plot for the display or a printout. Also note that plots in different cells are each produced with their own gnuplot instance, so all required setup information (axes, titles, plot styles etc.) must be included in each gnuplot command; there is no sharing of such information between different cells.
See the plot.qcalc spreadsheet included in the QCalc distribution for an example. Here is a screenshot showing gnuplot in action:
Note that the plots are really full instances of gnuplot running inside the table cells, which can be operated with the mouse as usual. For instance it is possible to rotate the 3D plot shown on the right by just dragging around the mouse in the cell.
QCalc is Copyright (c) 2007 Albert Graef and is distributed under the GNU General Public License. This document is Copyright (c) 2007 Albert Graef. The documentation is licensed under the terms of the GNU Free Documentation License.
Special thanks are due to Eddie Rucker from the Blue Montain College for testing, reporting bugs and providing examples.
QCalc is available together with the other Qt/Q applications as a source tarball, as well as source and binary RPM packages, from the Q website at http://q-lang.sourceforge.net.
You'll need the Q programming system, including the Qt/Q module, available from the Q website at http://q-lang.sourceforge.net. Currently this script needs Qt3 (http://trolltech.com), but we're planning to port it to Qt4 asap.
To utilize the plotting functionality discussed in Section 3.5, you'll also need X11 and a recent gnuplot version which supports the 'x11-external' option, available from http://gnuplot.sourceforge.net. (Currently you'll need the CVS version of gnuplot as of Dec 4 2007 or later. Also make sure that you compile gnuplot with png support, since gnuplot's png terminal is needed to render plots when printing a spreadsheet.)
As with other plain Q scripts, there's no compilation, so just run make install when installing from the sources. You may have to specify the proper installation prefix with prefix=/some/path; this should match Q's installation prefix, usually /usr/local or /usr. There are also some icons and desktop files included in the package, which are useful for the KDE and Gnome desktop environments, but these will have to be installed manually. (If you're installing from an RPM, hopefully these files will be copied the appropriate locations automatically, so that your application menu will show an entry for QCalc after installation.)