A cross-platform weather statistics application in C++
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.
Weather Analysis App on Windows 10 Pro 20H2.
Weather Analysis App on macOS Catalina.
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
- Add
- 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;
- Add
- 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.
- Add
- In Property Manager, add
Example running on Windows 10 once the program is compiled
- Select the menu: Debug -> Run