miercuri, 24 iunie 2009

Utilizarea JTable in Swing - Partea 2


Prima parte a acesui tutorial o puteti gasi aici.


3. Selectarea elementelor tabelului

In mod default putem sa afisam si sa editam datele dintr-un tabel. Din punct de vedere al selectarii datelelor dintr-un tabel exista o serie de operatii pe care le putem efectua fara un efort prea mare. Pentru selectii trebui sa utilizam obiecte din clasa ListSelectionModel. Spre deosebire de marea majoritate a componetelor de interfata grafica, un JTable dispune de doua modele de selecte, unul pentru linii si unul pentru coloane.

Exemplul din de mai jos reprezinta o aplicatie care ne permite sa activam sau sa dezactivam diferitele tipuri de selectii aplicabile unui tabel (celula, rand si coloana). Pe masura ce selectati diferite randuri sau coloane, cele doua obiecte de tip JLabel vor indica indicii elementelor selectate.


Cea mai mare parte a codului este alocata pentru a realiaza interfata grafica. Din momentul in care aceasta este realizata vom atasa doi listeneri care vor intercepta evenimentele pentru selectia pe rand si coloana. Partea interesanta a codului este reprezentata urmareste orice ListSelectionModel si updateaza textul de pe etichete. (Indicii care sunt fisati pe aceste etichete sunt preluati folosind metoda getSelectedIndices() aflata in clasa SelectionDebugger). Din moment ce depindem doar de list selection model, putem folosi aceasi listener atat pentru randuri cat si pentru coloane.de ListSelectionListener, care este sub forma de inner class.



// LECSelectionExample.java
// Un simplu tabel populat cu numere naturale consecutive. Acest tabel permite
// modificarea modului de selectie. Puteti selecta fie celule, linii sau coloane
// pentru tabel.

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

public class LECSelectionExample extends JFrame {

public LECSelectionExample( ) {
super("LEC Selection Model Test");
setSize(450, 350);
setDefaultCloseOperation(EXIT_ON_CLOSE);

TableModel tm = new AbstractTableModel( ) {
// Vom utiliza un simlu tabel de test needitabil populat cu
// numere naturale consecutive.
public int getRowCount( ) { return 10; }
public int getColumnCount( ) { return 10; }
public Object getValueAt(int r, int c) { return "" + (r+1)*(c+1); }
};

final JTable jt = new JTable(tm);

JScrollPane jsp = new JScrollPane(jt);
getContentPane( ).add(jsp, BorderLayout.CENTER);

// Setarea controalelor pentru selectie.
JPanel controlPanel, buttonPanel, columnPanel, rowPanel;

buttonPanel = new JPanel( );
final JCheckBox cellBox, columnBox, rowBox;
cellBox = new JCheckBox("Randuri", jt.getCellSelectionEnabled( ));
columnBox = new JCheckBox("Coloane", jt.getColumnSelectionAllowed( ));
rowBox = new JCheckBox("Randuri", jt.getRowSelectionAllowed( ));
cellBox.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
jt.setCellSelectionEnabled(cellBox.isSelected( ));
columnBox.setSelected(jt.getColumnSelectionAllowed( ));
rowBox.setSelected(jt.getRowSelectionAllowed( ));
}
} );

columnBox.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
jt.setColumnSelectionAllowed(columnBox.isSelected( ));
cellBox.setSelected(jt.getCellSelectionEnabled( ));
}
} );

rowBox.addActionListener(new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
jt.setRowSelectionAllowed(rowBox.isSelected( ));
cellBox.setSelected(jt.getCellSelectionEnabled( ));
}
} );

buttonPanel.add(new JLabel("Modul de selectie:"));
buttonPanel.add(cellBox);
buttonPanel.add(columnBox);
buttonPanel.add(rowBox);

columnPanel = new JPanel( );
ListSelectionModel csm = jt.getColumnModel( ).getSelectionModel( );
JLabel columnCounter = new JLabel("(Indicii coloanelor selectate)");
csm.addListSelectionListener(new SelectionDebugger(columnCounter, csm));
columnPanel.add(new JLabel("Coloanele selectate:"));
columnPanel.add(columnCounter);

