Chapter 13 Data Structure Classes

Storing and processing data is an essential part of any application. From simple classes that store information about size and position to complex types such as arrays and hash maps, wxWidgets provides a comprehensive selection of data structures. This chapter presents many of wxWidgets’ data structures, highlighting the frequently used methods of each structure. Less frequently used structures and features can be found by reading the complete APIs in the wxWidgets documentation.

Note that data structure theories and implementations are not covered in this book. However, anyone should be able to use the data structure classes, even without understanding their internals.

Why Not STL?

First, let’s deal with a question commonly asked about wxWidgets data structure classes: “Why doesn’t wxWidgets just use the Standard Template Library (STL)?” The main reason is historical: wxWidgets has existed since 1992, long before STL could reliably be used across different platforms and compilers. As wxWidgets has evolved, many of the data structure classes have gravitated towards an STL-like API, and it is expected that eventually STL equivalents will replace some wxWidgets classes.

Meanwhile, you can still use STL functionality in your wxWidgets applications by setting wxUSE_STL to 1 in setup.h (or by passing —enable-stl when configuring) to base wxString and other containers on the STL equivalents. Be warned that using STL with wxWidgets can increase both the library size and compilation time, especially when using GCC.

Strings

The benefits of working with a string class instead of standard character pointers are well established. wxWidgets includes its own string class, wxString, used both internally and for passing and returning information. wxString has all the standard operations you expect to find in a string class: dynamic memory management, construction from other strings, C strings, and characters, assignment operators, access to individual characters, string concatenation and comparison, substring extraction, case conversion, trimming and padding (with spaces), searching and replacing, C-like printf, stream-like insertion functions, and more.

Beyond being just another string class, wxString has other useful features. wxString fully supports Unicode, including methods for converting to and from ANSI and Unicode regardless of your build configuration. Using wxString gives you the ability to pass strings to the library or receive them back without any conversion process. Lastly, wxString implements 90% of the STL std::string methods, meaning that anyone familiar with std::string can use wxString without any learning curve.

Using wxString

Using wxString in your application is very straightforward. Wherever you would normally use std::string or your favorite string implementation, use wxString instead. All functions taking string arguments should take const wxString& (which makes assignment to the strings inside the function faster because of reference counting), and all functions returning strings should return wxString, which makes it safe to return local variables.

Because C and C++ programmers are familiar with most string methods, a long and detailed API reference for wxString has been omitted. Please consult the wxWidgets documentation for wxString, which provides a comprehensive list of all its methods.

You may notice that wxString sometimes has two or more functions that do the same thing. For example, Length, Len, and length all return the length of the string. In all cases of such duplication, the usage of std::string-compatible methods is strongly advised. It will make your code more familiar to other C++ programmers and will let you reuse the same code in both wxWidgets and other programs, where you can typedef wxString as std::string. Also, wxWidgets might start using std::string at some point in the future, so using these methods will make your programs more forward-compatible (although the wxString methods would be supported for some time for backwards compatibility).

wxString, Characters, and String Literals

wxWidgets has a wxChar type which maps either to char or wchar_t depending on the application build configuration (Unicode or ANSI). As already mentioned, there is no need for a separate type for char or wchar_t strings because wxString stores strings using the appropriate underlying C type. Whenever you work directly with strings that you intend to use with a wxWidgets class, use wxChar instead of char or wchar_t directly. Doing so ensures compatibility with both ANSI and Unicode build configuration without complicated preprocessor conditions.

When using wxWidgets with Unicode enabled, standard string literals are not the correct type: an unmodified string literal is always of type char*. In order for a string literal to be used in Unicode mode, it must be a wide character constant, usually marked with an L. wxWidgets provides the wxT macro (identical to _T) to wrap string literals for use with or without Unicode. When Unicode is not enabled, _T is an empty macro, but with Unicode enabled, it adds the necessary L for the string literal to become a wide character string constant. For example:


wxChar ch = wxT('*'),
wxString s = wxT("Hello, world!");
wxChar* pChar = wxT("My string");
wxString s2 = pChar;


For more details about using Unicode in your applications, please see Chapter 16, “Writing International Applications.”

Basic wxString to C Pointer Conversions

Because there may be times when you need to access a wxString’s data as a C type for low-level processing, wxWidgets provides several accessors:

Image   mb_str returns a C string representation of the string, a const char*, regardless of whether Unicode is enabled. In Unicode mode, the string is converted, and data may be lost.

Image   wc_str returns a wide character representation of the string, a wchar_t*, regardless of whether Unicode is enabled. In ANSI mode, the string is converted to Unicode.

Image   c_str returns a pointer to the string data (const char* in ANSI mode, const wchar_t* in Unicode mode). No conversion takes place.

You can convert between std::string and wxString by means of c_str, as follows:


std::string str1 = wxT("hello");
wxString str2 = str1.c_str( );
std::string str3 = str2.c_str( );


One trap when using wxString is the implicit conversion operator to const char *. It is advised that you use c_str to indicate clearly when the conversion is done. The danger of this implicit conversion may be seen in the following code fragment:


