I wrote a Java program with a Swing UI that calculates prime numbers. The primes are displayed into a listbox. I used a few optimizations to generate the primes faster. I’m using the NetBeans IDE, so there’s a lot of generated Swing code.
Currently, the program finds as many primes as the user has input into a spinner box. Ideally, I’d like to change the program to include just a simple start/stop button, and the primes are displayed in the list realtime, but that’s for a another day.
The program has 2 classes.
PrimeNumberCalculator.java
import javax.swing.DefaultListModel;
import java.text.NumberFormat;
import javax.swing.JOptionPane;
import primenumber.PrimeCalculator;
public class PrimeNumberCalculator extends javax.swing.JFrame {
private int currentIteration = 2; // Stores the next number to be checked
public DefaultListModel numListModel = new DefaultListModel(); // List model for the jList
NumberFormat numberFormatter = NumberFormat.getNumberInstance();
public PrimeNumberCalculator() {
initComponents(); // Do not delete
this.setLocationRelativeTo(null); // Center the window
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
StartButton = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
PrimesList = new javax.swing.JList();
StatusBar = new javax.swing.JPanel();
StatusLabel = new javax.swing.JLabel();
StatusNumber = new javax.swing.JLabel();
PrimeAmountSpinner = new javax.swing.JSpinner();
ClearButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Prime Number Calculator");
setMinimumSize(new java.awt.Dimension(250, 250));
setSize(new java.awt.Dimension(300, 400));
StartButton.setFont(StartButton.getFont().deriveFont(StartButton.getFont().getStyle() | java.awt.Font.BOLD));
StartButton.setText("Calculate");
StartButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
StartButtonActionPerformed(evt);
}
});
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
PrimesList.setFont(PrimesList.getFont());
PrimesList.setModel(numListModel);
jScrollPane1.setViewportView(PrimesList);
StatusLabel.setFont(StatusLabel.getFont());
StatusLabel.setText("Checked: ");
StatusLabel.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
StatusNumber.setFont(StatusNumber.getFont());
StatusNumber.setText("-");
javax.swing.GroupLayout StatusBarLayout = new javax.swing.GroupLayout(StatusBar);
StatusBar.setLayout(StatusBarLayout);
StatusBarLayout.setHorizontalGroup(
StatusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(StatusBarLayout.createSequentialGroup()
.addContainerGap()
.addComponent(StatusLabel)
.addGap(0, 0, 0)
.addComponent(StatusNumber)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
StatusBarLayout.setVerticalGroup(
StatusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, StatusBarLayout.createSequentialGroup()
.addContainerGap()
.addGroup(StatusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(StatusLabel)
.addComponent(StatusNumber))
.addContainerGap())
);
PrimeAmountSpinner.setFont(PrimeAmountSpinner.getFont());
PrimeAmountSpinner.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1), Integer.valueOf(1), null, Integer.valueOf(1)));
PrimeAmountSpinner.setToolTipText("Prime numbers to generate");
ClearButton.setFont(ClearButton.getFont());
ClearButton.setText("Clear");
ClearButton.setEnabled(false);
ClearButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
ClearButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(PrimeAmountSpinner, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(StartButton, javax.swing.GroupLayout.PREFERRED_SIZE, 106, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ClearButton)))
.addContainerGap())
.addComponent(StatusBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(StartButton)
.addComponent(PrimeAmountSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ClearButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE)
.addGap(0, 0, 0)
.addComponent(StatusBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// </editor-fold>
private void calculatePrimeNumbers() {
int primesToFind = Integer.parseInt(PrimeAmountSpinner.getValue().toString());
int primesFound = 0; // The primes that have been found in this test set
try {
while(primesFound < primesToFind) {
if ( PrimeCalculator.isPrime(currentIteration) ) {
numListModel.addElement( numberFormatter.format(currentIteration) ); // Add to the jList
primesFound++;
}
currentIteration++; // Increase the currentIteration counter to the next number to be checked
}
} catch (java.lang.OutOfMemoryError e) {
// To prevent out of memory errors if the prime cache grows too large
clearAll();
JOptionPane.showMessageDialog(this, "Out of memory. The program will now reset.", "Critical Error", JOptionPane.ERROR_MESSAGE);
}
}
private void clearAll() {
// Reset variables and values
currentIteration = 2;
StatusNumber.setText("-");
ClearButton.setEnabled(false);
// Clear the prime cache and list
PrimeCalculator.clearCache();
numListModel.clear();
System.gc();
}
private void StartButtonActionPerformed(java.awt.event.ActionEvent evt) {
calculatePrimeNumbers();
StatusNumber.setText( numberFormatter.format(currentIteration-1) );
ClearButton.setEnabled(true);
}
private void ClearButtonActionPerformed(java.awt.event.ActionEvent evt) {
clearAll();
PrimeAmountSpinner.requestFocusInWindow();
}
/**
@param args the command line arguments
*/
public static void main(String args[]) {
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code">
try {
javax.swing.UIManager.setLookAndFeel( javax.swing.UIManager.getSystemLookAndFeelClassName() );
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(PrimeNumberCalculator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(PrimeNumberCalculator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(PrimeNumberCalculator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(PrimeNumberCalculator.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 PrimeNumberCalculator().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton ClearButton;
private javax.swing.JSpinner PrimeAmountSpinner;
private javax.swing.JList PrimesList;
private javax.swing.JButton StartButton;
private javax.swing.JPanel StatusBar;
private javax.swing.JLabel StatusLabel;
private javax.swing.JLabel StatusNumber;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration
}
PrimeCalculator.java
import java.util.ArrayList;
public class PrimeCalculator {
public static ArrayList<Integer> primeNumberCache = new ArrayList<>();
public static boolean isPrime(int primeToCheck) {
boolean isPrime = true;
// Set the isPrime flag for this number to true initially, and set it to false later if the number is not prime
// Loop that will test the prime number against prime factors
for (int currentTest : primeNumberCache) {
/*
This code determines if the number is prime or not
The possible factors of a number can be reduced to prime numbers lower than the number
The second check tests the current number against all previous prime numbers
Because of factor pairs, only factors less than the square root of the number need to be checked
The first check stops the tests early if all primes that need to be checked have been
*/
double sqrtOfCurrentIteration = Math.sqrt(primeToCheck); // Cached for optimisation
if ( currentTest > sqrtOfCurrentIteration ) {
break; // For optimisation, break out of the loop if all important primes have been checked
}
//Test if the current number is evenly divisible (not prime)
if ( primeToCheck % currentTest == 0 ) {
isPrime = false;
break; // For optimisation, break out of the loop if the number is not prime
}
}
if (isPrime == true) {
primeNumberCache.add(primeToCheck); // Add the found prime number to the lists
return true;
} else {
return false;
}
}
public static int getPrimeCount() {
return primeNumberCache.size();
}
public static void clearCache() {
primeNumberCache.clear();
}
}