0

I'm learning wxWidgets, not wxPython, actual C++ library. I have ran into trouble to bind a double variable with wxTextCtrl. As far as I can understand it should be done through wxValidator template.

Here an example code, in which I want to keep in an array and edit 5 different doubles. To switching from value to value, I use wxComboBox. The main problem this code doesn't update double variable tracable when it calls TransferDataFromWindow() and doesn't read the value from this variable when it calls TransferDataToWindow() functions.

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef  WX_PRECOMP
  #include "wx/wx.h"
#endif //precompiled headers

#include "wx/log.h"
#include "wx/config.h"
#include "wx/splitter.h"
#include "wx/sizer.h"
#include <wx/spinctrl.h>
#include <wx/grid.h>

//#ifndef wxHAS_IMAGES_IN_RESOURCES
    //#include "../sample.xpm"
//#endif

class FMApp: public wxApp
{
public:
  virtual bool OnInit();
  virtual int OnExit();
};

IMPLEMENT_APP(FMApp)


class FMWnd: public wxFrame
{
public:
    FMWnd();
    virtual ~FMWnd();

    // callbacks
    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnSelectDB(wxCommandEvent& event);

private:

    uint        nTrackers;
    double      tracable;
    double      *allTrac;
    int         curTrackers;

    //=== LIFE ===//
    wxTextCtrl *lInTrac;
    wxComboBox *lTrac;

    /*inner functions*/
    void onTrackerChange( wxCommandEvent &);

    wxDECLARE_EVENT_TABLE();
};

enum{
    ID_TRACK= wxID_HIGHEST,
    ID_UNIT,
    //------- EVENTS -------//
    SELECT_TRANS,
    ID_ADD_TRACKABLE,
    FM_LAST
};

bool FMApp::OnInit()
{
    if ( !wxApp::OnInit() ) return false;
    SetVendorName(wxT("TEST"));
    SetAppName(wxT("---"));

    FMWnd *frame = new FMWnd;
    frame->Show(true);

    return true;
}

int FMApp::OnExit()
{
    return 0;
}




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wx/datetime.h"
#include "wx/colour.h"
#include "wx/notebook.h"
#include "wx/valgen.h"
#include "wx/valnum.h"



wxBEGIN_EVENT_TABLE(FMWnd, wxFrame)
  EVT_MENU(wxID_EXIT, FMWnd::OnQuit)
  EVT_MENU(wxID_ABOUT, FMWnd::OnAbout)
  EVT_COMBOBOX(ID_TRACK, FMWnd::onTrackerChange)
wxEND_EVENT_TABLE()


FMWnd::FMWnd()
    : wxFrame((wxFrame *) NULL, wxID_ANY, wxT("- TEST -"),
        wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE|wxWS_EX_VALIDATE_RECURSIVELY
        )
{
    // menu
    wxMenu *file_menu = new wxMenu;
    file_menu->AppendSeparator();
    file_menu->Append(wxID_EXIT, wxT("E&xit\tAlt-X"), wxT("Exit the program"));
    wxMenuBar *menu_bar = new wxMenuBar;
    menu_bar->Append(file_menu, wxT("&File"));
    SetMenuBar(menu_bar);

    // child controls
    wxPanel* p = new wxPanel(this, wxID_ANY);
    wxBoxSizer *lAmExDlg = new wxBoxSizer( wxHORIZONTAL );
    lAmExDlg->Add(lTrac = new wxComboBox(p,ID_TRACK),0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL| wxFIXED_MINSIZE, 3);
    lTrac->Append(wxT("---"));
    lTrac->Append(wxT("-1-"));
    lTrac->Append(wxT("-2-"));
    lTrac->Append(wxT("-3-"));
    lTrac->Append(wxT("-4-"));
    lTrac->Append(wxT("-5-"));
    lTrac->SetSelection(0l);
    lTrac->SetEditable(false);
    lAmExDlg->Add(lInTrac = new wxTextCtrl(p,wxID_ANY, wxT(""),wxDefaultPosition,wxDefaultSize,wxTE_LEFT, 
            wxMakeFloatingPointValidator(3,&tracable,wxNUM_VAL_THOUSANDS_SEPARATOR |wxNUM_VAL_NO_TRAILING_ZEROES)),
            4, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 3);

    wxBoxSizer *lTopSizer = new wxBoxSizer( wxVERTICAL );
    lTopSizer->Add(lAmExDlg, 1, wxEXPAND );
    p->SetSizer(lTopSizer);

    wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
    topSizer->SetMinSize(250, 100);
    topSizer->Add(p, 1, wxEXPAND);
    SetSizerAndFit(topSizer);

    curTrackers = -1;
    tracable = 20.0;
    nTrackers = 5;
    allTrac = new double[nTrackers];
    for(int cnt=0; cnt<nTrackers; ++cnt)allTrac[cnt] = 0.0;
    if (TransferDataToWindow())fprintf(stderr,"Cannot Transefer Data to Windows\n");
//  lInTrac->TransferDataToWindow();
}

