Skip to content

Commit c0c47c4

Browse files
committed
GUI Calculator example with Qt libraries
1 parent 4c7baca commit c0c47c4

File tree

12 files changed

+419
-0
lines changed

12 files changed

+419
-0
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(Calc)
2+
add_subdirectory(CalcQt)
23
add_subdirectory(FeatureShowcase)

examples/CalcQt/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
project(CalcQt)
2+
3+
find_package(Qt4 REQUIRED QtCore QtGui QtTest)
4+
include(${QT_USE_FILE})
5+
6+
set(CALCQT_HEADERS CalcQt/CalculatorWidget.h)
7+
qt4_wrap_cpp(CALCQT_HEADERS_MOC ${CALCQT_HEADERS})
8+
9+
include_directories(${CUKE_INCLUDE_DIRS} CalcQt)
10+
add_library(CalcQt CalcQt/CalculatorWidget ${CALCQT_HEADERS_MOC})
11+
12+
if(Boost_UNIT_TEST_FRAMEWORK_FOUND)
13+
include_directories(${Boost_INCLUDE_DIRS})
14+
add_executable(BoostCalculatorQtSteps CalcQtFeatures/BoostCalculatorQtSteps)
15+
target_link_libraries(BoostCalculatorQtSteps CalcQt ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${CUKE_LIBRARIES} ${QT_LIBRARIES})
16+
endif()
17+
18+
# build CalcQt executable
19+
set(CALCQT_SOURCES CalcQt/CalcQt.cpp CalcQt/CalculatorWidget.cpp)
20+
add_executable(calcqt ${CALCQT_SOURCES} ${CALCQT_HEADERS_MOC})
21+
target_link_libraries(calcqt ${QT_LIBRARIES})