rowPanel = new JPanel( );
ListSelectionModel rsm = jt.getSelectionModel( );
JLabel rowCounter = new JLabel("(Indicii randurilor selectate)");
rsm.addListSelectionListener(new SelectionDebugger(rowCounter, rsm));
rowPanel.add(new JLabel("Randuri selectate:"));
rowPanel.add(rowCounter);

controlPanel = new JPanel(new GridLayout(0, 1));
controlPanel.add(buttonPanel);
controlPanel.add(columnPanel);
controlPanel.add(rowPanel);

getContentPane( ).add(controlPanel, BorderLayout.SOUTH);
}

public static void main(String args[]) {
LECSelectionExample se = new LECSelectionExample( );
se.setVisible(true);
}

public class SelectionDebugger implements ListSelectionListener {
JLabel debugger;
ListSelectionModel model;

public SelectionDebugger(JLabel target, ListSelectionModel lsm) {
debugger = target;
model = lsm;
}
public void valueChanged(ListSelectionEvent lse) {
if (!lse.getValueIsAdjusting( )) {
// Se sare peste restul evenimentelor.
StringBuffer buf = new StringBuffer( );
int[] selection = getSelectedIndices(model.getMinSelectionIndex( ),
model.getMaxSelectionIndex( ));
if (selection.length == 0) {
buf.append("none");
}
else {
for (int i = 0; i < selection.length -1; i++) {
buf.append(selection[i]);
buf.append(", ");
}
buf.append(selection[selection.length - 1]);
}
debugger.setText(buf.toString( ));
}
}

// Aceastea metoda returneaza un array al indicilor selectati. Metoda
// nu poate intoarce valori care sunt null.
protected int[] getSelectedIndices(int start, int stop) {
if ((start == -1) || (stop == -1)) {
// Nimic selectat, asa ca vom intoarce un array gol
return new int[0];
}
int guesses[] = new int[stop - start + 1];
int index = 0;
// Parcurgere manuala
for (int i = start; i <= stop; i++) {
if (model.isSelectedIndex(i)) {
guesses[index++] = i;
}
}
int realthing[] = new int[index];
System.arraycopy(guesses, 0, realthing, 0, index);
return realthing;
}
}
}


Merita mentionat ca pentru aceasta aplicatia am fi putut prelua array-ul care continea indiici pentru randurile selectate din obiectul de tip JTable si array-ul care continea coloanele selectate din column model. Modivul pentru care nu am utilizat aceasta modalitate in exemplul nostru este ca am fi avut nevoie de listeneri separati pentru linii si pentru coloane.



4. Renderingul celulelor

Puteti construi proprii nostri render-eri pentru celulele dintr-un tabel. In mod standard dispuneti de rendereri pentru datele de tip Boolean (elemente de tip JCheckBox pentru afisare si editare), elemente de tip ImageIcon, valori numerice (elemente de tip JTextFiled). Pe langa aceastea puteti sa va creati si proprii rendereri pentru un anumit tip de clasa , pentru o anumita coloana, sau chiar pentru o anumita celula.


Interfata TableCellRenderer

Aceasta interfata ofera posibilitatea de a accesa componeta de rendering fara a specifica ce anume face aceasta componenta. Acest lucru functioneaza doarece un rederer in mod standard „lipeste” imaginea unui component de interfata grafica in pozitia indicata de noi. Singura metoda care este inclusa in aceasta interfata defineste, intializeaza si intoarce un component :


public abstract Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)

Aceasta metoda primeste o valoare, care poate fi de asemenea preluata specificandu-se celula din randul row, coloane column si tabelul table, si intoarce o componeta capabila sa deseneaze acea valoare in celula unui tabel.


Clasa DefaultTableCellRenderer