void FMWnd::OnQuit(wxCommandEvent&)
{
    Close(true);
}

void FMWnd::OnAbout(wxCommandEvent&)
{
    wxMessageBox(wxT("wxConfig demo\n(c) 1998-2001 Vadim Zeitlin"), wxT("About"),
                 wxICON_INFORMATION | wxOK);
}

FMWnd::~FMWnd()
{
    delete[] allTrac;
}

void FMWnd::onTrackerChange(wxCommandEvent& event){
    TransferDataFromWindow();
    lInTrac->TransferDataFromWindow();
    if(curTrackers >= 0){
        allTrac[curTrackers]=tracable;
        printf("Tr:%d Var:%g Val:%g\n",curTrackers,allTrac[curTrackers],tracable);
    }
    if (event.GetSelection() == 0){
        tracable = 0.;
        curTrackers = -1;
        lInTrac->SetValue("0.0");
        printf("Reset Tracker\n");
    } else {
        curTrackers = event.GetSelection() - 1;
        tracable = allTrac[curTrackers];
        TransferDataToWindow();
        lInTrac->TransferDataToWindow();
        printf("Set Tracker to %d\n",curTrackers);
    }

}
catalin
  • 1,927
  • 20
  • 20
rth
  • 2,946
  • 1
  • 22
  • 27

1 Answers1

1

Calling TransferDataFromWindow() transfers data using validators of the window children, not the window itself. You could call lInTrac->GetValidator()->TransferFromWindow() directly to make your current code work but, in fact, the whole idea of using explicit handlers and validators together is suspicious: your code will be more clear if you use one or the other, but not both of these mechanisms together.

I.e. either you need to use a (possibly custom) validator for the combobox or, maybe, override FMWnd::Transfer{To,From}Window() to handle this combobox and remove onTrackerChange() entirely, or you should just get the value directly from the text control using its GetValue() method in your explicit handler.

If you want immediate update, the latter is the only way to do it as using validator is really only compatible with some kind of "Apply"/"Submit" button.

VZ.
  • 21,740
  • 3
  • 39
  • 42
  • Thank you for your answer. Could you please correct my code in the way you think is the best and add it to the answer. Although I'm quite fluent in C++, your suggestion is not completely clear to me. I'll highly appreciate a chunk of (working) code to digest. – rth Feb 24 '19 at 04:23
  • The simplest is to stop using the validator in an unnatural way and just use `GetValue()` in your combobox handler. Creating custom validator is not that difficult but would take more code than it's reasonable to put in a comment here. – VZ. Feb 24 '19 at 16:46
  • Thank you for the comment. I actually ended up with 3 lines convertor {From,To} using `GetValue()` and simple `sscanf()`. However I think, it isn't the "**wx**" style. – rth Feb 24 '19 at 17:25