PDA

View Full Version : Socket,java e JTextArea...


SteR9
23-08-2003, 19:44
sto imparando a usare i socket con java e vorrei poter stampare in una JTextArea i comandi che mi invia il server però ogni volta che il server mi invia un comando mi si riapre una JTextArea mentre io vorrei che mi rimanesse aperta sempre la stessa e che i messaggi si accodassero uno dietro l'altro...ecco il codice del mio programma

import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
public class irc {
public static void main(String[] args) {


String pong="",pon="",comandi="",prova="";
char po[];

po = new char[9];
Socket smtpSocket = null;
PrintStream os = null;
DataInputStream is = null;
JTextArea outputarea = new JTextArea(30,30);


try {

smtpSocket = new Socket("irc.tin.it", 6667);
os = new PrintStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());

} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}


if (smtpSocket != null && os != null && is != null) {
try {


os.println("user user hostname ip :user");
os.println("nick guest1");

pong = is.readLine();
pong.getChars(5,13,po,0);
for (int i=0;i<9;i++)
pon += po[i];
System.out.println("pong="+pon);
System.out.println(pong);
os.println("pong "+pon);

String responseLine;
while ((responseLine = is.readLine()) != null) {
System.out.println("Server: " + responseLine);
prova += responseLine;
outputarea.append(responseLine);
JOptionPane.showMessageDialog(null,outputarea,"messaggio",
JOptionPane.INFORMATION_MESSAGE);
if (responseLine.indexOf("Ok") != -1) {
break;
}

}
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
}


help me please! :)

PGI
23-08-2003, 20:27
E' sufficiente eliminare l'uso di JOptionPane e sostituirlo con una finestra, sempre visibile, a cui connetti la JTextArea:

Ad esempio:


public static void main(String[] a) {
JFrame frame=new JFrame("Titolo");
frame.getContentPane().add(outputarea);
//la riga seguente è una funzione standard da sostituire
//con una chiusura dell'applicazione più consona
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.show();

ecc. ecc.


Puoi eliminare direttamente la chiamata a "showMessageDialog"


JOptionPane.showMessageDialog(null,outputarea,"messaggio",
JOptionPane.INFORMATION_MESSAGE);

SteR9
23-08-2003, 20:48
Originariamente inviato da PGI


non ho ancora studiato il jframe quindi basta che aggiungo ?

public static void main(String[] a) {
JFrame frame=new JFrame("Titolo");
frame.getContentPane().add(outputarea);
//la riga seguente è una funzione standard da sostituire
//con una chiusura dell'applicazione più consona
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.show();

SteR9
23-08-2003, 21:23
ok sono riuscito...e se ora volessi inviare un comando al server??
dovrei usare un action listener?

PGI
23-08-2003, 22:01
E' più lungo a dirsi che a farsi:

ti serve un'area di testo o un campo, a seconda che tu voglia inviare una o più linee di testo insieme. Poi imposti il layout del JFrame in modo che il componente di testo venga visualizzato con un minimo di coerenza:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
...

class...
...
static JTextField testoOut=new JTextField();
...
public static void main(String[] a) {
JFrame frame=new JFrame("Titolo");
JTextArea outputArea=new JTextArea();
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(testoOut, BorderLayout.SOUTH);
frame.getContentPane().add(outputArea, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.show();
...ecc...

Ora hai una finestra per "invio e ricezione";

Aggiungi a "testoOut" un gestore di eventi che reagisca alla pressione del tasto "enter" (il metodo più intuitivo per l'invio di testo da componenti a linea singola):

testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
inviaTestoAlServer();
}
}
});

"inviaTestoAlServer()" è un metodo che dovresti creare, il cui scopo è inviare testo sullo stream "os".


static void inviaTestoAlServer() {
os.println(testoOut.getText());
}


Ho scritto "al volo" ma dovrebbe essere tutto. In caso sono qui (magari tardi ma rispondo :) )

SteR9
24-08-2003, 06:46
mi da questo errore nella funzione keyPressed
identifier> expected
testoOut.addKeyListener(new KeyAdapter() {

PGI
24-08-2003, 13:00
controlla la successione di parentesi e la presenza di un punto e virgola al termine della settima linea.

Il codice seguente è corretto :):


testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
//
}
}
});

SteR9
24-08-2003, 13:02
posto il codice che facciamo prima...


import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
public class irc extends Frame implements KeyListener{

testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
inviaTestoAlServer();
}
}
});
static void inviaTestoAlServer() {
os.println(testoOut.getText());
}

