syntaxhighlighter.googlecode.com

sobota, 1 marca 2014

Swing - asynchroniczna aktualizacja JTable

Problem: chcemy asynchronicznie aktualizować JTable. Mamy zatem sytuację: tworzymy JTable. Wyświetlamy go. A teraz asynchronicznie, bez udziału użytkownika, dochodzą nowe wiersze do JTable.
Idea rozwiązania:
1. Wyświetlamy JTable
2. Asynchronicznie, w wątku systemowym, dodajemy wiersze do modelu JTable'a (tym modelem jest obiekt klasy dziedziczącej po DefaultTableModelu).

Oto kod:
/**
 * $Id$
 */
package pl.prv.wojsal.table;

import java.awt.BorderLayout;
import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa: WsPacjenciViewJTableAsynchronizm
 * <li>Opis: Test na asynchroniczna aktualizacje tablemodela, a tym samym jTable.
 * <li>Utworzono: 1 mar 2014, 10:23:02
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class WsPacjenciViewJTableAsynchronizm {

    public static void main(String[] args) {
        WsPacjenciViewJTableAsynchronizm m = new WsPacjenciViewJTableAsynchronizm();
        m.run();
    }

    private WsPacjenciTableModel    dataModel;

    /**
     *
     */
    private void run() {
        JFrame frame = new JFrame();

        JPanel panel = new JPanel();
        panel.setBackground(Color.BLUE);
        panel.setLayout(new BorderLayout());
        this.dataModel = new WsPacjenciTableModel("lp", "Data", "Nazwisko", "Imię", "Status");
        JTable table = new JTable();
        table.setModel(dataModel);
        JScrollPane jsp = new JScrollPane(table);
        panel.add(jsp);
        frame.setTitle("Lista zarejestrowanych pacjentów");
        frame.getContentPane().add(panel);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setBounds(500, 200, 700, 300);
        frame.setVisible(true);

        runAsynchronicznaAktualizacjaTableModelu();
    }

    /**
     * Asynchroniczne dodawanie wierszy do tabeli. Dodajemy wiersze do tablemodelu w watku systemowym.
     */
    private void runAsynchronicznaAktualizacjaTableModelu() {
        Thread th = new Thread(new Runnable() {

            int    lp    = 0;

            public void run() {
                while (true) {
                    System.out.println("Bede dodawal wiersz lp=" + this.lp);
                    WsPacjenciModel wiersz = WsPacjenciDaoMock.getNewModel(this.lp++);
                    dataModel.addWiersz(wiersz);
                    System.out.println("Dodalem wiersz lp=" + this.lp);
                    try {
                        Thread.sleep(3 * 1000l);
                    } catch (InterruptedException e) {
                        System.out.println(e.getLocalizedMessage());
                        e.printStackTrace();
                    }
                }
            }
        });
        th.start();
       
    }

}

=========================================================================
  /**
 * $Id$
 */
package pl.prv.wojsal.table;

import java.util.Date;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa: WsPacjenciModel
 * <li>Opis: Model wiersza tabeli.
 * <li>Utworzono: 1 mar 2014, 10:58:52
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class WsPacjenciModel {

    private int            lp;
    private Date        data;
    private String    imie;
    private String    nazwisko;
    private boolean        status;
    public int getLp() {
        return lp;
    }
    public void setLp(int lp) {
        this.lp = lp;
    }
    public Date getData() {
        return data;
    }
    public void setData(Date data) {
        this.data = data;
    }

    public String getImie() {
        return imie;
    }

    public void setImie(String imie) {
        this.imie = imie;
    }

    public String getNazwisko() {
        return nazwisko;
    }

    public void setNazwisko(String nazwisko) {
        this.nazwisko = nazwisko;
    }
    public boolean isStatus() {
        return status;
    }
    public void setStatus(boolean status) {
        this.status = status;
    }

}
===================================================================

/**
 * $Id$
 */
package pl.prv.wojsal.table;

import java.util.Vector;

import javax.swing.table.DefaultTableModel;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa: WsPacjenciTableModel
 * <li>Opis: Model tablea.
 * <li>Utworzono: 1 mar 2014, 10:29:24
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class WsPacjenciTableModel extends DefaultTableModel {

    /**
     *
     * @param nazwyKolumn
     */
    public WsPacjenciTableModel(String... nazwyKolumn) {
        super(nazwyKolumn, 0);
    }

    /**
     * @param wiersz
     */
    public void addWiersz(WsPacjenciModel wiersz) {
        Vector rowData = new Vector();
        rowData.add(wiersz.getLp());
        rowData.add(wiersz.getData());
        rowData.add(wiersz.getNazwisko());
        rowData.add(wiersz.getImie());
        rowData.add(wiersz.isStatus());
        this.insertRow(0, rowData);

    }
}
====================================================================

