10. [TD]: Implementation of the [ui] layer with a Swing interface-
Keywords: multi-layer architecture, Spring, dependency injection, Swing component library.
![]() |
10.1. Background
![]() |
In the [UI] layer, we want to build a Swing GUI. Netbeans has a tool, [Matisse], for building these Swing interfaces that is superior to what Eclipse offers. Swing interfaces are gradually being replaced by JavaFx interfaces. Netbeans and Eclipse use the same tool to build the latter. Therefore, if we build JavaFx interfaces, we can keep Eclipse throughout the entire layered architecture.
Netbeans can open any Maven project. We will therefore use the previous Maven project and add a Swing interface to it. In [2], we load (File / Open project) the Maven projects for the three layers that we built with Eclipse. Then, we build their binaries using [3]. The options [Build] and [Clean and Build] build the binary for the project to which they are applied. These binaries are placed in the [target] [4-5] folder of the project:
![]() |
option and [Clean] delete this folder. [target] and option rebuild it. Experience shows that when unexpected problems arise, the first thing to do is run a [Clean and Build] on the project to ensure you are working with the latest version of the project. This is particularly necessary when you have configuration files that, if modified, do not trigger an automatic recompilation when the project is run. You must then force this recompilation using a [Clean and Build] so that their new versions are installed in the [target] folder.
10.2. How the Application Works
Let’s return to the overall architecture of the [Elections] application:
![]() |
We are now focusing on a new implementation of the [ui] layer. The only implementation currently available is a console interface. We are now creating a graphical user interface.
The user will have the following interface to interact with the [Elections] application:
![]() |
![]() |
The graphical user interface is located in the [ui] layer. It is this layer that interacts with the user.
- At startup, the [main] console application instantiates the application’s three layers using Spring. This is done even before the graphical user interface is visible. Also during this initialization phase, information characterizing the election (number of seats to be filled, electoral threshold, competing lists) is requested from the [dao] layer. If this initialization phase fails (e.g., inability to access the data), an error message is displayed on the console and the graphical user interface is not displayed.
- If the data was read successfully, the graphical interface is displayed with the following information (see screenshot above):
- the number of seats to be filled in (2)
- the electoral threshold in (3)
- the IDs and names of the candidate lists in (4)
- The user then assigns the number of votes to each candidate list using fields 4 (id - name), 5 (votes), and 6 (to add).

- You can then use link (10) to calculate the seats:

