|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
[Java] Confronto tra icone e icone di bottoni (Campo Minato)
Ciao a tutti, sto progettando un applicazione che gestisca il gioco del Campo Minato e per il sistema di gioco sono ormai arrivato a concluderlo, mi serve il vostro aiuto per risolvere l'ultimo problema legato alla costruzione dei numeri che segnalano le mine confinanti.
Purtroppo non ho ancora generato il Javadoc e quindi il codice non è ancora commentato, quindi vi spiego qui tutti i vari campi e metodi delle classi in esame. Questa è la classe progettata per gestire il sistema del gioco: Codice:
package campoMinato;
import java.util.Random;
import javax.swing.*;
import componenti.*;
public class MyGameSystem {
private JButton [][] game;
private int rows, cols, mines, row, col, index;
private Random newrow, newcol;
private GenericComponent component;
public MyGameSystem(JButton [][] game, int rows, int cols, int mines) {
this.game = game;
this.rows = rows;
this.cols = cols;
this.mines = mines;
newrow = new Random();
newcol = new Random();
}
public void CreateGame() {
for (index = 0; index < mines; index++) {
row = newrow.nextInt(rows);
col = newcol.nextInt(cols);
CreateMines(row,col);
}
CreateNumbers();
}
public void CreateMines(int r, int c) {
if (game[r][c].getDisabledIcon() == null) {
component = new MineComponent("Icone/j9.gif");
game[r][c].setDisabledIcon(component.getIcon());
} else {
index--;
}
}
public void CreateNumbers() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (game[i][j].getDisabledIcon() == null) {
int n_mines = CountMines(i,j);
switch (n_mines) {
case 0: {
component = new NumberComponent("Icone/j0.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 1: {
component = new NumberComponent("Icone/j1.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 2: {
component = new NumberComponent("Icone/j2.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 3: {
component = new NumberComponent("Icone/j3.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 4: {
component = new NumberComponent("Icone/j4.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 5: {
component = new NumberComponent("Icone/j5.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 6: {
component = new NumberComponent("Icone/j6.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 7: {
component = new NumberComponent("Icone/j7.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
case 8: {
component = new NumberComponent("Icone/j8.gif");
game[i][j].setDisabledIcon(component.getIcon());
break;
}
}
}
}
}
}
public int CountMines(int r, int c) {
int n_mines = 0;
for (int i = r-1; i <= r+1; i++) {
for (int j = c-1; j <= c+1; j++) {
if (((i >= 0) && (j >= 0)) && ((i < rows) && (j < cols))) {
if (game[i][j].getDisabledIcon() == null)
n_mines++;
}
}
}
return n_mines;
}
}
game: Matrice di bottoni che rappresenta la griglia di gioco. rows: Intero che rappresenta il numero di righe di game. cols: Intero che rappresenta il numero di colonne di game. mines: Intero che rappresenta le mine che verranno inserite in game. row: Intero che rappresenta una riga generata a caso. col: Intero che rappresenta una colonna generata a caso. index: Intero che dice a runtime quante mine sono gia state create in game. newrow: Oggetto di classe Random che genererà una riga. newcol: Oggetto di classe Random che genererà una colonna. component: Oggetto che crea all'occorrenza l'icona mina o numero. Metodi: MyGameSystem() : Costruttore della classe. void CreateGame(): Metodo pubblico che crea il sistema di gioco utilizzando i metodi CreateMines() e CreateNumbers(). Il compito principale del metodo è quello di creare righe e colonne a caso nella griglia dove verranno inserite inanzitutto le mine. void CreateMines(): Metodo (pubblico) che utilizza come parametri gli interi rappresentanti la riga e colonna generati in CreateGame() per creare e inserire in griglia le mine (icona del bottone disabilitato). void CreateNumbers(): Metodo (pubblico) che una volta messe le mine in griglia si occupa di inserire nelle caselle rimaste i numeri (icona del bottone disabilitato) corrispondenti alle mine confinanti. Viene utilizzato il metodo intero CountMines() per contare queste mine confinanti e a seconda del valore restituito creare l'icona giusta da settare ai bottoni. int CountMines(): QUI STA IL MIO PROBLEMA Metodo intero (pubblico) che passati come parametri una riga e una colonna di un bottone, inizia un controllo nella griglia sulle 8 caselle confinanti al bottone, tralasciando le caselle con riga e colonna negative oppure fuori dai limiti della matrice. Questo metodo dovrebbe riconoscere SOLO l'icona mina e incrementare la variabile corrispondente alle mine confinanti da restituire, ma INVECE riconosce qualsiasi casella in cui sia stata gia settata l'icona del bottone disabilitato. So che l'errore è alla riga: if (game[i][j].getDisabledIcon() == null) perchè debbuggando in Eclipse mi entra e quindi incrementa la variabile anche quando trova un icona numero, quindi ho cercato di togliere il null e di confrontare l'icona del bottone disabilitato con l'icona della mina, ma il risultato non è stato quello aspettato, anzi è stato peggiorativo perchè non riconosceva nemmeno più le mine. Dunque in pratica, dovrei confrontare l'icona del bottone disabilitato con quella della mina che dovrebbero risultare uguali e invece non lo sono. C'è qualcuno che può aiutarmi? Spero di essere stato chiaro nell'esporvi il codice, se avete bisogno di migliori spiegazioni oppure anche delle classi GenericComponent, MineComponent, NumberComponent, ditelo che li posto tranquillamente. |
|
|
|
|
|
#2 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
Comunque le icone settate sui pulsanti non sono certo il modo migliore di gestire l'applicazione. Un po' di sano MVC non fa mai male..
__________________
|
|
|
|
|
|
|
#3 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
Codice:
package campoMinato;
import javax.swing.*;
import java.awt.*;
public class MyGamePanel extends JPanel {
private JButton [][] game;
MyGameSystem system;
public MyGamePanel(MyNewGameDialogBox attributes) {
super(new GridLayout(attributes.getAltezza(), attributes.getLarghezza()));
game = new JButton [attributes.getAltezza()][attributes.getLarghezza()];
for (int i = 0; i < attributes.getAltezza(); i++) {
for (int j = 0; j < attributes.getLarghezza(); j++) {
game[i][j] = new JButton();
add(game[i][j]);
}
}
system = new MyGameSystem(game,attributes.getAltezza(),attributes.getLarghezza(),attributes.getMines());
system.CreateGame();
}
}
Codice:
package campoMinato;
import javax.swing.*;
import java.awt.*;
import ascoltatori.*;
public class MyNewGameDialogBox extends JDialog {
private Box labels, textfields, buttons;
private JButton ok, annulla;
private JTextField width, height, mines;
private MyFrame mainFrame;
public MyNewGameDialogBox(MyFrame parent) {
super(parent,"Nuova Partita");
mainFrame = parent;
setLayout(new FlowLayout());
setSize(200,200);
labels = Box.createVerticalBox();
textfields = Box.createVerticalBox();
buttons = Box.createVerticalBox();
height = new JTextField(3);
width = new JTextField(3);
mines = new JTextField(3);
ok = new JButton("OK");
annulla = new JButton("Annulla");
labels.add(new JLabel("Altezza:"));
labels.add(Box.createVerticalStrut(20));
labels.add(new JLabel("Larghezza:"));
labels.add(Box.createVerticalStrut(20));
labels.add(new JLabel("Mine:"));
textfields.add(height);
textfields.add(Box.createVerticalStrut(20));
textfields.add(width);
textfields.add(Box.createVerticalStrut(20));
textfields.add(mines);
buttons.add(ok);
buttons.add(Box.createVerticalStrut(40));
buttons.add(annulla);
Container c = getContentPane();
c.add(labels);
c.add(textfields);
c.add(buttons);
ok.addActionListener(new MyNewGameDialogBoxListener(mainFrame, this));
annulla.addActionListener(new MyNewGameDialogBoxListener(mainFrame, this));
}
public int getAltezza() {
int h = Integer.parseInt(height.getText());
return h;
}
public int getLarghezza() {
int h = Integer.parseInt(width.getText());
return h;
}
public int getMines() {
int h = Integer.parseInt(mines.getText());
return h;
}
}
|
|
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Prima di tutto: la variabile globale component dovrebbe essere locale: ogni metodo usa la propria variabile, è una questione di sicurezza e soprattutto ti aiuta a scrivere codice corretto.
Domanda: cosa fanno le classi MineComponent e NumberComponent???? Ora mi verrebbe da consigliarti di fare così: crea un array globale di icone nella classe MyGameSystem Codice:
Icon[] icone = new Icon[10]; //dichiarazione
//nel costruttore
icone[0] = null;
for (int i = 1; i <= 9; i++) {
icone[i] = new Icon("Icone/j"+ i +".gif");
}
Codice:
public void CreateMines(int r, int c) {
if (game[r][c].getDisabledIcon() == null) {
component = new MineComponent(icone[9])
game[r][c].setDisabledIcon(icone[9]);
} else {
index--;
}
}
Codice:
public int CountMines(int r, int c) {
int n_mines = 0;
for (int i = r-1; i <= r+1; i++) {
for (int j = c-1; j <= c+1; j++) {
if (((i >= 0) && (j >= 0)) && ((i < rows) && (j < cols))) {
if (game[i][j].getDisabledIcon() == icone[9]) //c'è una mina!
n_mines++;
}
}
}
return n_mines;
}
Non è di certo il massimo, ma almeno vedi se così funziona
__________________
|
|
|
|
|
|
#5 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
Visto che ho postato il codice ne approfitto per fare qualche domanda legata all'information hiding, oltre all'oggetto component da mettere locale, secondo te è anche meglio mettere tutti i metodi della classe MyGameSystem private anzichè public al di fuori del costruttore e del metodo CreateGame()? Inoltre le variabili intere row e col e gli oggetti Random newrow e newcol li uso solo nel metodo CreateGame(), è meglio metterle anche quelle locali? Ultima modifica di Simone89RN : 15-07-2009 alle 18:49. |
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
Il discorso visibilità dei membri classe è abbastanza semplice: prova a pensare ad un programma maligno che avendo accesso alle tue classi modifichi tutte i campi che può, richiami tutti i metodi a cui può accedere, in una maniera il più possibile rovinosa per il tuo programma. Ora prendi tutti i metodi e mettili private, poi seleziona i metodi che necessariamente devono essere richiamati dall'esterno della tua classe e mettili public o package(default). Ovviamente la questione è molto molto molto più complessa, e non ho neanche considerato il modificatore protected. Possiamo in genere dire che i campi (variabili globali) di una classe sono di solito tutti private (si accedono eventualmente tramite set/get), a meno che non si tratti di costanti dichiarate final (e static) oppure di variabili che molto probabilmente devono essere utilizzate dalle sottoclassi, avendo progettato la tua classe specificatamente per essere estesa. In generale la tua applicazione avrebbe bisogno di una riveduta globale, in quanto la progettazione delle classi non è il massimo. Sto parlando dei vari ruoli e informazioni che sono "distribuiti" nelle varie classi. Sarebbe interessante vedere il codice delle classi *Component e dei gestori degli eventi tipo click mouse eccetera... Adesso devo scappare, a presto
__________________
|
|
|
|
|
|
|
#7 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
|
|
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Guarda hai ragione stiamo uscendo dal topic vero e proprio, il problema è risolto, ma in questa sezione (particolarmente) succede di continuo, se non sempre!
__________________
|
|
|
|
|
|
#9 |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Purtroppo sono sorti altri problemi. Provo a postarli qui anche se come ho gia detto non hanno a che fare nulla col titolo del topic.
Il sistema di gioco è praticamente finito, manca solo da visualizzare le icone di mine e numeri quando i bottoni sono premuti e disabilitarli, per questo ho settato l'icona del pulsante disabilitato con setDisabledIcon(), ma quando aggiungo il listener ai bottoni, e quindi nel actionPerformed() vado a disabilitare il bottone stesso facendo button.setEnabled(false) il risultato è che il bottone viene disabilitato senza che si visualizzi l'icona. Inoltre devo gestire anche l'icona della bandierina che appare quando l'utente clicca sul tasto destro del mouse sul bottone supponendo che in quella casella ci sia una mina. So che devo usare una classe che implementi l'interfaccia MouseListener, ma non so come riconoscere se il click sia stato fatto dal pulsante sinistro e destro del mouse. Chi mi sa aiutare? |
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
|
Per il pulsante sinistro/destro, dato il MouseEvent me:
Codice:
if(SwingUtilities.isLeftMouseButton(me)) {
...sinistro
} else if(SwingUtilities.isRightMouseButton(me)) {
...destro
}
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me! |
|
|
|
|
|
#11 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
|
|
|
|
|
|
|
#12 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
E' l'unica cosa che mi potrebbe venire in mente...
__________________
|
|
|
|
|
|
|
#13 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
|
|
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
Cioè quando lo disattivi l'icona sparisce? Se non sbaglio l'icona settata con setIcon() rimane anche nello stato disabled, se non ne viene specificata un'altra. Hai provato a sostituire a setDisabledIcon() setIcon, richiamandolo però ovviamente solo nel momento in cui fai setEnabled(false) ?
__________________
Ultima modifica di malocchio : 17-07-2009 alle 13:10. Motivo: dislessia mattutina |
|
|
|
|
|
|
#15 | |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Quote:
La seconda invece non mi è tanto chiara, perchè hai citato un metodo che non ho mai usato finora che è setSelectedIcon(), potresti rispiegarla meglio? |
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
Edito subito...
__________________
|
|
|
|
|
|
|
#17 |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Ok problema risolto, ora però mi manca da gestire la bandierina che l'utente con il tasto destro del mouse mette perchè crede che in quella casella ci sia la mina.
Mi servirebbe un metodo che all'evento del click del pulsante destro del mouse disattivi il bottone solo per il click del tasto sinistro del mouse ma non per quello destro, il setEnabled credo lo disattivi per qualunque evento giusto? Esiste un metodo che faccia quello che mi serve oppure mi tocca gestire gli eventi dei pulsanti? |
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
__________________
|
|
|
|
|
|
|
#19 |
|
Member
Iscritto dal: May 2009
Messaggi: 40
|
Ok tralasciando l'argomento "bandierine", ora alla mia applicazione manca solo da poter essere salvata e caricata su e da File System. E qui avrei bisogno di chiarimenti sulla classe JFileChooser che uso per trovare il file del gioco nel caso di caricamento e di scriverne il nome nel caso di salvataggio.
Inanzitutto visto che si tratta di salvare un vero e proprio progetto utilizzo la classe ObjectOutputStream in modo da poter serializzare tutte le classi che utilizzo a partire dal mio Frame, ma questa classe nel costruttore richiede un riferimento di tipo OutputStream e per questo uso la classe FileOutputStream per creare il file da passare a ObjectOutputStream. Parliamo di salvataggio: Quando vado nel blocco try per creare il mio FileOutputStream gli passo al costruttore: Codice:
try {
f = new FileOutputStream(chooser.getSelectedFile().getName());
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
Poi nel try di creazione del file ObjectOutputStream quando gli passo come parametro f, tutto va a buon fine senza eccezioni, ma quando vado a vedere se nella cartella che avevo scelto per salvare, non compare nessun file. La mia domanda è questa: il metodo chooser.getSelectedFile().getName() ti da effettivamente il percorso di salvataggio scelto con JFileChooser compreso il nome che l'utente ha scritto per creare il file? |
|
|
|
|
|
#20 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
e http://java.sun.com/javase/6/docs/ap...a.lang.Object) e, ovviamente http://java.sun.com/javase/6/docs/ap...m.html#close()
__________________
|
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 08:45.




















