From bd0f3345a938b35ce6a12f6150373b0955b8dd12 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 10 Jul 2011 15:24:15 -0500 Subject: Add Qt3 development HEAD version --- doc/html/tutorial2-03.html | 298 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 doc/html/tutorial2-03.html (limited to 'doc/html/tutorial2-03.html') diff --git a/doc/html/tutorial2-03.html b/doc/html/tutorial2-03.html new file mode 100644 index 0000000..4369305 --- /dev/null +++ b/doc/html/tutorial2-03.html @@ -0,0 +1,298 @@ + + + + + +Data Elements + + + + + + + +
+ +Home + | +All Classes + | +Main Classes + | +Annotated + | +Grouped Classes + | +Functions +

Data Elements

+ + +

+

We will use a C++ class called Element to provide storage and +access for data elements. +

(Extracts from element.h.) +

+ +

    private:
+
        double m_value;
+        QColor m_valueColor;
+        int m_valuePattern;
+        QString m_label;
+        QColor m_labelColor;
+        double m_propoints[2 * MAX_PROPOINTS];
+
+

Each element has a value. Each value is displayed graphically with a +particular color and fill pattern. Values may have a label associated +with them; the label is drawn using the label color and for each type +of chart has a (relative) position stored in the m_propoints array. +

+ +

    #include <qcolor.h>
+    #include <qnamespace.h>
+    #include <qstring.h>
+    #include <qvaluevector.h>
+
+

Although the Element class is a purely internal data class, it +#includes four Qt classes. Qt is often perceived as a purely GUI +toolkit, but it provides many non-GUI classes to support most aspects +of application programming. We use qcolor.h so that we can hold the +paint color and text color in the Element class. The use of qnamespace.h is slightly obscure. Most Qt classes are derived from the +Qt superclass which contains various +enumerations. The Element class does not derive from Qt, so we need to include qnamespace.h to have access to +the Qt enum names. An alternative approach would have been to have +made Element a Qt subclass. We include qstring.h to make use of Qt's Unicode strings. As a convenience we +will typedef a vector container for Elements, which is why we +pull in the qvaluevector.h header. +

    typedef QValueVector<Element> ElementVector;
+
+

Qt provides a number of containers, some value based like +QValueVector, and others pointer based. (See Collection Classes.) Here we've just typedefed one container +type; we will keep each data set of elements in one ElementVector. +

    const double EPSILON = 0.0000001; // Must be > INVALID.
+
+

Elements may only have positive values. Because we hold values as +doubles we cannot readily compare them with zero. Instead we specify a +value, EPSILON, which is close to zero, and consider any value +greater than EPSILON to be positive and valid. +

    class Element