// converts the input string to uppercase, outputs it to the
// screen, and returns the result (buggy)
const char *SayHELLO(const wxString& input)
{
    wxString output = input.Upper( );

    printf("Hello, %s! ", output);

    return output;
}


There are two nasty bugs in these four lines. The first is in the call to the printf function. The implicit conversion to a C string is automatically applied by the compiler in the case of functions like puts because the argument of puts is known to be of the type const char *. However, this is not done for printf, which is a function with a variable number of arguments whose types are unknown. Such a call to printf might do anything at all (including displaying the correct string on screen), although the most likely result is a program crash. The solution is to use c_str:


printf(wxT("Hello, %s! "), output.c_str( ));


The second bug is that returning the variable named output doesn’t work. The implicit cast is used again, so the code compiles, but it returns a pointer to a buffer belonging to a local variable that is deleted as soon as the function exits. The solution to this problem is also easy: have the function return a wxString instead of a C string. The corrected code looks like this:


// converts the input string to uppercase, outputs it to the
// screen, and returns the result (corrected)
wxString SayHELLO(const wxString& input)
{
    wxString output = input.Upper( );

    printf(wxT("Hello, %s! "), output.c_str( ));

    return output;
}


Standard C String Functions

Because most programs use character strings, the standard C library provides quite a few functions to work with them. Unfortunately, some of them have rather counterintuitive behavior (like strncpy, which doesn’t always terminate the resulting string with a NULL) or are considered unsafe with possible buffer overflows. Moreover, some very useful functions are not standard at all. This is why in addition to all wxString functions, there are a few global string functions that try to correct these problems: wxIsEmpty verifies whether the string is empty (returning true for NULL pointers), wxStrlen handles NULLs correctly and returns 0 for them, and wxStricmp is a platform-independent version of the case-insensitive string comparison function known either as stricmp or strcasecmp on different platforms.

The “wx/string.h” header also defines wxSnprintf and wxVsnprintf functions that should be used instead of the inherently dangerous standard sprintf. The “n” functions use snprintf, which does buffer size checks whenever possible. You may also use wxString::Printf without worrying about the vulnerabilities typically found in printf.

Converting to and from Numbers

Programmers often need to convert between string and numeric representations of numbers, such as when processing user input or displaying the results of a calculation.

ToLong(long* val, int base=10) attempts to convert the string to a signed integer in base base. It returns true on success, in which case the number is stored in the location pointed to by val, or false if the string does not represent a valid number in the given base. The value of base must be between 2 and 36, inclusive, or a special value 0, which means that the usual rules of C numbers are applied: if the number starts with 0x, it is considered to be in base 16; if it starts with 0-, it is considered to be in base 8, and in base 10 otherwise.

ToULong(unsigned long* val, int base=10) works identically to ToLong, except that the string is converted to an unsigned integer.

ToDouble(double* val) attempts to convert the string to a floating point number. It returns true on success (the number is stored in the location pointed to by val) or false if the string does not represent such a number.

Printf(const wxChar* pszFormat, ...) is similar to the C standard function sprintf, enabling you to put information into a wxString using standard C string formatting. The number of characters written is returned.

static Format(const wxChar* pszFormat, ...) returns a wxString containing the results of calling Printf with the passed parameters. The advantage of Format over Printf is that Format can be used to add to an existing string:


int n = 10;
wxString s = "Some Stuff";
s += wxString::Format(wxT("%d"),n );


operator<< can be used to append an int, a float, or a double to a wxString.

wxStringTokenizer

wxStringTokenizer helps you to break a string into a number of tokens, replacing and expanding the C function strtok. To use it, create a wxStringTokenizer object and give it the string to tokenize and the delimiters that separate the tokens. By default, white space characters will be used. Then call GetNextToken repeatedly until HasMoreTokens returns false.


wxStringTokenizer tkz(wxT("first:second:third:fourth"), wxT(":"));
while ( tkz.HasMoreTokens( ) )
{
    wxString token = tkz.GetNextToken( );
    // process token here
}


By default, wxStringTokenizer will behave in the same way as strtok if the delimiters string contains only white space characters. Unlike the standard functions, however, it will return empty tokens if appropriate for other non-white space delimiters. This is helpful for parsing strictly formatted data where the number of fields is fixed but some of them may be empty, as in the case of tab- or comma-delimited text files.

wxStringTokenizer’s behavior is governed by the last constructor parameter, which may be one of the following:

Image   wxTOKEN_DEFAULT: Default behavior as described previously; same as wxTOKEN_STRTOK if the delimiter string contains only white space, and same as wxTOKEN_RET_EMPTY otherwise.

Image   wxTOKEN_RET_EMPTY: In this mode, the empty tokens in the middle of the string will be returned. So a::b: will be tokenized into three tokens a, “”, and b.

Image   wxTOKEN_RET_EMPTY_ALL: In this mode, empty trailing tokens (after the last delimiter character) will be returned as well. a::b: will contain four tokens: the same as wxTOKEN_RET_EMPTY and another empty one as the last one.

