From 86f14f2d5a52c54cea0f66ea0e772722b7334da0 Mon Sep 17 00:00:00 2001 From: Berack96 Date: Thu, 11 Jan 2024 19:24:47 +0100 Subject: [PATCH] GUI refactoring - used only nodefactory for creation - merged MyDecisionPanel with LW --- .../berack/upo/ai/decision/PrototypeGUI.java | 2 +- .../berack/upo/ai/decision/VehicleGUI.java | 2 +- .../java/net/berack/upo/ai/gui/MainGUI.java | 14 +- .../berack/upo/ai/gui/MyDecisionPanel.java | 57 ++++++-- .../upo/ai/gui/nodes/DecisionNodeGUI.java | 2 +- .../net/berack/upo/ai/gui/nodes/NodeGUI.java | 23 ++++ .../upo/ai/gui/nodes/ProbabilityNodeGUI.java | 10 +- .../upo/ai/gui/nodes/UtilityNodeGUI.java | 2 +- .../ai/problem3/LikelihoodWeightingGUI.java | 124 ++++-------------- .../upo/ai/problem3/OutcomeChartGUI.java | 110 ---------------- 10 files changed, 111 insertions(+), 235 deletions(-) delete mode 100644 src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java diff --git a/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java b/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java index b361309..607eb0a 100644 --- a/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java +++ b/src/main/java/net/berack/upo/ai/decision/PrototypeGUI.java @@ -21,7 +21,7 @@ public class PrototypeGUI extends MyDecisionPanel { }; public PrototypeGUI() { - super(SmileLib.getNetworkFrom(PROTOTIPO), NODES); + this.buildPanel(SmileLib.getNetworkFrom(PROTOTIPO), NODES); } @Override diff --git a/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java b/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java index 0c56dbd..138a4f7 100644 --- a/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java +++ b/src/main/java/net/berack/upo/ai/decision/VehicleGUI.java @@ -23,7 +23,7 @@ public class VehicleGUI extends MyDecisionPanel { }; public VehicleGUI() { - super(SmileLib.getNetworkFrom(VEICOLO), NODES); + this.buildPanel(SmileLib.getNetworkFrom(VEICOLO), NODES); } @Override diff --git a/src/main/java/net/berack/upo/ai/gui/MainGUI.java b/src/main/java/net/berack/upo/ai/gui/MainGUI.java index 00123e2..545e149 100644 --- a/src/main/java/net/berack/upo/ai/gui/MainGUI.java +++ b/src/main/java/net/berack/upo/ai/gui/MainGUI.java @@ -1,11 +1,14 @@ package net.berack.upo.ai.gui; +import java.awt.BorderLayout; import java.awt.Dimension; +import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; @@ -32,6 +35,7 @@ public class MainGUI extends JFrame { public final PrototypeGUI PrototypeGUI = new PrototypeGUI(); public final VehicleGUI VehicleGUI = new VehicleGUI(); + private final Dimension size = new Dimension(500, 400); private final JMenuBar menuBar = new JMenuBar(); /** @@ -44,7 +48,7 @@ public class MainGUI extends JFrame { this.setJMenuBar(menuBar); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.setSize(500, 400); + this.setSize(this.size); this.setResizable(false); this.setLocationRelativeTo(null); this.setVisible(true); @@ -88,11 +92,15 @@ public class MainGUI extends JFrame { */ private void setPanel(MyPanel panel) { if(panel instanceof MyDecisionPanel) { - var scroll = new JScrollPane(panel); + var temp = new JPanel(new BorderLayout()); + temp.add(panel, BorderLayout.NORTH); + temp.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); + + var scroll = new JScrollPane(temp); scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scroll.getVerticalScrollBar().setUnitIncrement(20); - scroll.setPreferredSize(new Dimension(500, 400)); + scroll.setPreferredSize(this.size); this.setContentPane(scroll); } else this.setContentPane(panel); diff --git a/src/main/java/net/berack/upo/ai/gui/MyDecisionPanel.java b/src/main/java/net/berack/upo/ai/gui/MyDecisionPanel.java index 8fae2df..6a818b0 100644 --- a/src/main/java/net/berack/upo/ai/gui/MyDecisionPanel.java +++ b/src/main/java/net/berack/upo/ai/gui/MyDecisionPanel.java @@ -1,7 +1,6 @@ package net.berack.upo.ai.gui; import java.awt.Component; -import java.awt.Dimension; import java.awt.Font; import java.util.ArrayList; import java.util.List; @@ -24,21 +23,47 @@ import smile.Network; */ public abstract class MyDecisionPanel extends MyPanel { - public final Network net; - private final List update = new ArrayList<>(); + protected Network net; + protected final List update = new ArrayList<>(); + private Component[] components = new Component[0]; + + /** + * Aggiunge dei componenti nel caso siano necessari che verranno mostrati nella prima parte del pannello + * @param components i componenti da mostrare (devono essere pari) + */ + protected void setExtraComponents(Component[] components) { + if(components.length % 2 != 0) throw new IllegalArgumentException("Must be a an even length array"); + this.components = components; + } /** * Costruisce il dinamicamente da una rete e da una lista di nodi da mostrare. * Il risultato sarà già inserito nel pannello e per vedere i valori bisognerà utilizzare il metodo updateAll() * @param net la rete da mostrare - * @param nodes il sottoinsieme di nodi da mostrare + * @param nodes il sottoinsieme di nodi da mostrare o (empty / null) per tutti i nodi */ - protected MyDecisionPanel(Network net, String...nodes) { + public void buildPanel(Network net, String...nodes) { this.net = net; - var layout = new GroupLayout(this); + if(this.net == null) return; - var size = new Dimension(500, 400); - this.setSize(size); + if(nodes == null || nodes.length == 0) + this.buildNodes(this.net.getAllNodes()); + else { + var handles = new int[nodes.length]; + for(var i = 0; i < nodes.length; i++) handles[i] = this.net.getNode(nodes[i]); + this.buildNodes(handles); + } + } + + /** + * Costruisce i nodi passati in input nel pannello + * @param handles i nodi da costruire + */ + private void buildNodes(int[] handles) { + this.update.clear(); + this.removeAll(); + + var layout = new GroupLayout(this); this.setLayout(layout); layout.setAutoCreateGaps(true); @@ -47,8 +72,18 @@ public abstract class MyDecisionPanel extends MyPanel { var gBarch = layout.createParallelGroup(); var vGroup = layout.createSequentialGroup(); - for(var node: nodes) { - var handle = net.getNode(node); + for(var i = 0; i < this.components.length; i += 2) { + var comp1 = this.components[i]; + var comp2 = this.components[i+1]; + + gLabel.addComponent(comp1); + gBarch.addComponent(comp2); + vGroup.addGroup(layout.createParallelGroup() + .addComponent(comp1) + .addComponent(comp2)); + } + + for(var handle : handles) { var panel = factory.create(handle); update.add(panel); @@ -78,7 +113,7 @@ public abstract class MyDecisionPanel extends MyPanel { * Utile per cambiare il font in BOLD e aumentarne la grandezza * @param component il componente da cambiare il font */ - private void setFont(Component component) { + protected void setFont(Component component) { var font = component.getFont(); font = new Font(font.getName(), Font.BOLD, font.getSize() + 2); component.setFont(font); diff --git a/src/main/java/net/berack/upo/ai/gui/nodes/DecisionNodeGUI.java b/src/main/java/net/berack/upo/ai/gui/nodes/DecisionNodeGUI.java index 7b247a5..f12e6a6 100644 --- a/src/main/java/net/berack/upo/ai/gui/nodes/DecisionNodeGUI.java +++ b/src/main/java/net/berack/upo/ai/gui/nodes/DecisionNodeGUI.java @@ -60,7 +60,7 @@ public class DecisionNodeGUI extends NodeGUI { @Override public void updateNode() { var selected = this.net.isEvidence(this.node)? this.net.getEvidence(this.node) : -1; - var values = this.net.getNodeValue(this.node); + var values = this.getValues(); var max = -1; if(values.length == this.buttons.length) { max = 0; diff --git a/src/main/java/net/berack/upo/ai/gui/nodes/NodeGUI.java b/src/main/java/net/berack/upo/ai/gui/nodes/NodeGUI.java index e87c8b0..b29ae15 100644 --- a/src/main/java/net/berack/upo/ai/gui/nodes/NodeGUI.java +++ b/src/main/java/net/berack/upo/ai/gui/nodes/NodeGUI.java @@ -12,6 +12,7 @@ public abstract class NodeGUI extends JPanel { public final Network net; public final int node; + private double[] values = null; /** * Salva informazioni essenziali del nodo @@ -27,6 +28,28 @@ public abstract class NodeGUI extends JPanel { this.node = node; } + /** + * Permette di impostare dei valori custom da mostrare. + * Dopo la chiamata non verranno modificati i valori a schermo se non + * si ha chiamato il metodo updateNode. + * + * @param values i valori da mostrare (dovranno essere compresi tra 0 e 1) + */ + public void setValues(double[] values) { + for(var val : values) if(val < 0 || val > 1) throw new IllegalArgumentException(); + this.values = values; + } + + /** + * Mostra i valori del nodo. Se sono stati passati dei valori custom allora userà quelli, + * altrimenti prenderà i valori contenuti all'interno della rete. + * @return i valori del nodo + */ + public double[] getValues() { + if(this.values != null) return this.values; + return this.net.getNodeValue(this.node); + } + /** * In questo metodo si deve fare un refresh dei valori mostrati nel pannello. * I valori potranno essere presi direttamente dalla rete utilizzando le proprietà pubbliche net e node. diff --git a/src/main/java/net/berack/upo/ai/gui/nodes/ProbabilityNodeGUI.java b/src/main/java/net/berack/upo/ai/gui/nodes/ProbabilityNodeGUI.java index 0c9d1fd..2d89f9e 100644 --- a/src/main/java/net/berack/upo/ai/gui/nodes/ProbabilityNodeGUI.java +++ b/src/main/java/net/berack/upo/ai/gui/nodes/ProbabilityNodeGUI.java @@ -2,6 +2,7 @@ package net.berack.upo.ai.gui.nodes; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Label; import java.util.function.Consumer; @@ -68,10 +69,7 @@ public class ProbabilityNodeGUI extends NodeGUI { if(action == null) lName.setBorder(null); else lName.addActionListener(a -> action.accept(index)); - var size = barchart.getPreferredSize(); - size.width = 100; - size.height = 10; - barchart.setPreferredSize(size); + barchart.setPreferredSize(new Dimension(100, 10)); barchart.setBackground(COLORS[i % COLORS.length]); @@ -91,8 +89,8 @@ public class ProbabilityNodeGUI extends NodeGUI { @Override public void updateNode() { - var values = this.net.getNodeValue(this.node); - var evidence = this.net.isEvidence(this.node)? this.net.getEvidence(node) : -1; + var values = this.getValues(); + var evidence = this.net.isEvidence(this.node)? this.net.getEvidence(this.node) : -1; var enable = (values.length == this.outcomes.length); for(var i = 0; i < this.outcomes.length; i++) { diff --git a/src/main/java/net/berack/upo/ai/gui/nodes/UtilityNodeGUI.java b/src/main/java/net/berack/upo/ai/gui/nodes/UtilityNodeGUI.java index cfa837d..7999004 100644 --- a/src/main/java/net/berack/upo/ai/gui/nodes/UtilityNodeGUI.java +++ b/src/main/java/net/berack/upo/ai/gui/nodes/UtilityNodeGUI.java @@ -39,7 +39,7 @@ public class UtilityNodeGUI extends NodeGUI { @Override public void updateNode() { - var values = this.net.getNodeValue(this.node); + var values = this.getValues(); var val = (values.length == 1) ? String.format("% 5.2f", values[0]) : " "; this.utility.setText(val); } diff --git a/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java index 1cfb2e4..b91b10f 100644 --- a/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java +++ b/src/main/java/net/berack/upo/ai/problem3/LikelihoodWeightingGUI.java @@ -1,33 +1,24 @@ package net.berack.upo.ai.problem3; -import java.awt.Dimension; +import java.awt.Component; import java.awt.FileDialog; -import java.awt.Font; -import java.util.Collection; -import javax.swing.BorderFactory; -import javax.swing.GroupLayout; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; -import javax.swing.JPanel; import javax.swing.JSeparator; -import javax.swing.JTextArea; -import net.berack.upo.ai.gui.MyPanel; +import net.berack.upo.ai.gui.MyDecisionPanel; /** * Classe usata per far vedere il risultato di una run di lw su un network * @author Berack */ -public class LikelihoodWeightingGUI extends MyPanel { +public class LikelihoodWeightingGUI extends MyDecisionPanel { private LikelihoodWeighting lw = null; - private OutcomeChartGUI[] chartGUI = null; - - private final JPanel scroll = new JPanel(); // tried using JScrollPane but nothing shows up private int totalRuns = 1000; /** @@ -35,8 +26,13 @@ public class LikelihoodWeightingGUI extends MyPanel { * Siccome non c'è nessun network, il pannello sarà vuoto finchè non si apriranno dei network */ public LikelihoodWeightingGUI() { - this.scroll.setPreferredSize(new Dimension(500, 400)); - this.add(this.scroll); + var totLabel = new JLabel("Total Runs"); + var totValue = new JComboBox<>(new Integer[] {this.totalRuns, 5 * this.totalRuns, 10 * this.totalRuns, 20 * this.totalRuns}); + totValue.addItemListener(a -> this.totalRuns = (Integer) totValue.getSelectedItem()); + + this.setFont(totLabel); + this.setExtraComponents(new Component[] { totLabel, totValue }); + this.buildPanel(null); } /** @@ -66,7 +62,15 @@ public class LikelihoodWeightingGUI extends MyPanel { try { var net = SmileLib.getNetworkFrom(fileName); this.lw = new LikelihoodWeighting(net); - this.chartGUI = null; + this.buildPanel(net); + var totLabel = new JLabel("Total Runs"); + var totValue = new JComboBox<>(new Integer[] {this.totalRuns, 5 * this.totalRuns, 10 * this.totalRuns, 20 * this.totalRuns}); + totValue.addItemListener(a -> this.totalRuns = (Integer) totValue.getSelectedItem()); + this.setFont(totLabel); + + this.add(totLabel); + this.add(totValue); + this.updateAll(); } catch (Exception e) { e.printStackTrace(); @@ -81,93 +85,11 @@ public class LikelihoodWeightingGUI extends MyPanel { if(this.lw == null) return; this.lw.updateNetwork(totalRuns); - var nodes = this.lw.getAllNodes(); - - if(chartGUI == null) buildPanel(nodes); - - var i = 0; - for(var node : nodes) chartGUI[i++].updateValues(node.values, node.evidence); - - this.invalidate(); - this.validate(); - this.repaint(); - } - - /** - * Crea il pannello da zero usando i nodi passati in input come valori - * @param nodes i nodi da mostrare - */ - private void buildPanel(Collection nodes) { - var panel = new JPanel(); - var layout = new GroupLayout(panel); - - panel.setLayout(layout); - layout.setAutoCreateGaps(true); - - var gLabel = layout.createParallelGroup(); - var gBarch = layout.createParallelGroup(); - var vGroup = layout.createSequentialGroup(); - - var totLabel = new JLabel("Total Runs"); - var totValue = new JComboBox<>(new Integer[] {this.totalRuns, 5 * this.totalRuns, 10 * this.totalRuns, 20 * this.totalRuns}); - totValue.addItemListener(a -> this.totalRuns = (Integer) totValue.getSelectedItem()); - - var font = totLabel.getFont(); - font = new Font(font.getName(), Font.BOLD, font.getSize() + 2); - totLabel.setFont(font); - - gLabel.addComponent(totLabel); - gBarch.addComponent(totValue); - vGroup.addGroup(layout.createParallelGroup() - .addComponent(totLabel) - .addComponent(totValue)); - - this.chartGUI = new OutcomeChartGUI[nodes.size()]; - var i = 0; - - for(var node : nodes) { - var net = node.net; - var handle = node.handle; - - var label = new JTextArea(node.name); - label.setEditable(false); - label.setLineWrap(true); - label.setWrapStyleWord(true); - label.setOpaque(false); - label.setBorder(BorderFactory.createEmptyBorder()); - - var barch = new OutcomeChartGUI(node.outcomes, e -> { - if(net.isEvidence(handle) && net.getEvidence(handle) == e) - net.clearEvidence(handle); - else net.setEvidence(handle, e); - this.updateAll(); - }); - this.chartGUI[i++] = barch; - - font = label.getFont(); - font = new Font(font.getName(), Font.BOLD, font.getSize() + 2); - label.setFont(font); - - gLabel.addComponent(label); - gBarch.addComponent(barch); - vGroup.addGroup(layout.createParallelGroup() - .addComponent(label) - .addComponent(barch)); + for(var node : this.update) { + var values = this.lw.getNodeValue(node.node); + node.setValues(values); + node.updateNode(); } - - var hGroup = layout.createSequentialGroup(); - hGroup.addGroup(gLabel).addGroup(gBarch); - - layout.setVerticalGroup(vGroup); - layout.setHorizontalGroup(hGroup); - - var sizes = this.scroll.getPreferredSize(); - sizes.height = panel.getMinimumSize().height; - sizes.width -= 10; - panel.setPreferredSize(sizes); - - this.scroll.removeAll(); - this.scroll.add(panel); } @Override diff --git a/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java b/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java deleted file mode 100644 index 2b577f2..0000000 --- a/src/main/java/net/berack/upo/ai/problem3/OutcomeChartGUI.java +++ /dev/null @@ -1,110 +0,0 @@ -package net.berack.upo.ai.problem3; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.GridLayout; -import java.awt.Label; -import java.util.function.Consumer; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; - -/** - * Classe che rappresenta gli outcome di un nodo di un network. - * I valori deli outcome vengono visualizzati con un grafico. - * @author Berack - */ -public class OutcomeChartGUI extends JPanel { - public static final Color[] COLORS = { - new Color(255,127,0), - new Color(0,127,255), - new Color(0,255,127), - new Color(255,0,127), - new Color(127,0,255), - new Color(127,255,0), - }; - - private JButton[] outcomes; - private Label[] valuesChart; - private JLabel[] valuesPercent; - - /** - * Crea il JPanel da visualizzare a partire da un NetworkNode appropriamente inizializzato. - * Quando verrà visualizzato, il nodo avrà il nome degli output e i suoi valori in % - * con una barra colorata per indicare la grandezza visivamente. - * - * @param labels i label degli output del nodo - * @param action una azione da fare nel caso in cui venga premuto su un outcome - */ - public OutcomeChartGUI(String[] labels, Consumer action) { - var layout = new GridLayout(labels.length, 2); - this.setLayout(layout); - this.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(1, 0, 0, 0), BorderFactory.createLineBorder(Color.GRAY))); - - this.outcomes = new JButton[labels.length]; - this.valuesChart = new Label[labels.length]; - this.valuesPercent = new JLabel[labels.length]; - - for(var i = 0; i < labels.length; i++) { - var lName = new JButton(labels[i]); - var lValue = new JLabel(); - var barchart = new Label(); - - this.outcomes[i] = lName; - this.valuesChart[i] = barchart; - this.valuesPercent[i] = lValue; - - final var index = i; - lName.setContentAreaFilled(false); - lName.setFocusable(false); - if(action == null) lName.setBorder(null); - else lName.addActionListener(a -> action.accept(index)); - - var size = barchart.getPreferredSize(); - size.width = 100; - size.height = 100; - barchart.setPreferredSize(size); - barchart.setBackground(COLORS[i % COLORS.length]); - - - var panel1 = new JPanel(); - panel1.setLayout(new GridLayout(1, 2)); - panel1.add(lName); - panel1.add(lValue); - - var panel2 = new JPanel(); - panel2.setLayout(new BorderLayout()); - panel2.add(barchart, BorderLayout.LINE_START); - - this.add(panel1); - this.add(panel2); - } - } - - /** - * Modifica i valori mostrati a schermo cambiando anche la grandezza - * della barra indicante il valore - * @param values i nuovi valori da mostrare - * @param evidence indica l'evidenza del nodo - */ - public void updateValues(double[] values, int evidence) { - if(this.outcomes.length != values.length) throw new IllegalArgumentException("Arrays length myst be equals!"); - - for(var i = 0; i < this.outcomes.length; i++) { - var value = values[i] * 100; - var barchart = this.valuesChart[i]; - - var size = barchart.getSize(); - size.width = (int) (value * 1.5); - barchart.setSize(size); - barchart.setPreferredSize(size); - - this.valuesPercent[i].setText(String.format("% 4.2f%%", value)); - if(evidence == i) this.outcomes[i].setForeground(Color.RED); - else this.outcomes[i].setForeground(Color.BLACK); - } - } -}