- The link [Enregistrer] (12) allows you to save the results to the data source.
10.3. The [ElectionsSwing] implementation class of the [ui] layer
10.3.1. The Netbeans project
Note: Section 22.4 explains how to obtain Netbeans.
The final Netbeans project for the application will have the following form: [1]. Build it by following the steps in [2-5]:
![]() |
![]() |
Ensure that the project is configured to be compiled by a JDK 1.8 [1-6]:
![]() |
10.3.2. Maven Configuration
The new [elections-swing-metier-dao-jdbc] project will build on the previous [elections-console-metier-dao-jdbc] project. To do this, add a Maven dependency as follows [1-3]:
![]() |
![]() |
10.3.3. Building the GUI
To create the graphical user interface, we can proceed as follows:
![]() |
![]() |
- [1]: Adding an object to the [elections.ui.service] package
- [2]: Selecting option [JFrame Form] from the [Swing GUI Forms] category
![]() |
- [4]: Name the class
- [5]: the class package.
- Finish the wizard.
- [6]: the generated class
![]() |
- [7]: the [AbstractElectionsSwing] class in [Design] mode
- [8]: the [Navigator] tab that displays the [9] tree of window components
- [10]: the [Properties] tab, which displays the properties of the [jFrame] component selected in [9]
![]() |
- [11]: [JFrame] is a component container. Components can be arranged within the container according to various positioning rules called layouts. Here, we choose the layout [Free Design] [14], which allows components to be positioned freely within the container.
We find the components in the toolbar called the Palette:
![]() |
- [1]: the palette
- [2]: a component JLabel is placed in the component container
- By right-clicking on it, you can access various properties: its name [4], its text [3], or its event handlers [5]. We use [3] to set the text [6].
![]() |
- [1]: The [Properties] tab of the [JLabel] component provides access to its properties: its horizontal positioning [2], vertical positioning [3], the text font [4], and the text [5].
When a component is dropped and configured on the graphical interface and the work is saved (Ctrl-S), code is generated in the [AbstractElectionsSwing] class:
![]() |
![]() |
Do not modify this grayed-out code, as it is deleted and regenerated upon the next save. Any changes made would then be lost.
A tutorial on creating a graphical interface with Netbeans can be found at URL [https://netbeans.org/kb/docs/java/quickstart-gui.html?print=yes#design] (November 2015).
We will now build the following interface:
![]() |
The interface components are as follows:
No. | type | name | role |
JMenuBar | jMenuBar1 | a menu | |
JLabel | jLabelSAP | the number of seats to be filled | |
JLabel | jLabelSE | the electoral threshold | |
JComboBox | jComboBoxNomsListes | List of names of competing lists | |
JTextField | jTextFieldVoixListe | Number of votes for a list | |
JLabel | jLabelAjouter | to add a list to (8) | |
(JScrollPane, JList) | jListNomsVoix | the names and voices of the lists | |
JLabel | jLabelSupprimer | to remove from (8) the list selected in (8) | |
JLabel | jLabelCalculer | to calculate the election results | |
JLabel | jLabelEffacer | to clear the election results | |
JLabel | jLabelEnregistrer | to record the election results | |
(JScrollPane, JList) | jListResultats | to display the election results | |
(JScrollPane, JTextPane) | jTextPaneMessages | to view follow-up messages |
The annotation (JScrollPane, JList) [13-14] is there to indicate that when a [JList] component is dropped into the window, it is automatically inserted into a [JScrollPane] component that enables scrolling through the list. The [JScrollPane] component allows you to view all items in the list, even though only a limited number of them are visible at any given time. The same applies to the [JTextPane] and [15-16] components.
The menu can be created as follows:
![]() |
- [1, 2]: a [Menu Bar] component is placed on the window
- [3]: the default menu generated as shown in the [Navigator] tab
- [4,5,6]: by right-clicking on a menu item option, you can:
- change its text [4], its name [5]
- manage its events
- [7]: the desired menu
The desired menu is as follows:
Level 1 | Level 2 |
Elections | |
Exit | |
Lists | |
Add | |
Delete | |
Results | |
Calculate | |
Clear | |
Save | |
About |
You can test the graphical interface at any time:
![]() |
When building the interface, you must associate an event handler with certain labels and menus [Ajouter, Effacer, ...]. Here’s how to do it:
![]() |
- [1]: right-click on the component for which you want to manage an event
- [2]: Select the option [Events]
- [3]: Select an event category
- [4]: Select the event you want to manage
The Java code generated by this operation is as follows:
jLabelCalculer.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jLabelCalculerMouseClicked(evt);
}
});
...
private void jLabelCalculerMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
- lines 1-5: an event handler is added to the jLabelCalculer component. The addMouseListener method expects as a parameter a class that implements the following MouseListener interface:
![]() |
The MouseListener interface is implemented by various classes, including the MouseAdapter class. This class implements the five methods of the MouseListener interface, but these methods do nothing. Therefore, you must derive from this class to implement the method(s) of your choice. This is done in the code above and shown below:
jLabelCalculer.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
jLabelCalculerMouseClicked(evt);
}
});
The code above uses the anonymous class technique described in Section 2.5 of the [ref1] course.
Line 1: The parameter of the addMouseListener method is an anonymous class, defined on the fly. It is an instance of a class derived from the MouseAdapter class (line 1), whose mouseClicked method (lines 2–4) is overridden so that it performs a specific action.
The jLabelCalculerMouseClicked method called on line 3 is defined as follows:
private void jLabelCalculerMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
The developer handles the "MouseClicked" event by adding code to this method.
All event handlers are generated by Netbeans in this way. The developer can ignore the lines of code generated by Netbeans to associate a method with a component event. They can simply place their code in line 2 above. Here is an example:
private void jLabelCalculerMouseClicked(java.awt.event.MouseEvent evt) {
System.out.println("Mouse Clicked");
}
If you run the GUI and click on the [Calculer] link, a message appears on the console:
![]() |
- [1]: double-click on the label [Calculer]
- [2]: the handler for this event was executed and produced the messages mouseClicked in the Netbeans console.
The [jComboBoxNomsListes, jListNomsVoix, jListResultats] components are declared as follows:
protected javax.swing.JComboBox jComboBoxNomsListes;
protected javax.swing.JList jListNomsVoix;
protected javax.swing.JList jListResultats;
These components are lists that are normally configured with a type T: the type of the model elements displayed by the components. This type T can be any type. The value displayed in the list component is of type [String]. By default, the method [T.toString()] is used for display. To better control what is displayed, the type T here will be String. Therefore, the correct declaration of our lists is as follows:
protected javax.swing.JComboBox<String> jComboBoxNomsListes;
protected javax.swing.JList<String> jListNomsVoix;
protected javax.swing.JList<String> jListResultats;
We achieve this result by modifying one of the component’s properties:
![]() |
10.3.4. Code Separation
Let’s return to the structure of our application:
![]() |
The [AbstractElectionsSwing] class must implement the [ui] layer above. Its code, generated by Netbeans, currently contains only window management code and event handlers that do nothing at this point. Above, we see that the [AbstractElectionsSwing] class will need to handle interactions with the [métier] layer. This handling will take place in the event handlers. To clarify the code structure, we decide to place it in two classes:
- [AbstractElectionsSwing], which will remain as it was generated by Netbeans, with a few minor details. This class will not handle any events itself. The event handlers will be empty and declared abstract. They will be implemented by a class derived from [AbstractElectionsSwing].
- [ElectionsSwing], a class derived from [AbstractElectionsSwing], which will implement all event handlers.
This type of separation is not unusual. It can be found, for example, in the web pages ASP.NET (version, not MVC). The Netbeans project evolves as follows:
![]() |
The code for the [AbstractElectionsSwing] class evolves as follows:
public abstract class AbstractElectionsSwing {
....
private void jMenuItemCalculerActionPerformed(java.awt.event.ActionEvent evt) {
doCalculer();
}
...
private void jLabelCalculerMouseClicked(java.awt.event.MouseEvent evt) {
if (jLabelCalculer.isEnabled()) {
doCalculer();
}
}
....
// event managers
abstract protected void doSupprimer();
abstract protected void doCalculer();
abstract protected void doQuitter();
abstract protected void doEffacer();
abstract protected void doEnregistrer();
abstract protected void doAjouter();
abstract protected void doInformer();
abstract protected void doMajLabelAjouter();
abstract protected void doMajLabelSupprimer();
...
}
- line 1: the class is declared abstract
- lines 3-5: handling the click on the option menu item [jMenuItemCalculer]. We can see that event handling is delegated to the doCalculer method on line 19. This method is not implemented and is declared abstract. It will be implemented by the derived class [ElectionsSwing];
- lines 9–13: the click event handler for the [jLabelCalculer] label. A click always triggers an event, whether the [jLabel] component is active (enabled=true) or inactive (enabled=false). Here, we ensure that it is indeed active to handle the event;
- lines 15 and beyond: this technique of delegating event handling to an abstract method is applied to all event handlers.
The class [ElectionsSwing], derived from [AbstractElectionsSwing], implements all event handlers not implemented by [AbstractElectionsSwing]:
package elections.ui.service;;
...
public class ElectionsSwing extends AbstractElectionsSwing {
// event managers
@Override
protected void doInformer() {
...
}
@Override
protected void doAjouter() {
...
}
@Override
protected void doCalculer() {
...
}
@Override
protected void doEffacer() {
...
}
@Override
protected void doEnregistrer() {
...
}
@Override
protected void doQuitter() {
System.exit(0);
}
@Override
protected void doSupprimer() {
...
}
@Override
protected void doMajLabelAjouter() {
...
}
@Override
protected void doMajLabelSupprimer() {
...
}
}
- line 3: [ElectionsSwing] is derived from [AbstractElectionsSwing]
- lines 7–50: the event handlers for the graphical window
The methods of the derived class [ElectionsSwing] will manipulate the components of the parent class [AbstractElectionsSwing]. Currently, these components have a private scope, preventing the child class [ElectionsSwing] from accessing them:
private JMenuItem jMenuItemAPropos = null;
private JLabel jLabelAjouter = null;
To resolve this issue, we will ensure that the scope of the GUI components is [protected]:
![]() |
- set the [protected] attribute to [3];
10.3.5. Implementation of the [IElectionsUI] interface
Let’s return to the structure of our application:
![]() |
In the diagram above, the [ui] layer must expose the [IElectionsUI] interface to the [main] object:
package elections.ui.service;
public interface IElectionsUI {
/**
* lance le dialogue avec l'user
*/
public void run();
}
This interface was defined in the [elections-console-metier-dao-jdbc] project and described in section 9.4. Since this project is a dependency of the [swing] project, this interface is known.
Because the [AbstractElectionsSwing] class has become abstract, it can no longer be instantiated by Spring. The [ElectionsSwing] class must now be instantiated instead. The [ElectionsSwing] class must implement the [IElectionsUI] interface. Its code therefore changes as follows:
public class ElectionsSwing extends AbstractElectionsSwing implements IElectionsUI {
// interface [ElectionsUI] run method
public void run() {
...
}
- line 1: the class [ElectionsSwing] implements the interface [IElectionsUI]
- lines 4–6: the [run] method of this interface
What should the run method do? Display the graphical window. How do we do that? We can follow the [main] method generated by Netbeans in the [AbstractElectionsSwing] class, which does what is desired:
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
The [AbstractElectionsSwing] constructor used on line 28 is as follows:
public AbstractElectionsSwing() {
initComponents();
}
- Line 2: The [initComponents] method is a private method generated by the GUI generator. Its code cannot be changed.
The [run] method of the [ElectionsSwing] class could then be as follows:
@Override
public void run() {
// the graphical interface is displayed
SwingUtilities.invokeLater(new Runnable() {
public void run() {
init();
setVisible(true);
}
});
}
- Line 6: The graphical interface is initialized using the [init] method. Here, we would like to call the [initComponents] method of the parent class, but it is private. We therefore add the following [init] method to the parent class [AbstractElectionsSwing]:
protected void init(){
initComponents();
}
- (continued)
- because it is in the [AbstractElectionsSwing] class, the [init] method has access to the private [initComponents] method of the same class;
- because it has the attribute [protected], it is visible in the child class [ElectionsSwing];
- line 7: the graphical interface is made visible;
Note: Once the [run] method has been written in the [ElectionsSwing] class, the [main] method of the abstract class [AbstractElectionsSwing] can be removed.
10.3.6. The executable class
Let’s return to the structure of our application:
![]() |
We would like Spring to instantiate the [ui] layer as it did when it was implemented by a console application. To do this, the implementation class [ElectionsSwing] must have a reference to the [métier] layer:
@Component
public class ElectionsSwing extends AbstractElectionsSwing implements IElectionsUI{
// reference on the [business] layer
@Autowired
private IElectionsMetier metier;
...
- line 1: the [ElectionsSwing] class is a Spring component;
- lines 5-6: Spring injects a reference to the [métier] layer;
The graphical user interface is launched by executing the following [BootElectionsSwing] class:
![]() |
package elections.ui.boot;
import elections.ui.service.IElectionsUI;
public class BootElectionsSwing extends AbstractBootElections {
public static void main(String[] arguments) {
new BootElectionsSwing().run();
}
@Override
protected IElectionsUI getUI() {
return ctx.getBean("electionsSwing", IElectionsUI.class);
}
}
We explained similar code in Section 9.5 when discussing the code for the classes [AbstractBootElections] and [BootElectionsConsole]. On line 12, we retrieve the bean named [electionsSwing], which corresponds to the standard Spring name for the class [ElectionsSwing].
10.3.7. Initialization of the graphical user interface
When the GUI is displayed, some of its components have been initialized:

As shown above:
- that the combo box has been populated with the names of the lists;
- that the number of seats to be filled and the electoral threshold are displayed;
- that some links have been disabled;
- that a success message is displayed at the bottom of the window;
When will these initializations take place? They can only occur after the [electionsMetier] field of the [ElectionsSwing] class has been initialized. This is because the list names will be requested from the [metier] layer. Spring will initialize this field in the following order:
- using the parameterless constructor of the [ElectionsSwing] class;
- injection of dependencies, in this case the reference to the [métier] layer;
- execution of the [run] method of the [ElectionsSwing] class:
@Override
public void run() {
// the graphical interface is displayed
SwingUtilities.invokeLater(new Runnable() {
public void run() {
init();
setVisible(true);
}
});
}
- In line 12, we specified that we would call the [init] method of the parent class, which will draw the GUI components. We will redefine this method locally in the [ElectionsSwing] class. It is in this method that we will initialize the window components (combo boxes, labels) with data this time:
The local method [init] could have the following skeleton:
public class ElectionsSwing extends AbstractElectionsSwing implements IElectionsUI {
...
// reference on the [business] layer
@Autowired
private IElectionsMetier metier;
// initializations
public void init() {
// generation of components by the parent class
super.init();
// lists are requested from the [metier] layer
...
// associate list names with the jComboBoxNomsListes combo
...
// and election parameters
...
// on initialise les labels liés à ces deux informations
...
// message of success
...
// initialization status of certain components form
...
}
Note, on line 11, the call to the [init] method of the parent class.
10.3.8. The [Utilitaires] class
A number of static utility methods have been grouped together in the [Utilitaires] class:
![]() |
The [Utilitaires] class is as follows:
package istia.st.elections.ui;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
//utility class
class Utilitaires {
// manage label array status
public static void setEnabled(JLabel[] labels, boolean value) {
for (int i = 0; i < labels.length; i++) {
labels[i].setEnabled(value);
}
}
// manage the status of a table of menu options
public static void setEnabled(JMenuItem[] menuItems, boolean value) {
...
}
}
- Line 9: The setEnabled method sets the state of JLabel components defined in an array. The setEnabled method of a JLabel component allows you to enable or disable the JLabel.
Task: Following the example of the setEnabled method on line 9, write the setEnabled method on line 16 that does the same thing with JMenuItem components.
10.3.9. The code for the [ElectionsSwing] class
Let’s review the general structure of the [ElectionsSwing] class:
package istia.st.elections.ui;
...
public class ElectionsSwing extends AbstractElectionsSwing implements IElectionsUI {
// reference on the [business] layer
@Autowired
private IElectionsMetier metier;
// initializations
public void init() {
...
}
// event managers
@Override
protected void doInformer() {
...
}
@Override
protected void doAjouter() {
...
}
@Override
protected void doCalculer() {
...
}
@Override
protected void doEffacer() {
...
}
@Override
protected void doEnregistrer() {
...
}
@Override
protected void doQuitter() {
System.exit(0);
}
@Override
protected void doSupprimer() {
...
}
@Override
protected void doMajLabelAjouter() {
...
}
@Override
protected void doMajLabelSupprimer() {
...
}
}
We will examine the methods of the class one by one.
10.3.9.1. The [init] method
Let’s return to the graphical interface:
![]() |
The [init] method is designed to:
- to populate the [4] combo box with the IDs and names of the lists in the format [id - nom]
- to display a success message in [15]
- to initialize the labels [2] and [3]
- to disable certain links
The skeleton of the [init] method could be as follows:
@Override
protected void init() {
// generation of components by the parent class
super.init();
// local initializations
modèleNomsVoix = new DefaultListModel<>();
jListNomsVoix.setModel(modèleNomsVoix);
modèleRésultats = new DefaultListModel<>();
jListResultats.setModel(modèleRésultats);
String info;
try {
// lists are requested from the [business] layer
listes = ...
// associate list names with the jComboBoxNomsListes combo
...
// and election parameters
int nbSiegesAPourvoir = ...
double seuilElectoral = ...
// on initialise les labels liés à ces deux informations
...
// message of success
info = "Source de données lue avec succès";
} catch (ElectionsException ex1) {
// we note the error
info = getInfoForException("Les erreurs suivantes se sont produites :", ex1);
} catch (RuntimeException ex2) {
// we note the error
info = getInfoForException("Les erreurs suivantes se sont produites :", ex2);
}
// display info
jTextPaneMessages.setText(info);
jTextPaneMessages.setCaretPosition(0);
// form status
Utilitaires.setEnabled(new JLabel[] { jLabelAjouter, jLabelCalculer, jLabelEnregistrer, jLabelSupprimer }, false);
Utilitaires.setEnabled(
new JMenuItem[] { jMenuItemAjouter, jMenuItemCalculer, jMenuItemEnregistrer, jMenuItemSupprimer }, false);
// center window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
}
private String getInfoForException(String message, ElectionsException ex) {
// the message
StringBuffer info = new StringBuffer(String.format("%s -------------\n", message));
info.append(String.format("Code erreur : %d\n", ex.getCode()));
// errors are displayed
for (String erreur : ex.getErreurs()) {
info.append(String.format("-- %s\n", erreur));
}
return info.toString();
}
private String getInfoForException(String message, RuntimeException ex) {
// the message
StringBuffer info = new StringBuffer(String.format("%s -------------\n", message));
// display the exception stack
Throwable cause = ex;
while (cause != null) {
info.append(String.format("-- %s\n", cause.getMessage()));
cause = cause.getCause();
}
return info.toString();
}
Task: Complete the code for the [init] method.
Read in the course: components JTextField, JLabel
Note:
A JList component displays the data in a template. By default, this template is of type DefaultListModel (lines 2 and 3). A DefaultListModel object behaves somewhat like a ArrayList type:
- to add an object o to the model:
[DefaultListModel].addElement(Object o);
In this application, the object o will always be of type String.
- To remove element #i from the model:
[DefaultListModel].remove(int i);
- To retrieve element #i from the model:
[DefaultListModel].elementAt(int i);
To add an item to the [jComboBoxNomsListes] combo box, use the [addItem] method:
jComboBoxNomsListes.addItem(chaîne de caractères)
A JTextPane component has the methods getText() and setText() to read/write the displayed text.
10.3.9.2. Manage the state of the [Ajouter] link
The link [Ajouter] [6] is active only when the [5] field in the records is not empty. In the [AbstractElectionsSwing] class, the handler that tracks cursor movements in the [5] field is as follows:
private void jTextFieldVoixListeCaretUpdate(javax.swing.event.CaretEvent evt) {
doMajLabelAjouter()
}
Line 2 calls the [doMajLabelAjouter] method of the [ElectionsSwing] class.
protected void doMajLabelAjouter() {
// set label status [jLabelAjouter]
...
// set menu status [jMenuItemAjouter]
...
}
Task: Complete the code for the [doMajLabelAjouter] method.
10.3.9.3. Assign votes to each list
For each candidate list in (4), proceed as follows:
- select a list from (4)
- enter the number of votes in (5)
- confirm by clicking the link [Ajouter]
Input errors are flagged as shown in the following example:

If the number of votes is correct, the list is added to component (8), the number of votes is cleared, and the [Ajouter] link is disabled:
![]() | ![]() |
In the [AbstractElectionsSwing] class, the handler that manages the click on the [Ajouter] link is as follows:
private void jLabelAjouterMouseClicked(java.awt.event.MouseEvent evt) {
if (jLabelAjouter.isEnabled()) {
doAjouter();
}
}
Line 3 calls the [doAjouter] method of the [ElectionsSwing] class:
// list templates JList
private DefaultListModel<String> modèleNomsVoix = null;
private DefaultListModel<String> modèleRésultats = null;
// competing lists
private ListeElectorale[] listes;
// user-entered lists
private final List<ListeElectorale> listesSaisies = new ArrayList<>();
private ListeElectorale[] tListesSaisies;
...
@Override
protected void doAjouter() {
// is the number of votes correct?
...
// if error, then report it
if (erreur) {
JOptionPane.showMessageDialog(null, "Nombre de voix incorrect", "Elections : erreur",
JOptionPane.INFORMATION_MESSAGE);
jTextFieldVoixListe.requestFocus();
// back to graphical interface
return;
}
// no error - save the list
listesSaisies.add(...);
modèleNomsVoix.addElement(...);
// we clean up the vote count
jTextFieldVoixListe.setText("");
// form status (menus, labels)
...
}
- Line 25: Every time the user adds votes to a list and confirms their selection, this list is placed in the [listesSaisies] field on line 9. The list will be saved there along with the [id, version, nom, voix] information. The first three pieces of information come from the lists initially stored in the array on line 6. The combo box’s [getSelectedIndex] method returns the index of the selected list;
Task: Complete the code for the [doAjouter] method.
10.3.9.4. Manage the status of the [Supprimer] link
The link [Supprimer] [9] is active only when an item is selected in [8].
In the [AbstractElectionsSwing] class, the handler that responds to a click on an item in the [8] list is as follows:
private void jListNomsVoixValueChanged(javax.swing.event.ListSelectionEvent evt) {
doMajLabelSupprimer();
}
Line 2 calls the [doMajLabelSupprimer] method of the [ElectionsSwing] class.
@Override
protected void doMajLabelSupprimer() {
// lights up the [jLabelSupprimer] label and the corresponding option menu item
...
}
Task: Complete the code for method [doMajLabelSupprimer].
10.3.9.5. Delete a candidate list
The link [Supprimer] [9] allows you to delete the (name,voice) pair selected in (8). Once the deletion is complete, the [Supprimer] link is disabled. It will only be re-enabled when a new list is selected in (8).
![]() | ![]() |
In the [AbstractElectionsSwing] class, the handler that responds to a click on the [Supprimer] link is as follows:
private void jLabelSupprimerMouseClicked(java.awt.event.MouseEvent evt) {
if(jLabelSupprimer.isEnabled()){
doSupprimer();
}
}
Line 3 calls the [doSupprimer] method of the [ElectionsSwing] class.
@Override
protected void doSupprimer() {
// deletion of the selected list, the modèleNomsVoix template and the lists entered
...
// maj label status and form menu options
Utilitaires.setEnabled(...);
...
}
Task: Complete the code for the [doSupprimer] method.
10.3.9.6. Manage the status of the [Calculer] link
The link [Calculer] [10] is active only when there is at least one element in [8].
Task: Add the necessary code to manage this link in the previously written methods [doAjouter] and [doSupprimer]. The corresponding menu item option will also be managed.
Note: The number of elements in a DefaultListModel-type element is obtained using the size() method.
10.3.9.7. Calculate seats
The link [Calculer] [10] allows you to start the seat calculation and display the results in (14). If the calculation fails (all lists have been eliminated), an error message is displayed in [15]. In any case, after the calculation, the link [Calculer] [10] is disabled.
In the [AbstractElectionsSwing] class, the handler that responds to a click on the [Calculer] link is as follows:
private void jLabelCalculerMouseClicked(java.awt.event.MouseEvent evt) {
if(jLabelCalculer.isEnabled()){
doCalculer();
}
}
Line 3 calls the [doCalculer] method of the [ElectionsSwing] class.
// user-entered lists
private final List<ListeElectorale> listesSaisies = new ArrayList<>();
private ListeElectorale[] tListesSaisies;
...
@Override
protected void doCalculer() {
tListesSaisies = listesSaisies.toArray(new ListeElectorale[0]);
// calculation of seats
try {
...
} catch (ElectionsException ex) {
// we display the exception
...
return;
}
// display of results
...
// maj state form
Utilitaires.setEnabled(...);
}
Task: Complete the code for method [doCalculer].
10.3.9.8. Save the results to the data source
The link [Enregistrer] (12) allows you to save the seat calculation results to the data source. Once the save is successful, the [Enregistrer] link is disabled. If the save fails, an error message is displayed in [15]. In any case, the [Enregistrer] link is then disabled.
In class [AbstractElectionsSwing], the handler that manages the click on label [Enregistrer] is as follows:
private void jLabelEnregistrerMouseClicked(java.awt.event.MouseEvent evt) {
if(jLabelEnregistrer.isEnabled()){
doEnregistrer();
}
}
Line 3 calls the [doEnregistrer] method of the [ElectionsSwing] class:
@Override
protected void doEnregistrer() {
// registration is requested from the business layer
try {
...
} catch (ElectionsException ex) {
// exception is displayed
...
// back to graphical interface
return;
}
// uPGRADE FORM
Utilitaires.setEnabled(...);
...
}
Task: Complete the code for method [doEnregistrer].
10.3.9.9. Clear results
The link [Effacer] (11) clears the results displayed in (14).
In the [AbstractElectionsSwing] class, the handler that manages the click on the [Effacer] label is as follows:
private void jLabelEffacerMouseClicked(java.awt.event.MouseEvent evt) {
if(jLabelEffacer.isEnabled()){
doEffacer();
}
}
Line 3 calls the [doEffacer] method of the [ElectionsSwing] class:
@Override
protected void doEffacer() {
// empty the results list
....
// uPGRADE FORM
Utilitaires.setEnabled(...);
}
Task: Complete the code for the [doEffacer] method.
Note: The DefaultListModel class has a clear() method that removes all its elements.
10.3.10. Improvements
The previous graphical interface can be improved in several ways: the user might forget to enter the votes for all the lists in the drop-down menu, or they might accidentally enter votes from the same list multiple times.
Task: Improve the algorithm so that neither of these cases can occur. A simple solution is to maintain a dictionary of the entered lists, where the keys are the combo box items. We will also ensure that the link [Calculer] is enabled only when all lists have been entered.
See the [ref1] course: the HashTable class in section 3.8.






