Image   wxTOKEN_RET_DELIMS: In this mode, the delimiter character after the end of the current token is appended to the token (except for the last token, which has no trailing delimiter). Otherwise, it is the same mode as wxTOKEN_RET_EMPTY.

Image   wxTOKEN_STRTOK: In this mode, the class behaves exactly like the standard strtok function. Empty tokens are never returned.

wxStringTokenizer has two other useful accessors:

Image   CountTokens returns the number of remaining tokens in the string, returning 0 when there are no more tokens.

Image   GetPosition returns the current position of the tokenizer in the original string.

wxRegEx

wxRegEx represents a regular expression. This class provides support for regular expression matching and replacement. wxRegEx is either built on top of the system library (if it is available and has support for POSIX regular expressions, which is the case for most modern Unix variants, including Linux and Mac OS X) or uses the built-in library by Henry Spencer. Regular expressions, as defined by POSIX, come in two variations: extended and basic. The built-in library also adds an advanced mode, which is not available when using the system library.

On platforms where a system library is available, the default is to use the built-in library for Unicode builds, and the system library otherwise. Bear in mind that Unicode is fully supported only by the built-in library. It is possible to override the default when building wxWidgets. When using the system library in Unicode mode, the expressions and data are translated to the default 8-bit encoding before being passed to the library.

Use wxRegEx as you would use any POSIX regular expression processor. Due to the advanced nature and specialized uses of regular expressions, please see the wxWidgets documentation for a complete discussion and API reference.

wxArray

wxWidgets provides a dynamic array structure using wxArray, similar to C arrays in that the member access time is constant. However, these arrays are dynamic in the sense that they will automatically allocate more memory if there is not enough of it for adding a new element. Adding items to the arrays is also implemented in more or less constant time—but the price is pre-allocating the memory in advance. wxArray also provides range checking, asserting in debug builds or silently returning in release builds (though your program might get an unexpected value from array operations).

Array Types

wxWidgets has three different kinds of arrays. All derive from wxBaseArray, which works with untyped data and cannot be used directly. The macros WX_DEFINE_ARRAY, WX_DEFINE_SORTED_ARRAY, and WX_DEFINE_OBJARRAY are used to define a new class deriving from it. The classes are referred to as wxArray, wxSortedArray, and wxObjArray, but you should keep in mind that no classes with such names actually exist.

wxArray is suitable for storing integer types and pointers, which it does not treat as objects in any way—that is, the element referred to by the pointer is not deleted when the element is removed from the array. It should be noted that all of wxArray’s functions are inline, so it costs nothing to define as many array types as you want (either in terms of the executable size or speed). This class has one serious limitation: it can only be used for storing integral types (bool, char, short, int, long, and their unsigned variants) or pointers (of any kind). Data of type float or double should not be stored in a wxArray.

wxSortedArray is a wxArray variant that should be used when you will be searching the array frequently. wxSortedArray requires you to define an additional function for comparing two elements of the array element type and always stores its items in the sorted order (according to the sort function). Assuming that you search the array far less frequently than you add to it, wxSortedArray may lead to huge performance improvements compared to wxArray. It should be noted that wxSortedArray shares wxArray’s type restriction and should only be used for storing integral types or pointers.

wxObjArray class treats its elements like objects. It can delete them when they are removed from the array (invoking the correct destructor), and it copies them using the object’s copy constructor. The definition of the wxObjArray arrays is split into two parts. First, you should declare the new wxObjArray class using the WX_DECLARE_OBJARRAY macro. Second, you must include the file defining the implementation of template type <wx/arrimpl.cpp> and define the array class with the WX_DEFINE_OBJARRAY macro from a point where the full declaration of the array elements class is in scope. This technique will be demonstrated in the array sample code presented later in this chapter.

wxArrayString

wxArrayString is an efficient container for storing wxString objects and has the same features as the other wxArray classes. It is also very compact and doesn’t take more space than a C array wxString[] type (wxArrayString uses its knowledge of internals of wxString class to achieve this). All of the methods available in the other wxArray types are also available in wxArrayString.

This class is used in the same way as other dynamic arrays, except that no WX_DEFINE_ARRAY declaration is needed for it—you can use wxArrayString directly. When a string is added or inserted in the array, a copy of the string is created, so the original string may be safely deleted. In general, there is no need to worry about string memory management when using this class—it will always free the memory it uses.

The references returned by Item, Last, or operator[] are not constant, so the array elements may be modified in place:


array.Last( ).MakeUpper( );


There is also a variant of wxArrayString called wxSortedArrayString that has exactly the same methods as wxArrayString, but always keeps its strings in alphabetical order. wxSortedArrayString uses binary search in its Index, which makes it much more efficient if you rarely add strings to the array but search for them often. The Insert and Sort methods should not be used with wxSortedArrayString because they are likely to break the order of items.

Array Construction, Destruction, and Memory Management