Pachetul javax.swing include un renderer standard care produce un JLabel pentru a afisa text in fiecare celula din tabel. Clasa JTable utilizeaza acest renderer pentru a afisa numere, icoane si obiecte. JTable creaza un renderer default, il pozitioneaza in locatia corecta si ii ataseaza o icoana, in functie de tipul de data. Obiectele de tip Object sunt transformate in String folosind metoda toString() si sunt afisate folosind un simplu JLabel. Elementele de tip numar sunt afisate folosind o aliniere la drepta, iar icoanele sunt afisate folosind o aliniere pe centru. Valorile de tip Boolean nu folosesc DefaultTableCellRenderer. In locul acestuia utilizeaza un clasa de rendering proprie care extinde JCheckBox.


Bineinteles ca ne putem construi si proprii nostrii rendereri pe baze clasei DefaultTableCellRenderer. Mai jos aveti un exemplu de renderer pe care il putem utiliza pentru a afisa dimensiunile unor fisiere pe harddisk. Aceast renderer pune o icoana reprezentand un semn de exclamare in fata oricarei date care este mai mare decat o anumita valoare pe care o dam ca praramentru in contructor.



// LECBigRenderer.java
// A renderer for numbers that shows an icon in front of big numbers
// Un renderer pentru numere care arata o imagine in fara numerelor mari.

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

public class LECBigRenderer extends DefaultTableCellRenderer {
double threshold;
Icon bang = new ImageIcon("bang.gif");

public LECBigRenderer(double t) {
threshold = t;
setHorizontalAlignment(JLabel.RIGHT);
setHorizontalTextPosition(SwingConstants.RIGHT);
}

public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int col)
{
if (value instanceof Number) {
if (((Number)value).doubleValue( ) > threshold) {
setIcon(bang);
}
else {
setIcon(null);
}
}
else {
setIcon(null);
}
return super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, col);
}
}

Pentru a atasa acest renderer tabelului nostru, nu trebuie decat sa adaugam cateva linii de cod :
JTable jt = new JTable(fm);
// ...
jt.setDefaultRenderer(Number.class, new LECBigRenderer(100));


Figura de mai jos prezinta un exemplu care poate fi obtinut utilizandu-se acest renderer.



Clasa CellRenderePane

Aceasta clasa utilitar a fost construita pentru a impiedica rendererii sa propage apeluri catre repaint() si validate() pentru componete utilizand elemente de rendering precum JTree si JList. In cazul in care ati incercat sa va construti rendereri proprii pentru orice alt element de Swing, atunci ati putut observa ca nu puteti sa folositi acea clasa in mod direct. Acest pane este utilizat impreuna cu un renderer si diferitele metode paintComponent(), de care dispune, sunt utilizate pentru a reliza desenul efectiv. In mod normal nu trebuie sa modficati aceasta clasa.

marți, 16 iunie 2009

Aplicatie Java mobile - "Hello World !" MIDlet

Scopul acestui tutorial este de a prezenta elemente de baza cu privire la dezvoltarea de aplicatii mobile Java. Pentru a exemplifica notiunile prezentate se construieste o aplicatie simpla de tip HelloWorld.

Resursele necesare pentru dezvoltarea proiectului sunt de tip open-source si pot fi descarcate de pe Internet:
  • mediu de dezvoltare vizual care sa includa platforma Java ME (Micro Edition); acesta nu este obligatoriu, deoarece sursele pot fi compilate si din linia de comanda; exemplul descris in acest material este realizat in NetBeans; acest mediu, ajuns la versiunea 6.5.1, poate fi descarcat de la adresa http://www.netbeans.org/ si desi exista mai multe pachete trebuie ales acela care contine tehnologia Java ME; cel mai putin complex mediu de dezvoltare vizual utilizat pentru aplicatii Java mobile este inclus in Sun Java ME Software Development Kit (http://java.sun.com/javame/sdk/index.jsp)
  • emulatoare de dispozitive mobile care suporta aplicatii Java; un astfel de emulator este deja integrat in distributia de Netbeans; dispozitivul simulat este unul generic; daca se doreste testarea aplicatiei intr-un mediu cat mai apropiat de dispozitivul urmarit atunci se utilizeaza resurse puse la dispozitie de producator; de exemplu pentru dispoztive de tip Nokia, o sursa de SDK-uri (Standard Development Kit) pentru diferite generatii si modele este forum.nokia.com;

