Получение числового значения из wxTextCtrl

Я изучаю wxWidgets, а не wxPython, настоящую библиотеку C++. У меня возникли проблемы с привязкой двойной переменной к wxTextCtrl. Насколько я понимаю, это нужно делать через шаблон wxValidator.

Вот пример кода, в котором я хочу сохранить массив и отредактировать 5 разных двойников. Для перехода от значения к значению я использую wxComboBox. Основная проблема в том, что этот код не обновляет двойную переменную tracable при вызове TransferDataFromWindow() и не считывает значение из этой переменной при вызове TransferDataToWindow() функций.

#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);
    }

}

person rth    schedule 22.02.2019    source источник


Ответы (1)


При вызове TransferDataFromWindow() данные передаются с помощью валидаторов дочерних элементов окна, а не самого окна. Вы можете вызвать lInTrac->GetValidator()->TransferFromWindow() напрямую, чтобы заставить ваш текущий код работать, но на самом деле сама идея совместного использования явных обработчиков и валидаторов подозрительна: ваш код будет более понятным, если вы используете один или другой, но не оба эти механизма вместе.

т.е. либо вам нужно использовать (возможно, пользовательский) валидатор для поля со списком, либо, возможно, переопределить FMWnd::Transfer{To,From}Window() для обработки этого поля со списком и полностью удалить onTrackerChange(), или вы должны просто получить значение непосредственно из текстового элемента управления, используя его метод GetValue() в вашем явном обработчике.

Если вы хотите немедленное обновление, последнее - единственный способ сделать это, поскольку использование валидатора действительно совместимо только с какой-либо кнопкой «Применить» / «Отправить».

person VZ.    schedule 24.02.2019
comment
Спасибо за ваш ответ. Не могли бы вы исправить мой код так, как вы считаете лучшим, и добавить его в ответ. Хотя я неплохо разбираюсь в C++, ваше предложение мне не совсем понятно. Я буду очень признателен за кусок (рабочего) кода для переваривания. - person rth; 24.02.2019
comment
Самый простой — перестать использовать валидатор неестественным образом и просто использовать GetValue() в обработчике поля со списком. Создать собственный валидатор не так сложно, но это потребует больше кода, чем разумно разместить здесь в комментарии. - person VZ.; 24.02.2019
comment
Спасибо за комментарий. На самом деле я получил 3-строчный преобразователь {From,To}, используя GetValue() и простой sscanf(). Однако я думаю, что это не стиль wx. - person rth; 24.02.2019