public static void main(String[] args){

JTextField testoOut=new JTextField();
JTextArea outputarea = new JTextArea();
JFrame frame=new JFrame("Titolo");
frame.getContentPane().add(outputarea);
frame.getContentPane().add(testoOut, BorderLayout.SOUTH);
//la riga seguente è una funzione standard da sostituire
//con una chiusura dell'applicazione più consona
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.show();
String pong="",pon="",comandi="",prova="";
char po[];

po = new char[9];
Socket smtpSocket = null;
PrintStream os = null;
DataInputStream is = null;



try {

smtpSocket = new Socket("irc.dal.net", 6667);
os = new PrintStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());

} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}


if (smtpSocket != null && os != null && is != null) {
try {


os.println("user user hostname ip :user");
os.println("nick guest2993");

pong = is.readLine();
pong.getChars(5,13,po,0);
for (int i=0;i<9;i++)
pon += po[i];
System.out.println("pong="+pon);
System.out.println(pong);
os.println("pong "+pon);

String responseLine;
while ((responseLine = is.readLine()) != null) {
System.out.println("Server: " + responseLine);
prova += responseLine;
outputarea.append(responseLine + "\n");
if (responseLine.indexOf("Ok") != -1) {
break;
}

}
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}

}




grazie

PGI
24-08-2003, 13:14
Bel macello :)

All'esterno di un metodo in Java puoi inizializzare variabili ma non usare gli oggetti inizializzati.

testoOut.addKeyListener(...)

va a finire nel main.

Non è necessario che "irc" estenda Frame né che implementi KeyListener. O meglio, sarebbe il modo più "Java-style" di costruire l'applicazione, ma devi rimaneggiare ampiamente il codice per portarlo su quella strada.

PrintStream os = null; dovrebbe diventare

static PrintStream os= null;

e finire in un'area di visibilità di classe (quella in cui al momento si trova testoOut.addKeyListener(...) )

Così dovrebbe "andare"

SteR9
24-08-2003, 13:21
mmm non ho ben capito cosa devo fare....
in pratica lui non riconosce testoOut??

PGI
24-08-2003, 13:25
Non solo, anche se avessi dichiarato la variabile testoout "prima" comunque non avresti potuto attaccargli un keyListener.

Se mi dai 5 minuti ti sposto le linee di codice che andrebbero spostate e le evidenzio in grassetto, così tagliamo la testa al toro :)

PGI
24-08-2003, 13:35
Così dovrebbe compilare correttamente. Dovrebbe anche funzionare.


import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
public class temp /*extends Frame implements KeyListener*/{

/* testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
inviaTestoAlServer();
}
}
});*/

static JTextField testoOut = new JTextField();

static PrintStream os = null;

static void inviaTestoAlServer() {
if(os!=null) {
os.println(testoOut.getText());
}
}

public static void main(String[] args){

//JTextField testoOut=new JTextField();

//******************************************
testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
inviaTestoAlServer();
}
}
});
//******************************************

JTextArea outputarea = new JTextArea();
JFrame frame=new JFrame("Titolo");
frame.getContentPane().add(outputarea);
frame.getContentPane().add(testoOut, BorderLayout.SOUTH);
//la riga seguente è una funzione standard da sostituire
//con una chiusura dell'applicazione più consona
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.show();
String pong="",pon="",comandi="",prova="";
char po[];

po = new char[9];
Socket smtpSocket = null;
/*PrintStream os = null;*/
DataInputStream is = null;



try {

smtpSocket = new Socket("irc.dal.net", 6667);
os = new PrintStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());

} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}


if (smtpSocket != null && os != null && is != null) {
try {


os.println("user user hostname ip :user");
os.println("nick guest2993");

pong = is.readLine();
pong.getChars(5,13,po,0);
for (int i=0;i<9;i++)
pon += po[i];
System.out.println("pong="+pon);
System.out.println(pong);
os.println("pong "+pon);

String responseLine;
while ((responseLine = is.readLine()) != null) {
System.out.println("Server: " + responseLine);
prova += responseLine;
outputarea.append(responseLine + "\n");
if (responseLine.indexOf("Ok") != -1) {
break;
}

}
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}

}

PGI
24-08-2003, 13:42
Ho dimenticato una linea.

E' meglio che la linea di testo presente nel JTextField venga resettata dopo l'invio...a dire il vero è l'unico modo per inviare più comandi :D


static void inviaTestoAlServer() {
if(os!=null) {
os.println(testoOut.getText());
testoOut.setText("");
}
}

SteR9
24-08-2003, 14:01
funziona alla grande,ti ringrazio!:)

SteR9
24-08-2003, 14:38
e se volessi aggiungere uno scroller??che funzione devo usare??
perchè quando il testo diventa lungo sparisce...

PGI
24-08-2003, 15:36
La semplicità delle librerie Java ci viene in aiuto.

Occorre usare un "JScrollPane"

cambia questa riga

frame.getContentPane().add(outputarea);

con queste due

JScrollPane scroller=new JScrollPane(outputarea);
frame.getContentPane().add(scroller);

e il gioco è fatto.

