calculator.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2016 The Qt Company Ltd.
  4. ** Contact: https://www.qt.io/licensing/
  5. **
  6. ** This file is part of the examples of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:BSD$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and The Qt Company. For licensing terms
  14. ** and conditions see https://www.qt.io/terms-conditions. For further
  15. ** information use the contact form at https://www.qt.io/contact-us.
  16. **
  17. ** BSD License Usage
  18. ** Alternatively, you may use this file under the terms of the BSD license
  19. ** as follows:
  20. **
  21. ** "Redistribution and use in source and binary forms, with or without
  22. ** modification, are permitted provided that the following conditions are
  23. ** met:
  24. ** * Redistributions of source code must retain the above copyright
  25. ** notice, this list of conditions and the following disclaimer.
  26. ** * Redistributions in binary form must reproduce the above copyright
  27. ** notice, this list of conditions and the following disclaimer in
  28. ** the documentation and/or other materials provided with the
  29. ** distribution.
  30. ** * Neither the name of The Qt Company Ltd nor the names of its
  31. ** contributors may be used to endorse or promote products derived
  32. ** from this software without specific prior written permission.
  33. **
  34. **
  35. ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  36. ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  37. ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  38. ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  39. ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  42. ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  43. ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  44. ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  45. ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  46. **
  47. ** $QT_END_LICENSE$
  48. **
  49. ****************************************************************************/
  50. #include <QtWidgets>
  51. #include <cmath>
  52. #include "button.h"
  53. #include "calculator.h"
  54. //! [0]
  55. Calculator::Calculator(QWidget* parent)
  56. : QWidget(parent)
  57. {
  58. sumInMemory = 0.0;
  59. sumSoFar = 0.0;
  60. factorSoFar = 0.0;
  61. waitingForOperand = true;
  62. //! [0]
  63. //! [1]
  64. display = new QLineEdit("0");
  65. //! [1] //! [2]
  66. display->setReadOnly(true);
  67. display->setAlignment(Qt::AlignRight);
  68. display->setMaxLength(15);
  69. QFont font = display->font();
  70. font.setPointSize(font.pointSize() + 8);
  71. display->setFont(font);
  72. //! [2]
  73. //! [4]
  74. for (int i = 0; i < NumDigitButtons; ++i) {
  75. digitButtons[i] =
  76. createButton(QString::number(i), SLOT(digitClicked()));
  77. }
  78. Button* pointButton = createButton(".", SLOT(pointClicked()));
  79. Button* changeSignButton =
  80. createButton("\302\261", SLOT(changeSignClicked()));
  81. Button* backspaceButton =
  82. createButton("Backspace", SLOT(backspaceClicked()));
  83. Button* clearButton = createButton("Clear", SLOT(clear()));
  84. Button* clearAllButton = createButton("Clear All", SLOT(clearAll()));
  85. Button* clearMemoryButton = createButton("MC", SLOT(clearMemory()));
  86. Button* readMemoryButton = createButton("MR", SLOT(readMemory()));
  87. Button* setMemoryButton = createButton("MS", SLOT(setMemory()));
  88. Button* addToMemoryButton = createButton("M+", SLOT(addToMemory()));
  89. Button* divisionButton =
  90. createButton("\303\267", SLOT(multiplicativeOperatorClicked()));
  91. Button* timesButton =
  92. createButton("\303\227", SLOT(multiplicativeOperatorClicked()));
  93. Button* minusButton = createButton("-", SLOT(additiveOperatorClicked()));
  94. Button* plusButton = createButton("+", SLOT(additiveOperatorClicked()));
  95. Button* squareRootButton =
  96. createButton("Sqrt", SLOT(unaryOperatorClicked()));
  97. Button* powerButton =
  98. createButton("x\302\262", SLOT(unaryOperatorClicked()));
  99. Button* reciprocalButton =
  100. createButton("1/x", SLOT(unaryOperatorClicked()));
  101. Button* equalButton = createButton("=", SLOT(equalClicked()));
  102. //! [4]
  103. //! [5]
  104. QGridLayout* mainLayout = new QGridLayout;
  105. //! [5] //! [6]
  106. mainLayout->setSizeConstraint(QLayout::SetFixedSize);
  107. mainLayout->addWidget(display, 0, 0, 1, 6);
  108. mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);
  109. mainLayout->addWidget(clearButton, 1, 2, 1, 2);
  110. mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);
  111. mainLayout->addWidget(clearMemoryButton, 2, 0);
  112. mainLayout->addWidget(readMemoryButton, 3, 0);
  113. mainLayout->addWidget(setMemoryButton, 4, 0);
  114. mainLayout->addWidget(addToMemoryButton, 5, 0);
  115. for (int i = 1; i < NumDigitButtons; ++i) {
  116. int row = ((9 - i) / 3) + 2;
  117. int column = ((i - 1) % 3) + 1;
  118. mainLayout->addWidget(digitButtons[i], row, column);
  119. }
  120. mainLayout->addWidget(digitButtons[0], 5, 1);
  121. mainLayout->addWidget(pointButton, 5, 2);
  122. mainLayout->addWidget(changeSignButton, 5, 3);
  123. mainLayout->addWidget(divisionButton, 2, 4);
  124. mainLayout->addWidget(timesButton, 3, 4);
  125. mainLayout->addWidget(minusButton, 4, 4);
  126. mainLayout->addWidget(plusButton, 5, 4);
  127. mainLayout->addWidget(squareRootButton, 2, 5);
  128. mainLayout->addWidget(powerButton, 3, 5);
  129. mainLayout->addWidget(reciprocalButton, 4, 5);
  130. mainLayout->addWidget(equalButton, 5, 5);
  131. setLayout(mainLayout);
  132. setWindowTitle("Calculator");
  133. }
  134. //! [6]
  135. //! [7]
  136. void Calculator::digitClicked()
  137. {
  138. Button* clickedButton = qobject_cast<Button*>(sender());
  139. int digitValue = clickedButton->text().toInt();
  140. if (display->text() == "0" && digitValue == 0.0)
  141. return;
  142. if (waitingForOperand) {
  143. display->clear();
  144. waitingForOperand = false;
  145. }
  146. display->setText(display->text() + QString::number(digitValue));
  147. }
  148. //! [7]
  149. //! [8]
  150. void Calculator::unaryOperatorClicked()
  151. //! [8] //! [9]
  152. {
  153. Button* clickedButton = qobject_cast<Button*>(sender());
  154. QString clickedOperator = clickedButton->text();
  155. double operand = display->text().toDouble();
  156. double result = 0.0;
  157. if (clickedOperator == "Sqrt") {
  158. if (operand < 0.0) {
  159. abortOperation();
  160. return;
  161. }
  162. result = std::sqrt(operand);
  163. } else if (clickedOperator == "x\302\262") {
  164. result = std::pow(operand, 2.0);
  165. } else if (clickedOperator == "1/x") {
  166. if (operand == 0.0) {
  167. abortOperation();
  168. return;
  169. }
  170. result = 1.0 / operand;
  171. }
  172. display->setText(QString::number(result));
  173. waitingForOperand = true;
  174. }
  175. //! [9]
  176. //! [10]
  177. void Calculator::additiveOperatorClicked()
  178. //! [10] //! [11]
  179. {
  180. Button* clickedButton = qobject_cast<Button*>(sender());
  181. QString clickedOperator = clickedButton->text();
  182. double operand = display->text().toDouble();
  183. //! [11] //! [12]
  184. if (!pendingMultiplicativeOperator.isEmpty()) {
  185. //! [12] //! [13]
  186. if (!calculate(operand, pendingMultiplicativeOperator)) {
  187. abortOperation();
  188. return;
  189. }
  190. display->setText(QString::number(factorSoFar));
  191. operand = factorSoFar;
  192. factorSoFar = 0.0;
  193. pendingMultiplicativeOperator.clear();
  194. }
  195. //! [13] //! [14]
  196. if (!pendingAdditiveOperator.isEmpty()) {
  197. //! [14] //! [15]
  198. if (!calculate(operand, pendingAdditiveOperator)) {
  199. abortOperation();
  200. return;
  201. }
  202. display->setText(QString::number(sumSoFar));
  203. } else {
  204. sumSoFar = operand;
  205. }
  206. //! [15] //! [16]
  207. pendingAdditiveOperator = clickedOperator;
  208. //! [16] //! [17]
  209. waitingForOperand = true;
  210. }
  211. //! [17]
  212. //! [18]
  213. void Calculator::multiplicativeOperatorClicked()
  214. {
  215. Button* clickedButton = qobject_cast<Button*>(sender());
  216. QString clickedOperator = clickedButton->text();
  217. double operand = display->text().toDouble();
  218. if (!pendingMultiplicativeOperator.isEmpty()) {
  219. if (!calculate(operand, pendingMultiplicativeOperator)) {
  220. abortOperation();
  221. return;
  222. }
  223. display->setText(QString::number(factorSoFar));
  224. } else {
  225. factorSoFar = operand;
  226. }
  227. pendingMultiplicativeOperator = clickedOperator;
  228. waitingForOperand = true;
  229. }
  230. //! [18]
  231. //! [20]
  232. void Calculator::equalClicked()
  233. {
  234. double operand = display->text().toDouble();
  235. if (!pendingMultiplicativeOperator.isEmpty()) {
  236. if (!calculate(operand, pendingMultiplicativeOperator)) {
  237. abortOperation();
  238. return;
  239. }
  240. operand = factorSoFar;
  241. factorSoFar = 0.0;
  242. pendingMultiplicativeOperator.clear();
  243. }
  244. if (!pendingAdditiveOperator.isEmpty()) {
  245. if (!calculate(operand, pendingAdditiveOperator)) {
  246. abortOperation();
  247. return;
  248. }
  249. pendingAdditiveOperator.clear();
  250. } else {
  251. sumSoFar = operand;
  252. }
  253. display->setText(QString::number(sumSoFar));
  254. sumSoFar = 0.0;
  255. waitingForOperand = true;
  256. }
  257. //! [20]
  258. //! [22]
  259. void Calculator::pointClicked()
  260. {
  261. if (waitingForOperand)
  262. display->setText("0");
  263. if (!display->text().contains('.'))
  264. display->setText(display->text() + ".");
  265. waitingForOperand = false;
  266. }
  267. //! [22]
  268. //! [24]
  269. void Calculator::changeSignClicked()
  270. {
  271. QString text = display->text();
  272. double value = text.toDouble();
  273. if (value > 0.0) {
  274. text.prepend("-");
  275. } else if (value < 0.0) {
  276. text.remove(0, 1);
  277. }
  278. display->setText(text);
  279. }
  280. //! [24]
  281. //! [26]
  282. void Calculator::backspaceClicked()
  283. {
  284. if (waitingForOperand)
  285. return;
  286. QString text = display->text();
  287. text.chop(1);
  288. if (text.isEmpty()) {
  289. text = "0";
  290. waitingForOperand = true;
  291. }
  292. display->setText(text);
  293. }
  294. //! [26]
  295. //! [28]
  296. void Calculator::clear()
  297. {
  298. if (waitingForOperand)
  299. return;
  300. display->setText("0");
  301. waitingForOperand = true;
  302. }
  303. //! [28]
  304. //! [30]
  305. void Calculator::clearAll()
  306. {
  307. sumSoFar = 0.0;
  308. factorSoFar = 0.0;
  309. pendingAdditiveOperator.clear();
  310. pendingMultiplicativeOperator.clear();
  311. display->setText("0");
  312. waitingForOperand = true;
  313. }
  314. //! [30]
  315. //! [32]
  316. void Calculator::clearMemory()
  317. {
  318. sumInMemory = 0.0;
  319. }
  320. void Calculator::readMemory()
  321. {
  322. display->setText(QString::number(sumInMemory));
  323. waitingForOperand = true;
  324. }
  325. void Calculator::setMemory()
  326. {
  327. equalClicked();
  328. sumInMemory = display->text().toDouble();
  329. }
  330. void Calculator::addToMemory()
  331. {
  332. equalClicked();
  333. sumInMemory += display->text().toDouble();
  334. }
  335. //! [32]
  336. //! [34]
  337. Button* Calculator::createButton(const QString& text, const char* member)
  338. {
  339. Button* button = new Button(text);
  340. connect(button, SIGNAL(clicked()), this, member);
  341. return button;
  342. }
  343. //! [34]
  344. //! [36]
  345. void Calculator::abortOperation()
  346. {
  347. clearAll();
  348. display->setText("####");
  349. }
  350. //! [36]
  351. //! [38]
  352. bool Calculator::calculate(double rightOperand, const QString& pendingOperator)
  353. {
  354. if (pendingOperator == "+") {
  355. sumSoFar += rightOperand;
  356. } else if (pendingOperator == "-") {
  357. sumSoFar -= rightOperand;
  358. } else if (pendingOperator == "\303\227") {
  359. factorSoFar *= rightOperand;
  360. } else if (pendingOperator == "\303\267") {
  361. if (rightOperand == 0.0)
  362. return false;
  363. factorSoFar /= rightOperand;
  364. }
  365. return true;
  366. }
  367. //! [38]