examples/CalcQt/CalcQt/CalcQt.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <QApplication>
2+
3+
#include "CalculatorWidget.h"
4+
5+
int main(int argc, char *argv[])
6+
{
7+
//Q_INIT_RESOURCE(application);
8+
QApplication app(argc, argv);
9+
app.setApplicationName("Qt Calculator");
10+
CalculatorWidget widget;
11+
widget.show();
12+
return app.exec();
13+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#include "CalculatorWidget.h"
2+
3+
#include <stdio.h>
4+
#include <QGridLayout>
5+
#include <QKeyEvent>
6+
#include <QLabel>
7+
#include <QPushButton>
8+
#include <QSignalMapper>
9+
10+
CalculatorWidget::CalculatorWidget(QWidget* parent, Qt::WindowFlags flags)
11+
: QWidget(parent, flags)
12+
{
13+
QGridLayout* layout = new QGridLayout;
14+
layout->setSizeConstraint(QLayout::SetFixedSize);
15+
setLayout(layout);
16+
17+
QSizePolicy policy = sizePolicy();
18+
19+
displayLabel = new QLabel(this);
20+
layout->addWidget(displayLabel, 0, 0, 1, 3);
21+
displayLabel->setAutoFillBackground(true);
22+
displayLabel->setBackgroundRole(QPalette::Base);
23+
displayLabel->setAlignment(Qt::AlignRight);
24+
displayLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
25+
policy = displayLabel->sizePolicy();
26+
policy.setVerticalPolicy(QSizePolicy::Fixed);
27+
displayLabel->setSizePolicy(policy);
28+
29+
signalMapper = new QSignalMapper(this);
30+
QPushButton* button = new QPushButton(QString::number(0), this);
31+
QObject::connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
32+
signalMapper->setMapping(button, 0);
33+
layout->addWidget(button, 4, 1);
34+
digitButtons.push_back(button);
35+
for (unsigned int i = 1; i < 10; ++i)
36+
{
37+
QPushButton* button = new QPushButton(QString::number(i), this);
38+
QObject::connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
39+
signalMapper->setMapping(button, i);
40+
layout->addWidget(button, 1+(9-i)/3, (i-1)%3);
41+
digitButtons.push_back(button);
42+
}
43+
QObject::connect(signalMapper, SIGNAL(mapped(int)), SLOT(buttonClicked(int)));
44+
45+
clearButton = new QPushButton("C", this);
46+
layout->addWidget(clearButton, 1, 4);
47+
QObject::connect(clearButton, SIGNAL(clicked()), SLOT(clearButtonClicked()));
48+
49+
additionButton = new QPushButton("+", this);
50+
layout->addWidget(additionButton, 2, 4);
51+
QObject::connect(additionButton, SIGNAL(clicked()), SLOT(addButtonClicked()));
52+
53+
subtractionButton = new QPushButton("-", this);
54+
layout->addWidget(subtractionButton, 3, 4);
55+
QObject::connect(subtractionButton, SIGNAL(clicked()), SLOT(subtractButtonClicked()));
56+
57+
calculateButton = new QPushButton("=", this);
58+
layout->addWidget(calculateButton, 4, 4);
59+
QObject::connect(calculateButton, SIGNAL(clicked()), SLOT(calculateButtonClicked()));
60+
}
61+
62+
int CalculatorWidget::calculate(const QString& expression)
63+
{
64+
int result = 0;
65+
char operation = '+';
66+
QRegExp regexp("(\\d+)");
67+
int pos = 0;
68+
while ((pos = regexp.indexIn(expression, pos)) != -1) {
69+
int value = regexp.cap(1).toInt();
70+
switch (operation) {
71+
case '+': result += value; break;
72+
case '-': result -= value; break;
73+
}
74+
pos += regexp.matchedLength();
75+
if (pos < expression.length()) {
76+
operation = expression.at(pos).toAscii();
77+
}
78+
}
79+
return result;
80+
}
81+
82+
QString CalculatorWidget::display()
83+
{
84+
return displayLabel->text();
85+
}
86+
87+
void CalculatorWidget::keyPressEvent(QKeyEvent* event)
88+
{
89+
keyclickedButton = 0;
90+
int key = event->key();
91+
if (key >= Qt::Key_0 && key <= Qt::Key_9)
92+
{
93+
keyclickedButton = digitButtons[key - Qt::Key_0];
94+
}
95+
else
96+
{
97+
switch(key)
98+
{
99+
case Qt::Key_Plus: keyclickedButton = additionButton; break;
100+
case Qt::Key_Minus: keyclickedButton = subtractionButton; break;
101+
case Qt::Key_Return:
102+
case Qt::Key_Enter:
103+
case Qt::Key_Equal: keyclickedButton = calculateButton; break;
104+
case Qt::Key_Escape: keyclickedButton = clearButton; break;
105+
}
106+
}
107+
if (0 != keyclickedButton)
108+
{
109+
keyclickedButton->click();
110+
keyclickedButton->setDown(true);
111+
}
112+
}
113+
114+
void CalculatorWidget::keyReleaseEvent(QKeyEvent* event)
115+
{
116+
if (0 != keyclickedButton)
117+
{
118+
keyclickedButton->setDown(false);
119+
keyclickedButton = 0;
120+
}
121+
}
122+
123+
void CalculatorWidget::addButtonClicked()
124+
{
125+
displayLabel->setText(displayLabel->text()+"+");
126+
}
127+
128+
void CalculatorWidget::buttonClicked(int index)
129+
{
130+
displayLabel->setText(displayLabel->text()+QString::number(index));
131+
}
132+
133+
void CalculatorWidget::calculateButtonClicked()
134+
{
135+
displayLabel->setText(QString::number(calculate(displayLabel->text())));
136+
}
137+
138+
void CalculatorWidget::clearButtonClicked()
139+
{
140+
displayLabel->setText("");
141+
}
142+
143+
void CalculatorWidget::subtractButtonClicked()
144+
{
145+
displayLabel->setText(displayLabel->text()+"-");
146+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
class QLabel;
2+
class QPushButton;
3+
#include <QString>
4+
class QSignalMapper;
5+
#include <QWidget>
6+
7+
class CalculatorWidget : public QWidget
8+
{
9+
Q_OBJECT
10+
11+
public:
12+
13+
CalculatorWidget(QWidget* parent = 0, Qt::WindowFlags flags = 0);
14+
15+
QString display();
16+
17+
protected:
18+
19+
virtual void keyPressEvent(QKeyEvent* event);
20+
virtual void keyReleaseEvent(QKeyEvent* event);
21+
22+
private:
23+
24+
QLabel* displayLabel;
25+
QVector<QPushButton*> digitButtons;
26+
QPushButton* additionButton;
27+
QPushButton* calculateButton;
28+
QPushButton* clearButton;
29+
QPushButton* subtractionButton;
30+
31+
QPushButton* keyclickedButton;
32+
33+
QSignalMapper* signalMapper;
34+
35+
int calculate(const QString& expression);
36+
37+
private Q_SLOTS:
38+
39+
void addButtonClicked();
40+
void buttonClicked(int index);
41+
void calculateButtonClicked();
42+
void clearButtonClicked();
43+
void subtractButtonClicked();
44+
};
45+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
#include <boost/test/unit_test.hpp>
3+
#include <cucumber-cpp/defs.hpp>
4+
5+
#include <QApplication>
6+
#include <QTest>
7+
#include <QPushButton>
8+
9+
#include <CalculatorWidget.h>
10+
11+
static int argc = 0;
12+
static QApplication app(argc, 0);
13+
14+
std::istream& operator>> (std::istream& in, QString& val) { std::string s; in >> s; val = s.c_str(); return in; }
15+
std::ostream& operator<< (std::ostream& out, const QString& val) { out << val.toAscii().data(); return out; }
16+
17+
GIVEN("^I just turned on the calculator$") {
18+
cucumber::ScenarioScope<CalculatorWidget> calculator;
19+
calculator->move(0, 0);
20+
calculator->show();
21+
QTest::qWaitForWindowShown(calculator.get());
22+
QTest::qWait(200);
23+
}
24+
25+
WHEN("^I press (\\d+)$") {
26+
REGEX_PARAM(unsigned int, n);
27+
cucumber::ScenarioScope<CalculatorWidget> calculator;
28+
QTest::keyClick(calculator.get(), Qt::Key_0 + n, Qt::NoModifier, 200);
29+
}
30+
31+
WHEN("^I press add") {
32+
cucumber::ScenarioScope<CalculatorWidget> calculator;
33+
QTest::keyClick(calculator.get(), Qt::Key_Plus, Qt::NoModifier, 200);
34+
}
35+
36+
WHEN("^I press calculate") {
37+
cucumber::ScenarioScope<CalculatorWidget> calculator;
38+
QTest::keyClick(calculator.get(), Qt::Key_Return, Qt::NoModifier, 200);
39+
}
40+
41+
WHEN("^I press clear") {
42+
cucumber::ScenarioScope<CalculatorWidget> calculator;
43+
QTest::keyClick(calculator.get(), Qt::Key_Escape, Qt::NoModifier, 200);
44+
}
45+
46+
WHEN("^I press subtract") {
47+
cucumber::ScenarioScope<CalculatorWidget> calculator;
48+
QTest::keyClick(calculator.get(), Qt::Key_Minus, Qt::NoModifier, 200);
49+
}
50+
51+
THEN("^the display should be empty$") {
52+
cucumber::ScenarioScope<CalculatorWidget> calculator;
53+
BOOST_CHECK_EQUAL(calculator->display().size(), 0);
54+
QTest::qWait(200);
55+
}
56+
57+
THEN("^the display should show (.*)$") {
58+
REGEX_PARAM(QString, expected);
59+
cucumber::ScenarioScope<CalculatorWidget> calculator;
60+
BOOST_CHECK_EQUAL(expected, calculator->display());
61+
QTest::qWait(200);
62+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# language: en
2+
Feature: Addition
3+
In order to avoid silly mistakes
4+
As a math idiot
5+
I want to be told the sum of two numbers
6+
7+
Scenario Outline: Add two numbers
8+
Given I just turned on the calculator
9+
When I press <button1>
10+
And I press add
11+
And I press <button2>
12+
And I press calculate
13+
Then the display should show <result>
14+
15+
Examples:
16+
| button1 | button2 | result |
17+
| 2 | 3 | 5 |
18+
| 7 | 5 | 12 |
19+
| 9 | 1 | 10 |
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# language: en
2+
Feature: GUI behavior
3+
tests for buttons
4+
5+
Scenario Outline: Digit buttons
6+
Given I just turned on the calculator
7+
When I press <button>
8+
Then the display should show <output>
9+
10+
Examples:
11+
| button | output |
12+
| 0 | 0 |
13+
| 1 | 1 |
14+
| 2 | 2 |
15+
| 3 | 3 |
16+
| 4 | 4 |
17+
| 5 | 5 |
18+
| 6 | 6 |
19+
| 7 | 7 |
20+
| 8 | 8 |
21+
| 9 | 9 |
22+
23+
Scenario: Clear button
24+
Given I just turned on the calculator
25+
When I press 2
26+
And I press clear
27+
Then the display should be empty
28+
29+
Scenario: Addition button
30+
Given I just turned on the calculator
31+
When I press add
32+
Then the display should show +
33+
34+
Scenario: Subtraction button
35+
Given I just turned on the calculator
36+
When I press subtract
37+
Then the display should show -
38+
39+
Scenario Outline: Digit sequence
40+
Given I just turned on the calculator
41+
When I press <button1>
42+
And I press <button2>
43+
Then the display should show <output>
44+
45+
Examples:
46+
| button1 | button2 | output |
47+
| 2 | 2 | 22 |
48+
| 7 | 4 | 74 |
49+
| 3 | 8 | 38 |
50+
51+
Scenario Outline: Addition operation
52+
Given I just turned on the calculator
53+
When I press <button1>
54+
And I press add
55+
And I press <button2>
56+
Then the display should show <output>
57+
58+
Examples:
59+
| button1 | button2 | output |
60+
| 2 | 2 | 2+2 |
61+
| 7 | 4 | 7+4 |
62+
| 3 | 8 | 3+8 |
63+
64+
65+
Scenario Outline: Subtraction operation
66+
Given I just turned on the calculator
67+
When I press <button1>
68+
And I press subtract
69+
And I press <button2>
70+
Then the display should show <output>
71+
72+
Examples:
73+
| button1 | button2 | output |
74+
| 2 | 2 | 2-2 |
75+
| 7 | 4 | 7-4 |
76+
| 3 | 8 | 3-8 |
77+

0 commit comments

Comments
 (0)