swing_paradise 0.1.46

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of swing_paradise might be problematic. Click here for more details.

Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1557 -0
  3. data/doc/README.gen +1510 -0
  4. data/lib/swing_paradise/autoinclude.rb +3 -0
  5. data/lib/swing_paradise/awt/README.md +1 -0
  6. data/lib/swing_paradise/awt/color.rb +45 -0
  7. data/lib/swing_paradise/base_module/base_module.rb +993 -0
  8. data/lib/swing_paradise/classes +1 -0
  9. data/lib/swing_paradise/examples/001_quit_button_example.rb +55 -0
  10. data/lib/swing_paradise/examples/002_text_area_example.rb +55 -0
  11. data/lib/swing_paradise/examples/003_combo_box_example.rb +57 -0
  12. data/lib/swing_paradise/examples/004_jpanel_left_bound_example.rb +41 -0
  13. data/lib/swing_paradise/examples/005_box_layout_example.rb +39 -0
  14. data/lib/swing_paradise/examples/006_frame_example.rb +33 -0
  15. data/lib/swing_paradise/examples/007_textarea_responding_to_enter_key_example.rb +28 -0
  16. data/lib/swing_paradise/examples/008_scrolled_window_example.rb +41 -0
  17. data/lib/swing_paradise/examples/009_font_size_example.rb +39 -0
  18. data/lib/swing_paradise/examples/010_counter_example.rb +183 -0
  19. data/lib/swing_paradise/examples/011_button_with_image_example.rb +58 -0
  20. data/lib/swing_paradise/examples/012_quit_on_escape_key_being_pressed.rb +37 -0
  21. data/lib/swing_paradise/examples/013_simple_box_example.rb +38 -0
  22. data/lib/swing_paradise/examples/014_mouse_events_example.rb +41 -0
  23. data/lib/swing_paradise/examples/015_menu_example.rb +77 -0
  24. data/lib/swing_paradise/examples/016_file_chooser_example.rb +96 -0
  25. data/lib/swing_paradise/examples/017_buttons_example.rb +56 -0
  26. data/lib/swing_paradise/examples/018_colour_chooser_example.rb +51 -0
  27. data/lib/swing_paradise/examples/019_jeditorpane_example.rb +61 -0
  28. data/lib/swing_paradise/examples/020_table_example.rb +77 -0
  29. data/lib/swing_paradise/examples/021_jsplitpane_example.rb +66 -0
  30. data/lib/swing_paradise/examples/022_drawing_oval_example.rb +51 -0
  31. data/lib/swing_paradise/examples/023_show_message_dialog_example.rb +57 -0
  32. data/lib/swing_paradise/java_classes/border_factory/border_factory.rb +19 -0
  33. data/lib/swing_paradise/java_classes/box/box.rb +72 -0
  34. data/lib/swing_paradise/java_classes/button +1 -0
  35. data/lib/swing_paradise/java_classes/checkbox +1 -0
  36. data/lib/swing_paradise/java_classes/combobox +1 -0
  37. data/lib/swing_paradise/java_classes/default_table_model/default_table_model.rb +18 -0
  38. data/lib/swing_paradise/java_classes/frame +1 -0
  39. data/lib/swing_paradise/java_classes/jbutton/jbutton.rb +199 -0
  40. data/lib/swing_paradise/java_classes/jcheckbox/jcheckbox.rb +28 -0
  41. data/lib/swing_paradise/java_classes/jcombobox/jcombobox.rb +31 -0
  42. data/lib/swing_paradise/java_classes/jcomponent/jcomponent.rb +253 -0
  43. data/lib/swing_paradise/java_classes/jeditorpane/jeditorpane.rb +23 -0
  44. data/lib/swing_paradise/java_classes/jfilechooser/jfilechooser.rb +22 -0
  45. data/lib/swing_paradise/java_classes/jframe/jframe.rb +319 -0
  46. data/lib/swing_paradise/java_classes/jlabel/jlabel.rb +171 -0
  47. data/lib/swing_paradise/java_classes/jmenu/jmenu.rb +13 -0
  48. data/lib/swing_paradise/java_classes/jmenubar/jmenubar.rb +13 -0
  49. data/lib/swing_paradise/java_classes/jpanel/jpanel.rb +115 -0
  50. data/lib/swing_paradise/java_classes/jscrollpane/jscrollpane.rb +84 -0
  51. data/lib/swing_paradise/java_classes/jspinner/jspinner.rb +17 -0
  52. data/lib/swing_paradise/java_classes/jtextarea/jtextarea.rb +120 -0
  53. data/lib/swing_paradise/java_classes/jtextfield/jtextfield.rb +314 -0
  54. data/lib/swing_paradise/java_classes/label +1 -0
  55. data/lib/swing_paradise/java_classes/panel +1 -0
  56. data/lib/swing_paradise/java_classes/spinner +1 -0
  57. data/lib/swing_paradise/java_classes/textarea +1 -0
  58. data/lib/swing_paradise/misc/misc.rb +57 -0
  59. data/lib/swing_paradise/prototype/prototype.rb +79 -0
  60. data/lib/swing_paradise/requires/require_the_project.rb +15 -0
  61. data/lib/swing_paradise/toplevel_methods/misc.rb +293 -0
  62. data/lib/swing_paradise/version/version.rb +17 -0
  63. data/lib/swing_paradise/widget_collection/README.md +2 -0
  64. data/lib/swing_paradise/widget_collection/text_viewer.rb +160 -0
  65. data/lib/swing_paradise.rb +1 -0
  66. data/swing_paradise.gemspec +42 -0
  67. metadata +120 -0
