Skip to content

Commit 56c8e05

Browse files
committed
Merge pull request #58 from gambr/calcqt_example
GUI Calculator example with Qt libraries
2 parents 4c7baca + 2da6f72 commit 56c8e05

File tree

12 files changed

+411
-0
lines changed

12 files changed

+411
-0
lines changed

examples/CMakeLists.txt

+1
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

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
project(CalcQt)
2+
3+
find_package(Qt4 COMPONENTS QtCore QtGui QtTest)
4+
5+
if(QT4_FOUND)
6+
include(${QT_USE_FILE})
7+
set(CALCQT_HEADERS CalcQt/CalculatorWidget.h)
8+
qt4_wrap_cpp(CALCQT_HEADERS_MOC ${CALCQT_HEADERS})
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+
set(CALCQT_SOURCES CalcQt/CalcQt.cpp CalcQt/CalculatorWidget.cpp)
19+
add_executable(calcqt ${CALCQT_SOURCES} ${CALCQT_HEADERS_MOC})
20+
target_link_libraries(calcqt ${QT_LIBRARIES})
21+
endif()

examples/CalcQt/CalcQt/CalcQt.cpp

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

0 commit comments

Comments
 (0)