swing_paradise 0.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

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
+