Prentru a crea proiectul aplicatiei, in mediul NetBeans se alege File -> New Project si din categoria Java ME este selectat un proiect de tip Mobile Application.

La urmatorul pas al asistentului se defineste locatia (si se deselecteaza optiunea Create Hello MIDlet), iar la pasul trei (Default Platform Selection) sunt definite resurse cu privire la:
  • emulatorul utilizat; implicit, daca s-a instalat doar NetBeans, fara alte SDK-uri, este disponibil doar Sun Java Wireless Toolkit 2.5.2 for CLDC;
  • tipul de dispozitiv mobil (ecran color sau monocrom, cu tastatura qwerty)
  • configuratia dispozitivului; pentru acest proiect se alege CLDC-1.0; CLDC sau Connected Limited Device Configuration reprezinta un standard ce descrie caracteristicile hardware ale dispozitivului mobil; versiunea 1.0 a standardului descrie un dispozitiv cu 128 KB pentru masina virtuala Java, 32 KB pentru memoria dinamica, interfata vizuala limitata si cu capacitatea de a se conecta la o retea de date; acest standard este definit de un consortiu din care fac parte marii producatori de dispozitive mobile pentru a ajuta dezvoltatorii de software sa stabileasca limitele dispozitivului ce va rula aplicatia; de asemenea, aceste setari au impact si asupra modului in care proiectul va fi compilat;
  • profilul dispozitivului; pentru acest proiect se alege MIDP-2.0; MIDP sau Mobile Information Device Profile reprezinta o extensie a configuratiei hardware (CLDC) ce descrie caracteristicile sofware ale dispozitivului cu referire la framework-ul disponibil si la masina virtuala Java; combinatia aleasa (CLDC-1.0 si MIDP-2.0) este valabila pentru mai mult de 75% din dispozitivele mobile produse dupa 2005.
Odata creat proiectul de tip MobileApplication trebuie definit contextul obiectual pe baza caruia se va construi aplicatia. Asta inseamna inserarea unei resurse de tip MIDlet , prin intermediul optiunilor din meniul mediului NetBeans (File -> New File…) sau prin meniul contextual (New -> MIDlet) activat cu Click dreapta pe numele proiectului.
Prin adaugarea unei resurse de tip MIDlet, fisier cu extensia .java, este generate clasa MidletHelloWorld derivata din clasa abstracta MIDlet. Initial forma acestei clase

import javax.microedition.midlet.*;