Array classes are C++ objects and as such have the appropriate copy constructors and assignment operators. Copying a wxArray copies the elements, but copying a wxObjArray copies the array’s items. However, for the sake of memory efficiency, neither of these classes has a virtual destructor. It is not very important for wxArray, which has a trivial destructor, but it does mean that you should avoid deleting wxObjArray through a wxBaseArray pointer and that you should not derive your own classes from the array classes.

Automatic array memory management is quite trivial: the array starts by pre-allocating some minimal amount of memory (defined by WX_ARRAY_DEFAULT_INITIAL_SIZE). When further new items exhaust previously allocated memory, the array reallocates itself, adding 50% of the currently allocated amount, but no more than ARRAY_MAXSIZE_INCREMENT. The Shrink method deallocates any extra memory. The Alloc method can be quite useful if you know in advance how many items you are going to put in the array, and using it will prevent the array code from reallocating the memory more often than needed.

Array Sample Code

The array sample presented here shows the most complex case, using a wxObjArray to store custom objects. Using a wxArray for primitive types or pointers would work identically in terms of syntax and semantics, but the wxArray would never take ownership of the objects.


// Our data class to store in the array
class Customer
{
public:
    int CustID;
    wxString CustName;
};

// this part might be in a header or source (.cpp) file
// declare our array class:
// this macro declares and partly implements CustomerArray class
// (which derives from wxArrayBase)
WX_DECLARE_OBJARRAY(Customer, CustomerArray);

// the only requirement for the rest is to be AFTER the full
// declaration of Customer (for WX_DECLARE_OBJARRAY forward
// declaration is enough), but usually it will be found in the
// source file and not in the header
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(CustomerArray);

// Used when sorting to compare objects
int arraycompare(Customer** arg1, Customer** arg2)
{
    return ((*arg1)->CustID < (*arg2)->CustID);
}

// Show Array operations
void ArrayTest( )
{
    // Declare an instance of our array
    CustomerArray MyArray;

    bool IsEmpty = MyArray.IsEmpty( ); // will be true

    // Create some customers
    Customer CustA;
    CustA.CustID = 10;
    CustA.CustName = wxT("Bob");

    Customer CustB;
    CustB.CustID = 20;
    CustB.CustName = wxT("Sally");

    Customer* CustC = new Customer( );
    CustC->CustID = 5;
    CustC->CustName = wxT("Dmitri");

    // Append two customers to the array
    MyArray.Add(CustA);
    MyArray.Add(CustB);

    // Insert last customer into arbitrary place in the array
    // The array will not own this CustC object, it will own a copy
    MyArray.Insert(*CustC, (size_t)0);

    int Count = MyArray.GetCount( ); // will be 3

    // If not found, wxNOT_FOUND is returned
    int Index = MyArray.Index(CustB); // will be 2

    // Process each customer in the array
    for (unsigned int i = 0; i < MyArray.GetCount( ); i++)
    {
        Customer Cust = MyArray[i]; // or MyArray.Item(i);

        // Process Customer
    }

    // Sort the customers according to the sort function
    MyArray.Sort(arraycompare);

    // Remove Customer A from the array, but do not delete
    Customer* pCustA = MyArray.Detach(1);
    // We must deallocate the object ourself if using Detach
    delete pCustA;

    // Remove will also delete the Customer object
    MyArray.RemoveAt(1);

    // Clears the array, deleting all objects

    MyArray.Clear( );

    // The array never owned this object
    delete CustC;
}


WXList and WXNode

The wxList class is a doubly linked list that can store data of an arbitrary type. wxWidgets requires that you explicitly define a new list type for each type of list data, providing strong type checking for the list’s data type. The wxList class also allows you to optionally specify a key type for primitive lookups (see the wxHashMap section if you need a structure with fast random access).

The wxList class makes use of an abstract wxNode class. When you define a new list, a new node type deriving from wxNodeBase is also created, providing type-safe node operations. The most important methods of the node class are the self-explanatory GetNext, GetPrevious, and GetData, which provide access to the next node, the previous node, and the current node’s data.

The only remarkable operation for a wxList is data deletion. By default, removing a node does not delete the data being stored by that node. The DeleteContents method allows you to change this behavior and set the data itself to be deleted along with the nodes. If you want to empty a list of all data and delete the data, be sure to call DeleteContents with true before calling Clear.

Rather than rehash the contents of the manual, a small but comprehensive code example shows the wxList methods as well as how to create and use your custom list type. Note that the WX_DECLARE_LIST macro would typically appear in a header file, while the WX_DEFINE_LIST macro would almost always appear in a source file.


// Our data class to store in the list
class Customer
{
public:
    int CustID;
    wxString CustName;
};

// this part might be in a header or source file
// declare our list class:
// this macro declares and partly implements CustomerList class
// (which derives from wxListBase)
WX_DECLARE_LIST(Customer, CustomerList);

// the only requirement for the rest is to be AFTER the full
// declaration of Customer (for WX_DECLARE_LIST forward declaration
// is enough), but usually it will be found in the source file and
// not in the header

