-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCh6_Swing.html
More file actions
699 lines (680 loc) · 34.1 KB
/
Ch6_Swing.html
File metadata and controls
699 lines (680 loc) · 34.1 KB
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
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript: Ch6 Swing</title>
<meta name="title" content="Variations on a Theme: JavaScript: Ch6 Swing">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="UTF-8">
<meta name="description" content="An object-oriented Introduction">
<meta name="keywords" content="JavaScript,object orientation,introduction">
<meta name="author" content="Ralph P. Lano">
<meta name="robots" content="index,follow">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="book.css">
</head>
<body>
<center>
<div id="wrap">
<ul class="sidenav">
<p><a href="../index.html">Variations on a Theme</a><a href="index.html">JavaScript</a></p>
<li><a href="Ch1_Karel.html">Karel</a></li>
<li><a href="Ch2_Graphics.html">Graphics</a></li>
<li><a href="Ch3_Console.html">Console</a></li>
<li><a href="Ch4_Agrar.html">Agrar</a></li>
<li><a href="Ch5_MindReader.html">MindReader</a></li>
<li><a href="Ch6_Swing.html">Swing</a></li>
<li><a href="Ch7_Asteroids.html">Asteroids</a></li>
<li><a href="Ch8_Stocks.html">Stocks</a></li>
<li><a href="index.html"> </a></li>
<li><a href="AppA_Primer.html">Primer</a></li>
<li><a href="AppB_Libraries.html">Libraries</a></li>
<li><a href="AppC_Ideas.html">Ideas</a></li>
</ul>
<div class="content">
<p>
<img alt="" src="img/a6a5703b-cf7a-4778-aaa4-c635989a9ec5.png" style="display: block; margin-left: auto; margin-right: auto; width: 225px; height: 204px;" /></p>
<h1>
Swing</h1>
<p>
Programs with graphical user interfaces (GUI) are the topic of this chapter. Similar to graphic programs, there are ready-made components with which we can build small and large programs. It's a bit like Lego. In addition, we will learn some more about instance variables.</p>
<p>
.</p>
<h2>
<img alt="" src="img/377f7211-da52-4eb6-8c44-0ac3a14e6b81.png" style="width: 292px; height: 261px; float: right;" />Graphical User Interface</h2>
<p>
Most of the programs we deal with every day are programs with a graphical user interface (GUI or UI). GUIs consist of graphical elements, which we also call widgets or interactors, because we can interact with them. Well-known examples are:</p>
<ul>
<li>
Labels</li>
<li>
Buttons</li>
<li>
Textfields</li>
<li>
Checkboxes</li>
<li>
Radiobuttons</li>
<li>
Comboboxes</li>
</ul>
<p>
In the following we will see how to use them.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/dateAndTime" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/dateAndTime.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSLabel</h2>
<p>
We start again very simple, with the JSLabel. There is practically no difference to the Glabel we already know. It is used to display text in GUI programs:</p>
<pre style="margin-left: 40px;">
function setup() {
createGUI(300, 150);
let dt = new Date();
print(dt.toLocaleString());
let fritz = new JSLabel(dt.toLocaleString());
fritz.addStyle('font: 15px monospace;');
addWidget(fritz);
}</pre>
<p>
We see two differences to our previous programs: we now write createGUI() instead of createCanvas(). And we use mostly the setup() function, the draw() we will hardly use. Furthermore we see for the first time the class Date. This is very practical when you need date or time. If you are familiar with CSS, then the content of the addStyle() method should look familiar to you.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/firstButton" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/firstButton.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSButton</h2>
<p>
The JSLabel is not very interactive, and doesn't really deserve to be called an 'interactor'. That is different for the JButton, because you can click on it with the mouse. We'll start again very simple:</p>
<pre style="margin-left: 40px;">
function setup() {
createGUI(300, 150);
setLayout('border');
let btn = new JSButton("OK");
addWidget(btn, 'SOUTH');
}
</pre>
<p>
We create a new JSButton, on which "OK" should be written. We'll add that to the south of our program. When we start the program, we can press the button, but nothing happens.</p>
<p>
For the button to work properly, that is, to become interactive, we have to implement the actionPerformed() function. It is like the Hollywood principle: don't call us, we'll call you. This is like with mouse events, if you remember. But instead of the mousePressed(), now the function actionPerformed() is being called. This means that every time someone presses the button, this function is called.</p>
<pre style="margin-left: 40px;">
function actionPerformed(ev) {
print("hi:" + ev.getActionCommand());
}</pre>
<p>
Now every time we press on the button with the mouse, in the console part of our program "hi:" together with the buttons name is being displayed.</p>
<p>
.</p>
<h2>
<img alt="" src="img/3d9087be-7b2e-4d4e-af76-a1127aa0645b.png" style="margin-left: 10px; margin-right: 10px; width: 387px; height: 178px; float: right;" />Regions</h2>
<p>
In the two examples above, we have already used regions, NORTH and SOUTH. In total, there are three regions: SOUTH, NORTH, and CENTER. We can insert our widgets into any one of these regions.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/login" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/login.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSTextField</h2>
<p>
Using the JSTextField widget we can read text and numbers. In the following example, we want the users to log in with their names:</p>
<pre style="margin-left: 40px;">
let tf;
function setup() {
createGUI(300, 150);
setLayout('border');
let lbl = new JSLabel("Name: ");
addWidget(lbl, 'SOUTH');
tf = new JSTextField(10);
addWidget(tf, 'SOUTH');
let btn = new JSButton("Login");
addWidget(btn, 'SOUTH');
}
function actionPerformed(ev) {
print("Name: " + tf.getText());
}</pre>
<p>
We create a JSLabel, a JSTextField and a JSButton. The constructor of the JSTextField needs to know how wide the field should be. It is also important that the JSTextField variable <em>tf</em> is a global variable. If it were a local variable, then we could not access it in the actionPerformed() function.</p>
<p>
.</p>
<h2>
Global Variables</h2>
<p>
We have mentioned global variables briefly in the last chapters. The above example nicely shows what global variables are actually good for: they allow information to be exchanged between different functions. Up to now we could do this only by using parameters and return values.</p>
<p>
Another reason why global variables can be very practical is that all local variables are deleted when a function is exited. For example, in the rollTheDie() function,</p>
<pre style="margin-left: 40px;">
function rollTheDie() {
let rgen = new MyRandomGenerator();
let dieRoll = rgen.nextInt(1,6);
println(dieRoll);
}
</pre>
<p>
a new random generator is created each time the function is called and then it is deleted again when the function is exited. Both take time. But if we create the RandomGenerator as a global variable,</p>
<pre style="margin-left: 40px;">
let rgen = new MyRandomGenerator();
function rollTheDie() {
let dieRoll = rgen.nextInt(1,6);
println(dieRoll);
}</pre>
<p>
it is created only once, and in addition we can use it in any function of our class. This is much more resource-saving.</p>
<p>
.</p>
<h2>
Functions and Methods</h2>
<p>
We have been using the words function and method, and it maybe a little confusing what the difference is. It is actually very easy:</p>
<pre style="margin-left: 40px;">
async function setup() {
...
let hansel = new Student("Hänschen", 12345, 0.0);
println(hansel.name);
...
}
function rollTheDie() {
...
}
class Student {
constructor(_name, _id, _credits) {
...
}
incrementCredits(_credits) {
...
}
toString() {
...
}
}</pre>
<p>
When a function belongs to a class, it is called a method. In the above example, constructor(), incrementCredits() and toString() are methods, because they belong to the class Student. Also in Math.random() or GRect.setColor(), both random() and setColor() are methods, because they belong to a class.</p>
<p>
Conversely, setup() and rollTheDie() are functions, because they do not belong to any class. Also, println() and readLine() are functions, they also do not belong to any class. </p>
<p>
.</p>
<h2>
Global Variables vs Instance Variables vs. Locale Variables</h2>
<p>
Confucing may also be the difference between the three types of variables we have been using: global, instance and local variables. Consider this example:</p>
<pre style="margin-left: 40px;">
let rgen = new MyRandomGenerator();
async function setup() {
...
let hansel = new Student("Hänschen", 12345, 0.0);
...
}
class Student {
constructor(_name, _id, _credits) {
this.name = _name;
...
let local = 5;
}
}</pre>
<p>
Global variables are declared outside of any functions, like <em>rgen</em> above. They can be accessed from anywhere, and they live forever. </p>
<p>
Instance variables are declared in the constructor of a class and and always belong to a class or an object, like <em>name</em> in the above example. They are visible inside the entire class and all its methods, and they live as long as the object they belong to exists.</p>
<p>
Conversely, local variables are declared within a method or function, can only be accessed within this function, and are deleted when leaving the function. In the above example <em>hansel</em> is a local variable, as is <em>local</em>. Also parameters to functions or methods are considered to be local variables.</p>
<p>
Now the question arises, when do we use which? The answer is relatively simple in most cases:</p>
<ul>
<li>
if it is a calculation that can be performed locally in a method, then local variables are used, e.g. the conversion from degrees to fahrenheit is a local calculation,</li>
<li>
if an information is used in several methods, we should use an instance variable, if all those methods belong to the same class. </li>
<li>
if we are dealing with an internal state of an object, we should use an instance variable. For example, in the Student class, the name, ID and credits were internal states.</li>
</ul>
<p>
<strong>SEP: If possible, use local variables.</strong></p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/okCancel" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/okCancel.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Exercise: OKCancel</h2>
<p>
As a little exercise we add a cancel button to our program. How can we tell which of the two buttons was pressed? One way to do this is to use the getSource() method of the ActionEvent,</p>
<pre style="margin-left: 40px;">
let btn1 = new JSButton("OK");
...
function actionPerformed(ev) {
if (ev.getSource() === btn1) {
print("source: btn1");
} else if (ev.getSource() === btn2) {
print("source: btn2");
} else {
print("unknown source");
}
}
</pre>
<p>
to distinguish between several buttons or widgets in general. In this case the buttons or widgets must be instance variables.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/pizza" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/pizza.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSCheckBox</h2>
<p>
Next we will consider the JSCheckBox widget: we use check boxes when we have several choices.</p>
<pre style="margin-left: 40px;">
let topping1;
function setup() {
...
topping1 = new JSCheckBox("Tomatoes");
addWidget(topping1, 'CENTER');
let topping2 = new JSCheckBox("Bacon");
addWidget(topping2, 'CENTER');
let topping3 = new JSCheckBox("Onions");
addWidget(topping3, 'CENTER');
}</pre>
<p>
In the pizza example, we want to be able to select all possible combinations of toppings. This can best be achieved with check boxes. To determine which toppings were selected, there is the method isSelected():</p>
<pre style="margin-left: 40px;">
function actionPerformed(ev) {
print("source: " + ev.getSource().isSelected());
if (ev.getSource() === topping1) {
print("Tomatoes:" + topping1.isSelected());
}
}</pre>
<p>
We have to do that for all three toppings, of course.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/exam" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/exam.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSRadioButton</h2>
<p>
Radio buttons are used when making decisions. Let's look at the following example:</p>
<pre style="margin-left: 40px;">
let yes;
let no;
function setup() {
...
yes = new JSRadioButton("Yes");
yes.setSelected(true);
addWidget(yes, 'SOUTH');
no = new JSRadioButton("No");
addWidget(no, 'SOUTH');
}</pre>
<p>
Here we have two radio buttons, where the "yes" button is preselected. Radio buttons belong together in the sence that only one of the buttons can be selected at a time. If you want to know which button the user has selected, you can do this using:</p>
<pre style="margin-left: 40px;">
let b = yes.isSelected();</pre>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Ch6_Swing/favoriteColor" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/favoriteColor.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
JSComboBox</h2>
<p>
As an example for the JSComboBox we look at the example FavoriteColor. It is about selecting a color from a list:</p>
<pre style="margin-left: 40px;">
let colorPicker;
function setup() {
...
colorPicker = new JSComboBox();
colorPicker.addItem("Red");
colorPicker.addItem("White");
colorPicker.addItem("Blue");
addWidget(colorPicker, 'NORTH');
}
function actionPerformed(ev) {
println("Color:" + colorPicker.getSelectedItem());
}</pre>
<p>
In the init() method we initialize the colorPicker with the preset colors. To determine which color the user has selected, there is the getSelectedItem() method. But to access them in the actionPerformed() method, colorPicker must be an instance variable.</p>
<p>
Note: if we closely observe the behavior of the JSComboBox, we will notice that it has some small quirks. There's nothing we can do about it.</p>
<p>
.</p>
<h2>
UI Interactor Hierarchy</h2>
<p>
Similar to the hierarchy of the ACM graphics classes, there is also a hierarchy with the UI interactor classes. The most important ones are summarized in the following diagram, but there are many more:</p>
<p>
<img alt="" src="img/SwingClassDiagram.jpg" style="margin-left: 10px; margin-right: 10px; width: 673px; height: 405px;" /></p>
<p>
.</p>
<h2>
<img alt="" src="img/40c49c0e-a278-44cc-963a-fb7a816b117f.png" style="width: 246px; height: 198px; float: right;" />Layout</h2>
<p>
We already learned about the different regions SOUTH, NORTH, and CENTER. Those are a special feature of the BorderLayout. There are several other layouts besides the BorderLayout. Layouts are about how to "layout" several widgets on the screen. The following are some of the more important layouts:</p>
<ul>
<li>
<strong>BorderLayout:</strong> here there are three regions and widgets must be explicitly assigned to a region.</li>
<li>
<strong>FlowLayout:</strong> is the simplest layout, widgets are simply laid out side by side from left to right.</li>
<li>
<strong>GridLayout:</strong> the available space is divided into equally separated rows and columns, e.g. 3 by 2.</li>
</ul>
<p>
Let's look at a few examples. To use the BorderLayout we would use the following code:</p>
<pre style="margin-left: 40px;">
setLayout('border');
addWidget(new JSButton("0"), 'NORTH');
addWidget(new JSButton("1"), 'SOUTH');
...
</pre>
<p>
For the FlowLayout the code looks like this:</p>
<pre style="margin-left: 40px;">
setLayout('flow');
addWidget(new JSButton("0"));
addWidget(new JSButton("1"));
...</pre>
<p>
and the GridLayout is used in this fashion:</p>
<pre style="margin-left: 40px;">
setLayout('grid', 2);
addWidget(new JSButton("0"));
addWidget(new JSButton("1"));
...</pre>
<p>
The following depicts how the different layouts look graphically:</p>
<table align="center" border="0" cellpadding="10" cellspacing="10" style="width: 100%;">
<tbody>
<tr>
<td style="text-align: center; vertical-align: middle;">
<div style="display:block;">
<a href="./src/tryIt.html?name=Ch6_Swing/layoutExample" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/layoutExample1.png" style="width: 200px; height: 100px; display: block; margin: 0px auto;" />Try it</a></div>
</td>
<td style="text-align: center; vertical-align: middle;">
<div style="display:block;">
<a href="./src/tryIt.html?name=Ch6_Swing/layoutExample" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/layoutExample3.png" style="width: 200px; height: 100px; display: block; margin: 0px auto;" />Try it</a></div>
</td>
<td style="text-align: center; vertical-align: middle;">
<div style="display:block;">
<a href="./src/tryIt.html?name=Ch6_Swing/layoutExample" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/layoutExample2.png" style="width: 200px; height: 100px; display: block; margin: 0px auto;" />Try it</a></div>
</td>
</tr>
</tbody>
</table>
<p>
.</p>
<h2>
JSPanel</h2>
<p>
What the GCompound was for graphics programs is the JSPanel for UI programs: it allows us to combine several widgets into a new widget. Details about the JSPanel class can be found below in the project "Quiz".</p>
<p>
.</p>
<hr />
<h1>
Review</h1>
<p>
Congratulations! As we will soon see, we now have the tools to create almost any graphical user interface (UI). We know how to work with</p>
<ul>
<li>
Labels,</li>
<li>
Buttons,</li>
<li>
Textfields,</li>
<li>
Checkboxes,</li>
<li>
Radiobuttons,</li>
<li>
and Comboboxes.</li>
</ul>
<p>
We also learned about different layouts and briefly got to know the JSPanel.</p>
<p>
Equally important, however, was the deepening of our understanding of global, instance and local variables.</p>
<p>
.</p>
<hr />
<h1>
Projects</h1>
<p>
In the projects of this chapter we will create simple UIs. Some we will need later again. There's a lot to do, so let's get started.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/clock" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/clock.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Clock</h2>
<p>
We want to write a little digital clock. For this we use the Date class and its methods getHours(), getMinutes() and getSeconds(). For the display itself we use a JSLabel. And of course the text of the JSLabel should change once per second (better twice). For this you can use the setText() method of the JSLabel.</p>
<p>
It may make sense to write a method padWithZeros() that ensures that "06" minutes are displayed instead of "6" minutes.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/wordGuess" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/wordGuess.png" style="width: 200px; height: 80px; display: block;" />Try it</a></div>
<h2>
WordGuess</h2>
<p>
WordGuess is a graphical version of Hangman from the last chapter. It's about guessing a word by typing letters.</p>
<p>
We start by selecting a random word with the pickRandomWord() method. This word should be saved in the instance variable wordToGuess. Then we should create an instance variable, wordShown, with as many dashes, '-', as there are characters in the wordToGuess. Next, we create a JSLabel and add it to the northern region:</p>
<pre style="margin-left: 40px;">
wordLbl = new JSLabel(wordShown);
wordLbl.addStyle('font: 60px Courier;');
addWidget(wordLbl, 'NORTH');</pre>
<p>
What remains to be implemented is the method keyTyped(KeyEvent e). It is called when the user presses a key. Similar to Hangman, if a key was pressed, we check if the letter is in wordToGuess, and update the label if it is. Of course it also makes sense to count how many attempts were needed to guess the word correctly.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/stopWatch" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/stopWatch.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
StopWatch</h2>
<p>
A stopwatch needs a higher accuracy than what the Date class provides. For this purpose we can use the now() method of the Date class,</p>
<pre style="margin-left: 40px;">
startTime = Date.now();</pre>
<p>
which returns the milliseconds that have elapsed since 0 o'clock on January 1, 1970, UTC. </p>
<p>
We can use this to measure how much time has passed. We simply remember the time, when the user presses the "Start" button, and subtract from it the current time. To get the time in seconds, we simply divide this by 1000. If, however, we take this modulo 1000 we get only milliseconds.</p>
<p>
The display should be animated, so it makes sense to put the whole thing in a game loop. It also makes sense to have a delay of 20ms, otherwise the refresh of the display is to slow, and we will see nothing. And we should include two buttons, one to start and one to pause.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/countDown" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/countDown.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
CountDown</h2>
<p>
The CountDown works similar to the stopwatch. Instead of a JSLabel we use a JSTextField. The advantage is that you can edit it, i.e. you can set the number from which you want to count backwards. As soon as the user presses the "Start" button, the countdown should begin.</p>
<p>
.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/alarmClock" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/alarmClock.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
AlarmClock</h2>
<p>
Writing an alarm clock that uses the hour:minute:second format is surprisingly complicated. However, if you already have the methods for the conversion from hours:minutes:seconds to seconds convertTimeInSeconds() and from seconds to hours:minutes:seconds, convertSecondsInTime(), then it is not that difficult, and actually similar to the CountDown project.</p>
<p>
For this program we use a large JSLabel, which we place in the north. There is also a JSTextField in the south for entering the alarm time in the hours:minutes:seconds format. And there is a JSButton to start the alarm.</p>
<p>
It makes sense to use two instance variables:</p>
<pre style="margin-left: 40px;">
let alarmTime = -1;
let alarmStarted = false;</pre>
<p>
The first is simply the time in seconds, and the second is used to tell the game loop to do something:</p>
<pre style="margin-left: 40px;">
function draw() {
if (alarmStarted) {
...
}
}</pre>
<p>
If the JSButton is pressed, then alarmTime is set to the seconds, and alarmStarted is set to true, so that the game loop knows that it should now display something.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/editor" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/editor.png" style="width: 200px; height: 200px; display: block;" />Try it</a></div>
<h2>
Editor</h2>
<p>
Next on our list of things to do is a text editor. This consists of a JSTextField for the file name and two JSButtons, one for loading files, the other for saving files. We place these three widgets in the south, the lower part.</p>
<p>
In the middle part, the CENTER region, we place a JSTextArea:</p>
<pre style="margin-left: 40px;">
display = new JSTextArea("Enter text here...",10,20);
display.addStyle('font: 18px Courier;');
display.addStyle('width: 99%');
display.addStyle('height: 98%');
addWidget(display, 'CENTER');</pre>
<p>
A JSTextArea is like a JSTextField, only that you can enter multi-line text. In the next chapter we will learn how to load and save files. The 99% and 98% are needed, because I do not really understand CSS...</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/quiz" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/quiz.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Quiz</h2>
<p>
We want to write the UI for a MultipleChoice quiz. This consists of a question, i.e. a JSLabel, which we place in the upper area (NORTH). Then below follow the possible answers. These are, of course, radio buttons. Since they belong together, we group them into a button group. The radio buttons are placed in the middle area (CENTER). Finally, we also want to add two navigation buttons at the bottom, the SOUTH. The program should have no further functionality, this comes in the chapter after the next one.</p>
<p>
This program is a nice example how to use JSPanels. Multiple-choice questions do not always consist of three answers. Sometimes they are less, sometimes more. So it makes sense to summarize the questions and insert them into a JSPanel,</p>
<pre style="margin-left: 40px;">
let <span style="color:#0000ff;">answersPnl</span> = new JSPanel();
answersPnl.setLayout('grid', 1);
...
let btn1 = new JSRadioButton(answer1);
btn1.addStyle('justify-self: start;');
<span style="color:#0000ff;">answersPnl</span>.add(btn1);
...
addWidget(<span style="color:#0000ff;">answersPnl</span>, 'CENTER');</pre>
<p>
and then insert the JSPanel into the center region.</p>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/drawingEditor" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/drawingEditor.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
DrawingEditor</h2>
<p>
In the last chapter of this book we want to write a drawing editor. Until then, we can do some preparatory work. The idea is that we can choose between the shapes rectangle and circle with two radio buttons. Additionally we want to be able to set whether these shapes should be filled or not. This is best done with a check box. And finally, we want to be able to determine the color of the shapes with a combo box.</p>
<p>
.</p>
<hr />
<h1>
Challenges</h1>
<p>
.</p>
<div style="display:block; float: right; margin: 10px;">
<a href="./src/tryIt.html?name=Pr6_Swing/calculator" style="display: block; text-align: center;" target="_blank"><img alt="" src="img/calculatorGUI.png" style="width: 200px; height: 100px; display: block;" />Try it</a></div>
<h2>
Calculator</h2>
<p>
Our next project is a small calculator. This consists of a JSTextField (display) and 16 JSButtons. Best is to place the JSTextField in the north, and the JSButtons in a 4x4 GridLayout.</p>
<p>
When programming the logic of this calculator, we need to conisder the following: First, it makes sense to introduce two instance variables:</p>
<pre style="margin-left: 40px;">
let operand1 = 0;
let operation = '+';</pre>
<p>
For example, if we calculate "6 - 2" with our calculator, we first enter the number "6", then the "-" and then the "2". So we have to remember both the "6" and the "-" in between, hence the two instance variables.</p>
<p>
In the actionPerformed() method we must distinguish between the "=" character, the operators ("+", "-", "*" and "/"), and digits.</p>
<p>
When digits are entered, we simply append them to the display:</p>
<pre style="margin-left: 40px;">
let cmd = e.getActionCommand().charAt(0);
display.setText(display.getText() + cmd);</pre>
<p>
If an operator was entered, then we have to set the instance variables operand1 and operation, so</p>
<pre style="margin-left: 40px;">
operand1 = Number(display.getText());
display.setText("");
operation = cmd;</pre>
<p>
And if the "=" sign was pressed, then we have to perform the calculation and display the result:</p>
<pre style="margin-left: 40px;">
let operand2 = Number(display.getText());
let result = calculate(operand1, operand2, operation);
display.setText("" + result);</pre>
<p>
All that is left to do, is to implement the method calculate(double operand1, double operand2, char operation).</p>
<p>
.</p>
<hr />
<h1>
Questions</h1>
<ol>
<li>
There are local variables, instance variables and constants. Explain the difference.<br />
</li>
<li>
In the following example there are several variables, some with the same name. Describe how the variables are related and which are valid where.<br />
<br />
<span style="font-family:courier new,courier,monospace;"> class Lifetime {<br />
<br />
function run() {<br />
let i = 3;<br />
cow(i);<br />
}<br />
<br />
<span style="font-family:courier new,courier,monospace;">function</span> cow( n ) {<br />
for (let i=0; i<3; i++) {<br />
...<br />
}<br />
}<br />
}</span><br />
</li>
<li>
Name three different LayoutManagers.<br />
</li>
<li>
Sketch what the UI for the following code would look like.<br />
<br />
<span style="font-family:courier new,courier,monospace;">...<br />
face = new JSLabel("0:00:00");<br />
face.addStyle('font: 60px SansSerif;');<br />
addWidget(face, 'NORTH');<br />
<br />
tfAlarm = new JSTextField(10);<br />
tfAlarm.addStyle('text-align: right;');<br />
addWidget(tfAlarm, 'SOUTH');<br />
<br />
btnStart = new JSButton("Set Alarm");<br />
addWidget(btnStart, 'SOUTH');<br />
...</span><br />
</li>
<li>
If you click on a JButton, what kind of event is triggered?</li>
</ol>
<p>
.</p>
<hr />
<h1>
References</h1>
<p>
In this chapter the preferred reference is the book by Eric Roberts [1]. A nice but challenging tutorial is that by Oracle, the creators of Java [2].</p>
<p>
[1] The Art and Science of Java, von Eric Roberts, Addison-Wesley, 2008</p>
<p>
[2] The Swing Tutorial, <a href="http://docs.oracle.com/javase/tutorial/uiswing/">docs.oracle.com/javase/tutorial/uiswing/</a></p>
<p>
.</p>
<p class="footer">
Copyright © 2016-2023 <a href="http://www.lano.de">Ralph P. Lano</a>. All rights reserved.
</p>
</div>
</div>
</center>
</body>
</html>