Create own wxVariant

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Feneck91
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Feb 28, 2006 7:47 am

Create own wxVariant

Post by Feneck91 » Wed Jul 13, 2011 7:58 am

I look everywhre on internet to have a wiki about "how to create custom variant" ?
I would like to create my own variant 'using wxVariantData' to store couple of value (key / value) into a wxHashMap that takes 2 variants : a variant as key, another as value.
Why ? To make generic way to pop table from lua script returns parameters. An lua table is always a couple of key/value like dictionnaries, with key that could be 1,2,3... when no key is defined.
Some peaple has alredy done this kind of features ?
Thanks.

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Re: Create own wxVariant

Post by Auria » Wed Jul 13, 2011 12:32 pm

Which version of wx are you using? In wx 2.9 you can store really anything in the new wxAny : http://docs.wxwidgets.org/2.9.2/classwx_any.html
"Keyboard not detected. Press F1 to continue"
-- Windows

Feneck91
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Feb 28, 2006 7:47 am

Re: Create own wxVariant

Post by Feneck91 » Wed Jul 13, 2011 12:41 pm

wxWidgets 2.8.12, not have wxAny.
wxWidgets 3.0 should released one year ago, for the moment nothing is released....

RainRat
I live to help wx-kind
I live to help wx-kind
Posts: 178
Joined: Thu Jan 06, 2011 11:26 pm

Re: Create own wxVariant

Post by RainRat » Wed Jul 13, 2011 9:23 pm

You need to derive your custom wxVariant from the wxVariantData class, then override the pure virtual functions.
http://docs.wxwidgets.org/2.9.2/classwx ... _data.html

Code: Select all

class MyVariant : public wxVariantData {
	double m_double;
public:
	MyVariant(double d) : wxVariantData(), m_double(d) { }

	bool Eq(wxVariantData &data) const {
		MyVariant *value_ptr = dynamic_cast<MyVariant*>(&data);
		return (value_ptr != 0) && ((*value_ptr).m_double == m_double);
	}
	wxString GetType() const { return wxString("MyVariant"); }

	double GetDouble() const { return m_double; }
};
You will need to add whatever functions (comparisons, assignment operator, etc.) that wxHashMap needs to manipulate its elements.
Auria wrote:Which version of wx are you using? In wx 2.9 you can store really anything in the new wxAny : http://docs.wxwidgets.org/2.9.2/classwx_any.html
I was using wxVariant with wxDataViewListCtrl using custom renderers for some columns, but I couldn't seem to convert to using wxAny on the attempt I made a few months ago, so I'm not sure how backward compatible it is with some classes. It could have been my lack of understanding/experience. :oops:

Feneck91
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Feb 28, 2006 7:47 am

Re: Create own wxVariant

Post by Feneck91 » Thu Jul 21, 2011 6:36 am

I have wrote this code (see below) but it is not really easy to use because I need to cast all time I need to use it to the correct variant type.
Else it's seem to work fine.

Header

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        wxETKVariant.cpp
// Library:     wxETK
// Purpose:     Header of wxVariant extension classes.
// Author:      Stéphane Château
// Modified by:
// Created:     12/07/2011
// Licence:     LGPL
/////////////////////////////////////////////////////////////////////////////

#ifndef WX_ETK_VARIANT_H
#define WX_ETK_VARIANT_H

#include "wxETKTypes.h"
#include <wx/variant.h>

/**
 * Class used to record hash map into variant.
 *
 * To be used with wxVariant class. To use this class, call:
 *<pre>
 * wxVariant varMap(new wxETKVariantDataMap())
 *</pre>
 *
 * To convert a variant into the map, call:
 *<pre>
 * if (varValues.GetType() == wxETKVariantDataMap::STR_VARIANT_MAP_TYPE)
 * {    // To be sure it is the correct variant type, else cast throw exception
 *     wxETKVariantDataMap &rMap = (dynamic_cast<wxETKVariantDataMap>(*varValues.GetData());
 * }
 *</pre>
 *
 * @author Stéphane Château
 * @version Name : wxETK<br>
 *          Revision : <b>1.0</b>
 */
