A simple Java application that displays adjacency matrices using Swing will be presented.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AdjacencyMatrixView {
JButton[][] buttons;
JPanel panel;
public AdjacencyMatrixView(JButton[][] buttons, JPanel panel) {
this.buttons = buttons;
this.panel = panel;
}
public static Color getButtonBackgroundColor(boolean val) {
return val ? Color.PINK : Color.WHITE;
}
public void inPlaceUpdate(AdjacencyMatrix mat) {
var l = mat.order();
for(int x = 0; x < l; x++) {
for(int y = 0; y < l; y++) {
var currentButton = buttons[x][y];
currentButton.setBackground(getButtonBackgroundColor(mat.containsEdge(x,y)));
}
}
}
public void update(AdjacencyMatrix mat, JFrame f) {
var view = this;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
f.getContentPane().remove(view.panel);
f.invalidate();
f.validate();
f.repaint();
var newView = createView(mat, f);
view.buttons = newView.buttons;
view.panel = newView.panel;
f.add(newView.panel);
f.revalidate();
f.repaint();
}
});
}
public static AdjacencyMatrixView createView(AdjacencyMatrix mat, JFrame f) {
var l = mat.order();
var currentButtons = new JButton[l][l];
var p = new JPanel();
p.setLayout(new GridLayout(l,l));
for(int x = 0; x < l; x++) {
for(int y = 0; y < l; y++) {
var currentButton = new JButton(" ");
currentButton.putClientProperty("id", new int[]{x,y});
currentButtons[x][y] = currentButton;
currentButton.setBackground(getButtonBackgroundColor(mat.containsEdge(x,y)));
currentButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
int[] coord = (int[]) currentButton.getClientProperty("id");
mat.swapEdge(coord[0],coord[1]);
currentButton.setBackground(getButtonBackgroundColor(mat.containsEdge(coord[0],coord[1])));
}
});
p.add(currentButton);
}
}
return new AdjacencyMatrixView(currentButtons, p);
}
}
Lets create a main method that runs the GUI that we have built. This should create a JMenuBar that contains all the functionality related to mutable adjacency matrices described before.
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.regex.Pattern;
public class Application {
public static void main(String[] args) {
var mat = new java.util.concurrent.atomic.AtomicReference(new AdjacencyMatrix(5));
var f = new JFrame();
var view = AdjacencyMatrixView.createView(mat.get(), f);
f.add(view.panel);
var menu = new JMenuBar();
var fileMenu = new JMenu("File");
menu.add(fileMenu);
var newMenu = new JMenuItem("New");
newMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
var str = JOptionPane.showInputDialog("Enter a number:");
if(str != null) {
var p = Pattern.compile("[0-9]+");
var m = p.matcher(str);
if (m.matches()) {
var newMatrix = new AdjacencyMatrix(Integer.parseInt(str));
view.update(newMatrix, f);
mat.set(newMatrix);
}
}
}
});
fileMenu.add(newMenu);
var openMenu = new JMenuItem("Open");
openMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
var jfc = new JFileChooser();
jfc.showSaveDialog(f);
var currentFile = jfc.getSelectedFile();
if(currentFile != null) {
try {
var currentBytes = Files.readAllBytes(currentFile.toPath());
var newMatrix = AdjacencyMatrix.fromBytes(currentBytes);
view.update(newMatrix, f);
mat.set(newMatrix);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
fileMenu.add(openMenu);
var saveMenu = new JMenuItem("Save");
saveMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
var jfc = new JFileChooser();
jfc.showSaveDialog(f);
var currentFile = jfc.getSelectedFile();
if(currentFile != null) {
var currentBytes = mat.get().getBytes();
try {
Files.write(currentFile.toPath(), currentBytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
fileMenu.add(saveMenu);
var editMenu = new JMenu("Edit");
var complementMenu = new JMenuItem("Complement");
complementMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mat.get().complement();
view.inPlaceUpdate(mat.get());
}
});
editMenu.add(complementMenu);
var transposeMenu = new JMenuItem("Transpose");
transposeMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mat.get().transpose();
view.inPlaceUpdate(mat.get());
}
});
editMenu.add(transposeMenu);
var symmetricClosureMenu = new JMenuItem("Symmetric closure");
symmetricClosureMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mat.get().symmetricClosure();
view.inPlaceUpdate(mat.get());
}
});
editMenu.add(symmetricClosureMenu);
var symmetricComponentMenu = new JMenuItem("Symmetric component");
symmetricComponentMenu.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mat.get().symmetricComponent();
view.inPlaceUpdate(mat.get());
}
});
editMenu.add(symmetricComponentMenu);
var scramble = new JMenuItem("Randomize");
scramble.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
mat.get().randomize();
view.inPlaceUpdate(mat.get());
}
});
editMenu.add(scramble);
menu.add(editMenu);
f.setJMenuBar(menu);
f.setSize(500,500);
f.setVisible(true);
}
}
That is it. Now we have a rudimentary GUI for dealing with adjacency matrices, as grids of booleans. Clicking on any point in the grid will switch its value from true to false and back again. I didn't think I would post this part of the simple adjacency matrix program, but it doesn't hurt to add a little bit more to what I was doing.
No comments:
Post a Comment