SteR9
24-08-2003, 16:00
Originariamente inviato da PGI
La semplicità delle librerie Java ci viene in aiuto.

Occorre usare un "JScrollPane"

cambia questa riga

frame.getContentPane().add(outputarea);

con queste due

JScrollPane scroller=new JScrollPane(outputarea);
frame.getContentPane().add(scroller);

e il gioco è fatto.
perfetto però non scende automaticamente...non si può far si che scenda automaticamente ogni nuova linea?

PGI
24-08-2003, 16:10
Originariamente inviato da SteR9
perfetto però non scende automaticamente...non si può far si che scenda automaticamente ogni nuova linea?

Tutto si può fare! :D

Devi impostare la posizione del cursore nell'area di testo usando come indice la lunghezza del testo contenuto nell'area.

dopo la linea

outputarea.append(responseLine + "\n");


aggiungi questa

outputarea.setCaretPosition(outputarea.getText().length());

SteR9
24-08-2003, 17:03
visto che sto tentando di creare un client irc ora vorrei poter scrivere in un altro JFrame ciò che viene scritto nel canale,mi è abbastanza chiaro come fare,ma non ho ben chiaro come "estrarre" solo ciò che viene scritto nel canale....
non esiste un tutorial sulla creazione di un client??con anche tutti i comandi che può ricevere un server irc...

PGI
24-08-2003, 17:08
Per un tutorial sinceramente non saprei dove indirizzarti. Vediamo se qualcun'altro interviene.

SteR9
24-08-2003, 20:24
ma se voglio prendere solo
nick e messaggio come faccio?
da questa stringa
:nick!~java@213-140-31-168.fastres.net PRIVMSG #canale :messaggio

PGI
24-08-2003, 20:59
Fai un "parsing" (cioè estrai dalla stringa determinate parti di "testo" che corrispondono ad altrettante informazioni) secondo lo standard per IRC

http://www.irchelp.org/irchelp/rfc/rfc.html

E' meno semplice di quanto sembri, perchè lo standard IRC, benchè basato su un flusso di soli caratteri, ha una marea di "tag"

SteR9
25-08-2003, 09:55
non esiste una funzione che mi permetta di cercare una determinata parola dentro a una stringa??
in questo caso dovrei cercare PRIVMSG e "estrarre" il nick e il messaggio e poi andarlo a stampare nella finestra del canale

PGI
25-08-2003, 14:50
Rispondo a singhiozzo, mi spiace ma è un periodo in cui non posso stare on-line quanto vorrei.

Allora, cercare una parola in una stringa fa parte del più ampio mondo del trattamento di stringhe;

L'estrazione di una porzione di stringa richiede 2 indici, uno per l'inizio e uno per la fine della parte di testo che interessa.

Se vuoi estrarre il nick-name da quella stringa IRC devi prima sapere dove comincia e dove finisce il nick-name in un messaggio IRC, per quello occorre andare a vedere com'è definito lo standard.

Supponiamo che in un messaggio IRC il nick-name sia la prima informazione contenuta nella stringa, che l'inizio sia definito dai due punti ":" e la fine segnalata da un carattere di spazio " ".

Il nick-name, secondo questa ipotesi "semplicistica" è quella parte di testo compresa tra ":" e " ".

Data la stringa "msg", la sotto stringa rappresentante il nick sarà:

String nick=msg.substring(msg.indexOf(":")+1,msg.indexOf(" "));

Il metodo "String.substring(int i0, int i1)" restituisce un oggetto String che rappresenta la porzione di testo composta dai caratteri a partire da i0 (incluso) fino a i1 (escluso).

Poichè non conosco lo standar IRC non ti so dire quale sia la posizione del nick-name all'interno del messaggio nè quale sia il carattere terminatore, guarda nella pagina che ho postato e vedi se riesci a trovare le informazioni che ti servono.

Ciao.

SteR9
25-08-2003, 21:16
ok ho visto che funziona però mi si presenta subito un problema...
la stringa da cui devo estrarre il nick e il messaggio è
:Guest11056!~java@62.101.126.192 PRIVMSG #prova :ciao
quindi per estrarre il nick faccio
String nick=msg.substring(msg.indexOf(":")+1,msg.indexOf("!"));
il messaggio si trova anche lui dopo i : quindi come faccio ad estrarlo?

PGI
25-08-2003, 23:10
Se il primo ":" indica l'inizio del nick ed il secondo ":" quello del messaggio è sufficiente ottenere la sottostringa che parta dall'indice del secondo ":" fino al carattere che indica un "fine-messaggio".

otteniamo l'indice usando il metodo String.indexOf(char, startingIndex):

String ircString=":Guest11056!~java@62.101.126.192 PRIVMSG #prova :ciao "

//indice del secondo ":"
int start=ircString.indexOf(':',ircString.indexOf(':')+1)+1;

String message=ircString.substring(start, ircString.length());