class EXPORT_IMPORT wxETKVariantDataMap : public wxVariantData
{
private:
    // To declare a hashmap<wxVariant, wxVariant>
    WX_DECLARE_HASH_MAP( wxVariant,         // type of the keys
                         wxVariant,         // type of the values
                         wxStringHash,      // hasher
                         wxStringEqual,     // key equality predicate
                         wxHashMapVariant); // name of the class

public:
    static const wxString               STR_VARIANT_MAP_TYPE;

    /// @name typedef. Same as wxHashMap class, see wxWidgets documentation.
    //@{
    typedef wxHashMapVariant::size_type             size_type;
    typedef wxHashMapVariant::iterator              iterator;
    typedef wxHashMapVariant::const_iterator        const_iterator;
    typedef wxHashMapVariant::key_type              key_type;
    typedef wxHashMapVariant::const_key_type        const_key_type;
    typedef wxHashMapVariant::value_type            value_type;
    typedef wxHashMapVariant::Insert_Result         Insert_Result;
    //@}

private:
    /**
     * Map that record the values of this variant.
     */
    wxHashMapVariant                    m_mapValue;
public:
    /// @name Constructor / Destructor.
    //@{
    /**
     * Default constructor.
     */
    wxETKVariantDataMap();

    /**
     * Copy constructor.
     *
     *  \param _rOther Object to copy from.
     */
    wxETKVariantDataMap(const wxETKVariantDataMap& _rOther);

protected:
    /**
      * Default destructor.
      *
      * Is protected, must be allocated on the heap.
      */
    virtual ~wxETKVariantDataMap();
    //@}

public:
    /**
     * What type is it?
     *
     * @return a string name.
     */
    virtual wxString                    GetType() const;

    /// @name Operators.
    //@{
    /** Assignment operator.
     *
     *  @param _rOther Object to assign from.
     *  @return A reference to this.
     */
    wxETKVariantDataMap &              operator=(const wxETKVariantDataMap& _rOther);

    /** Element accessor.
     *
     * Use the key as an array subscript.
     * The only difference is that if the given key is not present in the hash map,
     * an element with the default value_type() is inserted in the table.
     *
     *  @param _rKey Key to find.
     *  @return A reference to the value found or added.
     */
    wxVariant &                         operator[](const wxVariant &_rKey);
    //@}

    /**
     * Override these to provide common functionality.
     *
     * @param _rvariantData Variant to test if is equal to this.
     * @return true if is same.
     */
    virtual bool                        Eq(wxVariantData& _rvariantData) const;

    /**
     *
     * Verify if key exists.
     *
     *  @param _rKey Key to find.
     *  @return true if the key exist, false else.
     */
    bool                                IsExist(const wxVariant &_rKey) const;

    /// @name Map operators. Same as wxHashMap class, see wxWidgets documentation.
    //@{
    void                                clear()                                 { return m_mapValue.clear(); }
    size_type                           size() const                            { return m_mapValue.size(); }
    size_type                           max_size() const                        { return m_mapValue.max_size(); }
    bool                                empty() const                           { return m_mapValue.empty(); }
    const_iterator                      end() const                             { return m_mapValue.end(); }
    iterator                            end()                                   { return m_mapValue.end(); }
    const_iterator                      begin() const                           { return m_mapValue.begin(); }
    iterator                            begin()                                 { return m_mapValue.begin(); }
    size_type                           erase(const key_type& _rKey)            { return m_mapValue.erase(_rKey); }
    void                                erase(const iterator& _rIt)             { return m_mapValue.erase(_rIt); }
    const_iterator                      find(const const_key_type& _rKey) const { return m_mapValue.find(_rKey); }
    iterator                            find( const const_key_type& _rKey)      { return m_mapValue.find(_rKey); }
    Insert_Result                       insert(const value_type& _rValue)       { return m_mapValue.insert(_rValue); }
    size_type                           count(const const_key_type& _rKey)      { return m_mapValue.count(_rKey); }
    //@}
};

#endif // WX_ETK_VARIANT_H
[b]Implementation[/b]

Code: Select all