#include <wx/listimpl.cpp>
WX_DEFINE_LIST(CustomerList);

// Used for sorting to compare objects
int listcompare(const Customer** arg1, const Customer** arg2)
{
    return ((*arg1)->CustID < (*arg2)->CustID);
}

// Show List operations
void ListTest( )
{
    // Declare an instance of our list
    CustomerList* MyList = new CustomerList( );

    bool IsEmpty = MyList->IsEmpty( ); // will be true

    // Create some customers
    Customer* CustA = new Customer;
    CustA->CustID = 10;
    CustA->CustName = wxT("Bob");

    Customer* CustB = new Customer;
    CustB->CustID = 20;
    CustB->CustName = wxT("Sally");

    Customer* CustC = new Customer;
    CustC->CustID = 5;
    CustC->CustName = wxT("Dmitri");

    // Append two customers to the list
    MyList->Append(CustA);
    MyList->Append(CustB);

    // Insert last customer into arbitrary place in the list
    MyList->Insert((size_t)0, CustC);

    int Count = MyList->GetCount( ); // will be 3

    // If not found, wxNOT_FOUND is returned
    int index = MyList->IndexOf(CustB); // will be 2

    // Customized node holds our customized data
    CustomerList::Node* node = MyList->GetFirst( );

    // Traverse the nodes and process the customers
    while (node)
    {
        Customer* Cust = node->GetData( );

        // Process Customer

        node = node->GetNext( );
    }

    // Returns the node at the specified position
    node = MyList->Item(0);

    // Sort the customers according to the sort function
    MyList->Sort(listcompare);

    // Remove Customer A node from the list
    MyList->DeleteObject(CustA);
    // CustA object is NOT deleted by removing the node
    delete CustA;

    // Returns the node whose client data is the object
    node = MyList->Find(CustB);

    // Specifies that data should be deleted when node is deleted
    MyList->DeleteContents(true);

    // Removes node from the list and deletes that node's
    // data (CustB)
    MyList->DeleteNode(node);

    // Clears the list, and deletes all stored data
    // (DeleteContents is true)
    MyList->Clear( );

    delete MyList;
}


WXHashMap

The wxHashMap class is a simple, type-safe, and reasonably efficient hash map class, with an interface that is a subset of the interface of STL containers. In particular, the interface is modeled after std::map and the non-standard std::hash_map. By using macros to create hash maps, you can choose from several combinations of keys and values, including int, wxString, or void* (arbitrary class).

There are three macros for declaring a hash map. To declare a hash map class named CLASSNAME with wxString keys and VALUE_T values:


WX_DECLARE_STRING_HASH_MAP(VALUE_T, CLASSNAME);


To declare a hash map class named CLASSNAME with void* keys and VALUE_T values:


WX_DECLARE_VOIDPTR_HASH_MAP(VALUE_T, CLASSNAME);


To declare a hash map class named CLASSNAME with arbitrary keys or values:


WX_DECLARE_HASH_MAP(KEY_T, VALUE_T, HASH_T, KEY_EQ_T, CLASSNAME);


HASH_T and KEY_EQ_T are the types used for the hashing function and key comparison. wxWidgets provides three predefined hashing functions: wxInteger Hash for integer types (int, long, short, and their unsigned counterparts), wxStringHash for strings (wxString, wxChar*, char*), and wxPointerHash for any kind of pointer. Similarly, three equality predicates are provided: wxInteger Equal, wxStringEqual, and wxPointerEqual.

The following code example shows the wxHashMap methods as well as how to create and use your custom hash type.


// Our data class to store in the hash
class Customer
{
    public:
        int CustID;
        wxString CustName;
};

// Declare our hash map class
// This macro declares and implements CustomerList as a hash map
WX_DECLARE_HASH_MAP(int, Customer*, wxIntegerHash,
                    wxIntegerEqual, CustomerHash);

void HashTest( )
{
    // Declare an instance of our list
    CustomerHash MyHash;

    bool IsEmpty = MyHash.empty( ); // will be true

    // Create some customers
    Customer* CustA = new Customer;
    CustA->CustID = 10;
    CustA->CustName = wxT("Bob");

    Customer* CustB = new Customer;
    CustB->CustID = 20;
    CustB->CustName = wxT("Sally");

    Customer* CustC = new Customer;
    CustC->CustID = 5;
    CustC->CustName = wxT("Dmitri");

    // Add the customers to the hash
    MyHash[CustA->CustID] = CustA;
    MyHash[CustB->CustID] = CustB;
    MyHash[CustC->CustID] = CustC;

    int Size = MyHash.size( ); // will be 3

    // count returns 0 or 1, i.e. is 20 in the hash?
    int Present = MyHash.count(20); // will be 1

    // Customized iterator for our hash map
    CustomerHash::iterator i = MyHash.begin( );

    // End represents one past the last element
    while (i != MyHash.end( ))
    {

        // first is the key, second is the value
        int CustID = i->first;
        Customer* Cust = i->second;

        // Process Customer

        // Advance to the next element in the hash
        i++;
    }

    // Remove Customer A from the hash
    MyHash.erase(10);
    // CustA object is NOT deleted by removing from hash
    delete CustA;

    // Return an iterator to the node with the specified key
    CustomerHash::iterator i2 = MyHash.find(21);

    // Find returns hash::end if the key was not found
    bool NotFound = (i2 == MyHash.end( )); // will be true

    // This time the find will be successful
    i2 = MyHash.find(20);

    // Removing an element using the iterator
    MyHash.erase(i2);
    delete CustB;

    // Side-effect: A NULL value is inserted in the hash for key 30
    Customer* Cust = MyHash[30]; // Cust will be NULL

    // Empties the hash map of all elements
    MyHash.clear( );

    delete CustC;
}