/**
 * $Id$
 */
package pl.prv.wojsal.table;

import java.util.Date;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa: WsPacjenciDaoMock
 * <li>Opis: Klasa DAO - wersja mock, dla testow.
 * <li>Utworzono: 1 mar 2014, 22:19:14
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class WsPacjenciDaoMock {

    private static String[]    nazwiska    = { "Ochódzki", "Jarząbek", "Talar", "Kloss", "Maliniak", "Karwowski", "Paszczywół" };
    private static String[]    imiona        = { "Ryszard", "Wacław", "Andrzej", "Hans", "Roman", "Stefan", "Zenon", "Wojciech", "Donald" };

    /**
     * @param lp
     * @return
     */
    public static WsPacjenciModel getNewModel(int lp) {
        WsPacjenciModel model = new WsPacjenciModel();
        model.setData(new Date());
        model.setImie(imiona[lp % imiona.length]);
        model.setNazwisko(nazwiska[lp % nazwiska.length]);
        model.setLp(lp);
        model.setStatus((lp % 3) == 0);
        return model;
    }

}

niedziela, 2 lutego 2014

Swing - obsługa długo trwających akcji

Problem dotyczy obsługi akcji w Swingu, w których występuje długie przetwarzanie danych. Pojawia się problem blokady wątku Swinga - kontrolki Swinga w tym czasie "nie żyją".

Oto rozwiązanie problemu, przy pomocy klasy SwingWorker, dostępnej w Java SE (od wersji 6).
Idea jest następująca:
  1. Tworzymy obiekt SwingWorker
  2. nadpisujemy metodę doInBackground() - tu umieszczamy logikę, która może trwać dowolnie długo
  3. nadpisujemy metodę done() - tu dajemy kod modyfikujący kontrolki Swinga
  4. Całość uruchamimay przez metodę execute()


package pl.prv.wojsal.action;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

import org.apache.log4j.Logger;

import pl.prv.wojsal.utils.UtCzas;
import pl.prv.wojsal.utils.UtLog;

/**
 * <pre>
 * <ul>
 * <li>Projekt: wsSwing
 * <li>Klasa:
 * <li>Opis: Obsluga akcji o dlugim czasie przetwarzania
 * <li>Utworzono: 02-02-2014, 14:24:12
 * <li>author: (c) Wojciech Salata
 * </ul>
 * </pre>
 */

public class ObslugaDlugiejAkcji {

    private static Logger    log    = Logger.getLogger(ObslugaDlugiejAkcji.class.getName());

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        UtLog.initLog4jForTests();
        ObslugaDlugiejAkcji m = new ObslugaDlugiejAkcji();
        m.run();
    }

    private JFrame    fr;

    /**
     *
     */
    private void run() {
        JPanel panel = new JPanel();
        final JLabel lb1 = new JLabel("Label chowany/pokazywany przez Bt1");
        panel.add(lb1);
        final JLabel lb2 = new JLabel("Label chowany/pokazywany przez Bt2");
        panel.add(lb2);

        JButton bt1 = new JButton("Button 1 (dluga akcja)");
        bt1.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                log.debug("Obsluga akcji bt1 - start");

                final ObslugaDlugiejAkcji oa1 = new ObslugaDlugiejAkcji();
                oa1.run();
                // UtCzas.sleep("To jest zle - to musi byc w doInBackground()");
                log.debug("Po oa1.run()");
                SwingWorker<Object, Object> sw = new SwingWorker<Object, Object>() {

                    @Override
                    protected Object doInBackground() throws Exception {
                        UtCzas.sleep("Czekamy na koniec akcji bt1");
                        log.debug("Koniec dlugiego przetwarzania bt1");
                        return null;
                    }

                    @Override
                    protected void done() {
                        boolean visible = lb1.isVisible();
                        lb1.setVisible(!visible);
                        oa1.dispose();
                        log.debug("Usuniete oa1");
                    }
                };
                sw.execute();

                log.debug("Obsluga akcji bt1 - koniec");
            }
        });
        panel.add(bt1);
        JButton bt2 = new JButton("Button 2");
        bt2.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                log.debug("Obsluga akcji bt2 - start");
                boolean visible = lb2.isVisible();
                lb2.setVisible(!visible);
                log.debug("Obsluga akcji bt2 - koniec");
            }
        });
        panel.add(bt2);
        this.fr = new JFrame();
        fr.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        fr.getContentPane().add(panel);
        fr.setSize(300, 200);
        fr.setVisible(true);
    }

    /**
     *
     */
    protected void dispose() {
        this.fr.dispose();
    }


}

