I have been struggling with a problem for the better part of two weeks and thought it was time to reach out for some help in this forum. In the words of another (also mentioned in this forum) I am in the forest and can't see the wood for the trees. I have some experience in programming in C++ but I am at a point where I think the solution is very simple but as I have been looking at it so long and so closely at it, I can't see it.
Desired outcome:
In a program I am developing, I have a dialog box which essentially accepts data and writes the data to a text file. The data in one of the fields can be be either a date (self explanatory), an event (eg 5,000 km) or a time period (eg 7 days). The type of data to be inserted depends on the choice from an adjacent combobox.
Proposed solution:
For this I have derived a control (DatePickerTextCtrl) based on wxTextCtrl (no validators) with a variable (isTypeDate - bool). If this variable is true, a single left mouse click in the textctrl should bring up a calendarctrl, if false it should behave like a normal wxTextCtrl. Single clicking a date on the calendarctrl should update the textctrl while a double click should do likewise but also close the calendarctrl. The behaviour is similar to DatePickerCtrl except it does not close the dialog on a single click.
The Coding problem:
During the past two weeks I have had varying levels of success but ultimately had all types of runtime errors ranging from memory leaks, trying to access illegal areas of memory and debug crashes leading to error locations in window.h, event.h etc. These errors have pushed me far beyond my debugging ability. The last few days I have gone back to basics but cannot get the currently selected date in the calendarctrl into the textctrl field. I have built a small test program based on the wxwidgets "minimal.cpp" sample which I am attaching to this topic together with my DatePickerTextCtrl code.
Specific issues:
- 1. Specifically, my current error shows up in the function InsertDate. For some reason, the textctrl pointer is no longer pointing to the correct location and so the text field is not being populated. I have made various attempts at finding the window, but this has also failed.
- 2. Also, I am having trouble getting my head around how to close the calendarctrl. (Not shown in the code are my attempts at using wxDialog in lieu of the wxFrame for the calendarctrl).
Class Definition (DatePickerTextCtrl.h):
Code: Select all
/////////////////////////////////////////////////////////////////////////////
// Name: DatePickerTextCtrl.h
// Purpose: wxCalendarCtrl in a dialog box linked to a wxTextCtrl
// Author: F. Vidmar
// Modified by:
// Created: 29.07.10
// RCS-ID: $Id: DatePickerTextCtrl.cpp nnnnn 2010-07-29 12:00:00Z FV $
// Copyright: (c) F. Vidmar
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _DatePickerTextCtrl_H_
#define _DatePickerTextCtrl_H_
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers
#ifndef WX_PRECOMP
#include "wx/frame.h"
#include "wx/dialog.h"
#include "wx/sizer.h"
#include "wx/textctrl.h"
#endif
#include "wx/calctrl.h"
#include <wx/dynarray.h>
#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
#include <wx/combobox.h>
#include <wx/memory.h>
#if wxUSE_DATEPICKCTRL
#include "wx/datectrl.h"
#if wxUSE_DATEPICKCTRL_GENERIC
#include "wx/generic/datectrl.h"
#endif // wxUSE_DATEPICKCTRL_GENERIC
#endif // wxUSE_DATEPICKCTRL
#ifdef wxHAS_NATIVE_CALENDARCTRL
#include "wx/generic/calctrlg.h"
#endif
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
class myComboBox : public wxComboBox
{
public:
myComboBox() { }
myComboBox(wxWindow *parent,
wxWindowID winid = wxID_ANY,
const wxString& value = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
int n = 0,
const wxArrayString choices = NULL,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxComboBoxNameStr)
: wxComboBox( parent, winid, value, pos, size, choices, style, validator, name )
{ SetSelection(n); } ;
virtual ~myComboBox() {};
protected:
private:
};
// Define a control type based on wxTextCtrl
class DatePickerTextCtrl : public wxTextCtrl
{
public:
DatePickerTextCtrl( wxWindow* parent,
int id,
const wxString title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxValidator& validator = wxDefaultValidator,
const wxString idname = wxTextCtrlNameStr,
const wxString fieldtype = wxT("Text"));
virtual ~DatePickerTextCtrl() { };
// event handlers (these functions should _not_ be virtual)
void SetTextCtrlType(wxString strType); // "Date" or other
bool GetTextCtrlType();
// Event management for calendar control
void OnCalendarChange(wxCalendarEvent& event);
void OnCalendarDClick(wxCalendarEvent& event);
void OnShowCalendar(wxMouseEvent& event);
void OnDateUpdate(wxCalendarEvent& event);
wxCalendarCtrl* m_calCtrl;
DatePickerTextCtrl* m_txtCtrl;
wxDateTime GetSelectedDate() {return selectedDate;};
void SetTextCtrlId(wxWindowID id) {txtCtrlId = id; };
void InsertDate();
void SetDate(wxDateTime today) { selectedDate = today; };
private:
bool isTypeDate;
wxFrame* thisDialog; // Frame control
wxDateTime today, selectedDate, currentDate;
wxWindowID txtCtrlId;
};
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// IDs for the controls and the menu commands
enum
{
// menu items
ID_PICKDATE = 4000,
ID_CALFRAMECTRL,
ID_CALCTRL
};
#endif // _DatePickerTextCtrl_H_
Constructor (DatePickerTextCtrl.cpp):
Code: Select all
/////////////////////////////////////////////////////////////////////////////
// Name: DatePickerTextCtrl.cpp
// Purpose: wxCalendarCtrl in a dialog box linked to a wxTextCtrl
// Author: F. Vidmar
// Modified by:
// Created: 29.07.10
// RCS-ID: $Id: DatePickerTextCtrl.cpp nnnnn 2010-07-29 12:00:00Z FV $
// Copyright: (c) F. Vidmar
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/event.h>
#include <wx/utils.h>
#include "wx/textctrl.h"
#include <wx/memory.h>
#if wxUSE_DATEPICKCTRL
#include "wx/datectrl.h"
// use this version if we're explicitly requested to do it or if it's the only
// one we have
#if !defined(wxHAS_NATIVE_DATEPICKCTRL) || \
(defined(wxUSE_DATEPICKCTRL_GENERIC) && wxUSE_DATEPICKCTRL_GENERIC)
#ifndef WX_PRECOMP
#include "wx/dialog.h"
#endif
#ifdef wxHAS_NATIVE_DATEPICKCTRL
// this header is not included from wx/datectrl.h if we have a native
// version, but we do need it here
#include "wx/generic/datectrl.h"
#else
// we need to define _WX_DEFINE_DATE_EVENTS_ before including wx/dateevt.h to
// define the event types we use if we're the only date picker control version
// being compiled -- otherwise it's defined in the native version implementation
#define _WX_DEFINE_DATE_EVENTS_
#endif
#include "wx/dateevt.h"
#include "wx/calctrl.h"
#endif // wxUSE_DATEPICKCTRL_GENERIC
#endif // wxUSE_DATEPICKCTRL
#include "DatePickerTextCtrl.h"
DatePickerTextCtrl::DatePickerTextCtrl(wxWindow* parent,
wxWindowID id,
const wxString title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString idname,
const wxString fieldtype)
: wxTextCtrl(parent, id, title, pos, size, style, validator, idname)
{
// Place links to calendar here
#if wxUSE_MEMORY_TRACING
wxDebugContext::SetCheckpoint();
#endif
SetTextCtrlType(fieldtype);
SetTextCtrlId(id);
m_txtCtrl = this;
Connect ( wxEVT_LEFT_DOWN, wxMouseEventHandler(DatePickerTextCtrl::OnShowCalendar));
Connect (ID_CALCTRL, wxEVT_CALENDAR_SEL_CHANGED,
wxCalendarEventHandler(DatePickerTextCtrl::OnDateUpdate),
NULL,
NULL);
/*
m_txtCtrl->Connect(wxEVT_CALENDAR_DOUBLECLICKED,
wxCalendarEventHandler(DatePickerTextCtrl::OnCalendarDClick),
NULL,
NULL);
*/
#if wxUSE_MEMORY_TRACING
// On MSW, Dump() crashes if using wxLogGui,
// so use wxLogStderr instead.
wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
wxDebugContext::PrintClasses();
wxDebugContext::Dump();
wxDebugContext::PrintStatistics();
// Set back to wxLogGui
// delete wxLog::SetActiveTarget(oldLog);
#endif
}
void DatePickerTextCtrl::SetTextCtrlType(wxString strType)
{
if (strType == wxT("Date"))
isTypeDate = true;
else
isTypeDate = false;
}
bool DatePickerTextCtrl::GetTextCtrlType()
{
return isTypeDate;
}
void DatePickerTextCtrl::OnShowCalendar(wxMouseEvent& event)
{
// Display calendar only if a date is expected
if (isTypeDate)
{
#if wxUSE_MEMORY_TRACING
wxDebugContext::SetCheckpoint();
#endif
m_calCtrl = NULL;
wxSize txtctlSize = m_txtCtrl->GetSize();
wxPoint calPnt = m_txtCtrl->GetScreenPosition();
calPnt.y += txtctlSize.GetHeight();
thisDialog = new wxFrame(GetParent(), ID_CALFRAMECTRL, wxT("Calendar"), calPnt, wxDefaultSize, wxSIMPLE_BORDER | wxSTAY_ON_TOP );
m_calCtrl = new wxCalendarCtrl(thisDialog,
ID_CALCTRL,
wxDateTime::Today(),
wxDefaultPosition,
wxDefaultSize,
wxCAL_SEQUENTIAL_MONTH_SELECTION);
m_calCtrl->Connect ( wxEVT_CALENDAR_SEL_CHANGED,
wxCalendarEventHandler(DatePickerTextCtrl::OnCalendarChange),
NULL,
NULL);
/*
m_calCtrl->Connect(wxEVT_CALENDAR_DOUBLECLICKED,
wxCalendarEventHandler(DatePickerTextCtrl::OnCalendarDClick),
NULL,
NULL);
*/
// Bring up calendar dialog with todays date or, if valid, with the date in the existing textctrl.
if (m_txtCtrl->GetValue().IsEmpty())
{
currentDate = wxDateTime::Today();
}
else
{
wxDateTime tempDate;
tempDate.ParseDate(m_txtCtrl->GetValue());
if (tempDate.IsValid())
currentDate = tempDate;
else
currentDate = wxDateTime::Today();
}
SetDate(currentDate);
m_txtCtrl->SetValue(selectedDate.Format(wxT("%d-%m-%Y")).c_str());
thisDialog->Fit();
thisDialog->Show();
}
else
// Standard wxTextCtrl
event.Skip();
#if wxUSE_MEMORY_TRACING
// On MSW, Dump() crashes if using wxLogGui,
// so use wxLogStderr instead.
// wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
wxDebugContext::PrintClasses();
wxDebugContext::Dump();
wxDebugContext::PrintStatistics();
// Set back to wxLogGui
// delete wxLog::SetActiveTarget(oldLog);
#endif
}
void DatePickerTextCtrl::OnCalendarChange(wxCalendarEvent& event)
{
selectedDate = event.GetDate();
static wxDateTime s_dateLast;
const bool mark = !s_dateLast.IsValid() || selectedDate != s_dateLast;
s_dateLast = event.GetDate();
InsertDate();
}
void DatePickerTextCtrl::OnCalendarDClick(wxCalendarEvent& event)
{
selectedDate = event.GetDate();
InsertDate();
}
void DatePickerTextCtrl::InsertDate()
{
wxWindow* ctrl = GetParent()->FindWindow(txtCtrlId);
wxTextCtrl* dateCtrl = wxDynamicCast(ctrl,wxTextCtrl);
if (dateCtrl)
dateCtrl->SetValue(selectedDate.Format(wxT("%d-%m-%Y")).c_str());
// m_txtCtrl->SetValue(selectedDate.Format(wxT("%d-%m-%Y")).c_str());
}
void DatePickerTextCtrl::OnDateUpdate(wxCalendarEvent& event)
{
m_txtCtrl->SetValue(selectedDate.Format(wxT("%d-%m-%Y")).c_str());
}
Windows XP Professional SP2
WxWidgets 2.9.0
Visual Studio Express C++
I would be greatly appreciative if anyone is in a position to provide some assistance in this problem even if it is simply pointing me in the right direction.
Thanks in anticipation,
Calypso