Tutto questo vale in generale solo se lo standard IRC non prevede l'uso del simbolo "due punti" a metà tra nick e messaggio.

SteR9
26-08-2003, 07:26
ho provato a fare questo programma

String ircString=":Guest11056!~java@62.101.126.192 PRIVMSG #prova :ciao ";
String nick=ircString.substring(ircString.indexOf(":")+1,ircString.indexOf("!"));
String canale=ircString.substring(ircString.indexOf("#")+1,ircString.indexOf(" "));
int start=ircString.indexOf(':',ircString.indexOf(':')+1)+1;
String message=ircString.substring(start, ircString.length());
System.out.println(message);
System.out.println(nick);
System.out.println(canale);

ma mi da questo errore
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:String
index out of range: -10
at java.lang.String.substring(String.java:1444)
at prova.main(prova.java:10)

e l'errore me lo da sulla stringa del canale...ma non ne capisco il motivo...le altre due vanno...

poi volevo sapere come faccio a passare l'input stream ad un metodo...io ho provato a fare così ma non va...

static void canale(Socket soc,String response){
DataInputStream input = null;
input = new DataInputStream(soc.getInputStream());
JTextArea outputCanale = new JTextArea();
JFrame canale=new JFrame("Canale");
JScrollPane scrollcanale=new JScrollPane(outputCanale);
canale.getContentPane().add(scrollcanale);
canale.getContentPane().add(testoCanale, BorderLayout.SOUTH);
canale.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canale.setSize(500,500);
canale.show();
outputCanale.append(response + "\n");
outputCanale.setCaretPosition(outputCanale.getText().length());


}

grazie per la tua pazienza!

PGI
26-08-2003, 11:40
Il problema è in questa linea

String canale=ircString.substring(ircString.indexOf("#")+1,ircString.indexOf(" "));

Il metodo String.substring(int i0, int i1) funziona "da i0 a i1";

Se i0 è maggiore di i1 è generata un'eccezione IndexOutOfBoundsException.

ircString.indexOf("#") è corretto, perchè c'è un solo "cancelletto" nella stringa;

":Guest11056!~java@62.101.126.192 PRIVMSG #prova :ciao "

ircString.indexOf(" ") non va, perchè noterai che c'è almeno uno spazio vuoto prima del cancelletto.

In sostanza, substring non funziona "all'indietro", ed il metodo è progettato per rilasciare un IndexOutOfBoundsException nel caso in cui si cerchi di farlo.

Come avrai intuito, la faccenda si risolve "dicendo" a String.indexOf(" ") di iniziare a cercare lo spazio vuoto a partire dall'indice del carattere "#", cioè cercare solo nella porzione di stringa "finale", con il metodo String.indexOf(String, int) dove int è l'indice del carattere da cui iniziare la ricerca.

L'estrazione corretta di "canale" è pertanto:

String canale=ircString.substring(ircString.indexOf("#")+1,ircString.indexOf(" ",ircString.indexOf("#")));

PGI
26-08-2003, 11:47
Originariamente inviato da SteR9
poi volevo sapere come faccio a passare l'input stream ad un metodo...io ho provato a fare così ma non va...


"Non va" è un tantinello generico :)

La porzione di codice è corretta tuttavia, essendo un metodo, è possibile che ci siano dei problemi una volta "messo insieme" al resto del codice.

Una perplessità: la necessità di usare metodi (e varibili) static deriva dal fatto che hai usato un programma "tutto nel main"; il modificatore "static" ha però una sua ragion d'essere che è molto diversa dall'uso che ne fai. Se il tuo programma comincia a prendere forma, e prima che sia troppo tardi :D , forse potresti pensare ad organizzarlo in metodi (e classi) "normali". Se invece sei in una fase di sperimentazione non è un problema.

SteR9
26-08-2003, 13:09
Originariamente inviato da PGI
"Non va" è un tantinello generico :)

La porzione di codice è corretta tuttavia, essendo un metodo, è possibile che ci siano dei problemi una volta "messo insieme" al resto del codice.

Una perplessità: la necessità di usare metodi (e varibili) static deriva dal fatto che hai usato un programma "tutto nel main"; il modificatore "static" ha però una sua ragion d'essere che è molto diversa dall'uso che ne fai. Se il tuo programma comincia a prendere forma, e prima che sia troppo tardi :D , forse potresti pensare ad organizzarlo in metodi (e classi) "normali". Se invece sei in una fase di sperimentazione non è un problema.
infatti volevo usare dei metodi...per esempio le stringhe di connessione metterle tutte in un metodo...però non capisco come faccio a passare tra i vari metodi l'inpuStream...illuminami! :D

PGI
26-08-2003, 13:38
Uso sempre il moficatore static per adattare l'esempio al tuo programma:

class IStreamForClass {
//oggetto InputStream con visibilità di classe
static InputStream iStream=null;

public static void main(String[] a) {
//alla prima occasione inizializza iStream facendolo puntare
//all'inputStream del socket;
iStream=socket.getInputStream();

//il gioco è fatto, adesso iStream punta al flusso del socket ed
//è visibile in qualunque metodo della classe IStreamForClass
}

static void doSomeOnStream() {
int i=iStream().read();
}

static void someElse() {
int h=iStream().read();
}
}

Aggiungendo la gestione delle eccezioni (che non ho messo per pigrizia :D ), quello sopra è un esempio di uso di variabili con visibilità di classe.

SteR9
26-08-2003, 14:04
allora io ho messo static InputStream iStream=null; nella classe poi nel main dopo aver creato il socket ho messo iStream=smtpSocket.getInputStream();
e ho creato questo metodo

static void canale(String response){
JTextArea outputCanale = new JTextArea();
JFrame canale=new JFrame("Canale");
JScrollPane scrollcanale=new JScrollPane(outputCanale);
canale.getContentPane().add(scrollcanale);
canale.getContentPane().add(testoCanale, BorderLayout.SOUTH);
canale.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canale.setSize(500,500);
canale.show();
response=iStream.readLine();
outputCanale.append(response + "\n");
outputCanale.setCaretPosition(outputCanale.getText().length());
ma mi da questo errore
cannot resolve symbol
symbol : method readLine ()
location: class java.io.InputStream
String response=iStream.readLine();
where's the problem??

PGI
26-08-2003, 14:35
Non prendere gli esempi alla lettera, io volevo mostrarti come usare una variabile di classe, non la tua variabile di classe :eek:

il metodo readLine() è dei "Reader" e non degli "InputStream" (che sono versioni "minori").

"iStream" deve diventare un Reader (meglio un BufferedReader)



class... {
static BufferedReader iStream=null;

costruttore() {
...
iStream=new BufferedReader(new InputStreamReader(socket.getInputStream());



iStream adesso punta ad un BufferedReader, che possiede il metodo readLine();

il metodo "canale" dovrebbe ora funzionare correttamente.

SteR9
26-08-2003, 16:30
mmm non ho capito molto bene...
class IStreamForClass {
//oggetto InputStream con visibilità di classe
static InputStream iStream=null;

public static void main(String[] a) {
//alla prima occasione inizializza iStream facendolo puntare
//all'inputStream del socket;
iStream=socket.getInputStream();

li devo dichiarare ??
e iStream=new BufferedReader(new InputStreamReader(socket.getInputStream());
lo devo mettere nel mio metodo?

PGI
26-08-2003, 16:54
al posto di

iStream=socket.getInputStream();

metti

iStream=new BufferedReader(new InputStreamReader(socket.getInputStream());

e al posto di


//oggetto InputStream con visibilità di classe
static InputStream iStream=null;


metti


//oggetto InputStream con visibilità di classe
static BufferedReader iStream=null;

SteR9
26-08-2003, 17:10
mi da questo errore
unreported exception java.io.IOException; must be caught or declared to be thrown
iStream=new BufferedReader(new InputStreamReader(smtpSocket.getInputStream()));
uses or overrides a deprecated API.

PGI
26-08-2003, 17:49
Nessun problema, è normale

usa un blocco try-catch per gestire l'eccezione IOException


try {
iStream=new BufferedReader(new InputStreamReader(socket.getInputStream());
} catch(IOException e) {
e.printStackTrace();
}


al posto del semplice

iStream=new BufferedReader(new InputStreamReader(smtpSocket.getInputStream()));


Lo stesso blocco try-catch deve essere usato anche quando chiamerai il metodo "readLine".

Per quanto riguarda il "deprecated", il compilatore segnala che da qualche parte nel codice è stato usato un metodo od un oggetto che in future versioni di Java potrebbe non essere più supportato.
Prima di "risolvere" occorre sapere qual'è:
ricompila il codice con l'opzione "deprecation" (javac -deprecation ...)

SteR9
26-08-2003, 18:10
allora ora in compilazione non mi da nessun errore ma quando lo lancio mi da questo errore
Exception in thread "main" java.lang.NullPointerException
at irc.main(irc.java:77)
cosa significa?? la riga 77 è questa
pong.getChars(5,13,po,0);
però è sempre andato...

ho provato a compilare con il deprecated gli "errori" sono questi
warning: readLine() in java.io.DataInputStream has been deprecated
pong = is.readLine();

warning: readLine() in java.io.DataInputStream has been deprecated
while ((responseLine = is.readLine()) != null) {

PGI
26-08-2003, 18:48
In quel pong.getChars(...) c'è qualcosa che è "null".

Può essere "po" (un array di char suppongo) ma è più probabile che sia la stringa "pong" o lo stream "is"

Stando alla documentazione "DataInputStream.readLine()" può restituire valori non corretti e deve essere sostituito con l'analogo readLine() di BufferedReader.

Ho il sospetto che quel DataInputStream "is" sia un duplicato del BufferedReader che abbiamo inserito prima.

Se is punta (o originariamente avrebbe dovuto farlo) all'instream del socket allora puoi sostituirlo con un riferimento ad iStream.

prova a cambiare

pong=is.readLine();

con

pong=iStream.readLine(); (in un blocco try-catch se manca).

Dare un'occhiata al codice intero aiuterebbe, può darsi che il "collage" di modifiche apportate abbia portato a qualche incoerenza.

SteR9
26-08-2003, 19:15
ok ora è corretto però rimane sempre lo stesso problema...
allego il codice...

import java.io.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
public class irc {

static BufferedReader iStream=null;
static JTextField testoCanale = new JTextField();
static JTextField testoOut = new JTextField();
static PrintStream os = null;


//metodo per l'invio di testo al server
static void inviaTestoAlServer() {
if(os!=null) {
os.println(testoOut.getText());
testoOut.setText("");
}
}

public static void main(String[] args){

//******************************************
testoOut.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent ke) {
if(ke.getKeyCode()==KeyEvent.VK_ENTER) {
inviaTestoAlServer();
}
}
});
//******************************************

JTextArea outputarea = new JTextArea();
JFrame frame=new JFrame("Titolo");
JScrollPane scroller=new JScrollPane(outputarea);
frame.getContentPane().add(scroller);
frame.getContentPane().add(testoOut, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
frame.show();
String pong="",pon="",comandi="",prova="";
char po[];

po = new char[9];
Socket smtpSocket = null;
DataInputStream is = null;



try {

smtpSocket = new Socket("irc.dal.net", 6667);
os = new PrintStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());

} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
try {
iStream=new BufferedReader(new InputStreamReader(smtpSocket.getInputStream()));
} catch(IOException e) {
e.printStackTrace();
}



if (smtpSocket != null && os != null && is != null) {
try {
os.println("user user hostname ip :user");
os.println("nick guest2993");

pong = iStream.readLine();
pong.getChars(5,13,po,0);
for (int i=0;i<9;i++)
pon += po[i];
System.out.println("pong="+pon);
System.out.println(pong);
os.println("pong "+pon);

String responseLine;
while ((responseLine = iStream.readLine()) != null) {
System.out.println("Server: " + responseLine);
prova += responseLine;
outputarea.append(responseLine + "\n");
outputarea.setCaretPosition(outputarea.getText().length());
canale();
if (responseLine.indexOf("Ok") != -1) {
break;
}

}
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}

static void canale(){

JTextArea outputCanale = new JTextArea();
JFrame canale=new JFrame("Canale");
JScrollPane scrollcanale=new JScrollPane(outputCanale);
canale.getContentPane().add(scrollcanale);
canale.getContentPane().add(testoCanale, BorderLayout.SOUTH);
canale.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canale.setSize(500,500);
canale.show();
try {
String response=iStream.readLine();
outputCanale.append(response + "\n");
outputCanale.setCaretPosition(outputCanale.getText().length());
} catch(IOException e) {
e.printStackTrace();
}



}
}

PGI
26-08-2003, 19:39
Che errore di dà? Il codice mi sembra ok (se escludiamo il fatto che non riesco a capire cosa debba fare :D )

C'è qualcosa da sistemare, il DataInputStream è un relitto, puoi eliminare ogni sua istanza e riferimento.

Nella linea

if (smtpSocket != null && os != null && is != null) {


quell'"is != null" credo debba diventare un "iStream!=null"

Sul mio sistema viene eseguito "correttamente" (non restituisce eccezioni se avviato)

SteR9
26-08-2003, 19:46
ho corretto tutti gli is ma continua a darmi questo errore

C:\Program Files\j2sdk_nb\j2sdk1.4.2\bin>java irc
Exception in thread "main" java.lang.NullPointerException
at irc.main(irc.java:77)
ma a te si connette al server?

SteR9
26-08-2003, 19:54
mmm ora non mi da nessun errore però non mi si connette a nessun server irc...ho provato a connettermi a un ftp e si connette...com'è possibile??

SteR9
26-08-2003, 19:59
ok ora funziona...

PGI
26-08-2003, 20:00
Di server IRC so meno di niente. Se lancio l'applicazione mi dà questo output:

pong=lla-r.se
:mozilla-r.se.eu.dal.net NOTICE AUTH :*** Looking up your hostname...
Server: :mozilla-r.se.eu.dal.net NOTICE AUTH :*** Checking Ident

SteR9
26-08-2003, 20:04
ok ora però mi manca la parte fondamentale....
come faccio a sapere se in una stringa è contenuta una determinata parola???


P.S lo so che rompo ma voglio imparare!! :D

PGI
26-08-2003, 20:15
puoi usare semplicemente il metodo String.indexOf(String), che restituisce -1 nel caso in cui la stringa in argomento non sia presente:

es:


boolean trovaValore(String parola, String messaggio) {
if(messaggio.indexOf(parola)<0) {
return false;
}
return true;
}


il metodo qui sopra restituisce "true" nel caso in cui la Stringa "parola" faccia parte della Stringa "messaggio"

P.S lo so che rompo ma voglio imparare!!

Non rompi, non ti preoccupare ;) Anzi, ti vedo bello combattivo, ed è perfetto, bisogna azzannarli questi linguaggi di programmazione :boxe:

SteR9
27-08-2003, 07:14
il metodo non sono riuscito a richiamarlo nel main perchè mi dava questo errore non-static method trovaValore(java.lang.String,java.lang.String) cannot be referenced from a static context
trovaValore(parola,ircString);
^
allora ho messo nel main questo if e funziona...
if(ircString.indexOf(parola)<0)
System.out.println("la parola non c'e'");
else
System.out.println("la parola c'e'");


cosa significa l'errore che mi ha dato con il metodo?

SteR9
27-08-2003, 10:49
ho bisogno di creare un JPanel e ho creato questo metodo
public void setContentPane1(){
JPanel P=new JPanel(new BorderLayout());
JPanel Pannello=new JPanel(new GridLayout(2,1));
Pannello.add(testoOut);
setContentPane(Pannello);
}

ma mi da questo errore
cannot resolve symbol
symbol : method setContentPane (javax.swing.JPanel)
location: class irc
setContentPane(Pannello);

perchè?dovrebbe essere giusto..

PGI
27-08-2003, 13:20
irc non è un JFrame (la clausola extends JFrame è stata rimossa).

Il compilatore pertanto non riconosce il metodo "setContentPane" poichè non è stato ereditato e non è stato definito nella classe irc.

cosa significa l'errore che mi ha dato con il metodo?

Avevamo accennato al fatto che il modificatore "static" facesse cose molto particolari (in "irc" lo trovi un po' dappertutto). In particolare, un metodo o una variabile "static" hanno un indirizzo di memoria unico per ogni istanza della jvm lanciata, a prescindere da quanti "figli" della classe che li contiene siano creati.

I metodi static possono accedere solo ad altri metodi static o a metodi costruttori o a variabili anch'esse static.

poichè "main" è un metodo "static", nel suo corpo puoi richiamare solo altri "static" (metodi, variabili) oppure costruttori.

Per dichiarare una variabile o un metodo "static" è sufficiente, come hai fatto più volte nel codice, aggiungere la parola chiave "static" nella dichiarazione della variabile o del metodo.

SteR9
27-08-2003, 17:30
ho aggiunto extends JFrame ho creato questo metodo
static void setContentPane1(){
JPanel P=new JPanel(new BorderLayout());
JPanel Pannello=new JPanel(new GridLayout(2,1));
Pannello.add(testoOut);
setContentPane(Pannello);
}

e in compilazione non mi da nessun errore però se richiamo il metodo nel main mi da questo errore

non-static method setContentPane(java.awt.Container) cannot be referenced from a static context
setContentPane(Pannello);
^
cosa dovrei fare per renderlo static??

PGI
27-08-2003, 17:45
Dovresti sovrascriverlo, ma il problema è un'altro: benchè tu abbia esteso JFrame quel setContentPane(Component) non ha alcuna influenza sulla tua applicazione, per come è strutturata, perchè "irc" non è un frame visibile.

Hai detto di voler aggiungere un pannello...ma esattamente dove lo devi aggiungere? Forse vuoi una terza finestra con un pannello oppure vuoi aggiungere un altro componente ad alla finestra dell'applicazione?

Affrontando in generale la questione del modificatore static, sarebbe meglio toglierli tutti. Devi riscrivere il codice in modo che il contenuto del main passi ad un altro metodo, accessibile ad un costruttore, o in un costruttore.

Allego un esempio di come può essere "riscritta" l'applicazione (un copia e incolla e un paio di "canc", il codice per il resto è sempre farina del tuo sacco)

SteR9
27-08-2003, 18:42
io in pratica vorrei che tutti i JFrame mi stessero dentro a una finestra principale....
grazie per avermi corretto il codice! :)

PGI
27-08-2003, 19:14
La faccenda va presa un po' alla larga.

Occorre innazitutto avere un'idea di come apparirà l'interfaccia (finestre bottoni e via dicendo) dell'applicazione.

In pratica, da quanti pannelli è composta? Devono avere tutti le stesse dimensioni? Al momento, ad esempio, ci sono due finestre di uguale dimensione, che possono essere accorpate in un JFrame. Ne è in arrivo una terza, dove va a finire?

Tutto questo fa parte della progettazione di un'interfaccia grafica. Poichè, fino ad un certo punto, puoi scrivere il codice per l'interfaccia separatamente dal resto dell'applicazione, il modo ideale di procedere sarebbe quello di farsi uno schizzo del risultato che desideri ottenere e poi riprodurlo.

Allego un esempio (un'immagine gif che rappresenta lo schizzo di un'interfaccia che non c'entra nulla con quello che stiamo facendo, ma è per dare un'idea).

L'importante è essere sfrontati: disegna la tua interfaccia ideale, non quella che credi di poter fare con Java perchè Java è pronto a stupirti.

Ciao.

SteR9
27-08-2003, 19:33
allora io avrei bisogno di creare più finestre...
in pratica una è quello della connessione con i messaggi del server poi una finestra per ogni canale e delle finestre per le conversazioni private tutte queste finestre penso che debbano essere create tramite dei metodi....per quanto riguarda i bottoni un gruppo di bottoni in alto bastano...

PGI
27-08-2003, 20:08
E' un client ben strano :D

Potresti usare un JDesktopPane per tenere insieme tutto quanto, c'è un tutorial (http://java.sun.com/docs/books/tutorial/uiswing/components/internalframe.html) sul sito di sun, se vuoi un condensato ti posto un esempio.

per creare un JFrame "a comando" è corretta l'intuizione di passare per un metodo.


public void createFrame(String titolo) {
JFrame frame=new JFrame(titolo);
JPanel panel=new JPanel();
frame.setContentPane(panel);
frame.setSize(400,400);
frame.show();
}


Tuttavia, per usare un minimo di programmazione orientata agli oggetti, dovresti pensare alla funzione che deve svolgere quella particolare finestra e crearne un modello che abbia tutti i metodi necessari per gestire la funzione che rappresenta con un minimo di autonomia rispetto al codice "principale".

SteR9
28-08-2003, 19:46
ho provato l'esempio ma non va...manca il metodo MyInternalFrame...cmq credo che abbandonerò l'idea di usare un JDesktopPane...mi sembra troppo difficile da utilizzare...

PGI
28-08-2003, 20:59
E' complicato quanto può esserlo una nuova classe. Scrivo un esempio funzionante, in ogni caso la scelta è tua :)


import java.beans.PropertyVetoException;
import javax.swing.*;
import javax.swing.text.*;

public class MainClass extends JFrame {
private JDesktopPane desktop=null;

public MainClass() {
super("DesktopPane");
desktop=new JDesktopPane();
getContentPane().add(desktop);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,500);
show();

//proviamo il metodo appendFrame
appendFrame();
}

//aggiunge un JInternalFrame al desktop
public void appendFrame() {
JInternalFrame f=createInternalFrame();
f.setVisible(true);
desktop.add(f);
try {
f.setSelected(true);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
}

//crea un JInternalFrame
public JInternalFrame createInternalFrame() {
JInternalFrame f=new JInternalFrame("Titolo", true, false, false, true);
JTextPane textPane=new JTextPane(new DefaultStyledDocument());
f.getContentPane().add(textPane);
f.setSize(400,400);
return f;
}

public static void main(String[] a) {
new MainClass();
}

}

SteR9
31-08-2003, 17:14
ho provato l'esempio ma non riesco a capire come dovrei fare per poter scrivere del testo dentro al frame che vado a creare..
ho provato f.append("ciao) ma non va...

PGI
31-08-2003, 20:10
IL fatto è che non scrivi testo dentro ad un frame ma in un componente di testo.

L'esempio serve unicamente a dimostrare l'uso delle classe JInternalFrame e JDesktopPane.

Se vuoi accedere a qualche componente all'interno del JInternalFrame è meglio creare una classe esterna che estenda JInternalFrame e prevedere un metodo per l'accesso al componente di testo. Ad esempio:


public class MyInternalFrame extends JInternalFrame {
private JTextArea textArea=new JTextArea();

MyInternalFrame() {
setLayout(new GridLayout(1,1));
add(textArea);
}

public void aggiungiTesto(String testo) {
textArea.append(testo);
}
}

SteR9
31-08-2003, 20:46
ma come faccio dalla classe con il JDesktop a richiamare questa classe?
se non chiedo troppo me lo potresti integrare nell'esempio di prima??
grazie!

PGI
01-09-2003, 00:29
Originariamente inviato da SteR9
ma come faccio dalla classe con il JDesktop a richiamare questa classe?
se non chiedo troppo me lo potresti integrare nell'esempio di prima??


Allego programma e sorgenti. Unzippa, rinomina "esegui" in "esegui.bat" (controlla sempre i bat che ti rifilano), lancialo e poi leggi i 4 file java in prove/src/prove/.

E' un esempio, triste ma funzionale, di applicazione con package e sorgenti "separati" che fa uso di JInternalFrame e aree di testo.