calculator.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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] = createButton(QString::number(i), SLOT(digitClicked()));
  76. }
  77. Button *pointButton = createButton(".", SLOT(pointClicked()));
  78. Button *changeSignButton = createButton("\302\261", SLOT(changeSignClicked()));
  79. Button *backspaceButton = createButton("Backspace", SLOT(backspaceClicked()));
  80. Button *clearButton = createButton("Clear", SLOT(clear()));
  81. Button *clearAllButton = createButton("Clear All", SLOT(clearAll()));
  82. Button *clearMemoryButton = createButton("MC", SLOT(clearMemory()));
  83. Button *readMemoryButton = createButton("MR", SLOT(readMemory()));
  84. Button *setMemoryButton = createButton("MS", SLOT(setMemory()));
  85. Button *addToMemoryButton = createButton("M+", SLOT(addToMemory()));
  86. Button *divisionButton = createButton("\303\267", SLOT(multiplicativeOperatorClicked()));
  87. Button *timesButton = createButton("\303\227", SLOT(multiplicativeOperatorClicked()));
  88. Button *minusButton = createButton("-", SLOT(additiveOperatorClicked()));
  89. Button *plusButton = createButton("+", SLOT(additiveOperatorClicked()));
  90. Button *squareRootButton = createButton("Sqrt", SLOT(unaryOperatorClicked()));
  91. Button *powerButton = createButton("x\302\262", SLOT(unaryOperatorClicked()));
  92. Button *reciprocalButton = createButton("1/x", SLOT(unaryOperatorClicked()));
  93. Button *equalButton = createButton("=", SLOT(equalClicked()));
  94. //! [4]
  95. //! [5]
  96. QGridLayout *mainLayout = new QGridLayout;
  97. //! [5] //! [6]
  98. mainLayout->setSizeConstraint(QLayout::SetFixedSize);
  99. mainLayout->addWidget(display, 0, 0, 1, 6);
  100. mainLayout->addWidget(backspaceButton, 1, 0, 1, 2);
  101. mainLayout->addWidget(clearButton, 1, 2, 1, 2);
  102. mainLayout->addWidget(clearAllButton, 1, 4, 1, 2);
  103. mainLayout->addWidget(clearMemoryButton, 2, 0);
  104. mainLayout->addWidget(readMemoryButton, 3, 0);
  105. mainLayout->addWidget(setMemoryButton, 4, 0);
  106. mainLayout->addWidget(addToMemoryButton, 5, 0);
  107. for (int i = 1; i < NumDigitButtons; ++i) {
  108. int row = ((9 - i) / 3) + 2;
  109. int column = ((i - 1) % 3) + 1;
  110. mainLayout->addWidget(digitButtons[i], row, column);
  111. }
  112. mainLayout->addWidget(digitButtons[0], 5, 1);
  113. mainLayout->addWidget(pointButton, 5, 2);
  114. mainLayout->addWidget(changeSignButton, 5, 3);
  115. mainLayout->addWidget(divisionButton, 2, 4);
  116. mainLayout->addWidget(timesButton, 3, 4);
  117. mainLayout->addWidget(minusButton, 4, 4);
  118. mainLayout->addWidget(plusButton, 5, 4);
  119. mainLayout->addWidget(squareRootButton, 2, 5);
  120. mainLayout->addWidget(powerButton, 3, 5);
  121. mainLayout->addWidget(reciprocalButton, 4, 5);
  122. mainLayout->addWidget(equalButton, 5, 5);
  123. setLayout(mainLayout);
  124. setWindowTitle("Calculator");
  125. }
  126. //! [6]
  127. //! [7]
  128. void Calculator::digitClicked()
  129. {
  130. Button *clickedButton = qobject_cast<Button *>(sender());
  131. int digitValue = clickedButton->text().toInt();
  132. if (display->text() == "0" && digitValue == 0.0)
  133. return;
  134. if (waitingForOperand) {
  135. display->clear();
  136. waitingForOperand = false;
  137. }
  138. display->setText(display->text() + QString::number(digitValue));
  139. }
  140. //! [7]
  141. //! [8]
  142. void Calculator::unaryOperatorClicked()
  143. //! [8] //! [9]
  144. {
  145. Button *clickedButton = qobject_cast<Button *>(sender());
  146. QString clickedOperator = clickedButton->text();
  147. double operand = display->text().toDouble();
  148. double result = 0.0;
  149. if (clickedOperator == "Sqrt") {
  150. if (operand < 0.0) {
  151. abortOperation();
  152. return;
  153. }
  154. result = std::sqrt(operand);
  155. } else if (clickedOperator == "x\302\262") {
  156. result = std::pow(operand, 2.0);
  157. } else if (clickedOperator == "1/x") {
  158. if (operand == 0.0) {
  159. abortOperation();
  160. return;
  161. }
  162. result = 1.0 / operand;
  163. }
  164. display->setText(QString::number(result));
  165. waitingForOperand = true;
  166. }
  167. //! [9]
  168. //! [10]
  169. void Calculator::additiveOperatorClicked()
  170. //! [10] //! [11]
  171. {
  172. Button *clickedButton = qobject_cast<Button *>(sender());
  173. QString clickedOperator = clickedButton->text();
  174. double operand = display->text().toDouble();
  175. //! [11] //! [12]
  176. if (!pendingMultiplicativeOperator.isEmpty()) {
  177. //! [12] //! [13]
  178. if (!calculate(operand, pendingMultiplicativeOperator)) {
  179. abortOperation();
  180. return;
  181. }
  182. display->setText(QString::number(factorSoFar));
  183. operand = factorSoFar;
  184. factorSoFar = 0.0;
  185. pendingMultiplicativeOperator.clear();
  186. }
  187. //! [13] //! [14]
  188. if (!pendingAdditiveOperator.isEmpty()) {
  189. //! [14] //! [15]
  190. if (!calculate(operand, pendingAdditiveOperator)) {
  191. abortOperation();
  192. return;
  193. }
  194. display->setText(QString::number(sumSoFar));
  195. } else {
  196. sumSoFar = operand;
  197. }
  198. //! [15] //! [16]
  199. pendingAdditiveOperator = clickedOperator;
  200. //! [16] //! [17]
  201. waitingForOperand = true;
  202. }
  203. //! [17]
  204. //! [18]
  205. void Calculator::multiplicativeOperatorClicked()
  206. {
  207. Button *clickedButton = qobject_cast<Button *>(sender());
  208. QString clickedOperator = clickedButton->text();
  209. double operand = display->text().toDouble();
  210. if (!pendingMultiplicativeOperator.isEmpty()) {
  211. if (!calculate(operand, pendingMultiplicativeOperator)) {
  212. abortOperation();
  213. return;
  214. }
  215. display->setText(QString::number(factorSoFar));
  216. } else {
  217. factorSoFar = operand;
  218. }
  219. pendingMultiplicativeOperator = clickedOperator;
  220. waitingForOperand = true;
  221. }
  222. //! [18]
  223. //! [20]
  224. void Calculator::equalClicked()
  225. {
  226. double operand = display->text().toDouble();
  227. if (!pendingMultiplicativeOperator.isEmpty()) {
  228. if (!calculate(operand, pendingMultiplicativeOperator)) {
  229. abortOperation();
  230. return;
  231. }
  232. operand = factorSoFar;
  233. factorSoFar = 0.0;
  234. pendingMultiplicativeOperator.clear();
  235. }
  236. if (!pendingAdditiveOperator.isEmpty()) {
  237. if (!calculate(operand, pendingAdditiveOperator)) {
  238. abortOperation();
  239. return;
  240. }
  241. pendingAdditiveOperator.clear();
  242. } else {
  243. sumSoFar = operand;
  244. }
  245. display->setText(QString::number(sumSoFar));
  246. sumSoFar = 0.0;
  247. waitingForOperand = true;
  248. }
  249. //! [20]
  250. //! [22]
  251. void Calculator::pointClicked()
  252. {
  253. if (waitingForOperand)
  254. display->setText("0");
  255. if (!display->text().contains('.'))
  256. display->setText(display->text() + ".");
  257. waitingForOperand = false;
  258. }
  259. //! [22]
  260. //! [24]
  261. void Calculator::changeSignClicked()
  262. {
  263. QString text = display->text();
  264. double value = text.toDouble();
  265. if (value > 0.0) {
  266. text.prepend("-");
  267. } else if (value < 0.0) {
  268. text.remove(0, 1);
  269. }
  270. display->setText(text);
  271. }
  272. //! [24]
  273. //! [26]
  274. void Calculator::backspaceClicked()
  275. {
  276. if (waitingForOperand)
  277. return;
  278. QString text = display->text();
  279. text.chop(1);
  280. if (text.isEmpty()) {
  281. text = "0";
  282. waitingForOperand = true;
  283. }
  284. display->setText(text);
  285. }
  286. //! [26]
  287. //! [28]
  288. void Calculator::clear()
  289. {
  290. if (waitingForOperand)
  291. return;
  292. display->setText("0");
  293. waitingForOperand = true;
  294. }
  295. //! [28]
  296. //! [30]
  297. void Calculator::clearAll()
  298. {
  299. sumSoFar = 0.0;
  300. factorSoFar = 0.0;
  301. pendingAdditiveOperator.clear();
  302. pendingMultiplicativeOperator.clear();
  303. display->setText("0");
  304. waitingForOperand = true;
  305. }
  306. //! [30]
  307. //! [32]
  308. void Calculator::clearMemory()
  309. {
  310. sumInMemory = 0.0;
  311. }
  312. void Calculator::readMemory()
  313. {
  314. display->setText(QString::number(sumInMemory));
  315. waitingForOperand = true;
  316. }
  317. void Calculator::setMemory()
  318. {
  319. equalClicked();
  320. sumInMemory = display->text().toDouble();
  321. }
  322. void Calculator::addToMemory()
  323. {
  324. equalClicked();
  325. sumInMemory += display->text().toDouble();
  326. }
  327. //! [32]
  328. //! [34]
  329. Button *Calculator::createButton(const QString &text, const char *member)
  330. {
  331. Button *button = new Button(text);
  332. connect(button, SIGNAL(clicked()), this, member);
  333. return button;
  334. }
  335. //! [34]
  336. //! [36]
  337. void Calculator::abortOperation()
  338. {
  339. clearAll();
  340. display->setText("####");
  341. }
  342. //! [36]
  343. //! [38]
  344. bool Calculator::calculate(double rightOperand, const QString &pendingOperator)
  345. {
  346. if (pendingOperator == "+") {
  347. sumSoFar += rightOperand;
  348. } else if (pendingOperator == "-") {
  349. sumSoFar -= rightOperand;
  350. } else if (pendingOperator == "\303\227") {
  351. factorSoFar *= rightOperand;
  352. } else if (pendingOperator == "\303\267") {
  353. if (rightOperand == 0.0)
  354. return false;
  355. factorSoFar /= rightOperand;
  356. }
  357. return true;
  358. }
  359. //! [38]