Storing and Processing Dates and Times

wxWidgets provides a comprehensive wxDateTime class for representing date and time information with many operations such as formatting, time zones, date and time arithmetic, and more. Static functions provide information such as the current date and time, as well as queries such as whether a given year is a leap year. Note that the wxDateTime class is the appropriate class to use even when you need to store only date or time information. Helper classes wxTimeSpan and wxDateSpan provide convenient ways for modifying an existing wxDateTime object.

wxDateTime

The wxDateTime class has too many methods to include in a concise discussion; the complete API reference is available in the wxWidgets documentation. What is presented here is an overview of the most frequently used wxDateTime methods and operations.

Note that although time is always stored internally in Greenwich Mean Time (GMT), you will usually work in the local time zone. Because of this, all wxDateTime constructors and modifiers that compose a date or time from components (for example hours, minutes, and seconds) assume that these values are for the local time zone. All methods returning date or time components (month, day, hour, minute, second, and so on) will also return the correct values for the local time zone by default; no effort is required to get correct results for your time zone. If you want to manipulate time zones, please refer to the documentation.

wxDateTime Constructors and Modifiers

wxDateTime objects can be constructed from Unix timestamps, time-only information, date-only information, or complete date and time information. For each constructor, there is a corresponding Set method that modifies an existing object to have the specified date or time. There are also individual modifiers such as SetMonth or SetHour that change just one component of the date or time.

wxDateTime(time_t) constructs an object with the date and time set according to the specified Unix timestamp.

wxDateTime(const struct tm&) constructs an object using the data from the C standard tm structure.

wxDateTime(wxDateTime_t hour, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0) constructs an object based on the specified time information.

wxDateTime(wxDateTime_t day, Month month = Inv_Month, int year = Inv_Year, wxDateTime_t hour = 0, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0) constructs an object with the specified date and time information.

wxDateTime Accessors

The accessors for wxDateTime are mostly self-explanatory: GetYear, GetMonth, GetDay, GetWeekDay, GetHour, GetMinute, GetSecond, GetMillisecond, GetDayOfYear, GetWeekOfYear, GetWeekOfMonth, and GetYearDay. wxDateTime also provides the following:

Image   GetTicks returns the date and time in Unix timestamp format (seconds since January 1, 1970 at midnight).

Image   IsValid returns whether or not the object is in a valid state (the object could have been constructed but never given a date or time).

Getting the Current Time

wxDateTime provides two static methods for retrieving the current time:

Image   wxDateTime::Now creates a wxDateTime object with the current time, accurate to up the second.

Image   wxDateTime::UNow creates a wxDateTime object with the current time, including milliseconds.

Parsing and Formatting Dates

The functions in this section convert wxDateTime objects to and from text. The conversions to text are mostly trivial: you can use the default date and time representations for the current locale (FormatDate and FormatTime), use the international standard representation defined by ISO 8601 (FormatISODate and FormatISOTime), or specify any format at all by using Format directly.

The conversions from text are more interesting because there are many more possibilities. The simplest cases can be taken care of with ParseFormat, which can parse any date in a specified (rigid) format. ParseRfc822Date parses dates using the format from RFC 822 that defines the format of email messages on the Internet.

The most interesting functions are ParseTime, ParseDate, and ParseDateTime, which try to parse the date and/or time in “free” format, allowing them to be specified in a variety of ways. These functions can be used to parse user input that is not bound by any predefined format. As an example, ParseDateTime can parse strings such as “tomorrow”, “March first”, and even “next Sunday”.

Date Comparisons

Two wxDateTime objects can easily be compared using one of many available comparison functions. All of these methods return true or false.

The following methods all make comparisons to one other wxDateTime object: IsEqualTo, IsEarlierThan, IsLaterThan, IsSameDate, and IsSameTime.

The following methods all make comparisons using two other wxDateTime objects: IsStrictlyBetween and IsBetween. The difference between these two is that IsStrictlyBetween would return false if the wxDateObject in question exactly equaled one of the range extremes, whereas IsBetween would return true.

Date Arithmetic

