Preface
Here is a third part of wxJSON tutorial provided by Luciano Cattani, author and maintainer of wxJSON library.
- Visit wxJSON homepage
- Read Part I of this tutorial
- Read Part II of this tutorial
- Read Part III of this tutorial
- Read Part IV of this tutorial
Describing a Table with wxJSON
How many times did you use a table in your application? I know the answer: many times. So the best thing would be to write a general-purpose panel window that is capable to show every possible table and table’s format.
It is not hard to write a similar panel: we only need to implement some basic data that will be passed as parameters to the panel window:
- the column’s names
- the column’s alignment, if not implicit in the data type
- the type of data in each column
- the border thickness, if any
- the column’s width in pixels or in panel’s width percentage, if needed
- a bidimensional array that contains the actual data that has to be displayed
A more complex work is to define a good data structure that holds this informations and the table’s data themselves. Because we have to show many different tables in our application, there is not a general structure suitable for our needs because the data type of each column may vary from table to table. But we need something to pass as a parameter to our general-purpose table-viewer panel.
The answer could be: use a JSON formatted wxString object. We define a JSON object that contains two main objects:
- a description of the columns
- the content of the rows
Below you find the format of the JSON text that describes a table containing three columns and three rows:
{ "Border" : 1, "Columns" : [ { "Name" : "City", "Width" : 50, "Unit" : "Percentage" }, { "Name" : "Temperature", "Width" : 20, "Unit" : "Percentage" }, { "Name" : "Date", "Width" : 30, "Unit" : "Percentage" "Alignment" : "center" } ] "Rows" : [ [ "Baltimora", 20, "20 july" ], [ "New York", 25, "23 july" ], [ "Los Angeles", 29, "25 july" ] ] }
Note that there is no need to specify the type of the data contained in each column because the JSON value object already carries it.
The code for displaying a table that is described in the above JSON text is similar to this one:
void DisplayTable( const wxString& jsonText ) { wxJSONReader reader; wxJSONvalue root; int numErrors = reader.Parse( jsonText, root ); if ( numErrors > 0 ) { // if there are errors in the JSON document return return; { // now display the column names wxJSONvalue columns = root["Columns"]; int border = root["Border"].AsInt(); int width; string align; for ( int i = 0; i < columns.Size(); i++ ) { width = columns[i]["Width"].AsInt(); DisplayColName( columns[i]["Name"].AsString(), width ); } // and now we display the data in the rows // note that we use a predefined alignment for data // unless a specific alignment is set: // // left for strings // right for numbers // the bidimensional array wxJSONValue rows = root["Rows"]; // the string that has to be displayed in the table's cell string valueString; // the default alignment: it is set depending on the data type wxJSONValue defaultAlign; // for all rows ... for ( int x = 0; x < rows.Size(); x++ ) { // .. and for all columns in the row for ( int y = 0; y < rows[x].Size(); y++ ) { // get the width of the column width = columns[y]["Width"].AsInt(); // get the value object wxJSONValue value = rows[x][y]; // check the type of the data wxJSONValue::wxJSONType type = value.GetType(); switch ( type ) { case wxJSONTYPE_NULL : // display an empty string valueString.clear();; break; case wxJSONTYPE_INT : case wxJSONTYPE_UINT : case wxJSONTYPE_DOUBLE : // numeric values are right-aligned defaulAlign = "right"; align = columns[y].Get( "Align", defaultAlign ).AsString(); valueString = value.AsString(); break; case wxJSONTYPE_STRING : case wxJSONTYPE_CSTRING : defaulAlign = "left"; align = columns[y].Get( "Align", defaultAlign ).AsString(); valueString = value.AsString(); break; case wxJSONTYPE_BOOL : defaulAlign = "center"; align = columns[y].Get( "Align", defaultAlign ).AsString(); valueString = value.AsString(); break; } // now that we have the alignment, the column's width and the // value of the data as a string: // note that numeric data are converted to a decimal string // and boolean values are converted to 'TRUE' or 'FALSE' when you // use the wxJSONValue::AsString() memberfunction DisplayValue( valueString, width, align ); } // continue for all columns } // continue for all rows } [/sourcecode] JSON format is very flexible: in future we can add new features to the application. For example we may decide that our general-purpose table-viewer panel will let the user to change the values in the table rows but only for some specific columns. We add a new item in the <code>Columns</code> array descriptors: the <code>Editable</code> flag which is a boolean type. Example: [sourcecode language="js"] "Columns" : [ { "Name" : "Temperature", "Width" : 50, "Unit" : "Percentage", "Editable" : true },
Note that this new format of our table description is compatible in both directions: it is normal that a new version of the application can read and handle old-style data but it is not very easy to maintain the old application compatible with a new data format that was introduced in a new version.
In our example, the simplicity and flexibility of JSON make the old application capable of reading the new format of JSON data. Of course, the data are not editable because the old application does not permit this operation. The old version of the application simply ignores the existance of the new Editable flag so that the JSON text can be read and processed as in the previous version.