/////////////////////////////////////////////////////////////////////////////
// Name:        wxETKVariant.cpp
// Library:     wxETK
// Purpose:     Implementation of wxVariant extension classes.
// Author:      Stéphane Château
// Modified by:
// Created:     12/07/2011
// Licence:     LGPL
/////////////////////////////////////////////////////////////////////////////
#include "wxETKVariant.h"

const wxString wxETKVariantDataMap::STR_VARIANT_MAP_TYPE = wxT("map");

wxETKVariantDataMap::wxETKVariantDataMap()
{
}

wxETKVariantDataMap::wxETKVariantDataMap(const wxETKVariantDataMap& _rOther)
{
    operator=(_rOther);
}

wxETKVariantDataMap::~wxETKVariantDataMap()
{
}

wxString wxETKVariantDataMap::GetType() const
{
    return STR_VARIANT_MAP_TYPE;
}

wxETKVariantDataMap& wxETKVariantDataMap::operator=(const wxETKVariantDataMap& _rOther)
{
    if (this == &_rOther)
    {
        return *this; // handle self assignment
    }

    m_mapValue = _rOther.m_mapValue;

    // assignment operator
    return *this;
}

bool wxETKVariantDataMap::Eq(wxVariantData& _rvariantData) const
{
    bool bRet = false;

    if (_rvariantData.GetType() == STR_VARIANT_MAP_TYPE)
    {
        wxETKVariantDataMap &rvariantData = dynamic_cast<wxETKVariantDataMap &>(_rvariantData);
        if (m_mapValue.size() == rvariantData.m_mapValue.size())
        {   // Verify if all keys/datas are present and same into the 2 maps
            for (wxHashMapVariant::const_iterator it = m_mapValue.begin();it!=m_mapValue.end();++it)
            {
                wxHashMapVariant::const_iterator itToFind = rvariantData.m_mapValue.find(it->first);
                if (   itToFind == rvariantData.m_mapValue.end()    // This key doesn't exists
                    || it->first != itToFind->first                 // This key is different (strange)
                    || it->second != itToFind->second               // This value is different
                   )
                {
                    break;
                }
            }
            // All is same
            bRet = true;
        }
    }

    return bRet;
}

wxVariant & wxETKVariantDataMap::operator[](const wxVariant &_rKey)
{
    return m_mapValue[_rKey];
}

bool wxETKVariantDataMap::IsExist(const wxVariant &_rKey) const
{
    return m_mapValue.find(_rKey) != m_mapValue.end();
}

RainRat
I live to help wx-kind
I live to help wx-kind
Posts: 178
Joined: Thu Jan 06, 2011 11:26 pm

Re: Create own wxVariant

Post by RainRat » Thu Jul 21, 2011 8:27 pm

Do you mean you have to cast in code outside of this class?

I needed to use dynamic_cast in my wxDataViewCustomRenderer in SetValue so that I could make the assignment of my custom variant to the local copy that Render() uses. There doesn't seem to be any way to avoid something like this. dynamic_cast is part of the language, so I've come to accept it, at least in this situation of interfacing with another library.

Also, I put a comment in this part of your code. I believe the break statement will only break you out of the for-loop, so you will always return "true." Instead of break, maybe just return false inside this inner if statement.
Feneck91 wrote:

Code: Select all

bool wxETKVariantDataMap::Eq(wxVariantData& _rvariantData) const
{
    bool bRet = false;

    if (_rvariantData.GetType() == STR_VARIANT_MAP_TYPE)
    {
        wxETKVariantDataMap &rvariantData = dynamic_cast<wxETKVariantDataMap &>(_rvariantData);
        if (m_mapValue.size() == rvariantData.m_mapValue.size())
        {   // Verify if all keys/datas are present and same into the 2 maps
            for (wxHashMapVariant::const_iterator it = m_mapValue.begin();it!=m_mapValue.end();++it)
            {
                wxHashMapVariant::const_iterator itToFind = rvariantData.m_mapValue.find(it->first);
                if (   itToFind == rvariantData.m_mapValue.end()    // This key doesn't exists
                    || it->first != itToFind->first                 // This key is different (strange)
                    || it->second != itToFind->second               // This value is different
                   )
                {
                    break; // just return false; instead of break
                }
            }
            // All is same
            bRet = true;  // <--- Always gets hit
        }
    }

    return bRet;
}

Post Reply