wxWidgets provides two very robust classes for performing arithmetic on wxDateTime objects: wxTimeSpan and wxDateSpan. wxTimeSpan is simply a difference in milliseconds and always gives fast, predictable results. On the other hand, time has larger meaningful units, such as weeks or months. wxDateSpan handles these operations in the most natural way possible, but note that manipulating intervals of this kind is not always well-defined. For example, Jan 31 plus one month will give Feb 28 (or 29), the last day of February, and not the non-existent Feb 31. Of course, this is what is usually wanted, but you still might be surprised that subtracting back the same interval from Feb 28 will result in Jan 28 (not the January 31 that we started with).

Many different operations may be performed with the dates, but not all combinations of them make sense. For example, multiplying a date by a number is an invalid operation, even though multiplying either of the time span classes by a number is perfectly valid.

Image   Addition: A wxTimeSpan or wxDateSpan can be added to wxDateTime resulting in a new wxDateTime object. Also, two objects of the same span class can be added together, resulting in another object of the same class.

Image   Subtraction: The same operations as addition are valid for subtraction. Additionally, a difference between two wxDateTime objects can be taken and will return a wxTimeSpan object.

Image   Multiplication: A wxTimeSpan or wxDateSpan object can be multiplied by an integer number, resulting in an object of the same type.

Image   Unary minus: A wxTimeSpan or wxDateSpan object may be negated, resulting in an interval of the same magnitude but in the opposite time direction.

The following small code example demonstrates how to use wxDateSpan and wxTimeSpan to change the time stored in a wxDateTime object. See the wxWidgets manual for a complete list of available methods.


void TimeTests( )
{
    // Get the current day and time
    wxDateTime DT1 = wxDateTime::Now( );

    // A span of 2 weeks and 1 day, or 15 days
    wxDateSpan Span1(0, 0, 2, 1);

    // Substract 15 days from today
    wxDateTime DT2 = DT1 - Span1;

    // Static creation of a one-day difference
    wxDateSpan Span2 = wxDateSpan::Day( );

    // Span 3 will now be 14 days
    wxDateSpan Span3 = Span1 - Span2;

    // 0 days (the span is defined as 2 weeks)
    int Days = Span3.GetDays( );

    // 14 days (2 weeks)
    int TotalDays = Span3.GetTotalDays( );

    // 2 weeks into the past
    wxDateSpan Span4 = -Span3;

    // A span of 3 months
    wxDateSpan Span5 = wxDateSpan::Month( ) * 3;

    // 10 hours, 5 minutes and 6 seconds
    wxTimeSpan Span6(10, 5, 6, 0);

    // Add the specified amount of time to DT2
    wxDateTime DT3 = DT2 + Span6;

    // Span7 is 3 times longer than Span6, but in the past
    wxTimeSpan Span7 = (-Span6) * 3;

    // SpanNeg will be true, the span is negative (in the past)
    bool SpanNeg = Span7.IsNegative( );

    // Static creation of a span of one hour
    wxTimeSpan Span8 = wxTimeSpan::Hour( );

    // One hour is not longer than 30+ hours (uses absolutes)
    bool Longer = Span8.IsLongerThan(Span7);
}


Helper Data Structures

wxWidgets makes use of several data structures internally and as parameters and return types in public library methods. Application programmers are encouraged to use the wxWidgets helper data structures in their projects.

wxObject

The wxObject class is the base class of all wxWidgets classes, providing run-time type information, reference counting, virtual destructor declaration, and optional debugging versions of new and delete. The wxClassInfo class is used to store meta-data about classes and is used by some of the wxObject methods.


MyWindow* window = wxDynamicCast(FindWindow(ID_MYWINDOW), MyWindow);


IsKindOf takes a wxClassInfo pointer and returns true if the object is of the specified type. For example:


bool tmp = obj->IsKindOf(CLASSINFO(wxFrame));


Ref takes a const wxObject& and replaces the current object’s data with a reference to the passed object’s data. The reference count of the current object is decremented, possibly freeing its data, and the reference count of the passed object is incremented.

UnRef decrements the reference count of the associated data and deletes the data if the reference count has fallen to 0.

wxLongLong

The wxLongLong class represents a 64-bit long number. A native 64-bit type is always used when available, and emulation code is used when the native type is unavailable. You would usually use this type in exactly the same manner as any other (built-in) arithmetic type. Note that wxLongLong is a signed type; if you want unsigned values, use wxULongLong, which has exactly the same API as wxLongLong except for some logical exceptions (such as the absolute value method). All of the usual mathematical operations are defined, as well as several convenient accessors:

Image   Abs returns the absolute value of the value as a wxLongLong, either as a copy if used on a constant reference or modifying it in place if mutable.

Image   ToLong returns a long representation of the stored value, triggering a debug assertion if any precision was lost.

Image   ToString returns the string representation of the stored value in a wxString.

wxPoint and wxRealPoint

wxPoint is used throughout wxWidgets for specifying integer screen or window locations. As the names imply, the point classes store coordinate pairs as x and y values. The data members are declared as public and can be accessed directly as x and y. wxPoint provides + and – – operators that allow you to add or subtract by wxPoint or wxSize. wxRealPoint stores coordinates as double rather than int and provides + and – – operators accepting only other wxRealPoint objects.

