In this tutorial, we will make a GUI calculator with Nana C++ Library. The calculator that we build will look like:
Let's see the code.
#include <nana/gui.hpp>
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/place.hpp>
#include <forward_list>
#include <map>
#include <cassert>
#include <iostream>
#include <chrono>
#include <thread>
using namespace nana;
#if defined(_MSC_VER) && (_MSC_VER < 1900) //VS2013
#else
#endif
struct stateinfo
{
enum class state{init, operated, assigned};
state opstate{ state::init };
double oprand { 0 };
double outcome{ 0 };
: operation("+"), procedure(proc), result(resl)
{ }
};
void numkey_pressed(stateinfo& state,
const arg_click& arg)
{
if(state.opstate != stateinfo::state::init)
{
if(state.opstate == stateinfo::state::assigned)
{
state.outcome = 0;
state.operation = "+";
}
state.result.caption("");
state.opstate = stateinfo::state::init;
}
if(rstr ==
"0") rstr.
clear();
if(d == ".")
{
if(rstr.
find(
'.') == rstr.npos)
}
else
state.result.caption(rstr + d);
}
void opkey_pressed(stateinfo& state,
const arg_click& arg)
{
if("C" == d)
{
state.result.caption("0");
state.procedure.caption("");
state.opstate = stateinfo::state::init;
state.outcome = 0;
state.operation = "+";
return;
}
else if( plus_minus == d)
{
auto s = state.result.caption();
if(s.size())
{
if(s[0] == '-')
s.erase(0, 1);
else
s.insert(0, 1, '-');
if(state.opstate == stateinfo::state::assigned)
{
state.outcome = -state.outcome;
state.operation = "=";
}
state.result.caption(s);
state.opstate = stateinfo::state::init;
}
return;
}
else if("%" == d)
{
auto s = state.result.caption();
if(s.size())
{
d = state.outcome * d / 100;
state.opstate = stateinfo::state::init;
}
return;
}
else if(state.opstate == stateinfo::state::operated)
return;
if(0 == oprandstr.
size()) oprandstr =
'0';
if("=" != d)
{
state.operation = d;
if(state.opstate != stateinfo::state::assigned)
else
pre_operation = "=";
proc = state.procedure.caption() + oprandstr ;
if((
"X" == d ||
"/" == d) && (proc.
find_last_of(
"+-") != proc.npos))
{
(( proc += ") " ) += d) += " ";
}
else
((proc += " ") += d) += " ";
state.opstate = stateinfo::state::operated;
}
else
{
if(state.opstate == stateinfo::state::init)
state.opstate = stateinfo::state::assigned;
}
switch(pre_operation[0])
{
case '+': state.outcome += state.oprand; break;
case '-': state.outcome -= state.oprand; break;
case 'X': state.outcome *= state.oprand; break;
case '/': state.outcome /= state.oprand; break;
}
state.procedure.caption(proc);
while(outstr.
size() && (
'0' == outstr.
back()))
if(outstr.
size() && (outstr.
back() ==
'.'))
if( outstr.
empty() ) outstr +=
'0';
state.result.caption(outstr);
}
int main()
{
place.
div(
"vert<procedure weight=10%><result weight=15%>"
"<weight=2><opkeys margin=2 grid=[4, 5] gap=2 collapse(0,4,2,1)>");
label procedure(fm), result(fm);
place[
"procedure"] << procedure;
place[
"result"] << result;
stateinfo state(procedure, result);
char keys[] = "Cm%/789X456-123+0.=";
{
Key = plus_minus;
else
auto & key_btn = op_keys.
front();
key_btn.caption(Key);
key_btn.typeface(keyfont);
{
}
place[
"opkeys"] << key_btn;
{
if ((
'0' <=
key &&
key <=
'9') || (
'.' ==
key))
numkey_pressed(state, arg);
else
opkey_pressed(state, arg);
});
}
#ifdef NANA_AUTOMATIC_GUI_TESTING
1, 1, [&bts, &result ]()
{
click(*bts[
'2']); Wait( 1);
click(*bts[
'+']); Wait( 1);
click(*bts[
'2']); Wait( 1);
std::cout <<
"The result of 2 + 2 is: " << result.caption() <<
"\n";
if ( r != 4 )
}
#endif
);
}