public class MidletHelloWorld extends MIDlet {

public void startApp() {
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}


supradefineste metodele abstracte:
  • startApp() – functia starter a aplicatiei; se executa prima, dupa initializarea instantei MidletHelloWorld
  • pauseApp() – functia este executata la aparitia unui eveniment ce implica blocarea aplicatiei de tip MIDlet; un scenariu des intalnit pe un dispozitiv mobil contine receptionarea unui apel telefonic in timpul executiei aplicatiei;
  • destroyApp() – functia de inchidere a aplicatiei; este executata la terminarea aplicatiei si contine rutinele de eliberare a resurselor; are rol asemanator functiei destructor;
Secventa de cod, descrisa anterior, reprezinta cel mai mic program de tip MIDlet. Acest program nu are efecte vizuale deoarece se termina imediat dupa ce a fost lansat in executie. Daca ne gandim la o aplicatie scrisa in C, MIDlet-ul MidletHelloWorld in forma curenta, este echivalent cu

void main()
{
}

Cele trei metode din clasa MidletHelloWorld sunt obligatorii, situatie generata prin derivarea din MIDlet. Ele gestioneaza starile posibile in care se gaseste aplicatia. Acest concept mai este intalnit si la alte aplicatii Java si anume la applet-uri.
Pentru a afisa un mesaj pe ecran, aplicatia trebuie sa aiba acces la controler-ul resurselor grafice. Acest lucru se face prin definirea unui obiect de tip Display ce este initializat la start-ul aplicatiei.

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class MidletHelloWorld extends MIDlet {
private Display display = null; //referinta la managerul vizual al aplicatiei
public void startApp() {
if(display==null)

display = Display.getDisplay(this);
}

public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}


Deoarece caracteristicile hardware si software ale dispozitivului mobil impun restrictii asupra aplicatiilor Java Mobile (lucrurile sunt total diferite fata de aplicatiile Java pentru PC), putem dezvolta doar aplicatii vizuale care afiseaza maxim un formular (sau fereastra) la un moment dat. Mai mult, deoarece ecranul are dimensiuni reduse, acest formular acopera tot display-ul dispozitivului. Pentru a gestiona aceste resurse vizuale si pentru a stabili ce formular este activ este nevoie de referinta de tip Display.

Pentru a afisa pe ecran textul Hello World ! este nevoie de un formular si de un container pentru string-ul respectiv. Astfel vom folosi un formular de tip TextBox (a nu se confunda cu control-ul TextBox din alte limbaje de programare) ce reprezinta un formular ce contine doar un control de tip casuta de dialog cu proprietatea multiline implicit setata. Motivul existentei acestui tip de resursa vizuala este dat tot de resursele limitate de care dispunem pe un telefon. Alte tipuri de formulare permit realizarea unor aplicatii mai complexe, insa ele vor fi descrise in alt post.
Prin adaugarea formularului, codul devine:

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;

public class MidletHelloWorld extends MIDlet {
private Display display = null; //referinta la managerul vizual al aplicatiei
private TextBox tbMainForm; //TextBox pentru a afisa mesajul de salut

public MidletHelloWorld(){
tbMainForm = new TextBox("My First MIDlet", "Hello World !", 100, 0);
}

public void startApp() {
if(display==null)
display = Display.getDisplay(this);
display.setCurrent(tbMainForm); //activarea formularului
}


public void pauseApp() {
}

public void destroyApp(boolean unconditional) {
}
}
In secventa de cod, se observa ca afisarea formularului s-a realizat in metoda startApp prin intermediul metodei setCurrent a obiectului de tip Display.
Compilarea si rularea aplicatiei conduce la obtinerea in emulator a imaginii urmatoare

La lansarea emulatorului, acesta nu executa imediat aplicatia. Pentru a o porni trebuia data comanda Launch (butonul din dreapta al emulatorului).
Cu toate ca aplicatia este destul de simpla, ea exemplifica foarte bine structura unui MIDlet, iar elementele prezentate se regasesc in toate aplicatiile de acest tip.
Pentru a-l testa intr-un mediu real, pe telefonul mobil personal, MIDlet-ul din acest exemplu trebuie instalat pe dispozitivul mobil. Acest lucru se face prin transmitere pe telefon (prin Bluetoth, IR, Wireless sau cablu de date) a 2 fisiere ce se gasesc in subdirectorul dist al proiectului (situatia este valabila doar pentru Netbeans). Daca proiectul se numeste MobileApplicationHelloWorld , atunci cele 2 fisiere sunt MobileApplicationHelloWorld.jad (descrierea aplicatiei) si MobileApplicationHelloWorld.jar (sursa aplicatiei).

luni, 15 iunie 2009

Utilizarea protocoalelor POP3 si SMTP in JAVA - Partea 1

Obiective


Scopul acestui tutorial este acela de a prezenta operatiunile de baza necesare pentru lucrul cu protocoalele POP3 si SMTP pentru citirea, respectiv trimiterea e-mailurilor. Veti invata de-a lungul acestui tutorial cum se face conectarea prin intermediul Java la un server ce recunoaste protocolul POP3, cum se citesc si cum se sterg mesajele dintr-o casuta de mail prin intermediul acestui protocol. De asemenea se va utiliza protocolul SMTP pentru trimiterea de email-uri catre o adresa antecunoscuta.


1. Protocolul POP3

Post Office Protocol 3 (POP3). POP3 este o metoda de descarcare de mesaje email de pe un server. Prin intermediul JAVA vom exemplifica procedura de conectare la un server ce recunoaste protocolul POP3 si modalitate de citire a mesajelor existente in casuta de mail la care ne-am conectat.

Metoda pentru conectare la un server ce foloseste protocolul POP3 si pentru citirea mailurilor existente in aceasta :

import java.net.Socket

public void conectareServerPOP3(String pop3Server,String userName,
String password){
//socketul se foloseste pentru a se obtine conexiunea cu
//serverul POP3
Socket socket ;
//prin intermediul inputStream-ului se vor extrage mesajele de la serverul POP3
BufferedReader inputStream;
//prin intermediul outputStream-ului se vor trimite mesaje catre serverul POP3
PrintWriter outputStream;
//numarul unic de identificare a unui mesaj intr-o casuta de mail
String uidl = new String();

int port = 110; //pop3 mail port
//pop3Server este o variabila de tip String ce contrine de fapt adresa serverului ce lucreaza cu protocolul POP3; ex: pop.austincc.edu
socket = new Socket(pop3Server,port);
//deschidem canalul de citire a mesajelor de la serverul POP3
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
//deschidem canalul de trimitere a mesajelor catre serverul POP3
outputStream = new PrintWriter(new OutputStreamWriter(
socket.getOutputStream()),true);
//luam un prim mesaj de la serverul POP3
//metoda validateOneLine() are rolul de a extrage un mesaj primit de la server si
//de a-l valida. Ea va fi explicata imediat
String connectMsg = validateOneLine();
//verificam daca serverul pop3 exista. Daca acesta exista mesajul ar trebui sa
//arate in felul urmator

Connected to pop3Server
+OK POP3 mailbox.austincc.edu
v2001.78 server ready

System.out.println("Connected to pop3Server " + connectMsg)
//acum se trimite username-ul la serverul pop3 si se verifica
//mesajul obtinut
outputStream.println("USER " + userName);
String userResponse = validateOneLine();

//Se afiseaza mesajul primit
System.out.println("USER " + userResponse);
//daca username-ul este corect raspunsul ar trebui sa arate in felul urmator

USER +OK User name accepted, password please

//se trimite parola catre serverul pop3 si se verifica mesajul obtinut
outputStream.println("PASS " + password);
System.out.println("PASS " + validateOneLine());

//daca parola este corecta raspunsul ar trebui sa arate in felul urmator


PASS +OK Mailbox open, 1 messages

System.out.println("Downloading Messages")
//dupa ce s-a realizat conexiunea le serverul POP3 se poate incepe
//downloadarea mesajelor din casuta de mail

try{
outputStream.println("STAT");
String stat = validateOneLine();
//se ia numarul de mesaje din casuta prin trimiterea
//mesajului STAT la server.
String numberMsgsStr=stat.substring(4,stat.indexOf(" ",5));
numberMsgs = Integer.parseInt(numberMsgsStr);
//se incepe citirea efectiva a mesajelor
msgNumber = 1;

while(msgNumber <= numberMsgs){ outputStream.println("UIDL " + msgNumber); uidl = validateOneLine(); while( !uidl.equals(“.”) ){ uidl = validateOneLine(); System.out.println(uidl+”\n”); } msgNumber++; } }catch(Exception e){ e.printStackTrace(); }
}

Metoda care citeste o linie de raspuns de la serverul POP3 si o valideaza :


private String validateOneLine(){
try{
//se citeste o linie din raspunsul primit de la serverul pop3 //prin intermediul canalului de comunicatii deschis in metoda //anterioara
String response = inputStream.readLine();

//daca textul mesajului incepe cu +OK inseamna ca acesta este un mesaj bun, comanda trimisa de noi anterior catre server este una acceptata
if(response.startsWith("+OK")){
return response;
}else{
System.out.println(response);
//Terminate the session.
outputStream.println("QUIT");
socket.close();
System.out.println(
"Premature QUIT on -ERR");
System.exit(0);
}//end else
}catch(IOException ex){
ex.printStackTrace();
}//end catch
//la aceasta linie de cod nu se va ajunge niciodata, insa ea este necesara pentru compilarea programului din cauza utilizarii blocului try- catch
return "Make compiler happy";
}//end validateOneLine()

Prin intermediul celor doua metode prezentate mai sus se realizeaza conexiunea la un server ce foloseste protocolul POP3 si sunt citite mesajele existente in casuta. Pentru conectarea la serverul POP3 este folosit un obiect de tip Socket din pachetul « java.net ». De asemenea pentru realizarea comunicatiei cu serverul prin trimiterea si primirea de mesaje se folosesc doua canale de comunicatie (BufferedReader inputStream; PrintWriter outputStream) .Este de mentionat ca protocolul POP3 nu utilizeaza niciun flag prin care sa diferentieze mesajele citite de acelea necitite din casuta de mail, asadar se va face citirea tuturor mesajelor

vineri, 12 iunie 2009

Utilizarea JTable in Swing - Partea 1

Obiective

Scopul acestui tutorial este de a exemplifica modul de functionare si utilitatea elementului JTable. In principal se vor aborda elemente legate de modul in care se utilizeaza, cum se poate contrui un renderer, un column model, sau diferitele moduri de selectie. Acest tutorial presupune cunostinte medii despre limbajul Java si despre modul de construire a interfetelor grafice folosind Swing. In cadrul sau vor fi abordate doar elementele necesare explicarii elementului JTable.

1. Introducere

Tabelele reprezinta una dintre cele mai des utilizate modalitati de vizualizare a datelor. Prin folosirea unui tabel inregistrarile dintr-o baza de date sunt usor de sortat si slectat. Informatiile despre spatiul liber disponibil pe hard pot fi afisate pentru mai multe calculatorare in perioade de timp diferite, folosind un tabel. Cotatiile la bursa pot fi de asemena urmarite cu usurinta sau vanzarile efectuate. Clasa JTable din pachetul Swing ofera posibilitatea de a efecuta foarte usor elementele descrise anterior si chiar mai mult.

Tabelele pot fi gandite ca un mod de reprezentare a datelor bidimensionale. De fapt, clasa JTable are chiar un constructor care primeste ca argument un masiv bidimensional de obiecte din clasa Object (Object [][]) si afiseaza continutul acestora in liniile si coloanele unui tabel. De exemplu figura urmatoare arata un tabel de obiecte String:


Acest exemplu a fost generat folosindu-se foarte putin cod. Tot ce a fost nevoie sa facem a fost sa cream un obiect de tip JTable folosind un argument de tip String[][] pentru continutul tabelului si un argument de tip String[] pentru header-ul tabelului. In loc sa adaugam tabelul direct pe fereastra l-am incapsulat intr-un ScrollPane.

// LECSimpleTable.java
// O simpla clasa de test utilizand un table model standard
import java.awt.*;
import javax.swing.*;

public class LECSimpleTable extends JFrame {

public LECSimpleTable( ) {
super("LEC JTable Test");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);

JTable jt = new JTable(new String[][] { {"acesta", "este"}, {"un", "test"} },
new String[] {"Coloana", "Rand"});
JScrollPane jsp = new JScrollPane(jt);
getContentPane( ).add(jsp, BorderLayout.CENTER);
}

public static void main(String args[]) {
LECSimpleTable st = new LECSimpleTable( );
st.setVisible(true);
}
}