Constructing a wxPoint is very straightforward:


wxPoint myPoint(50, 60);


wxRect

Used for manipulating rectangle information, the wxRect class is used by wxWidgets mostly with drawing or widget classes, such as wxDC or wxTreeCtrl. The wxRect class stores an x, y coordinate pair, as well as width and height, all of which are public. Rectangles can be added and subtracted from each other, and there are some other calculation methods as well.

GetRight returns the x position of the right edge of the rectangle.

GetBottom returns the y position of the bottom edge of the rectangle.

GetSize returns the size of the rectangle (the height and width) in a wxSize object.

Inflate increases the size of the rectangle by the specified values, either uniformly (one parameter) or differently in each direction (two parameters).

Inside determines whether a given point is inside the rectangle. The point can be specified as separate x and y coordinates or as a wxPoint.

Intersects takes another wxRect object and determines whether the two rectangles overlap.

Offset moves the rectangle by the specified offset. The offset can be specified as separate x and y coordinates or as a wxPoint.

A wxRect object can be constructed with data in three different ways. The following three objects would all represent the exact same rectangle:


wxRect myRect1(50, 60, 100, 200);
wxRect myRect2(wxPoint(50, 60), wxPoint(150, 260));
wxRect myRect3(wxPoint(50, 60), wxSize(100, 200));


wxRegion

A wxRegion represents a simple or complex region on a device context or window. It uses reference counting, so copying and assignment operations are fast. The primary use for wxRegion is to define or query clipping or update regions.

Contains returns true if the given coordinate pair, wxPoint, rectangle, or wxRect is within the region.

GetBox returns a wxRect representing the area of the region.

Intersect returns true if the given rectangle, wxRect, or wxRegion intersects the current region.

Offset moves the region by the specified offset. The offset is specified as separate x and y coordinates.

Subtract, Union, and Xor change the region in a variety of ways, offering ten overloads among the three methods. All these methods have overloads that take a wxRegion or a wxPoint parameter; see the wxWidgets documentation for a complete list of all available methods.

The following are the four most common ways to create a wxRegion; all these examples would create an object representing the same region:


wxRegion myRegion1(50, 60, 100, 200);
wxRegion myRegion2(wxPoint(50, 60), wxPoint(150, 260));
wxRect myRect(50, 60, 100, 200);
wxRegion myRegion3(myRect);
wxRegion myRegion4(myRegion1);


You can use the wxRegionIterator class to iterate through the rectangles in a region, for example to repaint “damaged” areas in a paint event handler, as in the following example:


// Called when the window needs to be repainted
void MyWindow::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);

    wxRegionIterator upd(GetUpdateRegion( ));
    while (upd)
    {
        wxRect rect(upd.GetRect( ));

        // Repaint this rectangle
        ...some code...

        upd ++ ;
    }
}


wxSize

wxSize is used throughout wxWidgets for specifying integer sizes for windows, controls, canvas objects, and so on. A wxSize object is also frequently returned when using methods that would return size information.

GetHeight and GetWidth return the height or width.

SetHeight and SetWidth take integer parameters for setting a new height or width.

Set takes both a height and a width parameter to update the current size.

A wxSize object is very simply created by specifying a height and a width:


wxSize mySize(100, 200);


wxVariant

The wxVariant class represents a container for any type. A variant’s value can be changed at runtime, possibly to a different type of value. This class is useful for reducing the programming for certain tasks, such as an editor for different data types, or a remote procedure call protocol.

wxVariant can store values of type bool, char, double, long, wxString, wxArrayString, wxList, wxDateTime, void pointer, and list of variants. However, an application can extend wxVariant’s capabilities by deriving from the class wxVariantData and using the wxVariantData form of the wxVariant constructor or assignment operator to assign this data to a variant. Actual values for user-defined types will need to be accessed via the wxVariantData object, unlike basic data types, for which convenience functions such as GetLong can be used.

Bear in mind that not all types can be converted automatically to all other types; for example, it doesn’t make much sense to convert a boolean into a wxDateTime object or to convert an integer to a wxArrayString. Use common sense to decide which conversions are appropriate, and remember that you can always get the current type using GetType. Here is a small example using wxVariant:


wxVariant Var;

// Store a wxDateTime, get a wxString
Var = wxDateTime::Now( );
wxString DateAsString = Var.GetString( );

// Store a wxString, get a double
Var = wxT("10.25");
double StringAsDouble = Var.GetDouble( );

// Type will be "string"
wxString Type = Var.GetType( );

// This is not a valid conversion, a string can't become a character
// so c will be 0 due to being unable to convert
char c = Var.GetChar( );


Summary

The data structures provided by wxWidgets allow you to easily pass and receive structured data to and from wxWidgets and within your own applications. By providing powerful data processing methods and classes such as wxRegEx, wxStringTokenizer, wxDateTime, and wxVariant, almost any data storage and processing needs can be met by wxWidgets without having to use third-party libraries.

Next, we’ll look at what wxWidgets offers for reading and writing data using files and streams.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.51.153