+    {
+    public:
+        enum { INVALID = -1 };
+        enum { NO_PROPORTION = -1 };
+        enum { MAX_PROPOINTS = 3 }; // One proportional point per chart type
+
+

We define three public enums for Elements. INVALID is used by +the isValid() function. It is useful because we are going to use a +fixed size vector of Elements, and can mark unused Elements by +giving them INVALID values. The NO_PROPORTION enum is used to +signify that the user has not positioned the Element's label; any +positive proportion value is taken to be the text element's position +proportional to the canvas's size. +

If we stored each label's actual x and y position, then every time the +user resized the main window (and therefore the canvas), the text +would retain its original (now incorrect) position. So instead of +storing absolute (x, y) positions we store proportional positions, +i.e. x/width and y/height. We can then multiply these positions by +the current width and height respectively when we come to draw the +text and the text will be positioned correctly regardless of any +resizing. For example, if a label has an x position of 300 and the +canvas is 400 pixels wide, the proportional x value is 300/400 = 0.75. +

The MAX_PROPOINTS enum is problematic. We need to store the x and y +proportions for the text label for every chart type. And we have +chosen to store these proportions in a fixed-size array. Because of +this we must specify the maximum number of proportion pairs needed. +This value must be changed if we change the number of chart types, +which means that the Element class is strongly coupled to the +number of chart types provided by the ChartForm class. In a +larger application we might have used a vector to store these points +and dynamically resized it depending on how many chart types are +available. +

        Element( double value = INVALID, QColor valueColor = Qt::gray,
+                 int valuePattern = Qt::SolidPattern,
+                 const QString& label = QString::null,
+                 QColor labelColor = Qt::black ) {
+            init( value, valueColor, valuePattern, label, labelColor );
+            for ( int i = 0; i < MAX_PROPOINTS * 2; ++i )
+                m_propoints[i] = NO_PROPORTION;
+        }
+
+

The constructor provides default values for all members of the Element class. New elements always have label text with no position. +We use an init() function because we also provide a set() function +which works like the constructor apart from leaving the proportional +positions alone. +

        bool isValid() const { return m_value > EPSILON; }
+
+

Since we are storing Elements in a fixed size vector we need to be +able to check whether a particular element is valid (i.e. should be +used in calculations and displayed) or not. This is easily achieved +with the isValid() function. +

(Extracts from element.cpp.) +

+ +

    double Element::proX( int index ) const
+    {
+        Q_ASSERT(index >= 0 && index < MAX_PROPOINTS);
+        return m_propoints[2 * index];
+    }
+
+

Getters and setters are provided for all the members of Element. +The proX() and proY() getters and the setProX() and setProY() setters +take an index which identifies the type of chart the proportional +position applies to. This means that the user can have labels +positioned separately for the same data set for a vertical bar chart, +a horizontal bar chart and for a pie chart. Note also that we use the +Q_ASSERT macro to provide pre-condition tests on the chart type +index; (see Debugging). +

Reading and Writing Data Elements +

+

(Extracts from element.h.) +

+ +

    QTextStream &operator<<( QTextStream&, const Element& );
+    QTextStream &operator>>( QTextStream&, Element& );
+
+

To make our Element class more self-contained we provide overloads +for the << and >> operators so that Elements may be written to +and read from text streams. We could just as easily have used binary +streams, but using text makes it possible for users to manipulate +their data using a text editor and makes it easier to generate and +filter the data using a scripting language. +

(Extracts from element.cpp.) +

+ +

    #include "element.h"
+
+    #include <qstringlist.h>
+    #include <qtextstream.h>
+
+

Our implementation of the operators requires the inclusion of qtextstream.h and qstringlist.h. +

    const char FIELD_SEP = ':';
+    const char PROPOINT_SEP = ';';
+    const char XY_SEP = ',';
+
+

The format we are using to store the data is colon separated fields +and newline separated records. The proportional points are semi-colon +separated, with their x, y pairs being comma separated. The field +order is value, value color, value pattern, label color, label points, +label text. For example: +

+20:#ff0000:14:#000000:0.767033,0.412946;0,0.75;0,0:Red :with colons:!
+70:#00ffff:2:#ffff00:0.450549,0.198661;0.198516,0.125954;0,0.198473:Cyan
+35:#0000ff:8:#555500:0.10989,0.299107;0.397032,0.562977;0,0.396947:Blue
+55:#ffff00:1:#000080:0.0989011,0.625;0.595547,0.312977;0,0.59542:Yellow
+80:#ff00ff:1:#000000:0.518681,0.694196;0.794063,0;0,0.793893:Magenta or Violet
+
+ +

There's no problem having whitespace and field separators in label +text due to the way we read Element data. +

    QTextStream &operator<<( QTextStream &s, const Element &element )
+    {
+        s << element.value() << FIELD_SEP
+          << element.valueColor().name() << FIELD_SEP
+          << element.valuePattern() << FIELD_SEP
+          << element.labelColor().name() << FIELD_SEP;
+
+        for ( int i = 0; i < Element::MAX_PROPOINTS; ++i ) {
+            s << element.proX( i ) << XY_SEP << element.proY( i );
+            s << ( i == Element::MAX_PROPOINTS - 1 ? FIELD_SEP : PROPOINT_SEP );
+        }
+
+        s << element.label() << '\n';
+
+        return s;
+    }
+
+

Writing elements is straight-forward. Each member is written followed +by a field separator. The points are written as comma separated (XY_SEP) x, y pairs, each pair separated by the PROPOINT_SEP +separator. The final field is the label followed by a newline. +

    QTextStream &operator>>( QTextStream &s, Element &element )
+    {
+        QString data = s.readLine();
+        element.setValue( Element::INVALID );
+
+        int errors = 0;
+        bool ok;
+
+        QStringList fields = QStringList::split( FIELD_SEP, data );
+        if ( fields.count() >= 4 ) {
+            double value = fields[0].toDouble( &ok );
+            if ( !ok )
+                errors++;
+            QColor valueColor = QColor( fields[1] );
+            if ( !valueColor.isValid() )
+                errors++;
+            int valuePattern = fields[2].toInt( &ok );
+            if ( !ok )
+                errors++;
+            QColor labelColor = QColor( fields[3] );
+            if ( !labelColor.isValid() )
+                errors++;
+            QStringList propoints = QStringList::split( PROPOINT_SEP, fields[4] );
+            QString label = data.section( FIELD_SEP, 5 );
+
+            if ( !errors ) {
+                element.set( value, valueColor, valuePattern, label, labelColor );
+                int i = 0;
+                for ( QStringList::iterator point = propoints.begin();
+                    i < Element::MAX_PROPOINTS && point != propoints.end();
+                    ++i, ++point ) {
+                    errors = 0;
+                    QStringList xy = QStringList::split( XY_SEP, *point );
+                    double x = xy[0].toDouble( &ok );
+                    if ( !ok || x <= 0.0 || x >= 1.0 )
+                        errors++;
+                    double y = xy[1].toDouble( &ok );
+                    if ( !ok || y <= 0.0 || y >= 1.0 )
+                        errors++;
+                    if ( errors )
+                        x = y = Element::NO_PROPORTION;
+                    element.setProX( i, x );
+                    element.setProY( i, y );
+                }
+            }
+        }
+
+        return s;
+    }
+
+

To read an element we read one record (i.e. one line). We break the +data into fields using QStringList::split(). Because it is possible +that a label will contain FIELD_SEP characters we use +QString::section() to extract all the text from the last field to the +end of the line. If there are enough fields and the value, colors and +pattern data is valid we use Element::set() to write this data into +the element; otherwise we leave the element INVALID. We then +iterate through the points. If the x and y proportions are valid and +in range we set them for the element. If one or both proportions is +invalid they will hold the value zero; this is not suitable so we +change invalid (and out-of-range) proportional point values to NO_PROPORTION. +

Our Element class is now sufficient to store, manipulate, read and +write element data. We have also created an element vector typedef for +storing a collection of elements. +

We are now ready to create main.cpp and the user interface through +which our users will create, edit and visualise their data sets. +

+ +
For more information on Qt's data streaming facilities see QDataStream Operators' Formats, and see +the source code for any of the Qt classes mentioned that are similar +to what you want to store. +
+

+« The 'Big Picture' | +Contents | +Mainly Easy » +

+

+ +


+ +
Copyright © 2007 +TrolltechTrademarks +
Qt 3.3.8
+
+ -- cgit v1.2.3