Dupa cum puteti observa folosind modele de date care au fost deja contruite, singurul lucru pe care trebuie sa il facem este sa trimitem ca parametrii datele noastre si header-ele pentru coloane, clasa JTabel ocupandu-se de restul operatiilor. Folosind modelele defaut puteti selecta mai multe randuri simultan, sa editati anumite celule, si sa interceptati evenimentele de selectie. Insa nu sunteti limitati doar la modelele default, si puteti obtine o serie de functionalitati destul de interesante in cazul in care suprascriteti comporatmentul modelelor default.

2. Realizarea unui Column Model

Mai jos aveti codul pentru un column model modficat, care ordoneaza coloanele in ordine alfabetica pe masura ce sunt adaugate:

// LECSortingColumnModel.java
// O extensie a clasei DefaultTableColumnModel care sorteaza noile
// coloane introduse.
import javax.swing.table.*;
public class LECSortingColumnModel extends DefaultTableColumnModel {
public void addColumn(TableColumn tc) {
super.addColumn(tc);
int newIndex = sortedIndexOf(tc);
if (newIndex != tc.getModelIndex( )) {
moveColumn(tc.getModelIndex( ), newIndex);
}
}
protected int sortedIndexOf(TableColumn tc) {
int stop = getColumnCount( );
String name = tc.getHeaderValue( ).toString( );
for (int i = 0; i < stop; i++) {
if (name.compareTo(getColumn(i).getHeaderValue( ).toString( )) <= 0) {
return i;
}
}
return stop;
}
}

