jsugar

Change the way JTables are created

Author
Maarten 'Vngngdn' Vangeneugden
Date
March 10, 2017, 5:48 p.m.
Hash
b6d81e9d1ea94dfcab91cd745d77e4a5ce44050d
Parent
356a23fc898d68a48ca704f7e9a786ea03e87e8d
Modified files
Window.java
anotherTest.java

Window.java

5 additions and 4 deletions.

View changes Hide changes
1
1
 * Window.java - Module to create a new window with JSugar.
2
2
 * Copyright © 2016 Maarten "Vngngdn" Vangeneugden
3
3
 * 
4
4
 * This program is free software: you can redistribute it and/or modify
5
5
 * it under the terms of the GNU General Public License as published by
6
6
 * the Free Software Foundation, either version 3 of the License, or
7
7
 * (at your option) any later version.
8
8
 * 
9
9
 * This program is distributed in the hope that it will be useful,
10
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
 * GNU General Public License for more details.
13
13
 * 
14
14
 * You should have received a copy of the GNU General Public License
15
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
16
 */
17
17
18
18
/*
19
19
 * TODO list:
20
20
 * - JSlider (It's the same as the JSpinner, only longer. So an extra.)
21
21
 * - JTable (And a JScrollBar to accompany it) (extra, because of JList)
22
22
 * - JFileChooser (?)
23
23
 * DONE list:
24
24
 * - JLabel
25
25
 * - JText
26
26
 * - JButton
27
27
 * - JDialogBoxes (you know, everything dialog related)
28
28
 * - JCheckbox
29
29
 * - JRadioButton (properly grouping them has been taken care of as well)
30
30
 * - JSpinner
31
31
 * - JComboBox
32
32
 * - JList
33
33
 */
34
34
35
35
import javax.swing.*; // FIXME: Maybe namespacing it to "javax.swing;" is a better idea.
36
36
import java.util.NoSuchElementException;
37
37
import java.lang.reflect.Method;
38
38
import java.io.File;
39
39
/**
40
40
 * Window class for the program.
41
41
 *
42
42
 * Window contains the necessary data and methods to present the user with what
43
43
 * he's familiar with as being a "window". To make it functional, the developer
44
44
 * can make use of a series of methods to add components to said window, remove
45
45
 * components, and so on.
46
46
 * Currently, Window also contains methods to show dialogs. This will be cleaned
47
47
 * in the near future.
48
48
 * @author Maarten Vangeneugden
49
49
 */