data/README.md ADDED
@@ -0,0 +1,1557 @@
1
+ [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://www.gobolinux.org/)
2
+ [![forthebadge](https://forthebadge.com/images/badges/made-with-ruby.svg)](https://www.ruby-lang.org/en/)
3
+ [![Gem Version](https://badge.fury.io/rb/swing_paradise.svg)](https://badge.fury.io/rb/swing_paradise)
4
+
5
+ This gem was <b>last updated</b> on the <span style="color: darkblue; font-weight: bold">11.04.2024</span> (dd.mm.yyyy notation), at <span style="color: steelblue; font-weight: bold">17:24:56</span> o'clock.
6
+
7
+ ## Introduction to the swing_paradise project and its different goals
8
+
9
+ In the last some months of the year 2023/2024 I thought about the
10
+ goals of this project. This made me re-arrange the introductionary
11
+ section here. I will keep a numbered list of the goals of the
12
+ swing_paradise project.
13
+
14
+ (1) This gem contains some add-on bindings to jruby-Swing. This
15
+ is the primary goal.
16
+
17
+ <b>Swing</b> is an extension of the <b>Abstract Window Toolkit</b> (AWT),
18
+ a GUI (graphical user interface).
19
+
20
+ As Swing depends on Java, this project here really only makes
21
+ sense for use via <b>jruby</b>.
22
+
23
+ At present the project is fairly incomplete, but over the
24
+ coming months this should be improved. Right now this project
25
+ is beta-quality and I do not recommend anyone to use this
26
+ project. However had, for some limited scope, this project may
27
+ be fairly useful even if incomplete.
28
+
29
+ (2) Note that while the primary focus of this project will be on
30
+ Swing-based applications and add-on improvements, to make working
31
+ with jruby and Swing suck less, there is a secondary focus for
32
+ this project as well, in that I will attempt to create as many
33
+ Swing-based applications as possible, to make working on Windows
34
+ suck less. Most of these add-ons will reside under
35
+ <b>swing_paradise/widget_collection/</b>, but some may be grouped
36
+ into different gems, under either gui/jruby/ or gui/universal_widgets.
37
+ The latter will probably become more relevant in the future,
38
+ whereas for now, gui/jruby/ will be where most of the gui-relevant
39
+ bindings reside under.
40
+
41
+ With "Swing-based applications" I specifically mean being able to
42
+ use custom, ad-hoc widgets that solve certain problems, such
43
+ as "I want to delete the first page of this .pdf file,
44
+ via a GUI", on windows. In fact, that has been one major use
45
+ case why I intensified code for this project in October
46
+ 2023 - I had to use windows as primary operating system
47
+ every now and then, and it always annoyed me compared
48
+ to Linux, so I decided to create widgets (and describe
49
+ them, too) that will help me on windows. Also note that
50
+ this is an ongoing effort - I can not predict how useful
51
+ and extensive this will be. Stay tuned nonetheless.
52
+
53
+ (3) Another focus of this project is to provide useful documentation
54
+ in regards to Swing, as well as jruby. This helps me as a mnemonic,
55
+ but it may also be helpful to new users, in what they can do
56
+ with the project here in the long run. When I started this
57
+ project there was next to no project that documented
58
+ Swing + jruby. So one aim of this project has been to
59
+ polish the documentation as much as possible.
60
+
61
+ ## Terminology
62
+
63
+ In Java-Swing, a window is called a <b>frame</b>, which is represented
64
+ by class <b>JFrame</b>.
65
+
66
+ The default layout for Java-Swing components is a border layout.
67
+
68
+ ## SwingParadise::BaseModule
69
+
70
+ SwingParadise::BaseModule is the core helper module of
71
+ this gem.
72
+
73
+ You can include it, since it is a module, via:
74
+
75
+ require 'swing_paradise/base_module/base_module.rb'
76
+ include SwingParadise::BaseModule
77
+
78
+ See also the distributed examples if you want to know
79
+ more about how to use this in practice.
80
+
81
+ Since as of 29th October 2023, this will also automatically
82
+ pull in most of the important java-swing methods. I found
83
+ this easier to work with, than have to remember which
84
+ widgets I need.
85
+
86
+ This is done via java_import statements, such as:
87
+
88
+ java_import javax.swing.JPasswordField
89
+
90
+ So basically you can omit a few lines in your application
91
+ by tapping into the BaseModule module.
92
+
93
+ ## Simplified quitting
94
+
95
+ Use the following method to <b>quit</b> easily:
96
+
97
+ do_quit
98
+
99
+ For instance, a <b>quit button</b> could then be done in this
100
+ manner:
101
+
102
+ quit_button.on_clicked {
103
+ do_quit
104
+ }
105
+
106
+ ## Useful java_import headers
107
+
108
+ include Java
109
+
110
+ java_import javax.swing.JButton
111
+ java_import javax.swing.JFrame
112
+ java_import javax.swing.JLabel
113
+ java_import javax.swing.JPanel
114
+ java_import javax.swing.JTextArea
115
+ java_import javax.swing.JScrollBar
116
+ java_import javax.swing.JTextField
117
+ java_import javax.swing.JSpinner
118
+ java_import javax.swing.SpinnerNumberModel
119
+ java_import java.lang.System
120
+ java_import java.awt.Font
121
+
122
+ ## Usage example for setBounds
123
+
124
+ _.setBounds(10, 20, 200, 40) /* is: x-coordinate, y-coordinate, width, height) */
125
+ _.set_bounds(10, 20, 200, 40) /* is: x-coordinate, y-coordinate, width, height) */
126
+
127
+ Note that both variants work. I prefer <b>.set_bounds()</b>.
128
+
129
+ <!---
130
+
131
+ https://www.rubydoc.info/gems/swing_paradise/0.1.13#jtextarea
132
+
133
+ -->
134
+ ## JTextArea
135
+
136
+ First, let's have a look as to how a JTextArea may look like (on Windows):
137
+
138
+ <img src="https://i.imgur.com/CWVYskn.png" style="margin: 1em">
139
+
140
+ The <b>JTextArea class</b> provides a component that displays multiple lines of
141
+ text.
142
+
143
+ If only one line of input is required from the user, then a <b>text field</b>
144
+ should be used rather than JTextArea.
145
+
146
+ In <b>raw Java</b>, the code for instantiating a new JTextArea goes like this:
147
+
148
+ text_area = new JTextArea(5, 20);
149
+ JScrollPane scroll_pane = new JScrollPane(text_area);
150
+ text_area.setEditable(false);
151
+
152
+ In the code above, the API for JTextArea() follows this
153
+ signature: <b>JTextArea(int rows, int columns)</b> - so you first
154
+ pass in the number of rows, and then pass in the number of columns.
155
+
156
+ In Java, you can set the background colour to a colour of your choosing via:
157
+
158
+ import java.awt.Color;
159
+ Color color = new Color(255,0,0); /* This is red. */
160
+ text_area.setBackground(color);
161
+
162
+ The textarea is quite flexible. For instance, you can force it to
163
+ ignore newlines entered by the user, thus making it essentially
164
+ a single-line input entry:
165
+
166
+ textview = create_textarea
167
+ textview.getDocument.putProperty('filterNewlines', true)
168
+
169
+ As this is a bit annoying to remember, I added this method:
170
+
171
+ textview.filter_newlines
172
+
173
+ As always, you need to include SwingParadise::BaseModule for
174
+ this add-on functionality.
175
+
176
+ Most of the time you probably don't want this behaviour though.
177
+
178
+ To set to a different background colour, use something like this:
179
+
180
+ textview.setBackground(Color::GREEN)
181
+
182
+ Line-wrapping and wrap-style can also be set:
183
+
184
+ textview.setLineWrap(true)
185
+ textview.setWrapStyleWord(false)
186
+
187
+ ## JComboBox - working with combo-boxes in Java swing and jruby
188
+
189
+ You can instantiate a new combo box via:
190
+
191
+ combo_box = JComboBox.new
192
+
193
+ Now, in order to fill it up, you can use something like this:
194
+
195
+ array = %w( apple bird cat dog eagle ferret )
196
+ array.each {|this_item|
197
+ combo_box.addItem(this_item)
198
+ }
199
+
200
+ So .addItem() can be used to add more elements to the combo-box.
201
+
202
+ As the above is a bit cumbersome, if you make use of
203
+ <b>SwingParadise::BaseModule</b>, you can use the following API
204
+ instead:
205
+
206
+ array = %w( apple bird cat dog eagle ferret )
207
+ combo_box(array) # So you can simply pass in the full Array here
208
+
209
+ To select a specific index, that is, a specific entry on that
210
+ combo box, you can use the method <b>.setSelectedIndex()</b>:
211
+
212
+ combo_box.setSelectedIndex(2) # For the third entry.
213
+
214
+ To query which index is the currently selected one on a
215
+ combo-box, use the method <b>.selected_index</b>, as in:
216
+
217
+ combo_box.selected_index
218
+
219
+ To obtain the selected entry, use <b>.selected_item</b>,
220
+ as in:
221
+
222
+ combo_box.selected_item
223
+
224
+ ## Java::JavaAwtEvent::ActionEvent
225
+
226
+ Events in java can be found under <b>java.awt.events.*</b>.
227
+
228
+ <b>class Java::JavaAwtEvent::ActionEvent</b> is the base class for
229
+ when Java Swing fires an event, such as when the user changes the
230
+ content of a combo-box.
231
+
232
+ The syntax to use it, from <b>jruby</b>, goes like this:
233
+
234
+ widget.add_action_listener { |event|
235
+ }
236
+
237
+ So you designate a block variable; I recommend to consistently call
238
+ it <b>event</b>, as that should simplify things.
239
+
240
+ How can you find out the specific event?
241
+
242
+ One way goes via the method <b>.get_action_command()</b>,
243
+ such as in:
244
+
245
+ event.get_action_command
246
+
247
+ action_command = event.get_action_command
248
+
249
+ For the changed content of a combo-box, the result
250
+ would <b>comboBoxChanged</b>.
251
+
252
+ To respond to this, you can use the following snippet:
253
+
254
+ case event.get_action_command
255
+ when /comboBoxChanged/
256
+ end
257
+
258
+ I needed this functionality for a widget that, when the user changes
259
+ the combo-box content, another entry is also changed, reflecting the
260
+ currently selected entry there.
261
+
262
+ ## Available colours
263
+
264
+ Just a simple listing of available colours in a java swing
265
+ application:
266
+
267
+ Color::RED
268
+ Color::BLUE
269
+ Color::GREEN
270
+ Color::BLACK
271
+
272
+ ## Obtaining the height and width of a widget
273
+
274
+ Use .getBounds as in:
275
+
276
+ frame.getBounds()
277
+ height = r.height
278
+ width = r.width
279
+
280
+ ## The GridLayout
281
+
282
+ A GridLayout in java-swing looks like this:
283
+
284
+ <img src="https://docs.oracle.com/javase/tutorial/figures/uiswing/layout/GridLayoutDemo.png" style="margin: 1em">
285
+
286
+ In other words: you arrange elements (widgets) in a 2D-like matrix. This
287
+ is also called <b>a grid of cells</b>. Each component in the grid
288
+ is <b>exactly</b> the same size.
289
+
290
+ To create a new GridLayout, in raw Java, use this:
291
+
292
+ /* API: GridLayout(int rows, int cols) */
293
+ GridLayout x = new GridLayout(3, 3); /* A 3x3 grid */
294
+
295
+ You can then add new elements to it via:
296
+
297
+ .add(new JButton("Button 1"));
298
+ .add(new JButton("Button 2"));
299
+
300
+ And so forth.
301
+
302
+ If you use SwingParadise::BaseModule then you can also make
303
+ use of the .create_grid() method.
304
+
305
+ grid = create_grid('2x2')
306
+ grid.add(button('Button 1'))
307
+ grid.add(button('Button 2'))
308
+
309
+ This should be equivalent to the above mentioned Java code.
310
+
311
+ ## JCheckBox and checkboxes in Java swing
312
+
313
+ Let's first look at an image how checkboxes look in Java swing:
314
+
315
+ <img src="https://i.imgur.com/E5gugWY.png" style="margin: 1em">
316
+
317
+ Let's next have a look at how we <b>add checkboxes in raw Java swing</b>:
318
+
319
+ JPanel panel = new JPanel();
320
+ panel.add(label);
321
+
322
+ JCheckBox one = new JCheckBox("one");
323
+ JCheckBox two = new JCheckBox("two");
324
+
325
+ panel.add(one);
326
+ panel.add(two);
327
+
328
+ So, we make use of <b>JCheckBox</b>. A second argument can be passed,
329
+ to determine whether the check-box is checked or whether it is not:
330
+
331
+ JCheckBox.new("Foobar", true)
332
+ JCheckBox.new("Foobar", false)
333
+
334
+ To determine whether a JCheckBox is <b>checked</b> - aka selected, the
335
+ following method can be used:
336
+
337
+ checkbox.isSelected()
338
+
339
+ Or, if you use the swing_paradise gem, you can also use:
340
+
341
+ checkbox.is_selected?
342
+
343
+ To mark the checkbox as checked, use:
344
+
345
+ checkbox.setSelected(true)
346
+
347
+ ## JFrame
348
+
349
+ To create a new frame, aka a new JFrame, from jruby, use:
350
+
351
+ frame = JFrame.new # This would be an untitled frame.
352
+ frame = JFrame.new("Frame Title") # And this would set the title to "Frame Title".
353
+
354
+ If you'd like to you could also use the full qualifier (full name),
355
+ which is:
356
+
357
+ frame = javax.swing.JFrame.new
358
+ # panel = Java::javax::swing::JFrame.new # This variant may also work, but is not as elegant as the one above.
359
+
360
+ However had, note that both variants shown above are more verbose, so
361
+ it may not be worth the extra time to type; nonetheless, should you
362
+ ever have a use case to scope specifically to a particular class,
363
+ you can preface it via <b>javax.swing</b> (or wherever else that
364
+ particular swing-class resides at).
365
+
366
+ To set a grid layout you can use the method called <b>.set_layout()</b>,
367
+ as seen in the following example:
368
+
369
+ frame.set_layout(
370
+ java.awt.GridLayout.new(2, 2, 2, 2)
371
+ )
372
+
373
+ This is especially useful for any 2D layouts.
374
+
375
+ To <b>exit a JFrame</b>, as the main pane, Java Swing usually
376
+ requires that you use something like this:
377
+
378
+ frame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
379
+
380
+ I found this a bit cumbersome to type and difficult to
381
+ remember, so the SwingParadise::BaseModule allows you
382
+ to use this method instead:
383
+
384
+ default_close
385
+
386
+ This one is easier for me to remember, and less to type, too.
387
+
388
+ Note that you can not add a JFrame to another JFrame. I ran into
389
+ this issue in December 2023, so I had to note this down here.
390
+
391
+ The explanation I found stated this:
392
+
393
+ "JFrame is a <b>top level container</b> and as such it cannot
394
+ be <b>added</b> to any other container."
395
+
396
+ Typically a JFrame contains two parts: a space area on top for
397
+ the menu bar, and the content pane below the menu bar. Often
398
+ the menu bar is missing, though, so the content pane is
399
+ ultimately more important than the menu bar.
400
+
401
+ Further methods for the JFrame include these (as a sample):
402
+
403
+ .setVisible(boolean b)
404
+ .setTitle(String title)
405
+ .setSize(int width, int height)
406
+ .setLocation(int horizontal, int vertical)
407
+ .pack()
408
+ .setDefaultCloseOperation(int operation)
409
+
410
+ By default a JFrame is not visible, so we have to use:
411
+
412
+ frame.setVisible(true)
413
+
414
+ To make it visible.
415
+
416
+ You can designate the size of the main JFrame via .setSize():
417
+
418
+ .setSize(int width, int height)
419
+ .setSize(600, 420)
420
+
421
+ Note that calling the method .pack() will resize the frame so that
422
+ it tightly fits around components embedded into its content
423
+ pane.
424
+
425
+ To make the whole application quit when the close-action is
426
+ triggered, use:
427
+
428
+ frame.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
429
+
430
+ ## JPanel
431
+
432
+ In raw jruby, you can create a new instance of JPanel by issuing
433
+ this:
434
+
435
+ panel = JPanel.new
436
+
437
+ You can then assign different layouts to be used. For instance,
438
+ to keep the panel left-aligned, meaning you will see new elements
439
+ all appear in a linear left-to-right fashion, you can use a
440
+ FlowLayout like this:
441
+
442
+ panel.layout = FlowLayout.new(FlowLayout::LEFT)
443
+
444
+ This would look similar to the following image:
445
+
446
+ <img src="https://i.imgur.com/Yr7t7hJ.png" style="margin: 1em">
447
+
448
+ This seems quite convenient and easy to use, so the swing_paradise
449
+ gem tries to make this even easier. Here is the proposed API
450
+ for the above two lines:
451
+
452
+ panel = create_panel { :left }
453
+
454
+ This is <b>exactly</b> the same as:
455
+
456
+ panel = JPanel.new
457
+ panel.layout = FlowLayout.new(FlowLayout::LEFT)
458
+
459
+ Note that FlowLayout is the default layout manager for
460
+ every JPanel. The components will be laid out in a single
461
+ row one after the other.
462
+
463
+ Here is another picture how this would look:
464
+
465
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-flow-layout-manager.jpg" style="margin: 1em">
466
+
467
+ JPanel can also be used to draw onto, via the method called
468
+ <b>paintComponent</b>. Whenever the GUI is resized, this
469
+ method will be automatically called.
470
+
471
+ Take note that .paintComponent() should not be called directly;
472
+ instead, use the .repaint() method in the event you wish to
473
+ draw onto the panel.
474
+
475
+ The API for paintComponent in raw Java Swing goes as follows:
476
+
477
+ public void paintComponent(Graphics g)
478
+
479
+ Graphics here belongs to AWT.
480
+
481
+ ## Working with colours in SWING and jruby
482
+
483
+ The generic way to handle colours in java-swing goes like this:
484
+
485
+ import java.awt.Color;
486
+ Color color = new Color(255,0,0); /* This is red. */
487
+
488
+ ## Using no specific layout
489
+
490
+ Via:
491
+
492
+ frame.setLayout(nil)
493
+
494
+ You can avoid using any specific layout.
495
+
496
+ ## GridBagLayout
497
+
498
+ GridBagLayout aligns components by placing them within a grid
499
+ of cells, allowing components to span more than one cell.
500
+
501
+ The following image shows how this may look like:
502
+
503
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-grid-bag-layout.jpg" style="margin: 1em">
504
+
505
+ ## JButton and buttons in swing
506
+
507
+ Java-Swing calls a button JButton. JButton is not the only button
508
+ available in Java-Swing: we can also use JCheckBox, JRadioButton,
509
+ JMenuItem, JCheckBoxMenuItem, JRadioButtonMenuItem or JToggleButton.
510
+
511
+ An example for a widget that uses three buttons will be shown
512
+ next (on Windows XP):
513
+
514
+ <img src="https://i.imgur.com/xBvl7Fq.png" style="margin: 1em">
515
+
516
+ You can add an icon to a button in swing.
517
+
518
+ First, let's show the Java version for this:
519
+
520
+ JButton button = new JButton(new ImageIcon("foobar.jpg"));
521
+
522
+ <b>ImageIcon</b> can be used for <b>pixel graphics</b>.
523
+
524
+ Next, the equivalent ruby code:
525
+
526
+ button = JButton.new(ImageIcon.new('foobar.jpg'))
527
+
528
+ If you use the swing_paradise gem, the above can be simplified a
529
+ little bit further:
530
+
531
+ button = button(ImageIcon.new('foobar.jpg'))
532
+
533
+ I may extend this API to simplify this further, such as
534
+ <b>button_with_image()</b> or something like that. In fact, in
535
+ February 2024 this was indeed extended: if you use SwingParadise::BaseModule
536
+ then you can use the method called <b>button_with_image()</b> to add
537
+ a button with an image. There are two ways to call this: one is by simply
538
+ passing the path to a local image. The second way is to also pass an
539
+ optional text that is displayed next to the image.
540
+
541
+ To change the background colour for a button, use the following API:
542
+
543
+ button.setBackground(Color.green) # This would make it green.
544
+
545
+ To let a JButton respond to on-click events, one has to
546
+ attach a listener, via the following API:
547
+
548
+ button.addActionListener(ActionListener listener)
549
+
550
+ In jruby this is implemented via a block form, that is via:
551
+
552
+ {
553
+ }
554
+
555
+ To <b>focus</b> on a button, use:
556
+
557
+ button.requestFocusInWindow();
558
+
559
+ To obtain the text (label) if a JButton, use the method
560
+ <b>.getText</b>.
561
+
562
+ If you make use of the swing-paradise gem then you can
563
+ simply call the .on_clicked {} method on a button,
564
+ such as via:
565
+
566
+ button = JButton.new('Please click me.')
567
+ button.on_clicked {
568
+ puts 'I was clicked.'
569
+ }
570
+
571
+ There is, interestingly enough, another way possible for
572
+ achieving the above, in that you specify a distinct
573
+ class that will be invoked when the button is called.
574
+
575
+ So, the code for the button at hand would then look like
576
+ this:
577
+
578
+ button = JButton.new('Please click me.')
579
+ button.addActionListener(ClickAction.new)
580
+
581
+ And you also need to define class ClickAction, like this:
582
+
583
+ class ClickAction
584
+
585
+ include ActionListener
586
+
587
+ def actionPerformed(event) # you can also use: "def action_performed" instead
588
+ puts 'This time the button was called from within clas ClickAction.'
589
+ end
590
+
591
+ end
592
+
593
+ This solution is not quite as convenient as the .on_clicked {} variant,
594
+ but perhaps there may be times when this is needed, so it is mentioned
595
+ here in the documentation. Personally I will continue to prefer
596
+ the <b>.on_clicked {} method variant</b> though - my brain has an
597
+ easier time remembering that variant.
598
+
599
+ You can also use tooltips for a button.
600
+
601
+ Examples:
602
+
603
+ button.setToolTipText('Press Alt+H to trigger this button.')
604
+ button.hint = 'Press Alt+H to trigger this button.'
605
+
606
+ If you need to obtain the tooltip-text, you can use:
607
+
608
+ puts button.getToolTipText
609
+
610
+ The location where the tooltip will be shown, can be obtained via:
611
+
612
+ puts button.getToolTipLocation(MouseEvent)
613
+
614
+ If you want to make the button have a flat-style look, use:
615
+
616
+ button.setBorderPainted(false)
617
+ button.setFocusPainted(false)
618
+ button.setContentAreaFilled(false)
619
+
620
+ The full <b>API documentation</b> for JButton can be found here:
621
+
622
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JButton.html
623
+
624
+ ## JLabel and text
625
+
626
+ You can right-align a JLabel widget via:
627
+
628
+ JLabel(String text, int horizontalAlignment)
629
+ JLabel label = new JLabel("Telephone", SwingConstants.RIGHT);
630
+
631
+ In jruby-swing this would look like this:
632
+
633
+ label = JLabel.new('Telephone', SwingConstants::RIGHT)
634
+
635
+ After you created a label, you can call several methods on it.
636
+
637
+ For instance, to change the foreground colour, use:
638
+
639
+ label.setForeground(Color c)
640
+
641
+ For the background colour use:
642
+
643
+ label.setBackground(Color c)
644
+
645
+ You can also set the label to be opaque, via:
646
+
647
+ label.setOpaque(boolean b)
648
+ label.setOpaque(true)
649
+ label.setOpaque(false)
650
+
651
+ If true is passed to the latter method then the label
652
+ will be transparent; if it is false, then the label will be
653
+ non-transparent.
654
+
655
+ Interestingly you can also use HTML markup in a JLabel. The
656
+ following example shows how this can be done:
657
+
658
+ label = JLabel.new("<html><span>This is your text</span></html>");
659
+
660
+ ## JColorChooser (javax.swing.colorchooser)
661
+
662
+ <b>JColorChooser</b> can be used to pick a certain colours.
663
+
664
+ Let's have a look at an image, to find out how this may actually look:
665
+
666
+ <img src="https://docs.oracle.com/javase/tutorial/figures/uiswing/components/ColorChooserDemoMetal.png" style="margin: 1em">
667
+
668
+ In raw Java, we would use the following to create a new JColorChooser instance:
669
+
670
+ banner = new JLabel("Some text.", JLabel.CENTER);
671
+ banner.setForeground(Color.yellow);
672
+ jcolorchooser = new JColorChooser(banner.getForeground());
673
+ add(jcolorchooser, BorderLayout.PAGE_END);
674
+
675
+ If you want to create a dialog, for the user to make a choice, you can
676
+ use the <b>.createDialog()</b> method:
677
+
678
+ jcolorchooser.createDialog()
679
+ jcolorchooser.createDialog # Remember, in ruby you can omit the ().
680
+
681
+ ## JOptionPane
682
+
683
+ <b>JOptionPane</b> can be used to ask the user about confirmation about
684
+ certain actions, such as <b>Do you really want to delete this
685
+ file?</b>.
686
+
687
+ ## BorderLayout
688
+
689
+ A BorderLayout places components in up to five areas:
690
+
691
+ <b>top</b>, <b>bottom</b>, <b>left</b>, <b>right</b>,
692
+ and <b>center</b>.
693
+
694
+ It is <b>the default layout manager</b> for every java JFrame.
695
+
696
+ It looks like this:
697
+
698
+ <img src="https://www.guru99.com/images/uploads/2012/06/java-border-layout-manager.jpg" style="margin: 1em">
699
+
700
+ ## BorderFactory
701
+
702
+ BorderFactory can be used to create a frame with a label.
703
+
704
+ Usage example in jruby:
705
+
706
+ _ = BorderFactory.createTitledBorder(' Shell ')
707
+ _.setTitleFont(Font.new('Tahoma', Font::PLAIN, 50)) # This here can be used to set the font that is used.
708
+
709
+ Many variants exist for BorderFactory.
710
+
711
+ For instance, to set a matte-border, you can use:
712
+
713
+ ImageIcon icon = createImageIcon("images/wavy.gif", "wavy-line border icon"); # 20x22
714
+ BorderFactory.createMatteBorder(-1, -1, -1, -1, icon));
715
+
716
+ ## ImageIcon
717
+
718
+ The name icon is a slight misnomer for this class, as it can also deal with
719
+ large images.
720
+
721
+ As argument to this class the path to a local filename should be supplied,
722
+ as a String.
723
+
724
+ Example:
725
+
726
+ image_icon = ImageIcon.new('/tmp/foobar.png')
727
+
728
+ You can also supply an URL instead of a String to a local path.
729
+
730
+ You can query the height and width of this image via:
731
+
732
+ image_icon.getImageHeight() # returns the image height, in n pixels.
733
+ image_icon.getImageWidth() # returns the image width, in n pixels.
734
+
735
+ Keep in mind that instances of class ImageIcon are non-graphical components.
736
+ This means that they have to be put into some container, such as
737
+ JLabel, e. g.:
738
+
739
+ JLabel.new(ImageIcon picture)
740
+ JLabel.new(image_icon) # re-using the variable defined above ^^^
741
+
742
+ You can also load images <b>asynchronously</b>. This can be done via
743
+ <b>Toolkit</b> from the AWT library.
744
+
745
+ Example in Java-Swing:
746
+
747
+ Image picture = Toolkit.getDefaultToolkit.getImage(String filename);
748
+ Image picture = Toolkit.getDefaultToolkit.getImage(String url);
749
+
750
+ In jruby-Swing:
751
+
752
+ picture = Toolkit.getDefaultToolkit.getImage(String filename)
753
+ picture = Toolkit.getDefaultToolkit.getImage('foobar.png')
754
+
755
+ If you need to load multiple images, possibly distributed on
756
+ various servers on the internet, you may want to make use
757
+ of class <b>MediaTracker</b>, which is part of the AWT
758
+ library. MediaTracker can monitor the loading process of many
759
+ images. Interestingly MediaTracker makes use of an id,
760
+ such as via the following method call:
761
+
762
+ .addImage(Image picture, int id)
763
+
764
+ ## Java::JavaAwtEvent::ActionEvent and events in general
765
+
766
+ An event in a SWING application is typically of class
767
+ <b>Java::JavaAwtEvent::ActionEvent</b>, as far as Ruby is
768
+ concerned.
769
+
770
+ ## JTextField
771
+
772
+ <b>JTextField</b> is a lightweight component that allows the
773
+ editing of a single line of text.
774
+
775
+ A <b>JTextField</b> - also known as an <b>entry</b> - is
776
+ a <b>subclass</b> of the <b>JTextComponent</b> class.
777
+
778
+ <b>Padding</b> can be added to a JTextField via the method
779
+ .setMargin() and passing proper insets to it.
780
+
781
+ Example:
782
+
783
+ setMargin(Insets m)
784
+
785
+ text_field = new JTextField("A text field example.");
786
+ text_field.setMargin(new Insets(10, 10, 10, 10));
787
+
788
+ JTextField can also be instantiated in this manner:
789
+
790
+ JTextField(String text, int columns)
791
+
792
+ So the second argument means how many columns this entry
793
+ should have.
794
+
795
+ Documentation for JTextField can be seen here:
796
+
797
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JTextField.html
798
+
799
+ ## Textfields in Java-SWING via JFormattedTextField
800
+
801
+ If you have a need to hide certain input elements, such as
802
+ via a user-password, you could use the following code, in
803
+ Java-SWING:
804
+
805
+ import javax.swing.text.MaskFormatter;
806
+ MaskFormatter mask_formatter = new MaskFormatter("###-##-####");
807
+
808
+ JFormattedTextField has three preconfigured format types:
809
+
810
+ numbers
811
+ dates
812
+ strings
813
+
814
+ ## JScrollBar
815
+
816
+ First, before this subsection explains some things about a <b>JScollBar</b>, let us state
817
+ that in many cases a developer may want to use <b>JScrollPane</b> instead.
818
+
819
+ <b>JScrollBar</b> is used to create a scrolling widget. This refers to
820
+ a widget that has a vertical and a horizontal bar - both of which
821
+ can be optional - allowing the mouse pointer to click and drag
822
+ the child-widget, to the right, left, up or down. This is especially
823
+ useful for a text-buffer widget, where regular text is displayed
824
+ that overflows to the right hand side (or somewhere else).
825
+
826
+ The following image shows how this looked on Windows XP:
827
+
828
+ <img src="https://i.imgur.com/6AEwGR7.png" style="margin: 1em">
829
+
830
+ So, to summarize: the scroll bar is used to determine the
831
+ viewing area of the component (the child-widget).
832
+
833
+ The scroll bar involves a knob that can be adjusted by the
834
+ user. This is meant for use with the mouse pointer.
835
+
836
+ How to create a new instance for a scroll bar in Java?
837
+
838
+ The following code example (<b>ScrollBarExample.java</b>) shows this:
839
+
840
+ import javax.swing.*;
841
+ import java.awt.*;
842
+
843
+ class ScrollBarExample {
844
+
845
+ public static void main(String[] args) {
846
+ final JFrame frame = new JFrame("ScrollBarExample");
847
+
848
+ JScrollBar scrollBarH = new JScrollBar(JScrollBar.HORIZONTAL, 30, 20, 0, 500);
849
+ JScrollBar scrollBarV = new JScrollBar(JScrollBar.VERTICAL, 30, 40, 0, 500);
850
+
851
+ frame.setSize(300,200);
852
+ frame.getContentPane().add(scrollBarH, BorderLayout.SOUTH);
853
+ frame.getContentPane().add(scrollBarV, BorderLayout.EAST);
854
+ frame.setVisible(true);
855
+ }
856
+
857
+ }
858
+
859
+ Which relevant properties does the scroll bar have?
860
+
861
+ orientation: This indicates a horizontal or a vertical Scrollbar.
862
+ value: This indicates the model's current value. The upper
863
+ limit on the model's value is maximum - extent and the
864
+ lower limit is minimum.
865
+ extent: This indicates the width of the knob of the scrollbar.
866
+ minimum: This indicates the minimum width of the track on which the scrollbar moves.
867
+ maximum: This indicates the maximum width of the track on which the scrollbar moves.
868
+
869
+ If you instantiate a new scrollbar in jruby, using this syntax:
870
+
871
+ JScrollBar.new
872
+
873
+ then the following initial values are used:
874
+
875
+ minimum = 0
876
+ maximum = 100
877
+ value = 0
878
+ extent = 10
879
+
880
+ The first argument is orientation (as Integer).
881
+
882
+ Example:
883
+
884
+ JScrollBar.new(int orientation)
885
+ JScrollBar.new(1)
886
+
887
+ In other words: you can use this to determine the orientation
888
+ of the scrollbar. The value <b>orientation=0</b> means we will
889
+ make use of a horizontal scroll bar, whereas the value
890
+ <b>orientation=1</b> means we will get a vertical scroll bar.
891
+ Most commonly a horizontal scroll bar is used.
892
+
893
+ The most commonly used methods of the JScrollBar class are
894
+ as follows:
895
+
896
+ - The addAdjustmentListener(AdjustmentListener l) method adds a
897
+ listener to the specified JScrollBar instance. The listener
898
+ will be notified every time a change to the model of the
899
+ scroll bar is detected.
900
+ - The getModel() method returns the model of the scroll bar.
901
+ - The getMaximum() method returns the maximum value (maximum -
902
+ extent) of the scrollbar.
903
+ - The getMinimum() method returns the minimum value of the scroll
904
+ bar.
905
+ - The getOrientation() method returns the orientation of the
906
+ scroll bar.
907
+ - The getValue() method returns the scrollbar’s value.
908
+ - The setMaximum() method is used to set the maximum value
909
+ of the scrollbar.
910
+ - The setMinimum() method is used to set the minimum value of the scroll bar.
911
+ - The setOrientation() method is used to set the orientation of the scroll bar.
912
+ - The setValue() method is used to set the scrollbar’s value.
913
+
914
+ If you want to set inner padding, you have to make use of
915
+ a border:
916
+
917
+ scroll_bar.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10))
918
+
919
+ ## Checking for the escape-key being pressed
920
+
921
+ In raw Java SWING, we can use the following line of code to check whether
922
+ the user has pressed the escape-key:
923
+
924
+ if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
925
+ }
926
+
927
+ In jruby SWING, this would be:
928
+
929
+ if (event.getKeyCode() == KeyEvent::VK_ESCAPE) {
930
+ }
931
+
932
+ Note that <b>KeyEvent::VK_ESCAPE</b> returns a number; in this case
933
+ that number is <b>27</b>.
934
+
935
+ ## The Graphics class
936
+
937
+ Available methods include:
938
+
939
+ drawLine(int xstart, int ystart, int xend, int yend)
940
+ drawRect(int xleft, int ytop, int width, int height)
941
+ drawOval(int xleft, int ytop, int width, int height)
942
+ drawString(String text, int xleft, int ybottom)
943
+ fillRect(int xleft, int ytop, int width, int height)
944
+ fillOval(int xleft, int ytop, int width, int height)
945
+ setColor(Color col)
946
+
947
+ All these int-arguments refer to <b>pixels</b>.
948
+
949
+ <b>.drawLine(xstart,ystart,xend,yend)</b> draws a line segment
950
+ between the points with coordinates (xstart, ystart) and
951
+ (xend, yend).
952
+
953
+ Note that .setColor(col) sets the colour of the drawing to col.
954
+ This colour is used until the setColor command is used again.
955
+
956
+ ## The mouse and mouse-events
957
+
958
+ A mouse event in jruby is of class <b>Java::JavaAwtEvent::MouseEvent</b>.
959
+
960
+ In Java-Swing two interfaces process mouse events:
961
+
962
+ 1) MouseListener
963
+ 2) MouseMotionListener
964
+
965
+ Note that key listeners react to key strokes (aka key press events).
966
+
967
+ ## JScrollPane
968
+
969
+ First, let's have a look how a JScrollPane may look like:
970
+
971
+ <img src="https://i.imgur.com/sGd0NN6.png" style="margin: 1em">
972
+
973
+ JScrollPane is the primary widget to be used when scrolling
974
+ should be used (in Swing).
975
+
976
+ Next, let's look at a raw Java example for how to work with a <b>JScrollPane</b>:
977
+
978
+ import java.awt.FlowLayout;
979
+ import javax.swing.JFrame;
980
+ import javax.swing.JScrollPane; /* This is where it resides. */
981
+ import javax.swing.JtextArea;
982
+
983
+ public class JScrollPaneExample {
984
+ private static final long serialVersionUID = 1L;
985
+
986
+ private static void createAndShowGUI() {
987
+
988
+ // Create and set up the window.
989
+ final JFrame frame = new JFrame("Scroll Pane Example");
990
+
991
+ // Display the window.
992
+ frame.setSize(500, 500);
993
+ frame.setVisible(true);
994
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
995
+
996
+ // set flow layout for the frame
997
+ frame.getContentPane().setLayout(new FlowLayout());
998
+
999
+ JTextArea textArea = new JTextArea(20, 20);
1000
+ JScrollPane scrollableTextArea = new JScrollPane(textArea);
1001
+
1002
+ scrollableTextArea.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
1003
+ scrollableTextArea.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
1004
+
1005
+ frame.getContentPane().add(scrollableTextArea);
1006
+ }
1007
+ public static void main(String[] args) {
1008
+
1009
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
1010
+ public void run() {
1011
+ createAndShowGUI();
1012
+ }
1013
+ });
1014
+ }
1015
+ }
1016
+
1017
+ In jruby this may look like so:
1018
+
1019
+ text_area = JTextArea.new(20, 20)
1020
+ scrollable_text_area = JScrollPane.new(text_area) # Add the scroll-pane here.
1021
+ scrollable_text_area.setHorizontalScrollBarPolicy(JScrollPane::HORIZONTAL_SCROLLBAR_ALWAYS)
1022
+ scrollable_text_area.setVerticalScrollBarPolicy(JScrollPane::VERTICAL_SCROLLBAR_ALWAYS)
1023
+
1024
+ In other words: you pass the widget that you want to see scroll-bars for,
1025
+ into JScrollPane.new() - in that case, the variable text_area.
1026
+
1027
+ The viewport that you see will display the content of the JTextArea then.
1028
+
1029
+ If the whole component fits into the viewport then the default behaviour is
1030
+ that the scroll bars disappear. This behaviour can be changed, though, via
1031
+ the horizontal and vertical policy.
1032
+
1033
+ ## Using mnemonics for JButton
1034
+
1035
+ You can use shortcut-keys, aka mnemonics, for buttons.
1036
+
1037
+ This is done in general via the method called <b>.setMnemonic()</b>.
1038
+
1039
+ Example for this:
1040
+
1041
+ button.setMnemonic(KeyEvent::VK_H)
1042
+
1043
+ VK_H means Alt+H. Alt here refers to the Alt-key. H is simply the letter
1044
+ H on the keyboard, so this means "press the alt-key as well as the h
1045
+ key".
1046
+
1047
+ If you instead want to enable Akt+H, use:
1048
+
1049
+ button.setMnemonic(KeyEvent::VK_A)
1050
+
1051
+ You can also use numbers instead. For instance:
1052
+
1053
+ button.setMnemonic(KeyEvent::VK_1)
1054
+
1055
+ This would allow you to respond to "Alt+1" key combinations. You can
1056
+ find examples related to this in the file at <b>examples/017_button_example.rb</b>.
1057
+ That file will, in the long run, contain all useful button-related
1058
+ activities that may be useful when designing applications via jruby-SWING.
1059
+
1060
+ As I find this a bit cumbersome to remember (I can't remember VK_1 or
1061
+ similar crypt names), I decided to add an API that simplifies this.
1062
+
1063
+ Usage example:
1064
+
1065
+ button.keycombo('Alt+1') # respond to alt+1
1066
+ button.keycombo('Alt+W') # respond to alt+W
1067
+
1068
+ Note that this currently (<b>January 2024</b>) only works for Alt-key
1069
+ combinations. At a later time I may extend this for more key-combinations.
1070
+
1071
+ ## Working with JTable
1072
+
1073
+ A new table can be created via:
1074
+
1075
+ JTable(int rows, int cols): Creates a table of size rows * cols.
1076
+
1077
+ Like a table with (2, 3), 2 rows, and 3 columns.
1078
+
1079
+ You can also simplify it a bit, by using
1080
+ <b>javax.swing.table.DefaultTableModel</b> via:
1081
+
1082
+ m = javax.swing.table.DefaultTableModel.new
1083
+ m.add_column("id")
1084
+ m.add_column("name")
1085
+ m.add_row(['1', "jimmy"].to_java)
1086
+ m.add_row(['2', "robert"].to_java)
1087
+
1088
+ table = JTable.new(m)
1089
+ # The fulle qualifier for JTable is javax.swing.JTable, by the way.
1090
+
1091
+ You can add java-specific objects, such as a vector, via:
1092
+
1093
+ m.add_row java.util.Vector.new('"ト', 'あ', 'い'])
1094
+
1095
+ You can also pass the columns by calling DefaultTableModel.new,
1096
+ like this:
1097
+
1098
+ m = DefaultTableModel.new(nil, ["No.", "Name", "Path"].to_java)
1099
+
1100
+ The <b>API documentation</b> for JTable can be found here:
1101
+
1102
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JTable.html
1103
+
1104
+ ## Converting an Array into Java::JavaLang:Object:
1105
+
1106
+ This can be done by calling .to_java.
1107
+
1108
+ Example for this:
1109
+
1110
+ pp ["1", "jimmy"].to_java # => #<Java::JavaLang::Object[2]: ["1", "jimmy"]>
1111
+
1112
+ ## JEditorPane()
1113
+
1114
+ <b>JEditorPane()</b> can be used to <b>display text via java-swing</b>.
1115
+
1116
+ Let's have a look at an image, how this may look:
1117
+
1118
+ <img src="https://i.imgur.com/aVioB68.png" style="margin: 1em">
1119
+
1120
+ If you need to obtain the current text stored in a JEditorPane,
1121
+ you can use the method called <b>.getText()</b>.
1122
+
1123
+ ## JComponent
1124
+
1125
+ Every <b>JComponent</b> can have one or more <b>borders</b>.
1126
+
1127
+ You can put a border around a JComponent. This is done via
1128
+ the <b>.setBorder()</b> method.
1129
+
1130
+ This method is usually combined with the <b>BorderFactory class</b>.
1131
+
1132
+ In raw Java swing, the code would look like this:
1133
+
1134
+ JPanel pane = new JPanel();
1135
+ pane.setBorder(BorderFactory.createLineBorder(Color.black));
1136
+
1137
+ ## javax.swing.border
1138
+
1139
+ This subsection may eventually contain some information about
1140
+ borders in java-swing applications.
1141
+
1142
+ ## JTextPane
1143
+
1144
+ <b>JTextPane</b> can be used to render HTML content.
1145
+
1146
+ The full scope of JTextPane is <b>javax.swing.JTextPane</b>.
1147
+
1148
+ ## Creating a MenuBar via JMenu
1149
+
1150
+ First, let's look at how a Menu (JMenu) looks in Java-Swing:
1151
+
1152
+ <img src="https://i.imgur.com/PNlkIfK.png" style="margin: 1em">
1153
+
1154
+ The primary menu bar is called <b>JMenuBar</b> in Java-Swing.
1155
+
1156
+ To then create a menu, in raw Java-Swing, the following code
1157
+ could be used:
1158
+
1159
+ JMenuBar menu_bar = new JMenuBar(); # Create a new menubar here.
1160
+ JMenu m1 = new JMenu("FILE");
1161
+ menu_bar.add(m1);
1162
+ JMenu m2 = new JMenu("Help");
1163
+ menu_bar.add(m2);
1164
+
1165
+ Or in jruby code:
1166
+
1167
+ menu_bar = JMenuBar.new
1168
+ m1 = JMenu.new("FILE")
1169
+ menu_bar.add(m1)
1170
+ m2 = JMenu.new("Help")
1171
+ menu_bar.add(m2)
1172
+
1173
+ If you use the swing_paradise gem then you can also use <<
1174
+ rather than .add(). Example:
1175
+
1176
+ menu_bar << m1
1177
+ menu_bar << m2
1178
+
1179
+ This is a bit shorter to type.
1180
+
1181
+ Take note that the constructor for <b>JMenu</b> is this:
1182
+
1183
+ JMenu(String menuTitle);
1184
+ JMenu.new(menuTitle) # This for jruby.
1185
+
1186
+ So the name of the menu entry should be given, as a <b>String</b>.
1187
+
1188
+ You can also attach mnemonics to this, such as via:
1189
+
1190
+ menu = JMenu.new('A Menu')
1191
+ menu.setMnemonic(KeyEvent.VK_A)
1192
+
1193
+ As can be seen from the above code, we first need to create a new
1194
+ <b>JMenuBar</b> - this is the first step.
1195
+
1196
+ Then, now that we have a menu-bar, we can add new menus to
1197
+ it, of class JMenu. We use the method called .add() to
1198
+ add menu-entries there.
1199
+
1200
+ Once you are done with the menu, it is time to add it. The menu
1201
+ is typically added to a <b>JFrame</b>, via the following
1202
+ API:
1203
+
1204
+ setJMenuBar(JMenuBar menuBar)
1205
+ frame.setJMenuBar(menuBar)
1206
+
1207
+ Take note that there are two distinct methods that are rather
1208
+ similar: one is called <b>.setJMenuBar</b> and the other one is
1209
+ called <b>.setMenuBar</b>. JMenuBar() is for Swing and MenuBar()
1210
+ is for AWT.
1211
+
1212
+ Individual Menu items behave like buttons.
1213
+
1214
+ If you have a need to disable an individual menu item then you
1215
+ can do so via:
1216
+
1217
+ setEnabled(boolean b)
1218
+
1219
+ Example in jruby-Swing for disabling a menu item:
1220
+
1221
+ menu_item.setEnabled(false)
1222
+
1223
+ To then bind an event to a menu-item, use <b>.addActionListener</b>.
1224
+
1225
+ Example for this:
1226
+
1227
+ first = JMenuItem.new('Item 1')
1228
+ m1.add(first)
1229
+ first.addActionListener {|event|
1230
+ puts 'Hello world!'
1231
+ }
1232
+ # Or, to exit, use this:
1233
+ first.add_action_listener { |event|
1234
+ System.exit(0) # or just exit, should be fine too.
1235
+ }
1236
+
1237
+ If you have a need to repaint the menu bar, you can use .revalidate()
1238
+ as in:
1239
+
1240
+ menu_bar.revalidate()
1241
+ menu_bar.revalidate # or this one, as ruby allows you to omit ()
1242
+
1243
+ Once you created your menu, you have to fill the submenus with
1244
+ JMenuItem entries. The following shows such an example I was
1245
+ using in January 2024:
1246
+
1247
+ open_a_local_file_entrypoint = JMenuItem.new('Open a local file', KeyEvent::VK_T)
1248
+ open_a_local_file_entrypoint.use_this_font = :hack_26
1249
+ open_a_local_file_entrypoint.addActionListener {|event|
1250
+ do_choose_a_local_file_then_read_it_in
1251
+ }
1252
+ m1.add(open_a_local_file_entrypoint)
1253
+
1254
+ So, to respond to the on-selected event, make use of .addActionListenere.
1255
+
1256
+ ## Working with JSplitPane
1257
+
1258
+ Via JSplitPane - to be found under <b>javax.swing.JSplitPane</b> - you can
1259
+ split a pane, such as splitting into a left and a right component.
1260
+
1261
+ Let's look at two images as to how <b>JSplitPane</b> looks like:
1262
+
1263
+ <img src="https://i.imgur.com/zDe6NHK.png" style="margin: 1em">
1264
+ <img src="https://i.imgur.com/ucVpEcj.png" style="margin: 1em">
1265
+
1266
+ To create a new <b>split-pane</b>, you would use the following code:
1267
+
1268
+ split_pane = JSplitPane.new(JSplitPane::VERTICAL_SPLIT)
1269
+
1270
+ You can then modify its layout, or whether it allows one-touch
1271
+ expendable behaviour:
1272
+
1273
+ split_pane.setContinuousLayout(true)
1274
+ split_pane.setOneTouchExpandable(true)
1275
+
1276
+ You can then put other widgets into it, such as a button on top:
1277
+
1278
+ button_on_top = JButton.new('A')
1279
+ split_pane.setTopComponent(button_on_top)
1280
+
1281
+ And a button on bottom:
1282
+
1283
+ button_on_bottom =JButton.new('B')
1284
+ split_pane.setBottomComponent(button_on_bottom)
1285
+
1286
+ ## Assigning Enter as the trigger key for all JButtons in a Java-Swing application
1287
+
1288
+ UIManager.put("Button.defaultButtonFollowsFocus", Boolean::TRUE)
1289
+
1290
+ ## Font, working with fonts and using fonts in a java-swing application
1291
+
1292
+ Working with fonts in a java-swing application (or jruby-swing application)
1293
+ can be a bit tricky. This paragraph here tries to gather useful information
1294
+ pertaining to this.
1295
+
1296
+ The raw Java code for creating a new font, goes like this:
1297
+
1298
+ Font use_this_font = new Font("SansSerif", Font.PLAIN, 20);
1299
+
1300
+ In jruby this would be equivalent to the following code:
1301
+
1302
+ use_this_font = Font.new('SansSerif', Font::Plain, 20)
1303
+
1304
+ Next follows a list, as example, how to handle different fonts - first
1305
+ in java-swing, then in jruby-swing:
1306
+
1307
+ widget.setFont(new Font("Times New Roman", Font.PLAIN, 12))
1308
+ widget.setFont(new Font("Hack", Font.PLAIN, 40))
1309
+
1310
+ # now in jruby:
1311
+ widget.setFont(Font.new("Times New Roman", Font::PLAIN, 12))
1312
+ widget.setFont(Font.new("Hack", Font::PLAIN, 40))
1313
+
1314
+ ## Choosing files via a GUI, through JFileChooser - file-chooser functionality
1315
+
1316
+ Let's first have a look how JFileChooser may look on WinXP:
1317
+
1318
+ <img src="https://i.imgur.com/pkEoG6T.png" style="margin: 1em">
1319
+
1320
+ You can use something like the following to get a file-chooser
1321
+ in jruby-swing:
1322
+
1323
+ file_chooser = JFileChooser.new
1324
+ # file_chooser.setFileSelectionMode(JFileChooser::DIRECTORIES_ONLY)
1325
+
1326
+ result = file_chooser.showOpenDialog(nil) # or pass true here, to show the open dialog.
1327
+ case result
1328
+ when JFileChooser::APPROVE_OPTION
1329
+ this_file = file_chooser.getSelectedFile.getAbsoluteFile.to_s
1330
+ # this_file = File.absolute_path(this_file)
1331
+ main_entry?.set_text(this_file)
1332
+ end
1333
+
1334
+ Adjust accordingly to your use case. Keep in mind that on closing, a
1335
+ file selection dialogue returns an integer value which is one of
1336
+ the following integer constants:
1337
+
1338
+ APPROVE_OPTION: indicates that the ‘Open’ or ‘Save’, in case of a
1339
+ save dialogue button of the dialogue has been
1340
+ clicked.
1341
+ CANCEL_OPTION: indicates that the ‘Cancel’ button of the dialogue
1342
+ has been clicked.
1343
+
1344
+ Note that <b>JFileChooser::APPROVE_OPTION</b> returns <b>0</b>.
1345
+
1346
+ To obtain the file that was selected, the method <b>.getSelectedFile</b>
1347
+ can be used, as shown in the code example above.
1348
+
1349
+ Since as of January 2024 you can also use UniversalWidgets.main_file?
1350
+ and UniversalWidgets.set_main_file() to keep track of the chosen file.
1351
+
1352
+ ## JDialog and dialogues in jruby-SWING
1353
+
1354
+ First, what is a dialogue?
1355
+
1356
+ A dialogue is basically a simple means, via a widget, to obtain
1357
+ information from the user. This can then be of help for user-program
1358
+ interaction.
1359
+
1360
+ Dialogues - that is, the widgets - are used when the application needs
1361
+ information from the user in order to proceed with a task or some
1362
+ other event.
1363
+
1364
+ In jruby-SWING, the primary use of dialogues happens via
1365
+ <b>JDialog</b>:
1366
+
1367
+ <b>JDialog</b> can be thought of to be <b>a pop-up window</b> that pops out
1368
+ when a message has to be displayed to the user.
1369
+
1370
+ The namespace for <b>JDialog</b> is <b>javax.swing.JDialog</b>.
1371
+
1372
+ Some dialoguses are pre-defined. For instance, a message dialogue
1373
+ can be invoked via:
1374
+
1375
+ JOptionPane.showMessageDialog(
1376
+ Component parent,
1377
+ String title,
1378
+ String message,
1379
+ int type
1380
+ );
1381
+
1382
+ More documentation pertaining to JDialog, in particular its API,
1383
+ can be seen here:
1384
+
1385
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JDialog.html
1386
+
1387
+ ## Working with JRadioButton
1388
+
1389
+ First, let's look at <b>two images</b> to see how a JRadioButton
1390
+ may look like:
1391
+
1392
+ <img src="https://i.imgur.com/E4S1VWL.png" style="margin-right: 1em">
1393
+ <img src="https://i.imgur.com/hSrhzWz.jpg" style="margin: 1em">
1394
+
1395
+ <b>JRadioButton</b>'s fully qualified namespace is
1396
+ <b>javax.swing.JRadioButton</b>. Its superclass is
1397
+ a <b>JToggleButton</b>.
1398
+
1399
+ To create a new JRadioButton via java-swing, use:
1400
+
1401
+ JRadioButton x = new JRadioButton("Foobar");
1402
+
1403
+ <b>Radio buttons</b> can be pressed and they can be grouped. They
1404
+ will stay pressed until another radio button of the group is
1405
+ pressed. A black dot appears inside the circular area if
1406
+ the button is pressed, as can be seen on the above image.
1407
+
1408
+ The text that is displayed on a radio-button can be defined
1409
+ via passing a String as the first argument, as seen in the
1410
+ above example. For sake of completion we will show how this
1411
+ is done in jruby too:
1412
+
1413
+ radio_button = JRadioButton.new('Foobar')
1414
+
1415
+ If you have a need to programmatically set that radio button
1416
+ selected or de-selected, use this method:
1417
+
1418
+ radio_button.setSelected(true) # It is now selected.
1419
+ radio_button.setSelected(false) # It is now de-selected.
1420
+
1421
+ .setActionCommand(String command) assigns the string command
1422
+ as the action command to the button. Radio buttons are not
1423
+ automatically assigned an action command. This is because
1424
+ their label is often not a text but a picture. The action
1425
+ command can be set via this method.
1426
+
1427
+ <b>.getActionCommand()</b> returns the action command
1428
+ assigned to the button.
1429
+
1430
+ Normally radio buttons are put into a <b>ButtonGroup</b>. This
1431
+ has the effect that if the user selects one radio button,
1432
+ all other radio buttons are de-selected. In other words:
1433
+ this achieves that only one radio button is actively
1434
+ selected at any given moment in time.
1435
+
1436
+ In order to group radio-buttons into a button group, we should
1437
+ first create a new instance of ButtonGroup, such as via:
1438
+
1439
+ button_group = ButtonGroup.new
1440
+
1441
+ Next, use the method <b>.add()</b> to add radio_buttons into that
1442
+ button group:
1443
+
1444
+ button_group.add(radio_button1)
1445
+ button_group.add(radio_button2)
1446
+
1447
+ The <b>API documentation</b> for <b>JRadioButton</b> can be seen here:
1448
+
1449
+ https://docs.oracle.com/javase/8/docs/api/javax/swing/JRadioButton.html
1450
+
1451
+ ## Java Swing Plaf
1452
+
1453
+ The javax.swing.plaf package contains several subpackages and related packages.
1454
+
1455
+ <b>Plaf</b> stands for <b>pluggable look and feel</b>.
1456
+
1457
+ ## Swing versus AWT
1458
+
1459
+ <b>Swing component</b> class names begin with a J. AWT components do
1460
+ not.
1461
+
1462
+ For instance, JButton is a swing-component whereas Button is an
1463
+ AWT component.
1464
+
1465
+ This distinction holds true for most components, but one exception
1466
+ is the <b>JComboBox</b>, which replaces the AWT Choice component.
1467
+
1468
+ The following table shows the AWT component and the nearest
1469
+ swing replacement:
1470
+
1471
+ AWT Component | Nearest Swing Replacement
1472
+ -------------------------------------------------
1473
+ Button | JButton
1474
+ Canvas | JPanel
1475
+ Checkbox | JCheckBox
1476
+ Checkbox in CheckboxGroup | JRadioButton in ButtonGroup
1477
+ Choice | JComboBox
1478
+ Component | JComponent
1479
+ Container | JPanel
1480
+ Label | JLabel
1481
+ List | JList
1482
+ Menu | JMenu
1483
+ MenuBar | JMenuBar
1484
+ MenuItem | JMenuItem
1485
+ Panel | JPanel
1486
+ PopupMenu | JPopupMenu
1487
+ Scrollbar | JScrollBar
1488
+ ScrollPane | JScrollPane
1489
+ TextArea | JTextArea
1490
+ TextField | JTextField
1491
+ Applet | JApplet
1492
+ Dialog | JDialog
1493
+ FileDialog | JFileChooser
1494
+ Frame | JFrame
1495
+ Window | JWindow
1496
+
1497
+ ## JPasswordField
1498
+
1499
+ JPasswordField is a specialized text field that can be used for inputting
1500
+ a password into a Swing-Application.
1501
+
1502
+ Cut and copy operations are not possible within this
1503
+ component, but text can be pasted into it.
1504
+
1505
+ On Windows it may look like this:
1506
+
1507
+ <img src="https://static.javatpoint.com/java/swing/images/java-jpasswardfield1.png" style="margin: 1em">
1508
+
1509
+ ## Potentially useful links pertaining to Java-Swing
1510
+
1511
+ https://web.mit.edu/6.005/www/sp14/psets/ps4/java-6-tutorial/components.html
1512
+ https://www.javatpoint.com/java-swing
1513
+
1514
+
1515
+ ## Contact information and mandatory 2FA (no longer) coming up in 2022 / 2023
1516
+
1517
+ If your creative mind has ideas and specific suggestions to make this gem
1518
+ more useful in general, feel free to drop me an email at any time, via:
1519
+
1520
+ shevy@inbox.lt
1521
+
1522
+ Before that email I used an email account at Google gmail, but in **2021** I
1523
+ decided to slowly abandon gmail, for various reasons. In order to limit the
1524
+ explanation here, allow me to just briefly state that I do not feel as if I
1525
+ want to promote any Google service anymore when the user becomes the end
1526
+ product (such as via data collection by upstream services, including other
1527
+ proxy-services). My feeling is that this is a hugely flawed business model
1528
+ to begin with, and I no longer wish to support this in any way, even if
1529
+ only indirectly so, such as by using services of companies that try to
1530
+ promote this flawed model.
1531
+
1532
+ In regards to responding to emails: please keep in mind that responding
1533
+ may take some time, depending on the amount of work I may have at that
1534
+ moment. So it is not that emails are ignored; it is more that I have not
1535
+ (yet) found the time to read and reply. This means there may be a delay
1536
+ of days, weeks and in some instances also months. There is, unfortunately,
1537
+ not much I can do when I need to prioritise my time investment, but I try
1538
+ to consider <b>all</b> feedback as an opportunity to improve my projects
1539
+ nonetheless.
1540
+
1541
+ In <b>2022</b> rubygems.org decided to make 2FA mandatory for every
1542
+ gem owner eventually:
1543
+
1544
+ see
1545
+ https://blog.rubygems.org/2022/06/13/making-packages-more-secure.html
1546
+
1547
+ However had, that has been reverted again, so I decided to shorten
1548
+ this paragraph. Mandatory 2FA may exclude users who do not have a
1549
+ smartphone device or other means to 'identify'. I do not feel it is
1550
+ a fair assumption by others to be made that non-identified people may
1551
+ not contribute code, which is why I reject it. Mandatory 2FA would mean
1552
+ an end to all my projects on rubygems.org, so let's hope it will never
1553
+ happen. (Keep in mind that I refer to mandatory 2FA; I have no qualms
1554
+ for people who use 2FA on their own, but this carrot-and-stick strategy
1555
+ by those who control the rubygems infrastructure is a very bad one to
1556
+ pursue.
1557
+