Implementarea modelului este una destul de simpla. Suprascriem metoda addColumn(), in acest fel asociind comportamentul dorit de noi. Puteti folosi acest column model cu orice tip de data. Din moment ce avem un tabel model si un column model le putem folosi pentru a construi un JTable. Ulterior acestei operatii toate coloanele pe care le adaugam sunt sortate in ordine alfabetica, indiferent de ordinea in care sunt adaugate initial. Rezultatul poate fi vizualizat in figura de mai jos


Mai jos aveti codul care care realizarea conexiunea dintre tabel si column model:

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

public class LECColumnExample extends JFrame {

public LECColumnExample( ) {
super("LEC Abstract Model JTable");
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);

DefaultTableModel dtm = new DefaultTableModel(new String[][] {
{"1", "2", "3"}, {"4", "5", "6"} },
new String[] {"numele", "ordonate", "crescator"});
LECSortingColumnModel scm = new LECSortingColumnModel( );
JTable jt = new JTable(dtm, scm);
jt.createDefaultColumnsFromModel( );

JScrollPane jsp = new JScrollPane(jt);
getContentPane( ).add(jsp, BorderLayout.CENTER);
}

public static void main(String args[]) {
LECColumnExample ce = new LECColumnExample( );
ce.setVisible(true);
}
}

