clinic-answer-weather-cpp

Weather Statistics Desktop Application

Example answer to the Lake Pend Oreille weather challenge of the LinkedIn Learning: Code Clinic: C++.

Note that this is my first wxWidgets C++ application. The learning curve was steep; and wxPython 4 was one tool used to prototype the application in Python before implementing in C++.

Derived requirements:

  • The application should be cross-platform between Windows 10 Pro 20H2, Ubuntu 2018.04 LTS, and macOS 10.15 Catalina.
  • The application should be possible to distribute closed-source by not relying upon a copy-left graphical toolkit or chart plotting library.
  • The application should print mean and median statistics within a selectable date-time range of these weather readings: Wind Speed, Air Temperature, Barometric Pressure.
  • The application should graphically chart plot the Barometric Pressure readings within the same selected date-time range.
  • The application should chart plot the linear and quadratic trends on the chart plot within the same selected date-time range.
  • The application should state the linear and quadratic trend equations in plain text that can be copy-pasted.

Refined requirements:

  • The application shall use the wxWidgets 3.0.x/3.1.x graphical toolkit for the design of the window frame and controls.
  • The application shall use wxChartDir 1.0.0 with the commercial ChartDirector for C++ 6.3 library to chart plot data upon a wxPanel window object of the wxWidgets window frame.
  • The application shall use Boost C++ 1.74.0.
  • Examples in the blog post shall only give hints.

Example screen shots of the completed application:

Weather Analysis App on Ubuntu 18.04 LTS.

Screen Shot of Weather Analysis App, Ubuntu, Main

Screen Shot of Weather Analysis App, Ubuntu, Selection 1

Weather Analysis App on Windows 10 Pro 20H2.

Screen Shot of Weather Analysis App, Windows 10, Main

Screen Shot of Weather Analysis App, Windows 10, Selection 1

Weather Analysis App on macOS Catalina.

Screen Shot of Weather Analysis App, macOS Catalina, Main

Screen Shot of Weather Analysis App, macOS Catalina, Selection 1

Hints for cross-platform design

Location of resource files (the TSV inputs)

#ifdef __WXMSW__
    const char* resourcesPath = "../resources";
#endif

#ifdef __WXGTK__
    const char* resourcesPath = "../resources";
#endif

#ifdef __WXOSX__
    wxStandardPaths stdPaths = wxStandardPaths::Get();
    wxString resourcePath = stdPaths.GetResourcesDir();
    resourcePath.Append("/resources");

    std::string resourcePathStd = resourcePath.ToStdString();
    const char* resourcesPath = resourcePathStd.c_str();
#endif

Selecting the font size and type, of a wxTextCtrl

#ifdef __WXMSW__
    // UTF-8 encoding of regular Courier New font at 9 points on Windows 10 Pro 
    wxString windowsNativeFontCourierNew("1;9;-19;0;0;0;400;0;0;0;0;0;0;2;48;Courier New");

    wxNativeFontInfo fontInfo;
    fontInfo.FromString(windowsNativeFontCourierNew);
    wxFont font(fontInfo);

    this->fldCalculation->SetFont(font);

    this->fldCalculation->SetValue(WeatherFrame::defaultFldCalculation);
#endif
#ifdef __WXGTK__
    this->fldCalculation->SetFont(
        wxFont(9, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
            false, "Courier New", wxFONTENCODING_UTF8)
    );

    this->fldCalculation->SetValue(WeatherFrame::defaultFldCalculation);
#endif
#ifdef __WXOSX__
    this->fldCalculation->SetFont(
        wxFont(14, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
            false, "Courier New", wxFONTENCODING_UTF8)
    );

    this->fldCalculation->SetValue(WeatherFrame::defaultFldCalculation);
#endif

Example compiling on Ubuntu with clang++