50
50
public class Window { // Must be public, in order to generate Javadoc.
51
51
	private JPanel panel; // The panel that contains all the components.
52
52
	private JFrame frame; // The "window" being presented to the user.
53
53
54
54
	/**
55
55
	 * Constructor of Window.
56
56
	 * By creating a new Window instance, this constructor will automatically
57
57
	 * start the initialization of the GUI. After doing so, the caller can
58
58
	 * start adding components to the window as pleased.
59
59
	 * @param title The title to be shown in the window's title bar.
60
60
	 */
61
61
	public Window(String title) {
62
62
		// Setting the UI style to the platform's UI style. Fuck Swing's,
63
63
		// really.
64
64
		try {
65
65
		UIManager.setLookAndFeel(
66
66
				UIManager.getSystemLookAndFeelClassName());
67
67
		} catch(Exception e) {
68
68
			e.printStackTrace();
69
69
		}
70
70
71
71
		if(title == null || title.equals("")) { // If the title was omitted:
72
72
			title = "JSugar";
73
73
		}
74
74
		this.panel = new JPanel();
75
75
		// TODO: The current title is "Hello world!" but that will become caller
76
76
		// defined soon.
77
77
		JFrame frame = new JFrame(title);
78
78
		// Makes it so that if the user clicks the X in the titlebar, the window
79
79
		// closes:
80
80
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
81
81
		//frame.getContentPane().add(lblHelloWorld); // So you use a get() in order to set() data? #JavaWTF
82
82
		frame.setContentPane(this.panel); // Connecting the component panel to the window.
83
83
		// Makes the window fit to the necessary width and height, so it can show all "subcomponents".
84
84
		frame.pack(); 	
85
85
		frame.setVisible(true); // Makes the window visible to the user.
86
86
		this.frame = frame;
87
87
	}
88
88
89
89
	/**
90
90
	 * Resizes the window to fit all components.
91
91
	 * By calling this method, the window will evaluate the currently visible
92
92
	 * components, and resize itself so that all components become properly
93
93
	 * visible.
94
94
	 */
95
95
	private void updateWindow() {
96
96
		this.frame.pack();
97
97
	}
98
98
99
99
	/**
100
100
	 * A series of tests for method and class handling.
101
101
	 * When a caller presents certain methods with data concerning reflection,
102
102
	 * the Java classes you need to use for that are quite opaque, and don't
103
103
	 * offer much safety in any way.
104
104
	 * The solution therefore, is run some validation checks, but these take up
105
105
	 * a decent amount of space in terms of LoC.
106
106
	 * This method takes care of all that. Call this function whenever data
107
107
	 * needs to be validated.
108
108
	 * @param methodName The name of the method, as it is declared in object.
109
109
	 * @param object The class instance in where this method will be called.
110
110
	 * @return The method that could be derived from the supplied data, or null
111
111
	 * if that wasn't possible.
112
112
	 * @throws NullPointerException if either methodName or object are null
113
113
	 * pointers.
114
114
	 * @throws IllegalArgumentException if methodName is empty, or the method
115
115
	 * does not appear to be declared in the given object, or object is not a
116
116
	 * class.
117
117
	 */
118
118
	// All unchecked typecasts are safe, and the use of raw types is taken care
119
119
	// of.
120
120
	@SuppressWarnings({"unchecked","rawtypes"})
121
121
	private Method handleReflectionData(String methodName, Object object) {
122
122
		// Null pointer checking:
123
123
		if (methodName == null || object == null) {
124
124
			throw new NullPointerException("One or more of the given parameters are null pointers.");
125
125
		}
126
126
127
127
		// XXX: Some might say the next line should be in an else{} block. But
128
128
		// Scoping rules require that I'd then have to wrap the rest of the
129
129
		// method in the same else to use it.
130
130
		Class methodClass = object.getClass(); 
131
131
		if (methodName.equals("")) {
132
132
			throw new IllegalArgumentException("The given methodName was empty.");
133
133
		}
134
134
		Method method;
135
135
		try { // First: Look if there's a method without parameters.
136
136
			method = methodClass.getMethod(methodName, null);
137
137
		}
138
138
		catch (NoSuchMethodException exception) {
139
139
			try {
140
140
				// It's possible that the method requires an event parameter, so
141
141
				// check for that as well:
142
142
				Class<?>[] parameters = {java.awt.event.ActionEvent.class};
143
143
				method = methodClass.getMethod(methodName, parameters);
144
144
			}
145
145
			catch (NoSuchMethodException e) {
146
146
				throw new IllegalArgumentException("The given method does not appear in the given class. Be aware that the given method mustn't have any parameters, or only 1 parameter, which has to be of type java.awt.event.ActionEvent.");
147
147
			}
148
148
		}
149
149
		// At this stage, the given data has been validated, and we've been able
150
150
		// to retrieve the method itself.
151
151
		return method;
152
152
	}
153
153
154
154
	/**
155
155
	 * Creates a button in the GUI for interaction.
156
156
	 * This function offers a convenient way to create a button, that can be
157
157
	 * directly interacted with by the user. After creation, the button itself
158
158
	 * is returned to the caller, if he wishes to do something else with it.
159
159
	 * @param text The text that will be displayed in the button.
160
160
	 * @param action The action that will be returned to the action listener.
161
161
	 * @param methodName The name of the method that will be called when an
162
162
	 * action is triggered.
163
163
	 * @param triggerObject The object instance that contains the given method.
164
164
	 * This may only be a null pointer if triggerMethod is not an instance
165
165
	 * method.
166
166
	 * performed. This method may accept an ActionEvent parameter as its only
167
167
	 * parameter, or no parameters at all.
168
168
	 * @throws NullPointerException if triggerMethod is a null pointer, or
169
169
	 * the empty String was given.
170
170
	 * @throws IllegalArgumentException if triggerMethod has more than 1
171
171
	 * parameter, or the 1 required parameter is not of type ActionEvent.
172
172
	 * @return The button that was created.
173
173
	 * @see java.awt.event.ActionEvent
174
174
	 * @see java.lang.reflect.Method#invoke
175
175
	 */
176
176
	public JButton createButton(String text, String action, String methodName, Object triggerObject) {
177
177
		Method triggerMethod = this.handleReflectionData(methodName, triggerObject);
178
178
179
179
		// For starters, we first assert that the given parameters are valid:
180
180
		if (text == null) {
181
181
			text = "";
182
182
		}
183
183
		if (action == null) {
184
184
			action = "";
185
185
		}
186
186
		
187
187
		// When the method gets here, everything's been validated correctly.
188
188
		JButton button = new JButton(text);
189
189
		button.setActionCommand(action);
190
190
		button.addActionListener(
191
191
				new java.awt.event.ActionListener() {
192
192
					public void actionPerformed(java.awt.event.ActionEvent event) {
193
193
						try {
194
194
							triggerMethod.setAccessible(true);
195
195
							if (triggerMethod.getParameterTypes().length == 0) {
196
196
								// FIXME: Next line throws a warning?
197
197
								triggerMethod.invoke(triggerObject, null);
198
198
							}
199
199
							else {
200
200
								triggerMethod.invoke(triggerObject, new Object[]{event});
201
201
							}
202
202
						}
203
203
						catch (Exception useless) {
204
204
							/*
205
205
							 * XXX: Some info on why I don't just throw said
206
206
							 * Exception to the caller:
207
207
							 * Java has this awful language constraint, which
208
208
							 * forces every damn exception that isn't a subclass
209
209
							 * of RuntimeException, to be declared in the method
210
210
							 * declaration. This tends to infect all underlying
211
211
							 * methods as well, and all that for reasons I can't
212
212
							 * comprehend. In order to keep JSugar a simple and
213
213
							 * clean library, I'll rather just handle it here,
214
214
							 * and throw a RuntimeException with appropriate
215
215
							 * details.
216
216
							 */
217
217
							throw new IllegalArgumentException("triggerMethod is not accessible from this context.");
218
218
						}
219
219
					}
220
220
				});
221
221
		this.addComponent(button);
222
222
		return button;
223
223
	}
224
224
225
225
	/**
226
226
	 * Ask the user for input through a dialog box.
227
227
	 * This method presents the user with an input field, that can accept
228
228
	 * textual input. The method will return the given input after the user's
229
229
	 * clicked a button to send.
230
230
	 * @param text The text/question to be asked to the user.
231
231
	 * @return A String, equal to what the user entered.
232
232
	 * @throws NullPointerException if text is a null pointer.
233
233
	 */
234
234
	public String inputDialog(String text) {
235
235
		if (text == null) {
236
236
			throw new NullPointerException("The given text/question was a null pointer.");
237
237
		}
238
238
		return JOptionPane.showInputDialog(text);
239
239
	}
240
240
241
241
	/**
242
242
	 * Give the user a dialog box.
243
243
	 * This method can be used to provide a simple dialog to the user.
244
244
	 * This will show the user the given question, after which a boolean value
245
245
	 * is returned, holding the choice.
246
246
	 * @param text The text/question to be asked to the user.
247
247
	 * @return True if the user confirms, False if he denies.
248
248
	 * @throws NullPointerException if text is a null pointer.
249
249
	 */
250
250
	public boolean confirmDialog(String text) {
251
251
		if (text == null) {
252
252
			throw new NullPointerException("The given text/question was a null pointer.");
253
253
		}
254
254
		final int ACCEPTED = 0;
255
255
		//final int DENIED = 1; // Not used in the current context.
256
256
		int result = this.choiceDialog(text, new String[]{"Confirm", "Deny"});
257
257
		if (result == ACCEPTED) {
258
258
			return true;
259
259
		}
260
260
		else {
261
261
			return false;
262
262
		}
263
263
	}
264
264
265
265
	/**
266
266
	 * Give the user a choice dialog box.
267
267
	 * This method gives the user a simple dialog with predefined choices.
268
268
	 * These choices are to be provided by the caller in a simple array.
269
269
	 *
270
270
	 * Tip: This method works extremely well with arbitrary created choices.
271
271
	 * That is: if the outcome of the dialog is trivial (e.g. Only 1 choice),
272
272
	 * then that value is immediately returned.
273
273
	 * @param text The text/question to be asked to the user.
274
274
	 * @param choices An array of Strings, containing the choices the user can
275
275
	 * pick.
276
276
	 * @return The index value of the picked choice, or -1 if no choices were
277
277
	 * given.
278
278
	 * @throws NullPointerException if text is a null pointer.
279
279
	 */
280
280
	public int choiceDialog(String text, String[] choices) {
281
281
		if (text == null) {
282
282
			throw new NullPointerException("The given text/question was a null pointer.");
283
283
		}
284
284
		// First: handling the trivial cases:
285
285
		if (choices.length == 0) {
286
286
			return -1;
287
287
		}
288
288
		else if (choices.length == 1) {
289
289
			return 0;
290
290
		}
291
291
		int answer = JOptionPane.CLOSED_OPTION;
292
292
		// The dialog needs to be shown again until the user has made a possible
293
293
		// choice, i.e. Chickening out using the close button is not possible
294
294
		// (Because that returns CLOSED_OPTION).
295
295
		while (answer == JOptionPane.CLOSED_OPTION) {
296
296
				JOptionPane.showOptionDialog(
297
297
					null, // The parent component. May become the panel?
298
298
					text, // The text/question to describe the goal
299
299
					"Dialog", // The text in the title bar
300
300
					JOptionPane.DEFAULT_OPTION, // The kind of available options
301
301
					JOptionPane.QUESTION_MESSAGE, // The type of message
302
302
					null, // The icon to show
303
303
					choices, // The possible choices
304
304
					choices[0] // The standard choice
305
305
					);
306
306
		}
307
307
		return answer;
308
308
	}
309
309
		
310
310
311
311
	/**
312
312
	 * Creates a label in the GUI for interaction.
313
313
	 * This function offers a convenient way to create a label, that can be
314
314
	 * directly interacted with by the user. After creation, the label itself
315
315
	 * is returned to the caller, if he wishes to do something else with it.
316
316
	 * @param text The text that will be displayed in the label.
317
317
	 * @return The label that was created.
318
318
	 */
319
319
	public JLabel createLabel(String text) {
320
320
		JLabel label = new JLabel(text);
321
321
		this.addComponent(label);
322
322
		return label;
323
323
	}
324
324
325
325
	/**
326
326
	 * Adds a checkbox to the window.
327
327
	 * By providing a String, you can use this method to easily
328
328
	 * create a checkbox, and add it to the window. 
329
329
	 * @param text The text to put next to the checkbox.
330
330
	 * @return The checkbox that was created and added to the GUI.
331
331
	 */
332
332
	public JCheckBox createCheckbox(String text) {
333
333
		JCheckBox checkbox = new JCheckBox(text);
334
334
		this.addComponent(checkbox);
335
335
		return checkbox;
336
336
	}
337
337
338
338
	/**
339
339
	 * Adds radio buttons to the window.
340
340
	 * Given a list of Strings, this method will create the same amount of radio
341
341
	 * buttons.
342
342
	 *
343
343
	 * The radio buttons will silently be grouped in a ButtonGroup object,
344
344
	 * making them automatically disable each other, so only 1 radio button can
345
345
	 * be enabled. This ButtonGroup is immutable.
346
346
	 *
347
347
	 * If you need a mutable ButtonGroup, create your own, and use the 
348
348
	 * {@link #addComponent} method to add the radio buttons manually.
349
349
	 * @param text An array of Strings. The length of the array will determine
350
350
	 * the amount of radio buttons that will be created.
351
351
	 * @return An array of radio buttons, in the same order as text.
352
352
	 */
353
353
	public JRadioButton[] createRadioButtons(String text[]) {
354
354
		JRadioButton[] radioButtons = new JRadioButton[text.length];
355
355
		ButtonGroup buttonGroup = new ButtonGroup();
356
356
		for (int i=0; i<radioButtons.length; i++) {
357
357
			radioButtons[i].setText(text[i]);
358
358
			buttonGroup.add(radioButtons[i]);
359
359
			this.addComponent(radioButtons[i]);
360
360
		}
361
361
362
362
		assert radioButtons.length == buttonGroup.getButtonCount() : "The amount of radio buttons ("+ radioButtons.length +") differs from the amount of buttons in buttonGroup ("+ buttonGroup.getButtonCount() +").";
363
363
		return radioButtons;
364
364
	}
365
365
366
366
	/**
367
367
	 * Adds a number spinner component to the GUI.
368
368
	 * This method allows the caller to create a so-called "spinner component"
369
369
	 * to the window. This spinner is an input box, in which only integers can
370
370
	 * be put.
371
371
	 *
372
372
	 * The caller can set a range, a start value, and a step size.
373
373
	 *
374
374
	 * The spinner created with this method may modify itself based on the
375
375
	 * parameters.
376
376
	 * For example: If the minimum and maximum value are equal, the spinner will
377
377
	 * be disabled.
378
378
	 *
379
379
	 * @param minimum The minimum value that can be selected.
380
380
	 * @param maximum The maximum value that can be selected.
381
381
	 * @param start The value that will initially be shown in the component.
382
382
	 * @param stepSize The step size when the user increases/decreases the
383
383
	 * value.
384
384
	 * @throws IllegalArgumentException if minimum is larger than maximum, 
385
385
	 * start is not in the range of the selectable values, or stepsize is not a
386
386
	 * natural number.
387
387
	 * @return The JSpinner that was added to the window.
388
388
	 */
389
389
	public JSpinner createSpinner(int minimum, int maximum, int start, int stepSize) {
390
390
		// As usual, we begin with checking the contract:
391
391
		if(minimum > maximum) {
392
392
			throw new IllegalArgumentException("The minimum value ("+ minimum +") was larger than the maximum value ("+ maximum +")");
393
393
		}
394
394
		// The "start ∉ [minimum, maximum]" is done by the SpinnerNumberModel
395
395
		// constructor, which will be constructed later.
396
396
		if(stepSize <= 0) { // stepSize ∉ ℕ¹ (In Belgium: ℕ₀)
397
397
			throw new IllegalArgumentException("The stepSize ("+ stepSize +") is not a natural number (excluding 0).");
398
398
		}
399
399
		// If the contract is valid, we can begin:
400
400
		/*
401
401
		 * I'd like to interject here, because this is a nice example of why
402
402
		 * JSugar was a good idea:
403
403
		 * If you want a spinner, you'll typically want an integer spinner. But
404
404
		 * in Swing, when you create a JSpinner, it creates a JSpinner, with a
405
405
		 * predefined 'SpinnerNumberModel' attached to it.
406
406
		 * It's this model you then have to extract from the created spinner, on
407
407
		 * which you need to apply the configuration.
408
408
		 * What you actually have to do, is create a SpinnerNumberModel
409
409
		 * yourself, put your settings on that, and then, create a JSpinner to
410
410
		 * which you give that SpinnerNumberModel.
411
411
		 * In essence: The entire Java framework is shit.
412
412
		 */
413
413
		SpinnerNumberModel spinnerSettings = new SpinnerNumberModel(
414
414
				start,
415
415
				minimum,
416
416
				maximum,
417
417
				stepSize
418
418
				);
419
419
		JSpinner spinner = new JSpinner(spinnerSettings);
420
420
		if(minimum == maximum) { // Trivial value is set already, --> disable.
421
421
			spinner.setEnabled(false);
422
422
		}
423
423
		this.addComponent(spinner);
424
424
		return spinner;
425
425
	}
426
426
427
427
	/**
428
428
	 * Adds a number spinner component to the GUI.
429
429
	 * This method allows the caller to create a so-called "spinner component"
430
430
	 * to the window. This spinner is an input box, in which only integers can
431
431
	 * be put.
432
432
	 * 
433
433
	 * Tip: This method is a convenience method, and works extremely well with
434
434
	 * arbitrary data.
435
435
	 * For example: The start value is automatically set to the minimal possible
436
436
	 * value, and the step size defaults to 1.
437
437
	 * If the minimum and maximum are equal, the component will be disabled, and
438
438
	 * thus, be locked on the only (trivially) possible value.
439
439
	 * If minimum is larger than maximum, the method will notify you of this,
440
440
	 * but also swap the values. So you can rest assured that the spinner will
441
441
	 * handle errors, but also, inform you about it.
442
442
	 * @param minimum The minimum value that can be selected.
443
443
	 * @param maximum The maximum value that can be selected.
444
444
	 * @return The JSpinner component that was added to the window.
445
445
	 */
446
446
	public JSpinner createSpinner(int minimum, int maximum) {
447
447
		// The disabling of equal values is done in the full createSpinner(), so
448
448
		// this is merely switching values if they need to be swapped.
449
449
		if(minimum > maximum) {
450
450
			System.err.println("minimum ("+ minimum +") was larger than maximum ("+ maximum +").");
451
451
			// FIXME: Consider whether it's appropriate to print a stacktrace
452
452
			// here, which may be convenient for debugging.
453
453
			
454
454
			// XXX: I know you don't need the help variable when swapping
455
455
			// integers, because you can also do basic arithmetics. Change it if
456
456
			// it causes too much eye burn for you.
457
457
			int swapValue = minimum;
458
458
			minimum = maximum;
459
459
			maximum = swapValue;
460
460
		}
461
461
462
462
		// Yeah, these 2 variables make you cringe huh, performance addicts?
463
463
		// Drown me in the tears of your useless performance-related opinions.
464
464
		int startValue = minimum;
465
465
		int stepSize = 1;
466
466
		return this.createSpinner(minimum, maximum, startValue, stepSize);
467
467
	}
468
468
469
469
	/**
470
470
	 * Adds a combobox to the GUI.
471
471
	 * Allows the caller to create a combobox by providing the values that
472
472
	 * should be put in it.
473
473
	 *
474
474
	 * This method can only be used for String values. If that is not what you
475
475
	 * need, consider creating your own combobox and adding it manually. Or, if
476
476
	 * you need a combobox for integers, consider {@link #createSpinner}.
477
477
	 *
478
478
	 * WARNING: {@link JComboBox#getSelectedItem} returns an object, not a
479
479
	 * String. You need to manually typecast this. This is a constraint of the
480
480
	 * Swing framework.
481
481
	 * @param items An array of Strings that will be put in the combobox.
482
482
	 * @throws NullPointerException if one of the values in items is a null
483
483
	 * pointer.
484
484
	 * @throws IllegalArgumentException if items is empty.
485
485
	 * @return The JCombobox that was added to the window.
486
486
	 */
487
487
	public JComboBox<String> addComboBox(String[] items) {
488
488
		// Contract validation:
489
489
		if(items.length == 0) {
490
490
			throw new IllegalArgumentException("The given array of items was empty.");
491
491
		}
492
492
		for(String item : items) {
493
493
			if(item == null) {
494
494
				throw new NullPointerException("One of the given Strings is a null pointer.");
495
495
			}
496
496
		}
497
497
		// Contract validated, create the component:
498
498
		JComboBox<String> comboBox = new JComboBox<String>(items);
499
499
		comboBox.setSelectedIndex(0);
500
500
		if(comboBox.getItemCount() == 1) { // Trivial selection
501
501
			comboBox.setEnabled(false);
502
502
		}
503
503
		this.addComponent(comboBox);
504
504
		return comboBox;
505
505
	}
506
506
507
507
	/**
508
508
	 * Creates a list of the given data, and adds it to the GUI.
509
509
	 * This will create a JList component, containing the given data. 
510
510
	 * To jar up your memory: A list in this context, is a component in which
511
511
	 * data of the same type is printed out. The user of said list, can then
512
512
	 * select a subset of these items.
513
513
	 *
514
514
	 * @see JList for a collection of possible operations.
515
515
	 * @param items The String items that will be put in the list.
516
516
	 * @throws NullPointerException if one of the values in items is a null
517
517
	 * pointer.
518
518
	 * @throws IllegalArgumentException if items is empty.
519
519
	 * @return A JList component, that was a added to the GUI.
520
520
	 */
521
521
	public JList createList(String[] items) {
522
522
		// Contract validation:
523
523
		if(items.length == 0) {
524
524
			throw new IllegalArgumentException("The given array of items was empty.");
525
525
		}
526
526
		for(String item : items) {
527
527
			if(item == null) {
528
528
				throw new NullPointerException("One of the given Strings is a null pointer.");
529
529
			}
530
530
		}
531
531
		// Contract validated, create the component:
532
532
		JList list = new JList(items);
533
533
		this.addComponent(list);
534
534
		return list;
535
535
	}
536
536
537
537
	/**
538
538
	 * Creates a table of the given data, and adds it to the GUI.
539
539
	 * This method allows you to create a table with sorting functionality in
540
540
	 * the GUI.
541
541
	 * This method relies on implications, deducted from the given data. That
542
542
	 * is, the length of the rows and columns is calculated by the longest
543
543
	 * length it can find in the nested array.
544
544
	 * To change the data, take a look at the JTable documentation.
545
545
	 *
546
546
	 * @see JTable for a collection of possible operations.
547
547
	 * @param items The String items that will be put in the list.
548
548
	 * @throws NullPointerException if one of the values in items is a null
549
549
	 * pointer.
550
550
	 * @throws IllegalArgumentException if items is empty, or the amount of
551
551
	 * column names does not correspond with the given amount of items.
552
552
	 * @return A JTable component, that was a added to the GUI.
553
553
	 */
554
554
	public JTable createTable(String[] columns, String[][] items) {
555
555
		// Contract validation:
556
556
		if(items.length == 0) {
557
557
			throw new IllegalArgumentException("The given array of items was empty.");
558
558
		}
559
559
		if(columns.length != items[0].length) {
560
560
			throw new IllegalArgumentException("The amount of columns does not correspond to the given amount of items.");
561
561
		for(String item : items) {
562
-
			if(item == null) {
563
-
				throw new NullPointerException("One of the given Strings is a null pointer.");
+
562
		for(int i=0; i<items.length; i++) {
+
563
			if(items[i] == null) {
+
564
				throw new NullPointerException("One of the given Strings is a null pointer.");
564
565
			}
565
566
		}
566
567
		// Contract validated, create the component:
567
568
		// Deducting max length:
568
569
		columnCount = columns.length;
569
-
		rowCount = items.length;
570
-
		
+
570
		int rowCount = items.length;
+
571
		
571
572
		JTable table = new JTable(items, columns);
572
573
		this.addComponent(table);
573
574
		return table;
574
575
	}
575
576
576
577
	/**
577
578
	 * Adds the given component to the GUI.
578
579
	 * This method allows its caller to give a pre-made component, so that it
579
580
	 * can be added to the GUI. Even though its main use is for the Window class
580
581
	 * itself, the user of JSugar can also use it to create components himself,
581
582
	 * and then add them. As such, this method doesn't provide parameters for
582
583
	 * reflection/action triggering purposes.
583
584
	 * @param component The component to be added to the window.
584
585
	 * @throws NullPointerException if the given component is a null pointer.
585
586
	 */
586
587
	public void addComponent(JComponent component) {
587
588
		int originalSize = this.panel.getComponentCount();
588
589
		this.panel.add(component); // Throws the exception if null.
589
590
		this.updateWindow();
590
591
591
592
		assert originalSize == this.panel.getComponentCount()-1 : "A component was supposed to be added to the window, but the total amount of components was unchanged after the addition.";
592
593
	}
593
594
594
595
	/**
595
596
	 * Removes the given component from the GUI.
596
597
	 * This method allows its caller to remove a component from the GUI.
597
598
	 * @param component The component to be removed.
598
599
	 * @throws NoSuchElementException if the given component does not exist in
599
600
	 * the GUI.
600
601
	 * @throws NullPointerException if the given component is a null pointer.
601
602
	 */
602
603
	public void removeComponent(JComponent component) {
603
604
		int originalSize = this.panel.getComponentCount();
604
605
		this.panel.remove(component);
605
606
		int newSize = this.panel.getComponentCount();
606
607
		if (originalSize != newSize+1) {
607
608
			throw new NoSuchElementException("The given component does not exist in the GUI.");
608
609
		}
609
610
		this.updateWindow();
610
611
	}
611
612
	/**
612
613
	 * Prompts the user with a file chooser dialog.
613
614
	 * By calling this method, the user will be presented with a file chooser
614
615
	 * dialog, out of which a single file can be selected. If the selected file
615
616
	 * exists, a File object is returned, a null pointer if the user cancelled.
616
617
	 * @return A File object representing the file the user selected, or null
617
618
	 * otherwise.
618
619
	 */
619
620
	public File openFileChooserDialog() {
620
621
		JFileChooser fileDialog = new JFileChooser();
621
622
		fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
622
623
623
624
		int userResponse = fileDialog.showOpenDialog(this.panel);
624
625
		if(userResponse == JFileChooser.APPROVE_OPTION) {
625
626
			return fileDialog.getSelectedFile();
626
627
		}
627
628
		else {
628
629
			return null;
629
630
		}
630
631
	}
631
632
}
632
633

anotherTest.java

2 additions and 0 deletions.

View changes Hide changes
1
1
import java.lang.reflect.Method;
2
2
public class anotherTest {
3
3
	public anotherTest() {
4
4
		Window window = new Window("anotherTest.java");
5
5
		JButton button = new JButton(); // Yeah, have to initialize that, because Java.
6
6
		button = window.createButton("Knopje!!", "???", "printSomething",  this);
7
7
		try {
8
8
			Thread.sleep(1000);
9
9
		} catch (InterruptedException e){
10
10
			e.printStackTrace();
11
11
		}
12
12
		button.setText("LOL");
13
13
		System.out.println("Done.");
14
14
+
15
		window.createRadioButtons(list);
+
16
15
17
		System.out.println("Okay, that worked...");
16
18
		try {
17
19
			Thread.sleep(1000);
18
20
		} catch (InterruptedException e){
19
21
			e.printStackTrace();
20
22
		}
21
23
		window.removeComponent(button);
22
24
	}
23
25
24
26
	public void printSomething() {
25
27
		System.out.println("Okay, I can print stuff.");
26
28
	}
27
29
}
28
30