marți, 9 iunie 2009

Formatare conditionala incrucisata



In tabela urmatoare trebuie aplicata formatare conditionala pe coloanele “Nume” si “Varsta” in functie de vechime : 

Doresc sa fie formatate inregistrarile ce corespund salariatilor cu o vechime mai mare de 5 ani .  Pentru asta selectam cele 2 coloane pe care am spus la inceputul prezentarii ca dorim sa le formatam (A6:B15). Mergem in meniu la Format – Conditional Formatting si ne va aparea casuta de dialog pentru formatarea conditionala :

Deoarece conditia de formatare se va pune pe valorile din alta coloana decat cele doua pe care dorim sa le formatam  , in prima rubrica a casutei Conditional Formatting vom alege Formula is si vom pune conditia ca vechimea salariatului sa fi mai mare decat 5 :

Criteriul pentru formatare introdus la rubrica Formula IS va fi : =$C8>5 . Dupa stabilirea criteriului de formatare mergem la Format , iar la categoria Patterns alegem o culoare de formatare (am ales albastru in acest exercitiu).

De ce am inghetat prin semnul “$” doar litera si nu am facut la fel si pentru numarul care compune adresa de celula pe care am folosit-o  in conditie ? Pentru ca asa cum se vede si in imaginea de mai sus formatam doua coloane in acelasi timp . In conditie avem ca celula de pornire in verificarea criteriului celula C8 . Aplicarea formatarii conditionale incepe cu prima dintre cele doua coloane pe care le-am selectat , adica “Nume” . Dupa ce verifica respectarea criteriului pentru prima celula din aceasta coloana , Excelul trece automat la a doua celula , apoi la a treia si asa mai departe . Astfel a fost verificat pentru care inregistrari din colona “Nume” conditia pusa pe coloana “Vechime” este respecata . Dupa ce se ajunge la capatul coloanei , Excelul va verifica respectarea criteriului pentru urmatoarea coloana pe care am selectat-o pentru formatare conditionala , adica pentru coloana “Varsta” . In momentul trecerii de pe coloana “Nume” pe coloana “Varsta” , daca nu am fi inghetat litera din adresa celulei de pornire  , in formula prin care am definit criteriul s-ar fi tecut de asemena pe coloana urmatoare(adica de pe coloana C pe coloana D) si s-ar fi comparat cu 5 valorile din coloana “Salariu” si nu cele din coloana “Vechime” .

 

Rezultatul formatarii conditionale va fi :