apt-get install clang-10 wx3.0-headers libwxgtk3.0-dev libwxgtk3.0-gtk3-dev libboost-all-dev 
#!/bin/bash
mkdir -p ./Debug/
clang++-10 *.cpp ../../../wxchartdir/wxdemo/common/*.cpp \
	$(wx-config --cxxflags --libs) -lchartdir \
	-L../../../wxchartdir/lib/linux64 \
	-I../../../wxchartdir/include \
	-I../../../wxchartdir/wxdemo/common \
	-std=c++11 -g -O0 -o Debug/WeatherApp.elf

Example running on Ubuntu once the program is compiled

#!/bin/bash
LD_LIBRARY_PATH=../../../wxchartdir/lib/linux64 ./Debug/WeatherApp.elf

Compiling with Xcode 12.2 on macOS 10.15

  • Re-use the minimal_cocoa Xcode project from the wxWidgets-3.1.4 samples/ directory (from the full downloaded wxWidgets source).
  • Add C++ sources to src/ as well as C++ source from wxChartDir wxdemo/common/ .
  • Add wxChartDir wxdemo/common/, wxChartDir include/ to header paths.
  • Have the Xcode subproject build the app-dynamic target with -std=c++11 or -std=gnu++11 .
  • Embed & Sign the resulting wxWidgets .dylib into the Xcode application bundle.
  • Embed & Sign the ChartDirector C++ 6.3 .dylib into the Xcode application bundle.
  • De-quarantine the ChartDirector .dylib to permit it to load with execution
    xattr -d com.apple.quarantine libchartdir.6.dylib
    
  • Add a build step script to execute a reference rewrite in the final executable so that it can locate the CharDirector .dylib in the Frameworks directory of the .app bundle.
    # Type a script or drag a script file from your workspace to insert its path.
    install_name_tool -change libchartdir.6.dylib \
      @executable_path/../Frameworks/libchartdir.6.dylib \
      "${TARGET_BUILD_DIR}/WeatherAnalysisApp.app/Contents/MacOS/WeatherAnalysisApp"
    

Example running on macOS 10.15 once the program is compiled

  • Select the menu: Product -> Run

Example compiling on Windows 10 with Visual Studio 2019

  • Install boost 1.74.0 source.
  • Install wxWidgets 3.1.4 source and binaries. For the binaries, separate the .lib files into a _lib directory and the .dll files into a _dll directory.
  • Install wxChartDir 1.0.0 source
  • Install ChartDirector C++ 6.3 binaries
  • Add the C:\wxWigets-3.1.4\lib\vc14x_x64_dll directory to the system PATH variable.
  • Add the C:\ChartDirector-6.3\lib64 directory to the system PATH variable.
  • In Visual Studio 2019, properties to set on the project:
    • In Property Manager, add C:\wxWidgets-3.1.4\wxwidgets.props to the execution configurations of the project.
    • In VC++ Directories:
      • Add C:\wxWidgets-3.1.4\lib\vc14x_x64_lib as a Library Directory
    • In C/C++ All Options:
      • Add C:\boost_1_74_0 , wxChartDir \include\, wxChartDir \wxdemo\common\ to Additional Include Directories
      • As needed, select from the following for Preprocessor Definitions: WIN32;DEBUG;_DEBUG;_WINDOWS;__WXMSW__;__WXDEBUG__;_UNICODE;WXUSINGDLL; wxMSVC_VERSION_ABI_COMPAT;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE; _CRT_NONSTDC_NO_DEPRECATE;xCHARTDIR_HIDE_OBSOLETE;
    • In Linker All Options:
      • Add C:\ChartDirector-6.3\lib64\chartdir60.lib to Additional Dependencies.
      • Add C:\ChartDirector-6.3\lib64;$(wxRootDir)\lib\$(wxCompilerPrefix)$(wxArchSuffix)_lib;$(wxLibOrDllDir); to Additional Library Directories.

Example running on Windows 10 once the program is compiled

  • Select the menu: Debug -> Run