piątek, 1 listopada 2013

SVN, Eclipse - dodawanie projektu wielomodułowego

Idea:
  1. Tworzymy projekt parent (pl.prv.wojsal.pom)
  2. Tworzymy podprojekty:
    1. core (pl.prv.wojsal.core)
    2. widok (pl.prv.wojsal.view)
    3. dao (pl.prv.wojsal.dao)
    4. utils (pl.prv.wojsal.utils)
 Struktura katalogów z projektami:
  • pl.prv.wojsal.pom
    • pl.prv.wojsal.core
    • pl.prv.wojsal.view
    • pl.prv.wojsal.dao
    • pl.prv.wojsal.utils
Dodajemy projekty do repozytorium SVN przy pomocy Eclipse: 
W Eclipse, na projekcie:
  1. Prawy przycisk myszy: Team -> Share Project: SVN
  2. URL:http://wojtek-Komputer/svn/wojsal/trunk/pl.prv.wojsal.pom

niedziela, 22 września 2013

MVC - architektura projektów

Podział na projekty aplikacji MVC. Architektura jest niezależna od technologii widoku (Swing/SWT/JSF itd) oraz od technologii bazy danych (SQL, CSV, ISAM, JMS, WebService itd)

  1. Core (M i C)
  2. View (V)
  3. DAO
  4. Utils

Core

Projekt Core zawiera warstwę Modelu (M) i logiki biznesowej (C).
Logika nic nie wie o technologii dostępu do danych oraz o technologii widoku.

View

Tu mogą być projekty uzależnione od technologii widoku, np.:
  • View.Swing
  • View.SWT
  • View.JSF
  • View.RCP
  • itd

DAO

       Tu mogą być różne projekty DAO  np.
  • DAO.SQL - dostęp do danych serwera SQL
  • DAO.CSV - dostęp do danych w plikach tekstowych CSV
  • DAO.JMS  - dostęp do danych pobieranych/wysyłanych przez komunikaty JMS
  • DAO.WS - dostęp do danych przez WebService
  • DAO.XML - dostęp do danych w plikach XML
  • itd

Utils

Różne narzędzia. Narzędzia nie dotyczą DAO oraz nie dotyczą View.

sobota, 21 września 2013

Swing - szablon walidacji

 ActionListener dla zwykłej kontrolki
    a. Kopiuj widok do modelu
    b. Akcja biznesowa z parametrem: model
    c. Kopiuj model do widoku
    d. Ustaw stan widoku w oparciu o model
    e. Walidacja wyniku akcji biznesowej w oparciu o model

ActionListener dla buttonów typu wykonaj/zapisz itp
   a. Walidacja modelu
   b. Wykonanie akcji biznesowej z parametrem: model

JSF2, RichFaces i Maven2

Jak skonfigurować Maven dla aplikacji webowej, która korzysta z JSF2, RichFaces 4.x?
Oto pom.xml:

<project
   xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>web.jsf2</artifactId>
    <parent>
        <groupId>pl.prv.wojsal</groupId>
        <artifactId>pom</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <packaging>war</packaging>
    <properties>
        <org.richfaces.bom.version>4.3.3.Final</org.richfaces.bom.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <wtpapplicationxml>true</wtpapplicationxml>
                    <wtpversion>2.0</wtpversion>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>pl.prv.wojsal</groupId>
            <artifactId>logika</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces</groupId>
            <artifactId>richfaces-bom</artifactId>
            <version>${org.richfaces.bom.version}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.richfaces.ui</groupId>
            <artifactId>richfaces-components-ui</artifactId>
            <version>${org.richfaces.bom.version}</version>
        </dependency>
        <dependency>
            <groupId>org.richfaces.core</groupId>
            <artifactId>richfaces-core-impl</artifactId>
            <version>${org.richfaces.bom.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
        </dependency>
    </dependencies>

</project>