1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
|
/****************************************************************************
** $Id$
**
** Tutorial
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
/*! \page tutorial.html
\title Qt Tutorial - The 14 Steps
This tutorial gives an introduction to GUI programming using the Qt
toolkit. It doesn't cover everything: the emphasis is on teaching the
programming philosophy of GUI programming, and Qt's features are
introduced as needed. Some commonly used features are never used in
this tutorial.
Chapter one starts with a ten-line hello-world and each subsequent
chapter introduces one or a few more concepts. By Chapter 14, the ten
lines from Chapter 1 have turned into a 650-line game.
If you're completely new to Qt, please read \link how-to-learn-qt.html
How to Learn Qt\endlink if you haven't already done so.
Tutorial chapters:
\list 1
\i \link t1.html Hello, World!\endlink
\i \link t2.html Calling it Quits\endlink
\i \link t3.html Family Values\endlink
\i \link t4.html Let There Be Widgets\endlink
\i \link t5.html Building Blocks\endlink
\i \link t6.html Building Blocks Galore!\endlink
\i \link t7.html One Thing Leads to Another\endlink
\i \link t8.html Preparing for Battle\endlink
\i \link t9.html With Cannon You Can\endlink
\i \link t10.html Smooth as Silk\endlink
\i \link t11.html Giving It a Shot\endlink
\i \link t12.html Hanging in the Air the Way Bricks Don't\endlink
\i \link t13.html Game Over\endlink
\i \link t14.html Facing the Wall\endlink
\endlist
This little game doesn't look much like a modern GUI application. It
uses a good few of the GUI techniques, but after you've worked through
it, we recommend reading the \link simple-application.html Simple
Application Walkthrough \endlink too. That discusses a very simple
application with all the common features (menu bars, tool bars,
on-line help, printing, a couple of dialogs) in detail.
*/
/*! \page t1.html
\title Qt Tutorial - Chapter 1: Hello, World!
<center><img src="t1.png" alt="Screenshot of tutorial one"></center>
This first program is a simple hello-world example. It contains only
the bare minimum you need to get a Qt application up and running.
The picture above is a snapshot of this program.
\include t1/main.cpp
\quotefile t1/main.cpp
\section1 Line-by-line Walkthrough
\skipto include
\printline qapp
This line includes the QApplication class definition. There has to be
exactly one QApplication object in every application that uses Qt.
QApplication manages various application-wide resources, such as the
default font and cursor.
\printline qpushbutton
This line includes the QPushButton class definition. The
\link hierarchy.html reference documentation \endlink for each class
mentions at the top which file needs to be included to use that class.
QPushButton is a classical GUI push button that the user can press
and release. It manages its own look and feel, like every other \l
QWidget. A widget is a user interface object that can process user
input and draw graphics. The programmer can change both the overall
\link QApplication::setStyle() look and feel\endlink and many minor
properties of it (such as color), as well as the widget's content. A
QPushButton can show either a text or a \l QPixmap.
\printline main
\printline {
The main() function is the entry point to the program. Almost always
when using Qt, main() only needs to perform some kind of initialization
before passing the control to the Qt library, which then tells the
program about the user's actions via events.
\c argc is the number of command-line arguments and \c argv is the
array of command-line arguments. This is a C/C++ feature. It is not
specific to Qt; however, Qt needs to process these arguments (see
following).
\printline QApplication
\c a is this program's QApplication. Here it is created and processes
some of the command-line arguments (such as -display under X Window).
Note that all command-line arguments recognized by Qt are removed from
\c argv (and \c argc is decremented accordingly). See the \l
QApplication::argv() documentation for details.
<strong>Note:</strong> It is essential that the QApplication object be
created before any window-system parts of Qt are used.
\printline QPushButton
Here, \e after the QApplication, comes the first window-system code: A
push button is created.
The button is set up to display the text "Hello world!" and be a
window of its own (because the constructor specifies 0 for the parent
window, inside which the button should be located).
\printline resize
The button is set up to be 100 pixels wide and 30 pixels high (plus the
window system frame). In this case we don't care about the button's
position, and we accept the default value.
\printline setMainWidget
The push button is chosen as the main widget for the application. If
the user closes a main widget, the application exits.
You don't have to have a main widget, but most programs do have one.
\printline show
A widget is never visible when you create it. You must call show() to
make it visible.
\printline exec
This is where main() passes control to Qt, and exec() will return when
the application exits.
In exec(), Qt receives and processes user and system events and passes
these on to the appropriate widgets.
\printline }
\section1 Behavior
You should now try to compile and run this program.
When you run it, you will see a small window filled with a single
button, and on it you can read the famous words, Hello World!
\section1 Exercises
Try to resize the window. Press the button. If you're running X
Window, try running the program with the -geometry option
(for example, \c {-geometry 100x200+10+20}).
You may now go on to \link t2.html Chapter 2.\endlink
[\link t2.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \page t2.html
\title Qt Tutorial - Chapter 2: Calling it Quits
<center><img src="t2.png" alt="Screenshot of tutorial two"></center>
Having created a window in \link t1.html Chapter 1, \endlink we will
now go on to make the application quit properly when the user tells it to.
We will also use a font that is more exciting than the default one.
\include t2/main.cpp
\quotefile t2/main.cpp
\section1 Line-by-line Walkthrough
\skipto qfont
\printline qfont
Since this program uses QFont, it needs to include qfont.h. Qt's font
abstraction is rather different from the horror provided by X, and
loading and using fonts has been highly optimized.
\skipto QPushButton
\printline QPushButton
This time, the button says "Quit" and that's exactly what the program
will do when the user clicks the button. This is not a coincidence.
We still pass 0 as the parent, since the button is a top-level window.
\printline resize
We've chosen another size for the button since the text is a bit
shorter than "Hello world!". We could also have used \l QFontMetrics
to set right size.
\printline setFont
Here we choose a new font for the button, an 18-point bold font from
the Times family. Note that we create the font on the spot.
It is also possible to change the default font (using \l
QApplication::setFont()) for the whole application.
\printline connect
connect() is perhaps \e the most central feature of Qt.
Note that connect() is a static function in QObject. Do not confuse it
with the connect() function in the socket library.
This line establishes a one-way connection between two Qt objects (objects
that inherit QObject, directly or indirectly). Every Qt object can have
both \c signals (to send messages) and \c slots (to receive messages). All
widgets are Qt objects. They inherit QWidget which in turn inherits
QObject.
Here, the \e clicked() signal of \e quit is connected to the \e
quit() slot of \e a, so that when the button is clicked, the
application quits.
The \link signalsandslots.html Signals and Slots\endlink documentation
describes this topic in detail.
\section1 Behavior
When you run this program, you will see an even smaller window than in
Chapter 1, filled with an even smaller button.
\section1 Exercises
Try to resize the window. Press the button. Oops! That connect()
would seem to make some difference.
Are there any other signals in QPushButton you can connect to quit?
Hint: The QPushButton inherits most of its behavior from QButton.
You may now go on to \link t3.html Chapter 3.\endlink
[\link t1.html Previous tutorial\endlink]
[\link t3.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \page t3.html
\title Qt Tutorial - Chapter 3: Family Values
<center><img src="t3.png" alt="Screenshot of tutorial three"></center>
This example shows how to create mother and child widgets.
We'll keep it simple and use just a single mother (uh, family values?)
and a lone child.
\include t3/main.cpp
\quotefile t3/main.cpp
\section1 Line-by-line Walkthrough
\skipto qvbox.h
\printline qvbox.h
We add an include of qvbox.h to get the layout class we'll use.
\skipto QVBox
\printline QVBox
Here we simply create a vertical box container. The QVBox arranges
its child widgets in a vertical row, one above the other, handing out
space according to each child's \l QWidget::sizePolicy().
\printline resize
We set its width to 200 pixels and the height to 120 pixels.
\printline quit
A child is born.
This QPushButton is created with both a text ("Quit") and a mother
(box). A child widget is always on top of its mother. When
displayed, it is clipped by its mother's bounds.
The mother widget, the QVBox, automatically adds the child centered in
its box. Because nothing else is added, the button gets all the space
the mother has.
\skipto show
\printline show
When a mother widget is shown, it will call show for all its children
(except those on which you have done an explicit \l QWidget::hide()).
\section1 Behavior
The button no longer fills the entire widget. Instead, it gets a
"natural" size. This is because there is now a new top-level widget,
which uses the button's size hint and size change policy to set the
button's size and position. (See \l QWidget::sizeHint() and \l
QWidget::setSizePolicy() for more information about these functions.)
\section1 Exercises
Try resizing the window. How does the button change? What is the
button's size-change policy? What happens to the button's height if
you run the program with a bigger font? What happens if you try to
make the window \e really small?
You may now go on to \link t4.html Chapter 4.\endlink
[\link t2.html Previous tutorial\endlink]
[\link t4.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \page t4.html
\title Qt Tutorial - Chapter 4: Let There Be Widgets
<center><img src="t4.png" alt="Screenshot of tutorial four"></center>
This example shows how to create your own widget, describes how to control the
minimum and maximum sizes of a widget, and introduces widget names.
\include t4/main.cpp
\quotefile t4/main.cpp
\section1 Line-by-line Walkthrough
\skipto MyWidget
\printuntil }
Here we create a new class. Because this class inherits from QWidget,
the new class is a widget and may be a top level window or a child
widget (like the push button in Chapter 3).
This class has only one member, a constructor (in addition to the
members it inherits from QWidget). The constructor is a standard Qt
widget constructor; you should always include a similar constructor
when you create widgets.
The first argument is its parent widget. To create a top-level window
you specify a null pointer as the parent. As you can see, this widget
defaults to be a top-level window.
The second argument is the widget's name. This is \e not the text
that appears in the window's title bar or in the button. It is a name
associated with a widget to make it possible to \link
QObject::queryList() look up \endlink this widget later, and there is
also a \link QObject::dumpObjectTree() handy debugging function
\endlink that will list a complete widget hierarchy.
\printline MyWidget
\printline QWidget
The implementation of the constructor starts here. Like most widgets,
it just passes on the \c parent and \c name to the QWidget
constructor.
\printuntil setMaximumSize
Because this widget doesn't know how to handle resizing, we fix its size
by setting the minimum and maximum to be equal. In the next chapter
we will show how a widget can respond to resize event from the user.
\printuntil setFont
Here we create and set up a child widget of this widget (the new widget's
parent is \c this) which has the widget name "quit". The widget
name has nothing to do with the button text; it just happens to be
similar in this case.
Note that \c quit is a local variable in the constructor. MyWidget
does not keep track of it, but Qt does, and will by default delete it
when MyWidget is deleted. This is why MyWidget doesn't need a
destructor. (On the other hand, there is no harm in deleting a child
when you choose to, the child will automatically tell Qt about its
imminent death.)
The setGeometry() call does the same as move() and resize() did in the
previous chapters.
\printline qApp
\printline }
Because the MyWidget class doesn't know about the application object, it
has to connect to Qt's pointer to it, \c qApp.
A widget is a software component and should know as little as possible
about its environment in order to be as general and reusable as
possible.
Knowing the name of the application object would break this principle,
so Qt offers an alias, qApp, for the cases in which a component such as
MyWidget needs to talk to the application object.
\printuntil }
Here we instantiate our new baby, set it to be the main widget, and
execute the application.
\section1 Behavior
This program is very similar in behavior to the previous one. The
difference lies in the way we have implemented it. It does behave
slightly differently, however. Just try to resize it to see.
\section1 Exercises
Try to create another MyWidget object in main(). What happens?
Try to add more buttons or put in widgets other than QPushButton.
You may now go on to \link t5.html Chapter 5.\endlink
[\link t3.html Previous tutorial\endlink]
[\link t5.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \page t5.html
\title Qt Tutorial - Chapter 5: Building Blocks
<center><img src="t5.png" alt="Screenshot of tutorial five"></center>
This example shows how to create and connect together several widgets
by using signals and slots, and how to handle resize events.
\include t5/main.cpp
\quotefile t5/main.cpp
\section1 Line-by-line Walkthrough
\skipto qapp
\printuntil qvbox
Three new include files are shown here. qslider.h and qlcdnumber.h are there
because we use two new widgets, QSlider and QLCDNumber. qvbox.h is
here because we use Qt's automatic layout support.
\skipto MyWidget
\printuntil }
\target constructor
\printuntil {
MyWidget is now derived from QVBox instead of QWidget. That way we use
the layout of the QVBox (which places all of its children vertically
inside itself). Resizes are now handled automatically by the QBVox and
therefore by MyWidget, too.
\skipto lcd
\printline lcd
\c lcd is a QLCDNumber, a widget that displays numbers in an LCD-like
fashion. This instance is set up to display two digits and to be a child of
\e this. It is named "lcd".
\printline QSlider
\printline slider
\printline slider
QSlider is a classical slider; the user can use the widget to drag
something to adjust an integer value in a range. Here we create a
horizontal one, set its range to 0-99 (inclusive, see the \l
QSlider::setRange() documentation) and its initial value to 0.
\printline connect
Here we use the \link signalsandslots.html signal/slot mechanism \endlink
to connect the slider's valueChanged() signal to the LCD number's
display() slot.
Whenever the slider's value changes it broadcasts the new value by
emitting the valueChanged() signal. Because that signal is connected to
the LCD number's display() slot, the slot is called when the signal is
broadcast. Neither of the objects knows about the other. This is
essential in component programming.
Slots are otherwise normal C++ member functions and follow the normal
C++ access rules.
\section1 Behavior
The LCD number reflects everything you do to the slider, and the
widget handles resizing well. Notice that the LCD number widget
changes in size when the window is resized (because it can), but the
others stay about the same (because otherwise they would look stupid).
\section1 Exercises
Try changing the LCD number to add more digits or \link
QLCDNumber::setMode() to change mode.\endlink You can even add four push
buttons to set the number base.
You can also change the slider's range.
Perhaps it would have been better to use \l QSpinBox than a slider?
Try to make the application quit when the LCD number overflows.
You may now go on to \link t6.html Chapter 6.\endlink
[\link t4.html Previous tutorial\endlink]
[\link t6.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \page t6.html
\title Qt Tutorial - Chapter 6: Building Blocks Galore!
<center><img src="t6.png" alt="Screenshot of tutorial six"></center>
This example shows how to encapsulate two widgets into a new component and
how easy it is to use many widgets. For the first time, we use a custom
widget as a child widget.
\target main
\include t6/main.cpp
\quotefile t6/main.cpp
\section1 Line-by-line Walkthrough
\skipto LCDRange
\printuntil };
The LCDRange widget is a widget without any API. It just has a
constructor. This sort of widget is not very useful, so we'll add some API later.
\printuntil }
This is lifted straight from the
\link t5.html#constructor MyWidget constructor \endlink in Chapter 5.
The only differences are that the button is left out and the class
is renamed.
\printline MyWidget
\printuntil }
MyWidget, too, contains no API except a constructor.
\printline MyWidget
\printuntil connect
The push button that used to be in what is now LCDRange has been
separated so that we can have one "Quit" button and many LCDRange
objects.
\printline grid
We create a QGrid object with four columns. The QGRid widget
automatically arranges its children in rows and columns; you can
specify the number of rows or of columns, and QGrid will discover its
new children and fit them into the grid.
\printline for
\printline for
\printline LCDRange
Four columns, four rows.
We create 4*4 LCDRanges, all of which are children of the grid object.
The QGrid widget will arrange them.
\printline }
That's all.
\section1 Behavior
This program shows how easy it is to use many widgets at a time. Each
one behaves like the slider and LCD number in the previous
chapter. Again, the difference lies in the implementation.
\section1 Exercises
Initialize each slider with a different/random value on startup.
The source contains three occurrences of "4". What happens if you
change the one in the \l QGrid constructor call? What about the other
two? Why is this?
You may now go on to \link t7.html Chapter 7.\endlink
[\link t5.html Previous tutorial\endlink]
[\link t7.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t7/lcdrange.h */
/*! \file t7/lcdrange.cpp */
/*! \file t7/main.cpp */
/*! \file t7/Makefile */
/*! \page t7.html
\title Qt Tutorial - Chapter 7: One Thing Leads to Another
<center><img src="t7.png" alt="Screenshot of tutorial seven"></center>
This example shows how to create custom widgets with signals and
slots, and how to connect them together in more complex ways. For the
first time, the source is split among several files.
\list
\i \l t7/lcdrange.h contains the LCDRange class definition.
\i \l t7/lcdrange.cpp contains the LCDRange implementation.
\i \l t7/main.cpp contains MyWidget and main.
\i \l t7/Makefile contains some rules for generating the meta object
information necessary for \link signalsandslots.html signal/slot
creation \endlink
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t7/lcdrange.h
This file is mainly lifted from \link t6.html#main main.cpp \endlink in
Chapter 6; only the changes are noted here.
\quotefile t7/lcdrange.h
\skipto ifndef
\printuntil define
This is the classic C construction to avoid errors if a header file
happens to be included more than once. If you don't use it already,
it is a very good habit to develop. The #ifndef should enclose \e all of the
header file.
\printline include
\c qvbox.h is included. LCDRange inherits QVBox, and the header file
of a parent class must always be included. We cheated a bit in the
previous chapters, and we let \c qwidget.h be included indirectly via
other header files such as \c qpushbutton.h.
\printline QSlider
This is another classic trick, but one that's much less used often. Because
we don't need QSlider in the \e interface of the class, only in the
implementation, we use a forward declaration of the class in the
header file and include the header file for QSlider in the .cpp
file.
This makes the compilation of big projects much faster, because when a
header file has changed, fewer files need to be recompiled. It can
often speed up big compilations by a factor of two or more.
\skipto LCDRange
\printuntil parent=0
Note the Q_OBJECT. This macro must be included in \e all classes that
contain signals and/or slots. If you are curious, it defines the
functions that are implemented in the
\link metaobjects.html meta object file \endlink.
\printline value
\printuntil valueChanged
These three members make up an interface between this widget and other
components in a program. Until now, LCDRange didn't really have an
interface at all.
value() is a public function for accessing the value of the LCDRange.
setValue() is our first custom slot and valueChanged() is our first
custom signal.
Slots must be implemented in the normal way (remember that a slot is also
a C++ member function). Signals are automatically implemented in the
\link signalsandslots.html meta object\endlink file. Signals follow the
access rules of protected C++ functions (i.e., they can be emitted only
by the class they are defined in or by classes inheriting from it).
The signal valueChanged() is used when the LCDRange's value has
changed - just as you guessed from the name. This is not the last
signal you'll see called <i>something</i>Changed().
\section2 \l t7/lcdrange.cpp
\quotefile t7/lcdrange.cpp
This file is mainly lifted from \link t6.html#main t6/main.cpp \endlink, and
only the changes are noted here.
\skipto connect
\printline connect
\printline display
\printline connect
\printline valueChanged
This code is from the LCDRange constructor.
The first connect is the same that you have seen in the previous chapter.
The second is new; it connects slider's valueChanged() signal to this
object's valueChanged \e signal. Connect() with 3 arguments always
connects to signals or slots in \c this object.
Yes, that's right. Signals can be connected to other signals. When
the first is emitted, the second signal is also emitted.
Let's look at what happens when the user operates the slider. The
slider sees that its value has changed and emits the valueChanged()
signal. That signal is connected both to the display() slot of the
QLCDNumber and to the valueChanged() signal of the LCDRange.
Thus, when the signal is emitted, LCDRange emits its own
valueChanged() signal. In addition, QLCDNumber::display() is called
and shows the new number.
Note that you're not guaranteed any particular order of execution -
LCDRange::valueChanged() may be emitted before or after
QLCDNumber::display()and is entirely arbitrary.
\skipto LCDRange::value
\printuntil }
The implementation of value() is straightforward; it simply returns
the slider's value.
\printline setValue
\printuntil }
The implementation of setValue() is equally straightforward. Note
that because the slider and LCD number are connected, setting the
slider's value automatically updates the LCD number as well. In
addition, the slider will automatically adjust the value if it is
outside its legal range.
\section2 \l t7/main.cpp
\quotefile t7/main.cpp
\skipto previous
\printline previous
\printuntil setValue
\printline previous
\printline }
\printline }
All of main.cpp is copied from the previous chapter except in
the constructor for MyWidget. When we create the 16 LCDRange object, we
now connect them using the \link signalsandslots.html
signal/slot\endlink mechanism. Each has its valueChanged() signal
connected to the setValue() slot in the previous one. Because LCDRange
emits the signal valueChanged() when its value changes (surprise!), we
are here creating a "chain" of signals and slots.
\section1 Behavior
On startup, the program's appearance is identical to the previous one.
Try operating the slider to the bottom right...
\section1 Exercises
Use the bottom right slider to set all LCDs to 50. Then set the top
half to 40 by clicking once to the left of the slider handle. Now,
use the one to the left of the last one operated to set the first
seven LCDs back to 50.
Click to the left of the handle on the bottom right slider. What
happens? Why is this the correct behavior?
You may now go on to \link t8.html Chapter 8.\endlink
[\link t6.html Previous tutorial\endlink]
[\link t8.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t8/lcdrange.h */
/*! \file t8/lcdrange.cpp */
/*! \file t8/cannon.h */
/*! \file t8/cannon.cpp */
/*! \file t8/main.cpp */
/*! \file t8/Makefile */
/*! \page t8.html
\title Qt Tutorial - Chapter 8: Preparing for Battle
<center><img src="t8.png" alt="Screenshot of tutorial eight"></center>
In this example, we introduce the first custom widget that can paint
itself. We also add a useful keyboard interface (with two lines of
code).
\list
\i \l t8/lcdrange.h contains the LCDRange class definition.
\i \l t8/lcdrange.cpp contains the LCDRange implementation.
\i \l t8/cannon.h contains the CannonField class definition.
\i \l t8/cannon.cpp contains the CannonField implementation.
\i \l t8/main.cpp contains MyWidget and main.
\i \l t8/Makefile contains some rules for generating the meta object
information necessary for \link signalsandslots.html signal/slot creation
\endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t8/lcdrange.h
This file is very similar to the lcdrange.h in Chapter 7. We have added
one slot: setRange().
\quotefile t8/lcdrange.h
\skipto setRange
\printline setRange
We now add the possibility of setting the range of the LCDRange.
Until now, it has been fixed at 0..99.
\section2 \l t8/lcdrange.cpp
\quotefile t8/lcdrange.cpp
There is a change to the constructor (we'll discuss that later).
\skipto ::setRange
\printuntil slider
\printline }
SetRange() sets the range of the slider in the LCDRange. Because we
have set up the QLCDNumber to always display two digits, we want to
limit the possible range of \c minVal and \c maxVal to 0..99 to avoid
overflow of the QLCDNumber. (We could have allowed values down to -9
but chose not to.) If the arguments are illegal, we use Qt's
qWarning() function to issue a warning to the user and return
immediately. qWarning() is a printf-like function that by default
sends its output to \c stderr. If you want, you can install your own handler
function using \l ::qInstallMsgHandler().
\section2 \l t8/cannon.h
CannonField is a new custom widget that knows how to display itself.
\quotefile t8/cannon.h
\skipto include
\skipto class
\printuntil parent=0
CannonField inherits QWidget, and we use the same idiom as for LCDRange.
\printuntil angleChanged
For the time being, CannonField only contains an angle value for which we
provide an interface using the same idiom as for value in LCDRange.
\printline protected
\printline paintEvent
This is the second of the many event handlers in QWidget that we
encounter. This virtual function is called by Qt whenever a widget needs
to update itself (i.e., paint the widget's surface).
\section2 \l t8/cannon.cpp
\quotefile t8/cannon.cpp
\skipto ::CannonField
\printuntil {
Again, we use the same idiom as for LCDRange in the previous chapter.
\printuntil }
The constructor initializes the angle value to 45 degrees and sets a
custom palette for this widget.
This palette uses the indicated color as background and picks other
colors suitably. (For this widget only the background and text
colors will actually be used.)
\skipto ::setAngle
\printuntil emit
\printline }
This function sets the angle value. We have chosen a legal range of
5..70 and adjust the given number of degrees accordingly. We have
chosen not to issue a warning if the new angle is out of range.
If the new angle equals the old one, we return immediately. It is
important to only emit the signal angleChanged() when the angle \e
really has changed.
Then we set the new angle value and repaint our widget. The \l
QWidget::repaint() function clears the widget (usually filling it with
its background color) and sends a paint event to the widget. This
results in a call to the paint event function of the widget.
Finally, we emit the angleChanged() signal to tell the outside world
that the angle has changed. The \c emit keyword is unique to Qt and
not regular C++ syntax. In fact, it is a macro.
\skipto ::paintEvent
\printuntil drawText
\printline }
This is our first attempt to write a paint event handler. The event
argument contains a description of the paint event. \l QPaintEvent
contains the region in the widget that must be updated. For the time
being, we will be lazy and just paint everything.
Our code displays the angle value in the widget at a fixed position.
First we create a QString with some text and the angle; then we create
a QPainter operating on this widget and use it to paint the string.
We'll come back to QPainter later; it can do a great many things.
\section2 \l t8/main.cpp
\quotefile t8/main.cpp
\skipto cannon.h
\printline cannon.h
We include our new class.
\skipto MyWidget
\printuntil };
This time we include a single LCDRange and a CannonField in our top-level
widget.
\skipto angle
\printline angle
In the constructor, we create and set up our LCDRange.
\printline setRange
We set the LCDRange to accept ranges from 5 to 70 degrees.
\printline cannonField
\printline CannonField
We create our CannonField.
\printuntil setValue
Here we connect the valueChanged() signal of the LCDRange to the
setAngle() slot of the CannonField. This will update CannonField's angle
value whenever the user operates the LCDRange. We also make the reverse
connection so that changing the angle in the CannonField will update the
LCDRange value. In our example we never change the angle of the
CannonField directly; but by doing the last connect() we ensure that no
future changes will disrupt the synchronization between those two values.
This illustrates the power of component programming and proper
encapsulation.
Notice how important it is to emit the angleChanged() signal only when
the angle actually changes. If both the LCDRange and the CannonField
had omitted this check, the program would have entered an infinite
loop upon the first change of one of the values.
\printline QGridLayout
\printline 2x2
So far we have used the no-assembly-required QVBox and QGrid widgets
for geometry management. Now, however, we want to have a little more
control over the layout, and we switch to the more powerful QGridLayout
class. QGridLayout isn't a widget; it is a different class that can
manage the children of \e any widget.
As the comment indicates, we create a two-by-two array with ten pixel
borders. (The constructor for \l QGridLayout can be a little cryptic,
so it's good to put in such comments.)
\printline addWidget
We add the Quit button in the top-left cell of the grid: 0, 0.
\printline addWidget
We put the angle LCDRange in the bottom-left cell, aligned to the top
of its cell. (This alignment is one of the things QGridLayout allows
but QGrid does not allow.)
\printline addWidget
We put the CannonField object in the bottom-right cell. (The top-
right cell is empty.)
\printline setColStretch
We tell QGridLayout that the right column (column 1) is stretchable.
Because the left column isn't (it has stretch factor 0, the default
value), QGridLayout will try to let the left-hand widgets' sizes be
unchanged and will resize just the CannonField when the MyWidget is
resized.
\printline setValue
We set an initial angle value. Note that this will trigger the
connection from LCDRange to CannonField.
\printline setFocus
Our last action is to set \c angle to have keyboard focus so that
keyboard input will go to the LCDRange widget by default.
LCDRange does not contain any keyPressEvent(), so that would seem not
to be terribly useful. However, its constructor just got a new line:
\quotefile t8/lcdrange.cpp
\skipto setFocusProxy
\printline setFocusProxy
The LCDRange sets the slider to be its focus proxy. That means that
when someone (the program or the user) wants to give the LCDRange
keyboard focus, the slider should take care of it. QSlider has a decent
keyboard interface, so with just one line of code we've given LCDRange
one.
\section1 Behavior
The keyboard now does something - the arrow keys, Home, End, PageUp
and PageDown all do something vaguely sensible.
When the slider is operated, the CannonField displays the new angle
value. Upon resizing, CannonField is given as much space as possible.
On Windows machines with an 8-bit display the new background color is
dithered to death. The next chapter works around this.
\section1 Exercises
Try to resize the window. What happens if you make it really narrow
or really squat?
If you remove the AlignTop, what happens to the LCDRange's position
and size? Why?
If you give the left-hand column a non-zero stretch factor, what
happens when you resize the window?
Leave out the setFocus() call. Which behavior do you prefer?
Try to change "Quit" to "&Quit" in the QButton::setText() call. How
does the button's look change? What happens if you press Alt+Q while
the program's running? (It is Meta+Q on a few keyboards.)
Center the text in the CannonField.
You may now go on to \link t9.html Chapter 9.\endlink
[\link t7.html Previous tutorial\endlink]
[\link t9.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t9/lcdrange.h */
/*! \file t9/lcdrange.cpp */
/*! \file t9/cannon.h */
/*! \file t9/cannon.cpp */
/*! \file t9/main.cpp */
/*! \file t9/Makefile */
/*! \page t9.html
\title Qt Tutorial - Chapter 9: With Cannon You Can
<center><img src="t9.png" alt="Screenshot of tutorial nine"></center>
In this example we become graphic by drawing a cute little blue
cannon. Only cannon.cpp differs from the previous chapter.
\list
\i \l t9/lcdrange.h contains the LCDRange
class definition.
\i \l t9/lcdrange.cpp contains the LCDRange
implementation.
\i \l t9/cannon.h contains the CannonField class
definition.
\i \l t9/cannon.cpp contains the CannonField
implementation.
\i \l t9/main.cpp contains MyWidget and main.
\i \l t9/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t9/cannon.cpp
\quotefile t9/cannon.cpp
\skipto ::paintEvent
\printuntil QPainter
We'll now start to use QPainter in earnest. We create a painter that
operates on this widget.
\printline setBrush
When QPainter fills a rectangle, a circle, or whatever, it fills the
shape using its brush. Here we set it to use a blue brush. (We
could also use a pattern.)
\printline setPen
And the edges of what QPainter draws are drawn using the pen. Here we
set it to NoPen, meaning that there will be no special edge when we
draw something; the blue brush will go all the way to the edges of
the things we draw.
\skipto translate
\printline translate
The \l QPainter::translate() function translates the coordinate
system of the QPainter; i.e., it moves it by an offset. Here we set
the (0, 0) point to the bottom-left corner of the widget. The x and
y directions remain unchanged, i.e., all the y coordinates inside the
widget are now negative (see \link coordsys.html The Coordinate
System\endlink for more information about Qt's coordinate system).
\printline drawPie
The drawPie() function draws a pie shape inside the specified
rectangle using a start angle and an arc length. The angles are
specified in 1/16th of a degree. Zero degrees is at the 3 o'clock
position. The drawing direction is counter-clockwise. Here we draw a
quarter of a circle in the bottom-left corner of the widget. The pie
is filled with blue and has no outline.
\printline rotate
The QPainter::rotate() function rotates the coordinate system of the
QPainter around the origin. The rotation argument is a \c float given
in degrees (not given in 1/16th of a degree as above) and clockwise.
Here we rotate the coordinate system \c ang degrees counter-clockwise.
\printline drawRect
The QPainter::drawRect() function draws the specified rectangle. Here
we draw the barrel of the cannon.
It can often be difficult to envision the resulting drawing when the
coordinate system has been transformed (translated, rotated, scaled, or
sheared) as above.
In this case the coordinate system is first translated and then rotated.
If the rectangle QRect(33, -4, 15, 8) had been drawn in the translated
coordinate system, it would have looked like this:
<img src="t9_1.png" alt="The cannon translated but not rotated">.
Note that the rectangle is clipped by the border of the CannonField
widget. When we rotate the coordinate system, for instance 60
degrees, the rectangle will be rotated around (0, 0), which is the
bottom-left corner because we have translated the coordinate system.
The result looks like this:
<img src="t9_2.png" alt="The cannon translated and rotated">.
We're done, except that we haven't explained why Windows didn't dither
this time.
\quotefile t9/main.cpp
\skipto main
\printline main
\printline {
\printline CustomColor
\printline QApplication
We tell Qt that we want a different color-allocation strategy for this
program. There is no single correct color-allocation strategy. Because
this program uses an unusual yellow but not many colors, \c
CustomColor is best. There are several other allocation strategies; you can read about them in the \l QApplication::setColorSpec()
documentation.
Mostly you can ignore this, since the default is good. Occasionally
some applications with unusual color use look bad; changing the
allocation strategy often helps then.
\section1 Behavior
When the slider is operated the angle of the drawn cannon changes
accordingly.
The Q on the Quit button is now underlined, and Alt+Q does what you
think it does. If you do not know why, you didn't do the exercises in
Chapter 8.
You may notice that the cannon flickers annoyingly, especially on a
slow machine. We'll fix this in the next chapter.
\section1 Exercises
Set a different pen instead of NoPen. Set a patterned brush.
Try "Q&uit" or "Qu&it" as button text instead of "&Quit". What
happens?
You may now go on to \link t10.html Chapter 10.\endlink
[\link t8.html Previous tutorial\endlink]
[\link t10.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t10/lcdrange.h */
/*! \file t10/lcdrange.cpp */
/*! \file t10/cannon.h */
/*! \file t10/cannon.cpp */
/*! \file t10/main.cpp */
/*! \file t10/Makefile */
/*! \page t10.html
\title Qt Tutorial - Chapter 10: Smooth as Silk
<center><img src="t10.png" alt="Screenshot of tutorial ten"></center>
In this example, we introduce painting in a pixmap to remove flickering.
We also add a force control.
\list
\i \l t10/lcdrange.h contains the LCDRange
class definition.
\i \l t10/lcdrange.cpp contains the LCDRange
implementation.
\i \l t10/cannon.h contains the CannonField class
definition.
\i \l t10/cannon.cpp contains the CannonField
implementation.
\i \l t10/main.cpp contains MyWidget and main.
\i \l t10/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t10/cannon.h
The CannonField now has a force value in addition to the angle.
\quotefile t10/cannon.h
\skipto angle
\printuntil forceChanged
The interface to the force follows the same practice as for the angle.
\skipto private
\printuntil cannonRect
We have put the definition of the cannon's enclosing rectangle in a
separate function.
\skipto ang
\printuntil };
The force is stored in the integer \c f.
\section2 \l t10/cannon.cpp
\quotefile t10/cannon.cpp
\skipto include
\skipto pixmap
\printline pixmap
We include the QPixmap class definition.
\skipto ::CannonField
\printuntil }
The force (\c f) is initialized to zero.
\skipto ::setAngle
\printuntil }
We have made a slight change in the setAngle() function. It repaints
only the portion of the widget that contains the cannon. The FALSE
argument indicates that the specified rectangle should not be erased
before a paint event is sent to the widget. This speeds up and smooths
the drawing a little bit.
\skipto ::setForce
\printuntil }
The implementation of setForce() is quite similar to that of
setAngle(). The only difference is that because we don't show the force
value, we don't need to repaint the widget.
\skipto ::paintEvent
\printuntil return
We have now optimized the paint event to repaint only the parts of the
widget that need updating. First we check whether we have to paint
anything at all, and we return if we don't.
\printline cannonRect
\printline pix
Then we create a temporary pixmap, which we use for flicker-free
painting. All the painting operations are done into this pixmap, and
then the pixmap is drawn on the screen in a single operation.
This is the essence of flicker-free drawing: Draw on each pixel
precisely once. Less, and you get drawing errors. More, and you get
flicker. It doesn't matter much in this example - when the code was
written there were still machines slow enough for it to flicker, but
not any more. We've kept the code for educational purposes.
\printline fill
We fill the pixmap with the background from this widget.
\printline QPainter
\printuntil end
We paint, as in Chapter 9, but now we paint in the pixmap.
At this point, we have a painter variable and a pixmap that looks
precisely right, but we still haven't painted on the screen.
\printline begin
\printline drawPixmap
So we open the painter on the CannonField itself and then draw the pixmap.
That's all. A couple of extra lines at the top and a couple at the
bottom, and the code is 100% flicker-free.
\skipto cannonRect
\printuntil }
This function returns the rectangle enclosing the cannon in widget
coordinates. First we create a rectangle with the size 50x50 and then
move it so its bottom left corner is equal to the widget's own bottom-
left corner.
The \l QWidget::rect() function returns the widget's enclosing
rectangle in the widget's own coordinates (where the top left corner
is 0, 0).
\section2 \l t10/main.cpp
\quotefile t10/main.cpp
\skipto MyWidget::MyWidget
\printuntil {
The constructor is mostly the same, but some new bits have been added.
\skipto force
\printline force
\printline force
We add a second LCDRange, which will be used to set the force.
\skipto force
\printline connect
\printline cannonField
\printline connect
\printline force
We connect the \c force widget and the \c cannonField widget, just like
we did for the \c angle widget.
\skipto QVBoxLayout
\printline QVBoxLayout
\printline addLayout
\printline addWidget
\printline addWidget
In Chapter 9 we put \c angle in the lower-left cell of the layout.
Now we want to have two widgets in that cell, so we make a vertical
box, put the vertical box in the grid cell, and put each of \c angle
and \c range in the vertical box.
\skipto force
\printline setValue
We initialize the force value to 25.
\section1 Behavior
The flicker has gone and we have a force control.
\section1 Exercises
Make the size of the cannon barrel be dependent on the force.
Put the cannon in the bottom-right corner.
Try adding a better keyboard interface. For example, make + and -
increase and decrease the force and enter shoot. Hint: \l QAccel and
new addStep() and subtractStep() slots in LCDRange, like \l
QSlider::addStep(). If you're bothered by the way the left and right
keys work (I am!), change that too.
You may now go on to \link t11.html Chapter 11.\endlink
[\link t9.html Previous tutorial\endlink]
[\link t11.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t11/lcdrange.h */
/*! \file t11/lcdrange.cpp */
/*! \file t11/cannon.h */
/*! \file t11/cannon.cpp */
/*! \file t11/main.cpp */
/*! \file t11/Makefile */
/*! \page t11.html
\title Qt Tutorial - Chapter 11: Giving It a Shot
<center><img src="t11.png" alt="Screenshot of tutorial eleven"></center>
In this example we introduce a timer to implement animated shooting.
\list
\i \l t11/lcdrange.h contains the LCDRange
class definition.
\i \l t11/lcdrange.cpp contains the LCDRange
implementation.
\i \l t11/cannon.h contains the CannonField class
definition.
\i \l t11/cannon.cpp contains the CannonField
implementation.
\i \l t11/main.cpp contains MyWidget and main.
\i \l t11/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t11/cannon.h
The CannonField now has shooting capabilities.
\quotefile t11/cannon.h
\skipto shoot
\printline shoot
Calling this slot will make the cannon shoot if a shot is not in the air.
\printline private
\printline moveShot
This private slot is used to move the shot while it is in the air,
using a \l QTimer.
\skipto private
\printline private
\printline paintShot
This private function paints the shot.
\skipto shotRect
\printline shotRect
This private function returns the shot's enclosing rectangle if
one is in the air; otherwise the returned rectangle is undefined.
\skipto timerCount
\printuntil shoot_f
\printline };
These private variables contain information that describes the shot. The
\c timerCount keeps track of the time passed since the shot was fired.
The \c shoot_ang is the cannon angle and \c shoot_f is the cannon force
when the shot was fired.
\section2 \l t11/cannon.cpp
\quotefile t11/cannon.cpp
\skipto include
\skipto math
\printline math
We include the math library because we need the sin() and cos() functions.
\skipto ::CannonField
\printuntil }
We initialize our new private variables and connect the \l
QTimer::timeout() signal to our moveShot() slot. We'll move the
shot every time the timer times out.
\skipto ::shoot
\printuntil start
\printline }
This function shoots a shot unless a shot is in the air. The \c timerCount
is reset to zero. The \c shoot_ang and \c shoot_f are set to the current
cannon angle and force. Finally, we start the timer.
\skipto ::moveShot
\printuntil repaint
\printline }
moveShot() is the slot that moves the shot, called every 50
milliseconds when the QTimer fires.
Its tasks are to compute the new position, repaint the screen with the
shot in the new position, and if necessary, stop the timer.
First we make a \l QRegion that holds the old shotRect(). A QRegion
is capable of holding any sort of region, and we'll use it here to
simplify the painting. ShotRect() returns the rectangle where the
shot is now - it is explained in detail later.
Then we increment the \c timerCount, which has the effect of moving the
shot one step along its trajectory.
Next we fetch the new shot rectangle.
If the shot has moved beyond the right or bottom edge of the widget, we
stop the timer or we add the new shotRect() to the QRegion.
Finally, we repaint the QRegion. This will send a single paint event
for just the one or two rectangles that need updating.
\skipto ::paintEvent
\printuntil }
The paint event function has been split in two since the previous
chapter. Now we fetch the bounding rectangle of the region that
needs painting, check whether it intersects either the cannon and/or
the shot, and if necessary, call paintCannon() and/or paintShot().
\skipto ::paintShot
\printuntil drawRect
\printline }
This private function paints the shot by drawing a black filled rectangle.
We leave out the implementation of paintCannon(); it is the same as
the paintEvent() from the previous chapter.
\skipto ::shotRect
\printuntil return
\printline }
This private function calculates the center point of the shot and returns
the enclosing rectangle of the shot. It uses the initial cannon force and
angle in addition to \c timerCount, which increases as time passes.
The formula used is the classical Newtonian formula for frictionless
movement in a gravity field. For simplicity, we've chosen to
disregard any Einsteinian effects.
We calculate the center point in a coordinate system where y
coordinates increase upward. After we have calculated the center
point, we construct a QRect with size 6x6 and move its center point to
the point calculated above. In the same operation we convert the
point into the widget's coordinate system (see \link coordsys.html The
Coordinate System\endlink).
The qRound() function is an inline function defined in qglobal.h (included
by all other Qt header files). qRound() rounds a double to the closest
integer.
\section2 \l t11/main.cpp
\quotefile t11/main.cpp
\skipto class
\printuntil };
The only addition is the Shoot button.
\skipto ::MyWidget
\skipto shoot
\printuntil setFont
In the constructor we create and set up the Shoot button exactly like we
did with the Quit button. Note that the first argument to the constructor
is the button text, and the third is the widget's name.
\skipto connect
\printline connect
Connects the clicked() signal of the Shoot button to the shoot() slot
of the CannonField.
\section1 Behavior
The cannon can shoot, but there's nothing to shoot at.
\section1 Exercises
Make the shot a filled circle. Hint: \l QPainter::drawEllipse() may
help.
Change the color of the cannon when a shot is in the air.
You may now go on to \link t12.html Chapter 12.\endlink
[\link t10.html Previous tutorial\endlink]
[\link t12.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t12/lcdrange.h */
/*! \file t12/lcdrange.cpp */
/*! \file t12/cannon.h */
/*! \file t12/cannon.cpp */
/*! \file t12/main.cpp */
/*! \file t12/Makefile */
/*! \page t12.html
\title Qt Tutorial - Chapter 12: Hanging in the Air the Way Bricks Don't
<center><img src="t12.png" alt="Screenshot of tutorial twelve"></center>
In this example, we extend our LCDRange class to include a text label.
We also provide something to shoot at.
\list
\i \l t12/lcdrange.h contains the LCDRange
class definition.
\i \l t12/lcdrange.cpp contains the LCDRange
implementation.
\i \l t12/cannon.h contains the CannonField class
definition.
\i \l t12/cannon.cpp contains the CannonField
implementation.
\i \l t12/main.cpp contains MyWidget and main.
\i \l t12/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t12/lcdrange.h
The LCDRange now has a text label.
\quotefile t12/lcdrange.h
\skipto QLabel
\printline QLabel
We name declare QLabel because we want to use a pointer to it in the class
definition.
\skipto class
\printuntil parent=0
\printline parent=0
\printline name=0
We have added a new constructor that sets the label text in addition to
the parent and name.
\skipto text
\printline text
This function returns the label text.
\skipto setText
\printline setText
This slot sets the label text.
\skipto private
\printuntil init
Because we now have two constructors, we have chosen to put the common
initialization in the private init() function.
\skipto QLabel
\printline label
We also have a new private variable: a QLabel. QLabel is one of Qt's
standard widgets and can show a text or a pixmap with or without a
frame.
\section2 \l t12/lcdrange.cpp
\quotefile t12/lcdrange.cpp
\skipto qlabel
\printline include
Here we include the QLabel class definition.
\skipto ::LCDRange
\printuntil }
This constructor calls the init() function, which contains the common
initialization code.
\skipto ::LCDRange
\printuntil }
This constructor first calls init() and then sets the label text.
\skipto ::init
\printuntil }
The setup of \c lcd and \c slider is the same as in the previous
chapter. Next we create a QLabel and tell it to align the contents
centered (both vertically and horizontally). The connect() statements
have also been taken from the previous chapter.
\skipto ::text
\printuntil }
This function returns the label text.
\skipto ::setText
\printuntil }
This function sets the label text.
\section2 \l t12/cannon.h
The CannonField now has two new signals: hit() and missed(). In addition
it contains a target.
\quotefile t12/cannon.h
\skipto slots
\skipto newTarget
\printline newTarget
This slot creates a target at a new position.
\skipto signals
\printuntil missed
The hit() signal is emitted when a shot hits the target. The missed()
signal is emitted when the shot moves beyond the right or bottom edge
of the widget (i.e., it is certain that it has not and will not
hit the target).
\skipto paintTarget
\printline paintTarget
This private function paints the target.
\skipto targetRect
\printline targetRect
This private function returns the enclosing rectangle of the target.
\skipto target
\printline target
This private variable contains the center point of the target.
\section2 \l t12/cannon.cpp
\quotefile t12/cannon.cpp
\skipto qdatetime
\printline qdatetime
We include the QDate, QTime, and QDateTime class definitions.
\skipto stdlib
\printline stdlib
We include the stdlib library because we need the rand() function.
\skipto newTarget
\printline newTarget
This line has been added to the constructor. It creates a "random"
position for the target. In fact, the newTarget() function will try
to paint the target. Because we are in a constructor, the CannonField
widget is invisible. Qt guarantees that no harm is done when calling
repaint() on a hidden widget.
\skipto ::newTarget
\printuntil repaint
\printline }
This private function creates a target center point at a new "random"
position.
We use the rand() function to fetch random integers. The rand() function
normally returns the same series of numbers each time you run a program.
This would make the target appear at the same position every time. To
avoid this, we must set a random seed the first time this function is
called. The random seed must also be random in order to avoid equal random
number series. The solution is to use the number of seconds that have
passed since midnight as a pseudo-random value.
First we create a static bool local variable. A static variable like
this one is guaranteed to keep its value between calls to the function.
The \c if test will succeed only the first time this function is called
because we set \c first_time to FALSE inside the \c if block.
Then we create the QTime object \c midnight, which represents the time
00:00:00. Next we fetch the number of seconds from midnight until
now and use it as a random seed. See the documentation for \l QDate,
\l QTime, and \l QDateTime for more information.
Finally we calculate the target's center point. We keep it within
the rectangle (x=200, y=35, width=190, height=255), (i.e., the
possible x and y values are x = 200..390 and y = 35..290) in a
coordinate system where we put y position 0 at the bottom edge of the
widget and let y values increase upwards X is as normal, with 0 at
the left edge and with x values increasing to the right.
By experimentation we have found this to always be in reach of the shot.
Note that rand() returns a random integer >= 0.
\skipto ::moveShot
\printuntil QRect
This part of the timer event has not changed from the previous chapter.
\printuntil hit
This \c if statement checks whether the shot rectangle intersects the
target rectangle. If it does, the shot has hit the target (ouch!).
We stop the shoot timer and emit the hit() signal to tell the outside
world that a target was destroyed, and return.
Note that we could have created a new target on the spot, but because the
CannonField is a component we leave such decisions to the user of the
component.
\printuntil missed
This \c if statement is the same as in the previous chapter, except that
it now emits the missed() signal to tell the outside world about the
failure.
\printuntil }
And the rest of the function is as before.
CannonField::paintEvent() is as before, except that this has been
added:
\skipto ::paintEvent
\skipto targetRect
\printline updateR
\printline paintTarget
These two lines make sure that the target is also painted when necessary.
\skipto ::paintTarget
\printuntil }
This private function paints the target; a rectangle filled with red and
with a black outline.
\skipto ::targetRect
\printuntil }
This private function returns the enclosing rectangle of the target.
Remember from newTarget() that the \c target point uses y coordinate 0 at
the bottom of the widget. We calculate the point in widget coordinates
before we call \l QRect::moveCenter().
The reason we have chosen this coordinate mapping is to fix the distance
between the target and the bottom of the widget. Remember that the widget
can be resized by the user or the program at any time.
\section2 \l t12/main.cpp
\quotefile t12/main.cpp
There are no new members in the MyWidget class, but we have slightly
changed the constructor to set the new LCDRange text labels.
\skipto ::MyWidget
\skipto angle
\printline ANGLE
We set the angle text label to "ANGLE".
\skipto force
\printline FORCE
We set the force text label to "FORCE".
\section1 Behavior
The cannon can shoot at a target; a new target is automatically created
when one has been hit.
The LCDRange widgets look a bit strange - the built-in layout
management in QVBox gives the labels too much space and the rest not
enough. We'll fix that in the next chapter.
\section1 Exercises
Make a cheat button that, when pressed, makes the CannonField display
the shot trajectory for five seconds.
If you did the "round shot" exercise from the previous chapter, try
changing the shotRect() to a shotRegion() that returns a \l QRegion so
you can have really accurate collision detection.
Make a moving target.
Make sure that the target is always created entirely on-screen.
Make sure that the widget cannot be resized so that the target isn't
visible. Hint: \l QWidget::setMinimumSize() is your friend.
Not easy; make it possible to have several shots in the air at the
same time. Hint: make a Shot object.
You may now go on to \link t13.html Chapter 13.\endlink
[\link t11.html Previous tutorial\endlink]
[\link t13.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t13/lcdrange.h */
/*! \file t13/lcdrange.cpp */
/*! \file t13/cannon.h */
/*! \file t13/cannon.cpp */
/*! \file t13/gamebrd.h */
/*! \file t13/gamebrd.cpp */
/*! \file t13/main.cpp */
/*! \file t13/Makefile */
/*! \page t13.html
\title Qt Tutorial - Chapter 13: Game Over
<center><img src="t13.png" alt="Screenshot of tutorial thirteen"></center>
In this example we start to approach a real playable game with a
score. We give MyWidget a new name (GameBoard) and add some slots.
We put the definition in gamebrd.h and the implementation in gamebrd.cpp.
The CannonField now has a game over state.
The layout problems in LCDRange are fixed.
\list
\i \l t13/lcdrange.h contains the LCDRange
class definition.
\i \l t13/lcdrange.cpp contains the LCDRange
implementation.
\i \l t13/cannon.h contains the CannonField class
definition
\i \l t13/cannon.cpp contains the CannonField
implementation.
\i \l t13/gamebrd.h contains the GameBoard
class definition.
\i \l t13/gamebrd.cpp contains the GameBoard
implementation.
\i \l t13/main.cpp contains MyWidget and main.
\i \l t13/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink.
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t13/lcdrange.h
\quotefile t13/lcdrange.h
\skipto include
\printuntil QWidget
We inherit QWidget rather than QVBox. QVBox is very easy to use, but
again it showed its limitations so we switch to the more powerful and
slightly harder to use QVBoxLayout. (As you remember, QVBoxLayout is
not a widget, it manages one.)
\section2 \l t13/lcdrange.cpp
\quotefile t13/lcdrange.cpp
\skipto layout
\printline layout
We need to include qlayout.h now to get the other layout management
API.
\printline LCDRange
\printline QWidget
We inherit QWidget in the usual way.
The other constructor has the same change. init() is unchanged,
except that we've added some lines at the end:
\skipto QVBoxLayout
\printline QVBoxLayout
We create a QVBoxLayout with all the default values, managing this
widget's children.
\printline addWidget
At the top we add the QLCDNumber with a non-zero stretch.
\printline addWidget
\printline addWidget
Then we add the other two, both with the default zero stretch.
This stretch control is something QVBoxLayout (and QHBoxLayout, and
QGridLayout) offers but classes like QVBox do not. In this case
we're saying that the QLCDNumber should stretch and the others should
not.
\section2 \l t13/cannon.h
The CannonField now has a game over state and a few new functions.
\quotefile t13/cannon.h
\skipto gameOver
\printline gameOver
This function returns TRUE if the game is over or FALSE if a game
is going on.
\skipto setGameOver
\printuntil restartGame
Here are two new slots: setGameOver() and restartGame().
\skipto canShoot
\printline canShoot
This new signal indicates that the CannonField is in a state where the
shoot() slot makes sense. We'll use it below to enable/disable the
Shoot button.
\skipto gameEnded
\printline gameEnded
This private variable contains the game state. TRUE means that the
game is over, and FALSE means that a game is going on.
\section2 \l t13/cannon.cpp
\quotefile t13/cannon.cpp
\skipto ::CannonField
\skipto gameEnded
\printline gameEnded
This line has been added to the constructor. Initially, the game is not
over (luckily for the player :-).
\skipto ::shoot
\printuntil }
We added a new isShooting() function, so shoot() uses it instead of
testing directly. Also, shoot tells the world that the CannonField
cannot shoot now.
\skipto ::setGameOver
\printuntil }
This slot ends the game. It must be called from outside CannonField,
because this widget does not know when to end the game. This is an
important design principle in component programming. We choose to
make the component as flexible as possible to make it usable with
different rules (for example, a multi-player version of this in which the
first player to hit ten times wins could use the CannonField unchanged).
If the game has already been ended we return immediately. If a game is
going on we stop the shot, set the game over flag, and repaint the entire
widget.
\skipto ::restartGame
\printuntil }
This slot starts a new game. If a shot is in the air, we stop shooting.
We then reset the \c gameEnded variable and repaint the widget.
moveShot() too emits the new canShoot(TRUE) signal at the same time as
either hit() or miss().
Modifications in CannonField::paintEvent():
\skipto ::paintEvent
\printuntil }
The paint event has been enhanced to display the text "Game Over" if
the game is over, i.e., \c gameEnded is TRUE. We don't bother to
check the update rectangle here because speed is not critical when
the game is over.
To draw the text we first set a black pen; the pen color is used
when drawing text. Next we choose a 48 point bold font from the
Courier family. Finally we draw the text centered in the widget's
rectangle. Unfortunately, on some systems (especially X servers with
Unicode fonts) it can take a while to load such a large font. Because
Qt caches fonts, you will notice this only the first time the font is
used.
\printuntil }
We draw the shot only when shooting and the target only when playing
(that is, when the game is not ended).
\section2 \l t13/gamebrd.h
This file is new. It contains the definition of the GameBoard class,
which was last seen as MyWidget.
\quotefile t13/gamebrd.h
\skipto include
\skipto class
\printuntil };
We have now added four slots. These are protected and are used internally.
We have also added two QLCDNumbers (\c hits and \c shotsLeft) which display
the game status.
\section2 \l t13/gamebrd.cpp
This file is new. It contains the implementation of the GameBoard
class, which was last seen as MyWidget.
\quotefile t13/gamebrd.cpp
We have made some changes in the GameBoard constructor.
\skipto ::GameBoard
\skipto cannonField
\printline cannonField
\c cannonField is now a member variable, so we carefully change the
constructor to use it. (The \e good programmers at Trolltech never
forget this, but I do. Caveat programmor - if "programmor" is Latin,
at least. Anyway, back to the code.)
\skipto hit
\printline connect
\printline hit
\printline connect
\printline missed
This time we want to do something when the shot has hit or missed the
target. Thus we connect the hit() and missed() signals of the
CannonField to two protected slots with the same names in this class.
\skipto shoot
\skipto connect
\printline fire
Previously we connected the Shoot button's clicked() signal directly
to the CannonField's shoot() slot. This time we want to keep track of
the number of shots fired, so we connect it to a protected slot in
this class instead.
Notice how easy it is to change the behavior of a program when you are
working with self-contained components.
\printline connect
\printline setEnabled
We also use the cannonField's canShoot() signal to enable or disable
the Shoot button appropriately.
\skipto restart
\printuntil connect
We create, set up, and connect the New Game button as we have done
with the other buttons. Clicking this button will activate the
newGame() slot in this widget.
\printuntil shotsLeftL
\printline QLabel
We create four new widgets. Note that we don't bother to keep the
pointers to the QLabel widgets in the GameBoard class because there's
nothing much we want to do with them. Qt will delete them when the
GameBoard widget is destroyed, and the layout classes will resize them
appropriately.
\skipto QHBoxLayout
\printuntil addStretch
\printline addWidget
The number of widgets in the top-right cell is getting large. Once it
was empty; now it's full enough that we group together the layout
setting for better overview.
Notice that we let all the widgets have their preferred sizes, instead
putting the stretch just to the left of the New Game button.
\skipto newGame
\printline newGame
\printline }
We're all done constructing the GameBoard, so we start it all using
newGame(). (NewGame() is a slot, but as we said, slots can be used as
ordinary functions, too.)
\skipto ::fire
\printuntil }
This function fires a shot. If the game is over or if there is a shot in the
air, we return immediately. We decrement the number of shots left and tell
the cannon to shoot.
\skipto ::hit
\printuntil }
This slot is activated when a shot has hit the target. We increment the
number of hits. If there are no shots left, the game is over. Otherwise,
we make the CannonField generate a new target.
\skipto ::missed
\printuntil }
This slot is activated when a shot has missed the target. If there are no
shots left, the game is over.
\skipto ::newGame
\printuntil }
This slot is activated when the user clicks the Restart button. It is
also called from the constructor. First it sets the number of shots
to 15. Note that this is the only place in the program where we set
the number of shots. Change it to whatever you like to change the
game rules. Next we reset the number of hits, restart the game, and
generate a new target.
\section2 \l t13/main.cpp
This file has just been on a diet. MyWidget is gone, and the only
thing left is the main() function, unchanged except for the name
change.
\section1 Behavior
Hits and shots left are displayed and the program keeps track of them.
The game can end, and there's a button to start a new game.
\section1 Exercises
Add a random wind factor and show it to the user.
Make some splatter effects when the shot hits the target.
Implement multiple targets.
You may now go on to \link t14.html Chapter 14.\endlink
[\link t12.html Previous tutorial\endlink]
[\link t14.html Next tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
/*! \file t14/lcdrange.h */
/*! \file t14/lcdrange.cpp */
/*! \file t14/cannon.h */
/*! \file t14/cannon.cpp */
/*! \file t14/gamebrd.h */
/*! \file t14/gamebrd.cpp */
/*! \file t14/main.cpp */
/*! \file t14/Makefile */
/*! \page t14.html
\title Qt Tutorial - Chapter 14: Facing the Wall
<center><img src="t14.png" alt="Screenshot of tutorial fourteen"></center>
This is the final example: a complete game.
We add keyboard accelerators and introduce mouse events to CannonField. We
put a frame around the CannonField and add a barrier (wall) to make the
game more challenging.
\list
\i \l t14/lcdrange.h contains the LCDRange
class definition.
\i \l t14/lcdrange.cpp contains the LCDRange
implementation.
\i \l t14/cannon.h contains the CannonField class
definition.
\i \l t14/cannon.cpp contains the CannonField
implementation.
\i \l t14/gamebrd.h contains the GameBoard
class definition.
\i \l t14/gamebrd.cpp contains the GameBoard
implementation.
\i \l t14/main.cpp contains MyWidget and main.
\i \l t14/Makefile contains some rules for
generating the meta object information necessary for
\link signalsandslots.html signal/slot creation \endlink
\endlist
\section1 Line-by-line Walkthrough
\section2 \l t14/cannon.h
The CannonField can now receive mouse events to make the user aim the
barrel by clicking on it and dragging. CannonField also has a barrier
wall.
\quotefile t14/cannon.h
\skipto CannonField
\skipto protected
\printuntil mouseReleaseEvent
In addition to the familiar event handlers, CannonField implements
three mouse event handlers. The names say it all.
\skipto paintBarrier
\printline paintBarrier
This private function paints the barrier wall.
\skipto barrierRect
\printline barrierRect
This private function returns the enclosing rectangle of the barrier.
\skipto barrelHit
\printline barrelHit
This private function checks if a point is inside the barrel of the cannon.
\skipto barrelPressed
\printline barrelPressed
This private variable is TRUE if the user has pressed the mouse on the
barrel and not released it.
\section2 \l t14/cannon.cpp
\quotefile t14/cannon.cpp
\skipto ::CannonField
\skipto barrelPressed
\printline barrelPressed
This line has been added to the constructor. Initially, the mouse is
not pressed on the barrel.
\skipto ::moveShot
\skipto else
\printuntil {
Now that we have a barrier, there are three ways to miss. We test for
the third, too.
\skipto ::mousePressEvent
\printuntil }
This is a Qt event handler. It is called when the user presses a
mouse button when the mouse cursor is over the widget.
If the event was not generated by the left mouse button, we return
immediately. Otherwise, we check if the position of the mouse cursor
is within the cannon's barrel. If it is, we set \c barrelPressed to
TRUE.
Notice that the pos() function returns a point in the widget's
coordinate system.
\skipto ::mouseMoveEvent
\printuntil setAngle
\printline }
This is another Qt event handler. It is called when the user already
has pressed the mouse button inside this widget and then moves/drags
the mouse. (You can make Qt send mouse move events even when no
buttons are pressed. See \l QWidget::setMouseTracking().)
This handler repositions the cannon's barrel according to the position of
the mouse cursor.
First, if the barrel is not pressed, we return. Next, we fetch the
mouse cursor's position. If the mouse cursor is to the left or below
the widget, we adjust the point to be inside the widget.
Then we calculate the angle between the bottom edge of the widget and
the imaginary line between the bottom-left corner of the widget and
the cursor position. Finally we set the cannon's angle to the new
value converted to degrees.
Remember that setAngle() redraws the cannon.
\skipto ::mouseReleaseEvent
\printuntil }
This Qt event handler is called whenever the user releases a mouse
button and it was pressed inside this widget.
If the left button is released, we can be sure that the barrel is no
longer pressed.
The paint event has two extra lines:
\skipto ::paintEvent
\skipto barrierRect
\printline barrierRect
\printline paintBarrier
paintBarrier() does the same sort of thing as paintShot(),
paintTarget(), and paintCannon().
\skipto ::paintBarrier
\printuntil }
This private function paints the barrier as a rectangle filled with
yellow and with a black outline.
\skipto ::barrierRect
\printuntil }
This private function returns the rectangle of the barrier. We fix
the bottom edge of the barrier to the bottom edge of the widget.
\skipto ::barrelHit
\printuntil }
This function returns TRUE if the point is in the barrel; otherwise it returns
FALSE.
Here we use the class \l QWMatrix. It is defined in the header file
qwmatrix.h, which is included by qpainter.h.
QWMatrix defines a coordinate system mapping. It can perform the same
transformations as the QPainter.
Here we perform the same transformation steps as we do when drawing
the barrel in the paintCannon() function. First we translate the
coordinate system and then we rotate it.
Now we need to check whether the point \c p (in widget coordinates) lies
inside the barrel. To do this, we invert the transformation matrix.
The inverted matrix performs the inverse transformation that we used
when drawing the barrel. We map the point \c p using the inverted
matrix and return TRUE if it is inside the original barrel rectangle.
\section2 \l t14/gamebrd.cpp
\quotefile t14/gamebrd.cpp
\skipto qaccel.h
\printline qaccel.h
We include the class definition of \l QAccel.
\skipto ::GameBoard
\skipto QVBox
\printline QVBox
\printline setFrameStyle
\printline cannonField
We create and set up a \l QVBox, set its frame style, and then create
\c CannonField as a child of that box. Because nothing else is in the
box, the effect is that the QVBox will put a frame around the
CannonField.
\skipto QAccel
\printline accel
\printline connectItem
\printline fire
\printline connectItem
\printline fire
Here we create and set up an accelerator. An accelerator is an object
that intercepts keyboard events to an application and calls slots if
certain keys are pressed. This mechanism is also called shortcut
keys. Note that an accelerator is a child of a widget and will be
destroyed when that widget is destroyed. QAccel is \e not a widget
and has no visible effect on its parent.
We define two shortcut keys. We want the slot fire() to be called
when the user presses Enter, and we want the application to quit when
key Ctrl+Q is pressed. Because Enter is sometimes Return and there
are even keyboards with \e both keys, we make both Enter and Return
invoke fire().
\printline connectItem
\printline quit
And then we set up Ctrl+Q to do the same thing as Alt+Q. Some
people are more used to Ctrl+Q (and anyway it shows how do do it).
CTRL, Key_Enter, Key_Return and Key_Q are all constants provided by
Qt. They're actually Qt::Key_Enter, etc., but practically all classes
inherit the \l Qt namespace class.
\printline QGridLayout
\printline addWidget
\printline addWidget
\printline setColStretch
We put \c box (the QVBox), not the CannonField, in the lower-right
cell.
\section1 Behavior
The cannon now shoots when you press Enter. You can also position the
cannon's angle using the mouse. The barrier makes it a little more
challenging to play the game. We also have a nice looking frame
around the CannonField.
\section1 Exercises
Write a space invaders game.
(This exercise was first done by
\link mailto:igorr@ifi.uio.no Igor Rafienko\endlink. You can
\link http://www.stud.ifi.uio.no/~igorr/download.html
download his game\endlink.)
The new exercise is: Write a Breakout game.
Final exhortation: Go forth now and create \e {masterpieces of the
programming art!}
\omit
Cf. Chapter 27 of The TeXbook
\endomit
[\link t13.html Previous tutorial\endlink]
[\link t1.html First tutorial\endlink]
[\link tutorial.html Main tutorial page\endlink]
*/
|