четвер, 11 жовтня 2012 р.

Робота з COM-портом на Java

Для робот з портами Java в JDK немає стандартного пакету. Тому необхідно встановити додаткову бібліотеку для роботи з послідовними та паралельними портами. Послідовний (COM-порт) доволі поширений в даний час, багато апаратного обладнання працює на ньому. Навіть в сучасному він використовується доволі часто. Сучасні прилади підключаються до USB, проте в багатьох використовується перехідник USB-COM, що дозволяють розробникам програмного забезпечення працювати з приладом через добре знайомий і легкий інтерфейс RS232 (COM).

Тож, що нам потрібно? Існує декілька java бібліотек для роботи з COM-портом , які побудовані з використанням Native-методів. Свого часу була популярна javax.Comm, її можна використовувати до цих пір, проте в даний час бібліотеку ніхто не підтримує, її розвиток не відбувається. На зміну javax.Comm прийшла інша java бібліотека – RXTX (http://rxtx.qbang.org/wiki/index.php/Main_Page). Методи в RXTX для роботи з COM-портом ідентичні до методів javax.Comm.

Встановлення

Встановлення бібліотеки можна здійснити декількома способами. Їх можна знайти в документації на сайтах підтримки RXTX.

1. Найпростіший спосіб:

• Знайти де у вас встановлене JDK, наприклад:  c:\Program Files\Java\jdk1.6.0_01\
• Скопіювати rxtxParallel.dll до c:\Program Files\Java\jdk1.6.0_01\jre\bin\
• Скопіювати rxtxSerial.dll до c:\Program Files\Java\jdk1.6.0_01\jre\bin\
 • Скопіювати RXTXcomm.jar до c:\Program Files\Java\jdk1.6.0_01\jre\lib\ext\

Якщо у вас JRE і вам просто необхідно виконати необхідну програму, яка використовує RXTX, то зробити теж саме але для відповідних каталогів JRE. Звичайно даний спосіб поганий для кінцевих користувачів вашого продукту. Оскільки не всі користувачі зможуть легко зробити необхідні маніпуляції з файлами.

2.Тому другий спосіб - це включити бібліотеку у jar файл вашого продукту. Якщо ви використовуєте NetBeans, то у проекті де знаходяться java файли необхідно створити каталог resources і помістити туди rxtxSerial.dll. .

Другий крок – це додавання власне java файлів, для цього можна завантажити джерельний код(source) бібліотеки з офіційного сайту і з папки src взяти усі .java файли і закинути в src-папку проекту по структурі каталогів gnu/io.

Детальніше можна знайти в різноманітній документації. Зокрема як підключити rxtx у Eclipse написано тут: http://rxtx.qbang.org/wiki/index.php/Using_RXTX_In_Eclipse

Для початку можете спробувати перший спосіб.



Програмування

Перейдемо власне до програмування. В інтернеті я знайшов хорошу реалізацію класу SerialPortHandler, який спрощує роботу з RXTX. Тому наведу дещо перероблений варіант далі (Оригінал: http://embeddedfreak.wordpress.com/2008/08/08/how-to-open-serial-port-using-rxtx/)

Для роботи необхідно перш за все, отримати ідентифікатор послідовного порту:

CommPortIdentifier portId =
  CommPortIdentifier.getPortIdentifier("COM4");

Далі необхідно відкрити порт, тобто вказати системі, що ви з ним працюєте:

SerialPort serialPort =(SerialPort) portId.open("Name of program", 5000);

У вищенаведеному рядочку ми відсилаємо назву програми і задаємо інтервал очікування відповіді. В даному випадку 5000 мс – 5 секунд. Якщо відповідь не приходить, то отримуємо виняток IOException.

Якщо пройшло все добре, порт знайдено в системі і вам надано ID для роботи з ним, то далі необхідно налаштувати порт для роботи з ним:

int baudRate = 9600; // 9600bps
try {
  serialPort.setSerialPortParams(
    baudRate,
    SerialPort.DATABITS_8,
    SerialPort.STOPBITS_1,
    SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException ex) {
  System.err.println(ex.getMessage());
}

Незабуваємо задати контроль потоку:

try {
  serialPort.setFlowControlMode(
        SerialPort.FLOWCONTROL_NONE);
  // OR
  // If CTS/RTS is needed
  //serialPort.setFlowControlMode(
  //      SerialPort.FLOWCONTROL_RTSCTS_IN | 
  //      SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException ex) {
  System.err.println(ex.getMessage());
}

Для того щоб записувати і отримувати дані з порта, необхідно отримати потоки вводу-виводу.

OutputStream outStream = serialPort.getOutputStream();
InputStream inStream = serialPort.getInputStream();

Далі наведено повний текст методів для роботи з COM-портом. Наводиться без змін з оригінальної статті. Для використання необхідно вказати свій ідентифікатор порту та швидкість роботи з ним.



public class SerialPortHandler {
    private SerialPort serialPort;
    private OutputStream outStream;
    private InputStream inStream;

    public void connect(String portName) throws IOException {
        try {
            // Obtain a CommPortIdentifier object for the port you want to open
            CommPortIdentifier portId =
                    CommPortIdentifier.getPortIdentifier(portName);

            // Get the port's ownership
            serialPort =
                    (SerialPort) portId.open("Demo application", 5000);

            // Set the parameters of the connection.
            setSerialPortParameters();

            // Open the input and output streams for the connection. If they won't
            // open, close the port before throwing an exception.
            outStream = serialPort.getOutputStream();
            inStream = serialPort.getInputStream();
        } catch (NoSuchPortException e) {
            throw new IOException(e.getMessage());
        } catch (PortInUseException e) {
            throw new IOException(e.getMessage());
        } catch (IOException e) {
            serialPort.close();
            throw e;
        }
    }

    /**
     * Get the serial port input stream
     * @return The serial port input stream
     */
    public InputStream getSerialInputStream() {
        return inStream;
    }

    /**
     * Get the serial port output stream
     * @return The serial port output stream
     */
    public OutputStream getSerialOutputStream() {
        return outStream;
    }

    /**
     * Sets the serial port parameters
     */
    private void setSerialPortParameters() throws IOException {
        int baudRate = 57600; // 57600bps

        try {
            // Set serial port to 57600bps-8N1..my favourite
            serialPort.setSerialPortParams(
                    baudRate,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);

            serialPort.setFlowControlMode(
                    SerialPort.FLOWCONTROL_NONE);
        } catch (UnsupportedCommOperationException ex) {
            throw new IOException("Unsupported serial port parameter");
        }
    }
}
Ряд прикладів по використанню RXTX можна знайти тут: http://rxtx.qbang.org/wiki/index.php/Examples

пʼятниця, 21 вересня 2012 р.

Узагальнення (Generics).

Вступ

 В JDK 5.0 з’явилось декілька нових розширень до мови програмування Java. Одне з таких нововведень – це узагальнення (generics).

 Ви можливо вже знайомі з подібними конструкціями з інших мов, найімовірніше з шаблонами (templates) в С++. Якщо так, то ви побачите, що є як подібності так і важливі відмінності. Якщо ви незнайомі з подібними конструкціями звідкілясь, це на краще, ви можете розпочати вивчення з нуля без помилкових уявлень.

Узагальнення дозволяють вам абстрагуватися над типами. Найбільш загальним прикладом є контейнерні типи, такі як у ієрархії Колекцій.

Ось типовий приклад даного виду:

List myIntList = new LinkedList(); // 1
myIntList.add(new Integer(0)); // 2
Integer x = (Integer) myIntList.iterator().next(); // 3


Приведення в рядку 3 є злегка надокучливим. Зазвичай, програміст знає, який тип даних поміщено у відповідний список. Проте, приведення є важливим. Компілятор може лише гарантувати, що ітератор поверне Object. Щоб забезпечити коректне присвоєння змінній типу Integer, необхідне приведення до типу.

Звичайно, приведення не тільки призводить до надмірності в коді. Це також призводить до можливостей помилок часу виконання, тож програма буде неправильною.

А що якщо програміст зможе вказати свої справжні наміри і задати список з конкретними обмеженнями щодо типів даних для розміщення у ньому? Це основна ідея узагальнень. Ось версія програмного фрагменту даного вище з використанням узагальнень:

List<Integer> 
    myIntList = new LinkedList<Integer>(); // 1'
myIntList.add(new Integer(0)); // 2'
Integer x = myIntList.iterator().next(); // 3'


Запримітьте оголошення типу для змінної myIntList. Написавши List<Integer>, зазначаємо, що це не довільний список, а цілочисельний список. Ми говоримо, що List є узагальненим інтерфейсом, що отримує параметр типу – в даному випадку, Integer. Ми також зазначаємо параметр типу, коли створюємо об’єкт списку.

Зазначте, також, що приведення в рядку 3 відкинуто. Зараз, ви мабуть думаєте, що ми перетасували безладдя в коді . Замість приведення до Integer в рядку 3, ми маємо Integer як параметр типу в рядку 1. Проте, тут є значна велика відмінність. Тепер компілятор може провірити коректність типів в програмі під час компіляції. Коли ми кажемо, що myIntList є оголошеним з типом List<Integer>, це говорить нам дещо про змінну myIntList, яка міститеми правильні дані, коли б змінна не застосовувалась і компілятор гарантуватиме це. А приведення ж нам говорить інше, що програміст думає, що це вірно в даній точці коду.

В результаті ж, особливо в великих програмах, це покращує читабельність та робастність (правильну роботу) програми.



Визначення простого узагальнення

Ось невеликий витяг з визначень інтерфейсів List та Iterator в пакеті java.util:
public interface List <E> {
    void add(E x);
    Iterator<E> iterator();
}

public interface Iterator<E> {
    E next();
    boolean hasNext();
}

Усе це повинне бути зрозуміле вам, окрім вмісту в кутових дужках. Це – оголошення формального параметру типу інтерфейсів List and Iterator.

Параметри типу можуть застосовуватись усюди в оголошенні узагальнення, особливо де ви застосовуєте звичайні типи (щоправда існують деякі важливі обмеження; дивість секцію The Fine Print)

У вступі, ви побачили виклик (invocation) узагальненого типу при оголошенні List, як то List<Integer>. При виклику (так званого параметризованного типу) всі входження формального параметра типу (E в данному випадку) заміняються актуальним аргументом типу (в даному випадку Integer).

Ви можливо уявили, що List<Integer> створює версію List де E замінюється на Integer:
public interface IntegerList {
    void add(Integer x);
    Iterator<Integer> iterator();
}

Дане уявлення корисне, проте дещо помилкове.

Воно користе, тому що параметризований тип List<Integer> справді має методи подібні до наведеного представлення.

Проте воно помилкове, тому що власне саме оголошення узагальнень ніколи не доповнюється таким чином. Не існує багатьох копій коду – ні в текстовому, ні в двійковому, ні на диску чи в пам’яті. Якщо ви С++ програміст, ви зрозумієте, що це значна відмінність від шаблонів C++.

Оголошення узагальненого типу компілюється один раз і поміщається у файл класу, як звичайний клас або оголошеня інтерфейсу.

Параметри типу є аналогами до звичайних параметрів, що використовуються в методах та конструкторах. Коли метод викликається актуальний аргумент підставляється у формальний параметр, і тіло методу виконується. Коли здійснюється оголошення узагальнення, актуальний аргумент типу підставляється у формальний параметр типу.

Зазначимо правила найменування. Ми рекомендуємо щоб ви використовували стислі назви (по можливості простий символ) для параметрів типу. Краще уникати нижнього регістру символі в таких назвах, що робить формальні параметри типу відмінними від звичайних класів та інтерфейсів. Багато контейнерних типів використовують E, для елементів, як в прикладах наведених вище. Ми розглянемо деякі інші умовності пізніше в прикладах.

Generics  - Java Tutorials (Bonus)
Частковий переклад: Volodimirg 

Оригінал повністю: http://docs.oracle.com/javase/tutorial/extra/generics/index.html

понеділок, 23 липня 2012 р.

JComboBox

Комбінований список (combo box)— це компонент графічного інтерфейсу користувача (ГІК), що поєднує в собі текстове поле та випадний список. Компонент дозволяє або ввести необхідне значення у полі, або вибрати його із випадного списку. Комбіновані списки є альтернативою радіокнопкам. Перевагою є можливість додання великої кількості пунктів вибору і при цьому компонент займає небагато місця на екрані.
В Swing комбінований список реалізовує клас JComboBox. Комбінований список може бути в двох режимах: з можливість друку значення варіанту і без такої можливості. Для встановлення відповідного стану слугує метод setEditable(). Таким чином в компоненті можна буде друкувати як в звичайному текстовому полі, здійснюючи швидкий вибір пункту.
Пункти меню можна задати як в конструкторі так і додавати кожен пункт окремо методом addItem(String item):
  
String[] items={"Жовтий", "Синій", "Червоний"};
combo = new JComboBox(items);
combo.setEditable(true);
або:
  
combo = new JComboBox();
combo.setEditable(true);
combo.addItem("Синій");
combo.addItem("Жовтий");
combo.addItem("Червоний");
Пункти можна також вставляти за індексом в списку:
  
combo.insertItemAt("Світлосірий", 5);
Також можна видаляти пункти зі списку:
  
combo.removeItem("red");
combo.removeItemAt(0);
Повністю видалити всі пункти можна з допомогою методу removeAllItems().
Коли користувач вибирає певний пункт комбінованого списку, генерується подія ActionEvent. В обробнику подій можна визначити, що саме викликало подію методом getSource() застосувавши його до екземпляра події. Даний метод поверне посилання на об’єкт ComboBox. Далі об’єктну змінну можна використати для визначення пункту, який був вибраний методом getSelectedItem():
  
public void actionPerformed(ActionEvent event)
            {
                Object srs=event.getSource();
                JComboBox combo=(JComboBox)srs;
                if(combo.getSelectedItem().equals("Синій")) 
                    panel.setBackground(Color.BLUE); 
….
}
Наступна програма виводить список із вибором кольорів, при виборі певного кольору, колір панелі змінюється на вибраний із списку: Вибрано зелений колір
  
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class TestComboBox {
     public static void main(String[] args){
         ComboBoxFrame frame=new ComboBoxFrame();
         frame.setSize(250,225);
         frame.setTitle("TestComboBox");
         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         frame.setVisible(true);   
     }
}
 
class ComboBoxFrame extends JFrame {
    JPanel panel=new JPanel();
    JComboBox combo;
 
    ComboBoxFrame(){
 
        //створюємо комбінований список і додаємо пункти
        combo = new JComboBox();
        combo.setEditable(true);
        combo.addItem("Виберіть колір");
        combo.addItem("Синій");
        combo.addItem("Жовтий");
        combo.addItem("Червоний");
        combo.addItem("Зелений");
        combo.addItem("Білий");
        combo.addItem("Світлосірий");
        combo.addItem("Розовий");
        combo.addItem("Голубий");
 
        //додаємо обробника подій
        combo.addActionListener(new ActionListener(){
          //реалізовуємо метод обробки події  
          public void actionPerformed(ActionEvent event)
            {
                if(combo.getSelectedItem().equals("Синій")) 
                    panel.setBackground(Color.BLUE);
                if(combo.getSelectedItem().equals("Жовтий")) 
                    panel.setBackground(Color.YELLOW);
                if(combo.getSelectedItem().equals("Червоний")) 
                    panel.setBackground(Color.RED);
                if(combo.getSelectedItem().equals("Білий")) 
                    panel.setBackground(Color.WHITE);
                if(combo.getSelectedItem().equals("Світлосірий")) 
                    panel.setBackground(Color.LIGHT_GRAY);
                if(combo.getSelectedItem().equals("Зелений")) 
                    panel.setBackground(Color.GREEN);   
                if(combo.getSelectedItem().equals("Розовий")) 
                    panel.setBackground(Color.PINK);
                if(combo.getSelectedItem().equals("Голубий")) 
                    panel.setBackground(Color.CYAN);  
            }});
 
 
        panel.add(combo); // додаємо список до панелі
        this.add(panel);  //додаємо панель у фрейм
 
    }
 
}
Зовнішній вигляд комбінованого боксу можна дещо модифікувати визначивши спеціальний візуалізатор(custom renderer). Візуалізатор для комбінованого боксу повинен реалізовувати інтерфейс ListCellRenderer. Якщо компонент редагований, то редактор комбінованого боксу повинен реалізовувати інтерфейс ComboBoxEditor.

Детальніше дивіться офіційний Java посібник: How to Use Combo Boxes.

понеділок, 16 липня 2012 р.

Суміщення двох байт в Java

Постала необхідність прочитати з приладу потік байтів і їх перетворити на ряд двобайтових чисел. Готового методу в Java я не знайшов. Рішення підказав всезнаючий Інтернет:

public static short twoBytesToShort(byte b1, byte b2) {
          return (short) ((b1 << 8) | (b2 & 0xFF));
}
Інший приклад знайшов в книзі по Java. Тож це, також, можна зробити за допомогою потоку вводу даних DataInputStream:
FileInputStream fin=new FileInputStream("D://result.txt");
DataInputStream din=new DataInputStream(fin);
short s=din.readShort();
Якщо байти об'єднані в неправильній послідовності, тобто перший байт має бути другим, а другий першим в двобайтовому слові, то можна скористатись методом reverseBytes():
short k=Short.reverseBytes(s);

понеділок, 9 липня 2012 р.

PDFLib для PHP

Розглянемо процес генерування PDF документів засобами PHP. Для цього існує ряд бібліотек, одною з таких є PDFLib. Розглянемо основні особливості роботи з даною бібліотекою. Усі приклади перевірені на PHP 5.2.4. При роботі з PHP 5.3 можливо прийдеться внести певні зміни.

1. Встановлення і налаштування необхідних елементів
Для роботи необхідно поставити пакет веб-розробника денвер. Що можна завантажити з офіційного сайту або самостійно поставити веб-сервер Apache та php. Процес встановлення можна почитати в офіційній документації.

Для встановлення бібліотеки, що дозволить нам генерувати pdf документи необхідно:

• Зайти на http://php.net/releases/ і скачати колекцію PECL модулів для відповідної версії інтерпритатора PHP, яка встановлена у Денвері 3. У випадку встановлення Денвера 3 з офіційного сайту з php 5.2.4, качаємо наступний архів zip: http://museum.php.net/php5/pecl-5.2.4-Win32.zip. При використанні безплатного модуля з оф. сайту pdflib у створеному документі буде непотрібний нам фоновий напис, тому то користуємося PECL модулем.

• З даного архіву беремо php_pdf.dll і кладемо її в директорію:
     <denwer_root>\usr\local\php5\ext\ 
• В <denwer_root>\usr\local\php5\php.ini знаходимо секцію Windows Extensions і додаємо наступний рядок тексту:   
     extension=php_pdf.dll
• Перезапускаємо Apache — на цьому встановлення завершене.
• Для перевірки можна скористатися функцією phpinfo(). У виданій нею інформації повинно бути вказана підтримка pdf, що й зображено на рисунку.Для цього необхідно створити файл з розширення php із наступним змістом:
         
    <?
      PHP  
      phpinfo(); 
    ?>

Далі при запущеному Apache запустити його на виконання ввівши URL-адресу у веб-браузері.

Бібліотеку pdf підключено


2. Друк тексту

Після того як усе встановлено починаємо створення документу. Наступна програма демонструє створення pdf документу з однією сторінкою і написом на даній сторінці.
  
         <?php
          // Створити вказівник на новий PDF документ
          $pdf = pdf_new();
          // відкрити файл (міняємо адресу під власну)
          pdf_open_file($pdf, "/home/univer.ua/www/example1.pdf"); 
          // розпочати нову сторінку (A4)
          pdf_begin_page($pdf, 595, 842);
          // отримати і використати об'єкт шрифт з кириличною кодировкою cp1251
          $fontdir = "C:\WINDOWS\Fonts";
          pdf_set_parameter($pdf, "FontOutline", "arialMyName=$fontdir\arial.ttf");
          $arial = pdf_findfont($pdf,"arialMyName", "cp1251" ,0 );
          pdf_setfont($pdf, $arial, 10);
          // надрукувати текст
          pdf_show_xy($pdf, "Це перший рядок нашого документу,", 50, 750); 
          pdf_show_xy($pdf, "а це другий рядок", 50,730);
          // кінець сторінки
          pdf_end_page($pdf);
          // закрити і зберегти файл
          pdf_close($pdf);
        ?>

Після збереження скрипта під певною назвою (наприклад test.php), його можна запустити у браузері за адресом ВІРТУАЛЬНИЙ_ХОСТ/test.php. Так якщо був створений віртуальний хост univer.ua, то відповідно адреса буде http://univer.ua/test.php. За адресою вказаною на початку файлу буде створений example1.pdf. Результат зображено на рисунку:
Простий PDF документ
Почнемо з першого кроку – створення вказівника на PDF файл.
  
    $pdf = pdf_new();
Це здійснюється за допомогою функції pdf_new(), яка повертає вказівник на цей документ. Згодом цей вказівник використовується для всіх наступних інструкцій по створенню PDF документу.
 
       // відкриваємо файл
       pdf_open_file($pdf, "example.pdf");
Як тільки документ був створений, в нього можна вставити початок нової сторінки функцією pdf_begin_page()
 
      // розпочати нову сторінку (A4)
      pdf_begin_page($pdf, 595, 842); 
І кінець сторінки функцією pdf_end_page().
      // end page
      pdf_end_page($pdf);  
Якщо ще потрібні сторінки, то знову ж потрібно використати ці функції. Функція pdf_begin_page() потребує два додаткові параметри - ширину і висоту створюваного документу в пунктах (один пункт(точка) рівний 1/72 дюйма). Між викликом pdf_begin_page() і pdf_end_page() знаходиться код, який пише в файл. Це може бути вставка тексту, картинок або геометричних фігур. В даному випадку – це лише текст. Тому все що необхідно вибрати шрифт і використати його в тексті документу. Вибір і регістрація шрифтів виконується функцією pdf_findfont() та pdf_setfont().

Функція pdf_findfont() вибирає шрифт для використання в документі, і вимагає ввести ім’я шрифту, метод кодування та булевий параметр, що вказує чи слід його інтегрувати в PDF документ; а повертає вона об’єкт-шрифт, який можна згодом використовувати при виклику функції pdf_setfont(). Виклик даної функції необхідно буде здійснювати на кожній сторінці документу, навіть якщо шрифт той же що і на попередніх.
        // отримати і використати об'єкт шрифт
        $fontdir = "C:\WINDOWS\Fonts";
        pdf_set_parameter($pdf, "FontOutline", "arialMyName=$fontdir\arial.ttf");
        $arial = pdf_findfont($pdf,"arialMyName", "cp1251" ,0 );
        pdf_setfont($pdf, $arial, 10);  
Як тільки шрифт вибраний, можна використати функцію pdf_show_xy() для запису тексту у відповідне місце на сторінці.
      // надрукувати текст
      pdf_show_xy($pdf, "Це перший рядок нашого документу,",50,750); 
      pdf_show_xy($pdf, "а це другий рядок", 50,730);
Функція вимагає вказівник на PDF документ, посилання на об’єкт-шрифт, текст для запису і координати X Y, куди починати записувати текст. Ці координати вказуються відносно точки (0,0), яка знаходиться в лівому нижньому куті документу, а не у верхньому як можна б було сподіватись.
Як тільки текст був записаний, сторінка закривається викликом функції pdf_end_page(). Далі можна додати ще сторінку або, просто закрити документ із допомогою pdf_close(). Дана функція зберігає документ з ім’ям вказаним при виклику pdf_open_file() і знищує вказівник на документ.

3. Вставлення зображень

Розширення PDF в PHP дозволяє набагато більше, ніж просто писати текст в документ. Так можна додавати зображення у документ. Далі наводиться приклад, який здійснює це.
  
      <?php
        // створити вказівник для нового PDF документу
        $pdf = pdf_new();
        
        // відкрити файл
        pdf_open_file($pdf, "/home/univer.ua/www/example1.pdf"); 
        
        // розпочати нову сторінку (A4)
        pdf_begin_page($pdf, 595, 842);
        
        // отримати і використати об'єкт шрифт
        $fontdir = "C:\WINDOWS\Fonts";
        pdf_set_parameter($pdf, "FontOutline", "arialMyName=$fontdir\arial.ttf");
        $arial = pdf_findfont($pdf,"arialMyName", "cp1251" ,0 );
        pdf_setfont($pdf, $arial, 10);
        
        // надрукувати текст
        pdf_show_xy($pdf, "Еней був паробок моторний,",60, 750); 
        pdf_show_xy($pdf, "і хоть куди козак", 60, 730);
        pdf_show_xy($pdf, "Удавсь на всеє зле проворний,", 60, 710);
        pdf_show_xy($pdf, "Завзятіший од всіх бурлак", 60, 690);
        
        // додати зображення над текстом і після
        $image = pdf_open_image_file($pdf, "jpeg", "/home/univer.ua/www/univer.jpg", 0, 0);
        pdf_place_image($pdf, $image, 70, 770, 0.25);
        pdf_place_image($pdf, $image, 70, 660, 0.25);
        // кінець сторінки
        pdf_end_page($pdf);
        
        // закрити і зберегти файл
        pdf_close($pdf);
      ?>
Вставлення зображень в pdf
Вставка зображення здійснюється за допомогою двох функцій pdf_open_image_file() та pdf_place_image(). Перша з них приймає тип зображення - GIF, JPEG, TIFF або PNG – та назву файлу в якості аргументів, і повертає вказівник на зображення, який згодом можна повторно використовувати в документі.

Вказівник на рисунок, повернутий вище, далі можна передати функції pdf_place_image(), яка розташує зображення у певному місці на сторінці. Координати, передані даній функції (другий і третій аргумент) відносяться до лівого нижнього кута зображення, а четвертий аргумент задає параметр масштабування рисунку при відображенні (1 – покаже зображення у 100% масштабі, 0.5 – зменшить його в два рази.)

 4. Малювання ліній

Модуль PDF включає в себе велику кількість функцій, які можуть малювати ліній, круги та інші фігури. Ось код, що здійснює малювання лінії:
  
      <?php
        // створити вказівник для PDF документу
        $pdf = pdf_new();
        
        // відкрити файл
        pdf_open_file($pdf, "/home/univer.ua/www/letter.pdf");
        
        // розпочати сторінку (A4)
        pdf_begin_page($pdf, 595, 842);
        
        // отримати і використати об'єкт шрифт
        $fontdir = "C:\WINDOWS\Fonts";
        pdf_set_parameter($pdf, "FontOutline", "arialMyName=$fontdir\arial.ttf");
       $arial = pdf_findfont($pdf,"arialMyName","cp1251",0);
        pdf_setfont($pdf, $arial, 15);
        
        // встановити колір для ліній
        pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 0, 0);
        
        // встановити логотип з самого верху сторінки по центру
        $image = pdf_open_image_file($pdf, "jpeg", "/home/univer.ua/www/univer.jpg", 0, 0);
        pdf_place_image($pdf, $image, 170, 785, 0.5);
        
        // намалювати лінію під логотипом
        pdf_moveto($pdf, 20, 780);
        pdf_lineto($pdf, 575, 780);
        pdf_stroke($pdf);
        
        // намалювати лінію знизу сторінки
        pdf_moveto($pdf, 20,50); 
        pdf_lineto($pdf, 575, 50); 
        pdf_stroke($pdf);
        
        // написати деякий текст під лінією
        pdf_show_xy($pdf, "Цілком конфіденційно", 200, 35);
        
        // кінець сторінки
        pdf_end_page($pdf);
        
        // close and save file
        pdf_close($pdf);
      ?>
В результаті letter.pdf матиме вигляд:
Лінії в pdf
В даному випадку малювання лінії включає в себе використання функцій pdf_moveto(), pdf_lineto() та pdf_stroke().
В наведеному вище прикладі малюється лінія з точки (20,780) до точки (575, 780). Щоб це зробити, спочатку необхідно помістити курсор в початкову точку (20,780), з допомогою функції pdf_moveto().
  pdf_moveto($pdf, 20, 780);
Далі необхідно задати кінцеву точку з допомогою pdf_lineto():
  pdf_lineto($pdf, 575, 780);
Далі малюється лінія з допомогою pdf_stroke().
  pdf_stroke($pdf); 
Колір лінії задається функцією pdf_setcolor(), яка приймає декілька параметрів: вказівник на PDF документ, тип лінії: "stroke", "fill" або "both", кольорова палітра (RGB або CMYK), і список кольорових значень, що підходять до вибраної палітри.
pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 0, 0);
Необхідно помітити, що список кольорових значень, що передаються pdf_setcolor() повинен бути заданий в процентій величині інтенсивності - тобто, інтенсивність даного кольору, виражена в процентах від максимально можливого. Наприклад, якщо я хочу задати (RGB: 255,0,0) в якості кольору, виклик функції pdf_setcolor() буде виглядати так:
  pdf_setcolor($pdf, "stroke", "rgb", 1, 0, 0, 0);
 Заливка жовтим кольором буде виглядати так:
  pdf_setcolor($pdf, "fill", "rgb", 1, 1, 0, 0);
 
5. Квадрати та круги 

Лінії - це не єдине, що можна малювати – круги і прямокутники також можна малювати.
  
      <?php
        // створити вказівник на PDF документ
        $pdf = pdf_new();
        
        // відкрити файл
        pdf_open_file($pdf, "/home/univer.ua/www/shapes.pdf");
        
        // розпочати нову сторінку (A4)
        pdf_begin_page($pdf, 595, 842);
        
        // встановити колір заповнення
        pdf_setcolor($pdf, "fill", "rgb", 1, 1, 0, 0);
        
        // встановити колір малювання контору
        pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 0, 0);
        
        // намалювати прямокутник
        pdf_rect($pdf, 50, 500, 200, 300);
        pdf_fill_stroke($pdf);
        
        // встановити колір заповнення
        pdf_setcolor($pdf, "fill", "RGB", 0, 0.25, 0.5, 0);
        
        // встановити колір малювання контору
        pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 1, 0);
        
        // намалюватиколо
        pdf_circle($pdf, 150, 650, 100);
        pdf_fill_stroke($pdf);
        
        // кінець сторінки
        pdf_end_page($pdf);
        
        // закрити і зберегти документ
        pdf_close($pdf);
      ?>
Коло намальоване на квадраті  

В даному випадку функція the pdf_rect() використовується для малювання прямокутника із допомогою заданих координат лівого нижнього кута, висоти і ширини. Далі прямокутник замальовується і обводиться двума різними кольорами з допомогою функції
  
       pdf_fill_stroke()
       pdf_setcolor($pdf, "fill", "rgb", 1, 1, 0, 0);
       pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 0, 0);
       pdf_rect($pdf, 50, 500, 200, 300);
       pdf_fill_stroke($pdf);
Круги малюються функцією pdf_circle(), яка приймає три аргументи: координати X та Y центру кругу і довжини радіусу.
       pdf_circle($pdf, 150, 650, 100);
Можливість малювання геометричних зображень "на льоту" може пригодитися в різних ситуаціях. Наприклад, з використанням циклу "for" та функції pdf_lineto() можна згенерувати сітку з ліній.
  
      <?php
        // створити вказівник на новий PDF документ
        $pdf = pdf_new();
        
        // відкрити файл
        pdf_open_file($pdf, "/home/univer.ua/www/grid.pdf");
        
        // створити нову сторінку (A4)
        pdf_begin_page($pdf, 595, 842);
        
        // встановити колір малювання
        pdf_setcolor($pdf, "stroke", "rgb", 0, 0, 0, 0);
        
        // намалювати вертикальні лініх (рухаємось по осі X з кроком 20)
        for ($x=0; $x<=595; $x+=20)
        {
         pdf_moveto($pdf, $x, 0);
         pdf_lineto($pdf, $x, 842);
         pdf_stroke($pdf);
        }
        
        // намалювати горизонтальні лінії (рухаємося по осі Y)
        for ($y=0; $y<=842; $y+=20)
        {
         pdf_moveto($pdf, 0, $y);
         pdf_lineto($pdf, 595, $y);
         pdf_stroke($pdf);
        }
                // кінець сторінки
        pdf_end_page($pdf);
        
        // закрити і зберегти файл
        pdf_close($pdf);
      ?>

Сітка на PDF-сторінці
6. Задання інформації про документ

Можна задавати інформацію про документ із допомогою функцій сімейства pdf_set_info(); Ця інформація визначає творця документа, назву і вміст. Наступний приклад демонструє це:
  
      <?php
        // створити вказівник для нового PDF документу
        $pdf = pdf_new();
        
        // відкрити файл
        pdf_open_file($pdf, "/home/univer.ua/www/eneida.pdf");
        
        // розпочати нову сторінку (A4)
        pdf_begin_page($pdf, 595, 842);
        
        // встановити інформацію про документ
        pdf_set_info($pdf, "Author", "Іван Котляревський");
        pdf_set_info($pdf, "Creator", "Іван Котляревський");
        pdf_set_info($pdf, "Title", "Енеїда"); 
        pdf_set_info($pdf, "Subject", "Початок"); 
        pdf_set_info($pdf, "Keywords", "Еней козак Троя");
        
        // отримати і використати об'єкт шрифт
        $fontdir = "C:\WINDOWS\Fonts";
        pdf_set_parameter($pdf, "FontOutline", "arialMyName=$fontdir\\times.ttf");
        $arial = pdf_findfont($pdf,"arialMyName", "cp1251" ,0 );
        pdf_setfont($pdf, $arial, 12);
        
        // надрукувати текст
        pdf_show_xy($pdf, "Еней був паробок моторний",60, 750); 
        pdf_show_xy($pdf, "І хлопець хоть куди козак", 60, 730);
        pdf_show_xy($pdf, "Удавсь на всеє зле проворний,", 60, 710);
        pdf_show_xy($pdf, "Завзятіший од всіх бурлак", 60, 690);
        
        
        // кінець сторінки
        pdf_end_page($pdf);
        
        // закрити і зберегти документ
        pdf_close($pdf);
      ?>  
Далі при перегляді документу в Adobe Reader, ви зможете побачити цю інформацію у Властивостях документу.

Властивості документу

Як бачимо опис кожного пункту описується окремо у pdf_set_info().

7. Кругові діаграми

Наступний приклад демонструє як PHP може приймати числові дані і генерувати з них діаграми, наприклад, так звані «кругові діаграми»

Форма знизу запитує декілька порцій даних, у вигляді чисел, що розділяються комами. Після вводу декількох чисел скрипт "pie.php" конвертує їх із абсолютних чисел в сектори даних відносних розмірів і використовує дані сектори для генерації PDF документу, що містить кругову діаграму, виділяючи різні сектори і заливаючи їх різними кольорами.
  

<html>
<head>
<basefont face=arial>
</head>

<body>

<h3>Pie Chart Generator</h3>
<table cellspacing="5" cellpadding="5">
<form action="pie.php" method=POST>
<tr>
<td>Enter numeric values (pie segments), separated by commas</td> </tr>
<tr> <input name="data" type="text" /></td> </tr> <tr> <td><input name="submit" type="submit" value="Generate PDF Pie Chart" /></td> </tr>

</form> </table>

</body>
</html>


А ось скрипт:
  
<?php
// raw data
$data = $_POST['data'];
$slices = explode(",", $data);

// initialize some variables
$sum = 0;
$degrees = Array();
$diameter = 200;
$radius = $diameter/2;

// set up colours array for pie slices (rgb, as percentages of
intensity) // add more to these if you like $colours = array(
 array(0,0,0), 
 array(0,0,1), 
 array(0,1,0), 
 array(1,0,0),
 array(0,1,1), 
 array(1,1,0), 
 array(1,0,1), 
);

// calculate sum of slices
$sum = array_sum($slices);

// convert each slice into corresponding percentage of 360-degree circle
for ($y=0; $y<sizeof($slices); $y++) {
 $degrees[$y] = ($slices[$y]/$sum) * 360;
}

// start building the PDF document
// create handle for new PDF document
$pdf = pdf_new();

// open a file
pdf_open_file($pdf, "chart.pdf");

// start a new page (A4)
pdf_begin_page($pdf, 500, 500);

// set a stroke colour
pdf_setcolor($pdf, "stroke", "rgb", 1, 1, 0);

// draw baseline
pdf_moveto($pdf, 250, 250);
pdf_lineto($pdf, 350, 250);
pdf_stroke($pdf);

for ($z=0; $z<sizeof($slices); $z++)
{
 // set a fill colour
 pdf_setcolor($pdf, "fill", "rgb", $colours[$z][0],
$colours[$z][1], $colours[$z][2]);

 // calculate coordinate of end-point of each arc by obtaining 
 // length of segment and adding radius
 // remember that cos() and sin() return value in radians 
 // and have to be converted back to degrees!
 $end_x = round(250 + ($radius * cos($last_angle*pi()/180))); 
 $end_y = round(250 + ($radius * sin($last_angle*pi()/180)));

 // demarcate slice with line
 pdf_moveto($pdf, 250, 250);
 pdf_lineto($pdf, $end_x, $end_y);

 // calculate and draw arc corresponding to each slice
 pdf_arc($pdf, 250, 250, $radius, $last_angle,
($last_angle+$degrees[$z]));

 // store last angle
 $last_angle = $last_angle+$degrees[$z];

 // fill slice with colour
 pdf_fill_stroke($pdf);
}

// redraw the circle outline
pdf_circle($pdf, 250, 250, 100);
pdf_stroke($pdf);

// end page
pdf_end_page($pdf);

// close and save file
pdf_close($pdf);

?>

Дані, введені у форму, передаються скрипту "pie.php" змінної $data; ці дані згодом діляться на окремі компоненти функцією explode(), і кожне значення присвоюється масиву $slices. Далі в циклі ці числа конвертуються в градуси для круга і для кожного сектора малюється дуга, В кожному проході циклу також обчислюється координати кінцевої точки дуги і малюється сегмент лінії для того, щоб відокремити дугу від решти окружності. Як тільки кругова діаграма намальована, використовується функція pdf_fill_stroke() для заливки її кольором; колір береться з масиву $colours.

понеділок, 25 червня 2012 р.

Розділ 7 Лінійні діаграми

7.1 Вступ

Даний розділ описує лінійні діаграми (або ж лінійні графіки - line charts), що можуть бути створені з JFreeChart. Створення лінійних графіків можливе через використання інтерфейсу CategoryDataset або інтерфейсу XYDataset.

7.2 Графіки засновані на CategoryDataset
7.2.1 Загальний огляд


Лінійні графіки засновані на CategoryDataset просто з’єднують кожну точку(категорія, значення) даних прямими лініями. В даній секції представлений приклад, що генерує графік, показаний на рисунку 7.1

Рисунок 7.1 – Приклад лінійного графіка.

Повний джерельний код даної демо програми (LineChartDemo1.java) наявний для завантаження разом з JFreeChart Developer Guide.

7.2.2 Набір даних (Dataset)

Першим кроком, як завжди, є створення набору даних. В прикладі для цього використано клас DefaultCategoryDataset:

DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(212, "Classes", "JDK 1.0");
dataset.addValue(504, "Classes", "JDK 1.1");
dataset.addValue(1520, "Classes", "SDK 1.2");
dataset.addValue(1842, "Classes", "SDK 1.3");
dataset.addValue(2991, "Classes", "SDK 1.4");

Зауважте, що ви можете використовувати будь-яку реалізацію інтерфейсу CategoryDataset для вашого набору даних.

7.2.3 Конструювання діаграми


Метод createLineChart() класу ChartFactory надає зручний шлях створення діаграми. Ось код:

// create the chart...
JFreeChart chart = ChartFactory.createLineChart(
  "Java Standard Class Library", // chart title
  "Release", // domain axis label
  "Class Count", // range axis label
  dataset, // data
  PlotOrientation.VERTICAL, // orientation
  false, // include legend
  true, // tooltips
  false // urls
);


В даному випадку метод створює об’єкт JFreeChart із заголовком (title), без легенди, з відповідними осями, візуалізатором та генератором підказок. Набір даних створений в попередньому пункті.

7.2.4 Модифікація діаграми

Діаграма буде ініціалізована використовуючи налаштування по замовчування для більшості атрибутів. Ви ж, звивайно, можете модифікувати будь-які налаштування і тим самим змінити зовнішній вигляд діаграми. В цьому прикладі, ми модифікуємо діаграму наступним чином:

• Буде додано два підзаголовка до діаграми
• Буде встановлений білий фоновий колір діаграми
• Фоновий колір для самої області графіка (plot) встановимо світло-сірим
• Лінії координатної сітки зробимо білими
• Вісь значень буде модифіковано так, щоб показувала лише цілі числа
• Візуалізатор (renderer) буде модифікований так, щоб здійснив заповнення точок на графіку білим кольором

Перший підзаголовок додається до позиції по замовчуванню (під основним заголовком):

chart.addSubtitle(new TextTitle("Number of Classes By Release"));

Наступний підзаголовок вимагає дещо більше коду. Встановлюємо шрифт та розміщуємо знизу діаграми з вирівнюванням вправо:

TextTitle source = new TextTitle(
  "Source: Java In A Nutshell (4th Edition) "
  + "by David Flanagan (O’Reilly)"
);
source.setFont(new Font("SansSerif", Font.PLAIN, 10));
source.setPosition(RectangleEdge.BOTTOM);
source.setHorizontalAlignment(HorizontalAlignment.RIGHT);
chart.addSubtitle(source);

Змінити фоновий колір діаграми просто, тому, що це атрибут класу JFreeChart:

chart.setBackgroundPaint(Color.white);

Для зміни інших атрибутів, ми передусім повинні отримати посилання на об’єкт CategoryPlot:

CategoryPlot plot = (CategoryPlot) chart.getPlot();

Щоб встановити фоновий колір для області побудови графіка і змінити колір ліній сітки:

plot.setBackgroundPaint(Color.lightGray);
plot.setRangeGridlinePaint(Color.white);

Область побудови графіка (plot)  відповідає за малювання даних та осей на діаграмі. Дещо з цієї роботи делеговано візуалізатору (renderer), до якого вим можете доступитися через метод getRenderer(). Візуалізатор містить атрибути, що пов’язані з зовнішнім виглядом елементів даних всередині діаграми:

LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer(); 
renderer.setShapesVisible(true);
renderer.setDrawOutlines(true); 
renderer.setUseFillPaint(true);

Область грофіка (plot) також управляє вісями діаграми. В прикладі, вісь значень модифікується так, щоб показувались лише цілі значення для міток шкали:

// change the auto tick unit selection to integer units only...
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

Існує також багато інших шляхів для модифікації діаграми, які можна знайти в різноманітних прикладах та документації.

7.2.5 Повний код програма

Далі наведений повний джерельний код демонстраційної програми.

 
// -------------------
// LineChartDemo1.java
// -------------------
// (C) Copyright 2002-2005, by Object Refinery Limited.
//
//

package demo;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.HorizontalAlignment;

import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RefineryUtilities;
/**
* A simple demonstration application showing how to create a line chart using
* data from a {@link CategoryDataset}.
*/
public class LineChartDemo1 extends ApplicationFrame {
/**
* Creates a new demo.
*
* @param title the frame title.
*/
public LineChartDemo1(String title) {
    super(title);
    CategoryDataset dataset = createDataset();
    JFreeChart chart = createChart(dataset);
    ChartPanel chartPanel = new ChartPanel(chart);
    chartPanel.setPreferredSize(new Dimension(500, 270));
    setContentPane(chartPanel);
}
/**
* Creates a sample dataset.
*
* @return The dataset.
*/
private static CategoryDataset createDataset() {
   DefaultCategoryDataset dataset = new DefaultCategoryDataset();
   dataset.addValue(212, "Classes", "JDK 1.0");
   dataset.addValue(504, "Classes", "JDK 1.1");
   dataset.addValue(1520, "Classes", "SDK 1.2");
   dataset.addValue(1842, "Classes", "SDK 1.3");
   dataset.addValue(2991, "Classes", "SDK 1.4");
   return dataset;
}
/**
* Creates a sample chart.
*
* @param dataset a dataset.
*
* @return The chart.
*/

private static JFreeChart createChart(CategoryDataset dataset) {
   // create the chart...
    JFreeChart chart = ChartFactory.createLineChart(
    "Java Standard Class Library", // chart title
    "Release", // domain axis label
    "Class Count", // range axis label
    dataset, // data
    PlotOrientation.VERTICAL, // orientation
    false, // include legend
    true, // tooltips
    false // urls
);
chart.addSubtitle(new TextTitle("Number of Classes By Release"));
TextTitle source = new TextTitle(
    "Source: Java In A Nutshell (4th Edition) "
    + "by David Flanagan (O’Reilly)"
);
source.setFont(new Font("SansSerif", Font.PLAIN, 10));
source.setPosition(RectangleEdge.BOTTOM);
source.setHorizontalAlignment(HorizontalAlignment.RIGHT);
chart.addSubtitle(source);
chart.setBackgroundPaint(Color.white);
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setRangeGridlinePaint(Color.white);

// customise the range axis...
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// customise the renderer...
LineAndShapeRenderer renderer
= (LineAndShapeRenderer) plot.getRenderer();
renderer.setShapesVisible(true);
renderer.setDrawOutlines(true);
renderer.setUseFillPaint(true);
renderer.setFillPaint(Color.white);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
    JFreeChart chart = createChart(createDataset());
    return new ChartPanel(chart);
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
    LineChartDemo1 demo = new LineChartDemo1("Line Chart Demo");
    demo.pack();
    RefineryUtilities.centerFrameOnScreen(demo);
    demo.setVisible(true);
}
} 
 
 

 7.3 Лінійні діаграми засновані на XYDataset
 
Графіки засновані на XYDataset з’єднують кожну (х,y) точку прямою лінією. В даному розділі представлена показова програма, яка генерує діаграму показану на рисунку 7.2


Рисунок 7.2 – Показова діаграма, що використовує XYPlot

Повний джерельний код (LineChartDemo2.java) доступний для завантаження разом з JFreeChart Developer Guide.

7.3.2 Набір даних 

Для даної діаграми використано XYSeriesCollection (ви можете використовувати будь-яку реалізацію інтерфейсу XYDataset). Даний набір даних створений наступним чином:
 
XYSeries series1 = new XYSeries("First");
series1.add(1.0, 1.0);
series1.add(2.0, 4.0);
series1.add(3.0, 3.0);
series1.add(4.0, 5.0);
series1.add(5.0, 5.0);
series1.add(6.0, 7.0);
series1.add(7.0, 7.0);
series1.add(8.0, 8.0);
XYSeries series2 = new XYSeries("Second");
series2.add(1.0, 5.0);
series2.add(2.0, 7.0);
series2.add(3.0, 6.0);
series2.add(4.0, 8.0);
series2.add(5.0, 4.0);
series2.add(6.0, 4.0);
series2.add(7.0, 2.0);
series2.add(8.0, 1.0);
XYSeries series3 = new XYSeries("Third");
series3.add(3.0, 4.0);
series3.add(4.0, 3.0);
series3.add(5.0, 2.0);
series3.add(6.0, 3.0);
series3.add(7.0, 6.0);
series3.add(8.0, 3.0);
series3.add(9.0, 4.0);
series3.add(10.0, 3.0);
XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series1);
dataset.addSeries(series2);
dataset.addSeries(series3);
return dataset;

Зауважте, що кожна серія даних (series) має не тільки y-значення, а й х-значення і не залежить від інших серій. Набір даних також може прийняти null для y-значень. Коли в наявності null, об'єднувальна лінія не малюється, результатом є переривчаста лінія серії.

7.3.3 Конструювання діаграми

Метод createXYLineChart() класу ChartFactory надає зручний спосіб створення діаграми:
 
JFreeChart chart = ChartFactory.createXYLineChart(
"Line Chart Demo 2", // chart title
"X", // x axis label
"Y", // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);

Даний метод створює JFreeChart об’єкт з заголовком, легендою та область побудови діаграми з відповідними осями та візуалізатором. Набір даних той же що створений в попередньому пункті. Діаграма створена з легендою та підказками (URL оголошено нечинним – даний атрибут використовується в створенні мап зображень HTML )

7.3.4 Модифікація діаграми

Графік ініціалізований налаштуваннями по замовчуванню для більшості атрибутів. Ви звичайно можете модифікувати будь-які налаштування та змінити зовнішній вигляд вашої діаграми. В даному прикладі, декілька атрибутів модифіковано:

• Фон діаграми
• Фон області побудови діаграми
• Зсув осей
• Колір ліній координатної сітки
• Модифіковано візуалізатор для оформлення точок даних
• Написи на шкалі осі  значень (range axis) змінюємо так, щоб відображалися лише цілі числа

Змінити фон діаграми просто:
 
// set the background color for the chart...
chart.setBackgroundPaint(Color.white);

Зміна ж фону області побудови діаграми, зсуву осей, кольору ліній сітки, вимагає отримання посилання на область побудови (plot). Також необхідне приведення типу до XYPlot, щоб отримати доступ до методів даного типу:

 
// get a reference to the plot for further customisation...
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);

Для оформлення точок, модифікуємо візуалізатор
 
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setShapesVisible(true);
renderer.setShapesFilled(true);

Фінальна модифікація – це зміна осі значень (range axis). Та підписи на шкалі (tick units) осі значень:
 
// change the auto tick unit selection to integer units only...
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

Зверніться до джерельного коду та документації для ознайомлення з іншими можливостями по зміні.

7.3.5 Повний код програми
Далі наведено повний код демонстраційної програми:
 
//
// -------------------
// LineChartDemo2.java
// -------------------
// (C) Copyright 2002-2005, by Object Refinery Limited.
//
//
package demo;
import java.awt.Color;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
/**
* A simple demonstration application showing how to create a line chart using
* data from an {@link XYDataset}.
* * IMPORTANT NOTE: THIS DEMO IS DOCUMENTED IN THE JFREECHART DEVELOPER GUIDE.
* DO NOT MAKE CHANGES WITHOUT UPDATING THE GUIDE ALSO!!
*/
public class LineChartDemo2 extends ApplicationFrame {
    /**
    * Creates a new demo.
    *
    * @param title the frame title.
    */
    public LineChartDemo2(String title) {
        super(title);
        XYDataset dataset = createDataset();
        JFreeChart chart = createChart(dataset);
        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);
    }
    /**
    * Creates a sample dataset.
    *
    * @return a sample dataset.
    */
    private static XYDataset createDataset() {
        XYSeries series1 = new XYSeries("First");
        series1.add(1.0, 1.0);
        series1.add(2.0, 4.0);

        series1.add(3.0, 3.0);
        series1.add(4.0, 5.0);
        series1.add(5.0, 5.0);
        series1.add(6.0, 7.0);
        series1.add(7.0, 7.0);
        series1.add(8.0, 8.0);
        XYSeries series2 = new XYSeries("Second");
        series2.add(1.0, 5.0);
        series2.add(2.0, 7.0);
        series2.add(3.0, 6.0);
        series2.add(4.0, 8.0);
        series2.add(5.0, 4.0);
        series2.add(6.0, 4.0);
        series2.add(7.0, 2.0);
        series2.add(8.0, 1.0);
        XYSeries series3 = new XYSeries("Third");
        series3.add(3.0, 4.0);
        series3.add(4.0, 3.0);
        series3.add(5.0, 2.0);
        series3.add(6.0, 3.0);
        series3.add(7.0, 6.0);
        series3.add(8.0, 3.0);
        series3.add(9.0, 4.0);
        series3.add(10.0, 3.0);
        XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(series1);
        dataset.addSeries(series2);
        dataset.addSeries(series3);
        return dataset;
    }
    /**
    * Creates a chart.
    *
    * @param dataset the data for the chart.
    *
    * @return a chart.
    */
    private static JFreeChart createChart(XYDataset dataset) {
        // create the chart...
        JFreeChart chart = ChartFactory.createXYLineChart(
            "Line Chart Demo 2", // chart title
            "X", // x axis label
            "Y", // y axis label
            dataset, // data
            PlotOrientation.VERTICAL,
            true, // include legend
            true, // tooltips
            false // urls
        );
        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
        chart.setBackgroundPaint(Color.white);
        // get a reference to the plot for further customisation...
        XYPlot plot = (XYPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);
        XYLineAndShapeRenderer renderer
        = (XYLineAndShapeRenderer) plot.getRenderer();
        renderer.setShapesVisible(true);
        renderer.setShapesFilled(true);
        // change the auto tick unit selection to integer units only...
        NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        // OPTIONAL CUSTOMISATION COMPLETED.
        return chart;
    }

    /**
    * Creates a panel for the demo (used by SuperDemo.java).
    *
    * @return A panel.
    */
    public static JPanel createDemoPanel() {
        JFreeChart chart = createChart(createDataset());
        return new ChartPanel(chart);
    }
    /**
    * Starting point for the demonstration application.
    *
    * @param args ignored.
    */
    public static void main(String[] args) {
        LineChartDemo2 demo = new LineChartDemo2("Line Chart Demo 2");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }
} 



The JFreeChart Developer Guide Version 1.0.9

Переклад volodimirg

Розділ 4 Використання JFreeChart


4.1 Загальний огляд

Даний розділ надає інформацію для простого вступу до JFreeChart та орієнтована на нових користувачів JFreeChart.

4.2 Створення вашої першої  діаграми
4.2.1 Загальний огляд

Створення діаграм з JFreeChart – це трьох-кроковий процес. Вам необхідно:
•    Створити набір даних (dataset), що міститиме дані для зображення в діаграмі
•    Створити об’єкт JFreeChart, що буде відповідати за промальовування діаграми
•    Намалювати діаграму на певній поверхні (частіше всього це панель на екрані, хоча і не завжди)
Щоб продемонструвати даний процес, ми для прикладу опишемо програму (First.java) що створює кругову діаграму зображену на рисунку 4.1

Рис. 4.1 ­- Кругова діаграма створена з використанням First.java

Кожен з трьох кроків, разом з джерельним кодом описані в наступних секціях.


4.2.2 Дані

Крок перший вимагає створення набору даних для нашої діаграми. Це може бути просто зроблено, використовуючи DefaultPieDataset клас, наступним чином:

// створюємо набір даних...
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("Category 1", 43.2);
dataset.setValue("Category 2", 27.9);
dataset.setValue("Category 3", 79.5);

Зазначте, що JFreeChart може створити кругову діаграму використовуючи дані з будь-якого класу, що реалізовує інтерфейс PieDataset. Клас DefaultPieDataset, використаний вище, надає зручну реалізацію даного інтерфейсу, проте ви можете розробити додаткову реаліцію, якщо хочете[Все це подібне до того як клас Swing – JTable отримує дані через інтерфейс TableModel]

4.2.3 Створення кругової діаграми

Другий крок стосується того, як ми представимо набір даних створений в попередній секції. Нам необхідно створити JFreeChart об’єкт, що може намалювати діаграму, використовуючи дані з нашого набору для діаграми. Ми використаємо ChartFactory клас, таким чином:

// створюємо діаграму...
JFreeChart chart = ChartFactory.createPieChart(
"Sample Pie Chart",
dataset,
true, // legend?
true, // tooltips?
false // URLs?
);


Зазначте, як ми передали посилання на набір даних у метод createPieChart. JFreeChart отримав посилання на даний набір даних, тож тепер JFreeChart може отримати дані, при зображенні даграми.

Діаграма, що створюється нами використовує налаштування по замовчуванню для більшості атрибутів. Існує багато шляхів модифікації зовнішнього вигляду діаграми створеної з JFreeChart, проте в даному прикладі ми використаємо стандартний вигляд.

4.2.4 Вивід діаграми
 
Останнім кроком є зображення діаграми де-небудь. JFreeChart доволі гнучка, щодо місць промальовки діаграми, завдяки використаннню класу Graphics2D.

Так давайте зобразимо діаграму у фреймі на екрані. ChartFrame надає відповідний механізм (ChartPanel) для відображення діаграм:

// create and display a frame...
ChartFrame frame = new ChartFrame("Test", chart);
frame.pack();
frame.setVisible(true);

І на цьому все….

4.2.5 Повний код програми

Тут наведена повний текст програми, тож ви можете побачити, які пакети необхідно імпортувати і порядок розташування фрагментів коду поданих в попередніх секціях:

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
public class First {
/**
* The starting point for the demo.
*
* @param args ignored.
*/
public static void main(String[] args) {
 // create a dataset...
 DefaultPieDataset dataset = new DefaultPieDataset();
 dataset.setValue("Category 1", 43.2);
 dataset.setValue("Category 2", 27.9);
 dataset.setValue("Category 3", 79.5);
 // create a chart...
JFreeChart chart = ChartFactory.createPieChart(
  "Sample Pie Chart",
  dataset,
  true, // legend?
  true, // tooltips?
  false // URLs?
);
 // create and display a frame...
 ChartFrame frame = new ChartFrame("First", chart);
 frame.pack();
 frame.setVisible(true);
 }
}


Сподіваємося це переконало вас, що створювати і зображати графіки з JFreeChart нескладно. Звичайно, що тут є ще багато чого для освоєння…


The JFreeChart Developer Guide Version 1.0.9

Переклад volodimirg

пʼятниця, 22 червня 2012 р.

Вкладки Java

За створенням вкладок відповідає клас JTabbedPane. Це контейнер з поміченими вкладками. Кожна вкладка має ім’я і є звичайним контейнером. Щоб додати вкладку до JTabbedPane, просто викличте addTab(мітка_вкладки, екземпляр_контейнера). Зауважте, що хоча одночасно показується одна вкладка, всі інші вкладки також завантажені в пам’ять. Тому, якщо пам’ять для вас є критичним ресурсом, то необхідно вжити відповідних заходів із звільнення пам’яті. Результат виконання TestTabbedPane.java

import javax.swing.*;
 
public class TestTabbedPane {
 
    public static final int FRAME_WIDTH = 350;
    public static final int FRAME_HEIGHT = 200;
 
    public static void main(String[] args) {
        //створюємо вкладку
        JFrame frame = new JFrame();
        frame.setTitle ("Test Tabbed Pane");
        frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
        JTabbedPane tabby = new JTabbedPane();
 
        //створюємо панелі для вкладок
        JPanel panel1= new JPanel();
        JPanel panel2 = new JPanel();      
 
        //додаємо на першу вкладку групу радіокнопок
        ButtonGroup radioGroup=new ButtonGroup();
        panel1.add(new JLabel("Ваш вік?"));
        JRadioButton radioButton;
        panel1.add(radioButton=new JRadioButton("12..18"));
        radioGroup.add(radioButton);
        panel1.add(radioButton=new JRadioButton("19..30"));
        radioGroup.add(radioButton);
        panel1.add(radioButton=new JRadioButton("30..60"));
        radioGroup.add(radioButton);
 
        //на другу панель додаємо просто напис
        panel2.add(new JLabel("Друга вкладка"));
 
        //додаємо панелі у JTabbedPane
        tabby.addTab("Перша", panel1);
        tabby.addTab("Друга", panel2);
 
        // додаємо вкладки у фрейм
        frame.add(tabby);
        frame.setVisible(true);
 
    }
}


Повний варіант книги знаходиться на Вікіпідручнику

середа, 20 червня 2012 р.

Меню в Java

Стандартне меню в java реалізоване в класі JMenu. Меню може містити інші меню у вигляді підменю. Для того щоб розмістити пункти меню в горизонтальну смугу використовується інший клас JMenuBar.

Рядок меню можна розмістити не тільки зверху вікна, але і знизу і посередині.

Таким чином спочатку створюється рядок меню:

JMenuBar menuBar = new JMenuBar();
Щоб помістити рядок меню у верхню частину фрейму пишеться:
frame.SetJMenuBar(menuBar);
Далі залишається заповнити його відповідними меню. Для цього для кожного меню створюється свій об’єкт:
JMenu fileMenu=new JMenu(“Файл”);
JMenu editMenu=new JMenu(“Редагувати”);
Далі усі основні меню додають до рядка меню:
menuBar.add(fileMenu);
menuBar.add(editMenu);
Аналогічно додємо до меню пункти підменю:
JMenu fileMenu = new JMenu("Файл");
menuBar.add(fileMenu);
JMenuItem openItem = new JMenuItem ("Відкрити");
fileMenu.add(openItem);
Також до пунктів меню можна додати розділювачі:
fileMenu.addSeparator().
До кожного пункту меню можна додати зображення та свій обробник події. Наступна програма демонструє створення меню та роботу з ним. ProgramMenu.java
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
 
public class ProgramMenu {
         public static final int DEFAULT_WIDTH = 300;
         public static final int DEFAULT_HEIGHT = 200;
 
    public static void main(String[] args) {
        //створюємо фрейм
        JFrame frame = new JFrame();
        frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //додаємо меню
        frame.add(new Menu(frame));
        frame.setVisible(true);
 
 
    }
}
 
class Menu extends JMenuBar{  
    public Menu(JFrame frame ){
       //створюємо рядок меню
       JMenuBar menuBar = new JMenuBar();
       //додаємо рядок меню у фрейм
       frame.setJMenuBar(menuBar);
 
       //Меню "Файл"
       JMenu fileMenu = new JMenu("Файл");
       menuBar.add(fileMenu);
       //додаємо пункти в меню файл
       JMenuItem openItem = new JMenuItem ("Відкрити");
       fileMenu.add(openItem);
       //додаємо розділювач
       fileMenu.addSeparator();
 
 
       JMenuItem saveItem = new JMenuItem ("Зберегти");
       fileMenu.add(saveItem);
 
       //створити меню "закрити" в якому поряд з написом буде зображення
       JMenuItem closeItem = new JMenuItem ("Закрити", new ImageIcon("CloseIcon.jpg"));
       fileMenu.add(closeItem);
       //додаємо обробник подій використавши безіменний внутрішній клас
       closeItem.addActionListener(new ActionListener( ) {
            @Override
            public void actionPerformed(ActionEvent e) { System.exit(0); }
        });
 
 
       // додаємо гарячу клавіші Ctrl-X до пункту "Закрити" 
        closeItem.setMnemonic(KeyEvent.VK_X);
        closeItem.setAccelerator(
                KeyStroke.getKeyStroke(KeyEvent.VK_X, Event.CTRL_MASK));
 
       // меню "Вигляд"
       JMenu viewMenu = new JMenu("Вигляд");
       menuBar.add(viewMenu);
 
       // меню "Допомога"
       JMenu helpMenu = new JMenu("Допомога");
       menuBar.add(helpMenu);
       // можна використати метод add() 
       // для додавання пунктів в меню зразу ж при створенні
       JMenuItem helpItem = helpMenu.add("Довідка");
       JMenuItem aboutItem = helpMenu.add("Про програму");      
    }   
}
Повний варіант книги знаходиться на Вікіпідручнику

вівторок, 19 червня 2012 р.

Кнопки Java

У Swing кнопки реалізовує компонент JButton. Кнопка генерує подію ActionEvent, коли на неї натискають. Щоб обробити цю подію в програмі реєструється відповідний обробник ActionListener, який повинен реалізовувати метод actionPerformed(). Метод actionPerformed отримує в якості аргумента подію, що відбулася. Крім мітки на кнопці може бути розміщене зображення. Клас JButton має відповідний конструктор для задання напису, зображення або обох зразу. Завантаження зображення здійснює зручний у використанні клас ImageIcon. Наступний приклад демонструє створення кнопки із зображенням та обробки події натиснення кнопки.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
 
public class PictureButton {
 
    public static void main(String[] args) {
     ButtonFrame frame = new ButtonFrame();
     frame.setSize(300, 100);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}
 
class ButtonFrame extends JFrame{
 
    JLabel label=new JLabel();
    int i=0;
 
  ButtonFrame(){
    Icon icon = new ImageIcon("icon.gif");
    JButton button = new JButton(icon);
    // додаємо обробник подій, що визначається у внутрішньому класі
    button.addActionListener(new ActionListener( ) {
      public void actionPerformed(ActionEvent ae) {
          i++;
          label.setText("Натиснуто разів: "+ i);
      }  
    }); 
    //встанолюємо менеджер розташування
    setLayout(new FlowLayout( ));
    add(button);
    add(label);
    }
}
 
Якщо ми не використовуємо панелі, то при розміщенні компонентів напряму у фрейм необхідно встановити менеджер розташування, який керує розміщенням елементів один відносно одного (дивіться розділ про менеджери розташування). JFrame немає менеджера розташування по замовчуванню. У JPanel використовується по замовчуванню FlowLayout. Це найпростіший менеджер, який розміщує компоненти один за одним.
Необхідно зазначити, що при натисненні кнопки чи іншого компонента в джава генерується відповідний рядок «діюча команда» чи по іншому «команда дії» (action command). Це просто рядок (String), що дозволяє ідентифікувати компонент, що надсилає подію. По замовчуванню у JButton діюча команда та ж, що і мітка кнопки.
Щоб отримати діючу команду з події, необхідно викликати метод getActionCommand() для відповідної події. Наступний код визначає чи натиснута клавіша Yes:
public void actionPerformed(ActionEvent e){
if (e.getActionCommand( ).equals("Yes") {
 //the user pressed "Yes"; do something
 ...
}
}

Можна змінити діючу команду викликавши метод кнопки setActionCommand(). Наступний рядок змінює команду на «confirm»:
myButton.setActionCommand("confirm");
Використання для кнопок відмінних від їхніх міток діючих команд дозволяє полегшити інтернаціоналізацію інтерфейсу команд. Тобто переведення інтерфейсу з однієї мови на іншу. Так назви кнопок можуть бути записані у файл, який запросто може модифікуватися і його зміна не призведе до необхідності переписування коду програми. Таким чином перекладом інтерфейсу на іншу мову можуть здійснювати і непрограмісти.
Як і у компонента JLabel, написи у JButton можна задавати за допомогою HTML:
JButton htmlButton = new JButton( "<html>"
        + "В<font size=-1>икористовуємо<font size=+0> "
        + "<br> HTML ");

 Повний варіант книги знаходиться на Вікіпідручнику

Мітки Java

Мітка (JLabel) – це рядок тексту або зображення, що розміщується в компоненті. Це один з найпростіших компонентів графічного інтерфейсу. Вони дозволяють задавати вирівнювання тексту (вправо, зліва, по-центру) в середині компонента та не мають особливих подій, які б асоціювалися з ними. Наступний код демонструє різноманітні способи створення міток.
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
 
public class Labels {
    public static void main(String[] args) {
     LabelFrame frame = new LabelFrame();
     frame.setSize(150, 200);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setVisible(true);
    }
}
 
class LabelFrame extends JFrame{
    //створюємо панель
    JPanel panel=new JPanel();
 
    LabelFrame(){
     // вирівнювання за замовчуванням (CENTER)
    JLabel label1 = new JLabel("Багато левів, ");
    // вирівнювання вліво
    JLabel label2 = new JLabel("тигрів з тигрицями", SwingConstants.LEFT); 
    // мітка без тексту, вирівнювання за замовчуванням
    JLabel label3 = new JLabel(); 
    // створюємо іконку
    Icon icon = new ImageIcon("icon.gif");
    // створюємо мітку із зображенням
    JLabel label4 = new JLabel(icon); 
    // задаємо текст для label3
    label3.setText("і ведмедів");
    // встановлюємо вирівнювання
    label3.setHorizontalAlignment(SwingConstants.RIGHT);
    //додаємо мітки в панель
    panel.add(label1);
    panel.add(label2);
    panel.add(label3);
    panel.add(label4);
    //додаємо панель у фрейм
    this.add(panel);
    }
}
Константи вирівнювання визначені в інтерфейсі SwingConstants. Щоправда вирівнювання тексту відбувається всередині компоненти Label, тому коли компонента підганяється під розмір вмісту, вирівнювання непомітне. Для зміни кольору і шрифту в класі Component існують методи setFont() та setColor(), які застосовуються не тільки для міток, але й для будь-яких компонентів. В тексті мітки можливе також застосування HTML:
JLabel label=new JLabel ("<html>"+ "S<font size=-2>MALL");

Повний варіант книги знаходиться на Вікіпідручнику

вівторок, 12 червня 2012 р.

Вступ в класи та методи

Клас, метод, ООП

Класи

Класи – це спеціального виду конструкції, які, дозволяють об’єднати ряд змінних різних типів в одне ціле. Крім власне даних, класи зазвичай включають підпрограми (в термінології java - методи) і можуть включати блоки(сукупність інструкцій між фігурними дужками {}) та інші класи(внутрішні класи). Таким чином утворюються нові типи даних.
Роз’яснення принципів побудови і роботи з класами доволі громіздка тема, тому тут розглянемо лише спрощені основи їх роботи і створення. Детальніше дивіться розділ присвячений класам. Розглянути зараз необхідно через те, що Java повністю об’єктно-орієнтована мова і з класами та пов’язаними з ними методами Ви стикатиметесь на кожному кроці. Зокрема навіть вивід даних System.out.prinln(); - здійснюється за допомогою класу System та методу println().
Для прикладу розглянемо наступну задачу: «Ви фанат збору 1 гривневих монет:). Назбирали їх чимало і хочете купити невеличкий сейф, щоб туди вмістилася ваша вся колекція і вбудувати цей сейф у стіну, щоб його з вашою колекцією не вкрали:). В інтернет-магазині вказані розміри сейфу. Постає питання, який же сейф вибрати? Оскільки сейф не один, то щоб не розраховувати вручну кожного разу об'єм сейфу, Ви захотіли написати відповідну програму.»
І так маємо:
/** 
 * CoinVoume.java
 */
public class CoinVolume {
    public static void main(String[] args) {
    double width1=10, height1=15, depth1=20;
    double width2=15, height2=20, depth2=15;
    double width3=15, height3=25, depth3=15;
 
    int    cointAmount=15000; //кількість монет - непогано зібрав :)
    double coinVolume=2*2*0.1; //приблизний об'єм монети=2*діаметр*товщину
    double safeVolume1;
    double safeVolume2;
    double safeVolume3;
    double totalCoinVol;
 
    totalCoinVol=cointAmount*coinVolume; // заг. об'єм, який займають монети
 
    safeVolume1=width1*height1*depth1; //об'єм першого сейфу
    safeVolume2=width2*height2*depth2;  //об'єм другого сейфу
    safeVolume3=width3*height3*depth3;  //об'єм третього сейфу
 
 
    System.out.println("Об'єм 1-го сейфу="+safeVolume1);
    System.out.println("Об'єм 2-го сейфу="+safeVolume2);
    System.out.println("Об'єм 3-го сейфу="+safeVolume3);
 
    System.out.println("Загальний об'єм монет="+totalCoinVol);
    }
}

Результат виконання:
Об'єм 1-го сейфу=3000.0
Об'єм 2-го сейфу=4500.0
Об'єм 3-го сейфу=5625.0
Загальний об'єм монет=6000.0 
Як бачимо з трьох не підійшов жоден, потрібен більший. Проте додавання кожного нового сейфу вимагає дописування доволі багатьох інструкції. Потрібно оголошувати три змінні для довжини, ширини та глибини сейфу, також потрібна змінна для об’єму та додавати інструкції обчислення та виводу на екран результатів. Звичайно, можна оцінювати по одному змінюючи значення змінних, але тоді прийдеться кожного разу перекомпільовувати і запускати програму. А якщо ви захочете ще раз оцінити розміри деяких сейфів, прийдеться виконувати роботу ще раз. Ось тут в пригоді і стане нам клас Safe. Зверніть увагу, що назва класу пишеться з великої букви. Рекомендовано давати назви класів з великої. Таким чином дуже просто розрізнити його від інших складових програми, наприклад назву класу від назви змінної, які прийнято називати з маленької букви.
Оголосити найпростіший клас можна так:
class Safe{
    double width;
    double height;
    double depth;
    double safeVolume;
}
Для його оголошення використовується ключове слово class та назва класу, далі іде тіло класу у фігурних дужках {}. Проте, хоч клас існує, ми не можемо так просто його використовувати. Ми повинні спочатку створити екземпляр даного класу (об’єкт). Для цього необхідно написати наступну інструкцію:
Safe mySafe1=new Safe();
де Safe – назва класу, mySafe – назва змінної, яка посилатиметься на наш об'єкт, new Safe() – створює об’єкт(при цьому відбувається виділення пам’яті під об’єкт). Таким чином ми створили перший сейф. Щоб створити другий сейф використовується аналогічна інструкція:
Safe mySafe2=new Safe(); //як бачимо змінилась лише назва змінної
Інколи класи порівнюють з формочкою для випічки печива, а саме печиво – це уже конкретний створений екземпляр (об’єкт). Форма може бути одна, а печива на її основі можна зробити безліч із різною начинкою. Так сама і з класом – це шаблон, а на його основі можемо створити безліч екземплярів даного класу.
Проте як же ми можемо звернутися до змінних об’єкту? Для цього використовується операція «.»(точка), а сама інструкція звернення в такій формі - назваОб’єкту.змінна:
mySelf1.width=10;
Перепишемо нашу програму з використанням класу Safe:
class Safe{
    double width=0;
    double height=0;
    double depth=0;
    double safeVolume=0; //додамо змінну, в якій зберігатиметься об'єм сейфу
}
public class CoinVolume {
    public static void main(String[] args) {
    //створюємо перший сейф
    Safe mySafe1=new Safe();
    //вказуємо його розміри
    mySafe1.width=10;
    mySafe1.height=15;
    mySafe1.depth=20;
    //обчислюємо об'єм сейфу
    mySafe1.safeVolume=mySafe1.width*mySafe1.height*mySafe1.depth;
 
    //аналогічно для другого сейфу
    Safe mySafe2=new Safe();
    mySafe2.width=10;
    mySafe2.height=15;
    mySafe2.depth=20;
    mySafe2.safeVolume=mySafe1.width*mySafe1.height*mySafe1.depth;
 
    //виводимо на консоль об'єми сейфів
    System.out.println("Об'єм 1-го сейфу="+mySafe1.safeVolume);
    System.out.println("Об'єм 2-го сейфу="+mySafe2.safeVolume);
    }
}
Щоб зосередитись на основному, з програми усунено обчислення об’єму монети. Компіляцію програми здійснюємо так же само як і попередню, за назвою класу в якому знаходиться метод main()— javac CoinVolume.java. Клас Safe не обов'язково може бути в одному і тому ж файлі, що і клас CoinVolume.
І так клас ми добавили, проте тепер вона виглядає складнішою ніж попередній варіант. Ситуацію виправити може використання методів.

Методи

Методи в java – це аналог підпрограм, функцій, процедур в інших мовах програмування. За допомогою методів ми виносимо текст повторюваного коду програми окремо в тіло методу, після чого можна викликати даний метод з будь-якого місця програми, безліч разів.
Спрощене оголошення та визначення методу, який ми зараз будемо використовувати, має вигляд:
тип_повернення  назва_методу(параметри){

//тіло методу;
інструкція1;
інструкція2;
…..
інструкціяN;
}
Тип_повернення – результат виконання методу, наприклад він може повертати об’єм сейфу, тоді тип_повернення буде double. Якщо метод нічого не повертає, то вказується слово ключове слово void.
Виклик методу здійснює наступна інструкція: назва_методу(параметри). Взагалі в термінології мов програмування для виклику методу використовуються аргументи, а в самому методі – це уже параметри, оскільки передаються лише значення змінних, а не самі змінні. Аргументи та параметри повинні бути одного і того ж типу. Якщо ми передаємо цілочисельне значення, то і параметр повинен бути цілочисельним і т.п. Тобто в методі створюються нові змінні. В деяких мовах, наприклад в С++, як аргумент можна передати посилання на певну змінну, таким чином її можна буде модифікувати в функції через вказівник на дану змінну. В Java в метод передаються лише значення змінних, тому розрізнення аргументів і параметрів менш суттєве і ми там і там використовуватимемо термін «параметр». Об'єкти ж в методи передаються по посиланню. Тобто, при передачі в якості аргументу об'єкта, буде передане посилання на об'єкт, а не створений новий об'єкт.
Повернемось до нашої програми. Повторюваними є присвоювання значень змінним, обчислювання та вивід об’ємів. Тому корисно буде створити два методи safeValue (double width, double height, double depth) та safeVolume (). Перший для присвоєння змінним значень, а другий для обчислення об'єму.
Модифікована програма матиме вигляд:
class Safe{
    double width=10; // поля класу можуть бути ініціалізовані з самого початку
    double height=10;
    double depth=10;
    double safeVolume=0;
 
    // метод присвоєння значень змінним
    void safeValue(double aWidth, double aHeight, double aDepth){
        width=aWidth;
        height=aHeight;
        width=aWidth;
    }
 
    // метод для обчислення об'єму сейфа
    double safeVolume(){
        return width*height*width;
    }
}
public class CoinVolume {
public static void main(String[] args) {
    double width1=10, height1=20, depth1=40;
    Safe mySafe1=new Safe(); //створюємо перший сейф
    Safe mySafe2=new Safe(); //створюємо другий сейф
 
    //задаємо розміри сейфу
    //викликаємо метод safeValue() класу Safe, що ініціалізує поля об'єкту
    mySafe1.safeValue(width1,height1,depth1);
    mySafe2.safeValue(10.0, 15.0, 15.5); //можна і так
 
    //виводимо на екран об'єми сейфів
    //для чого викликаємо метод safeVolume(), який повертає обчислений об'єм кожного сейфу
    System.out.println("Об'єм 1-го сейфу="+mySafe1.safeVolume());
    System.out.println("Об'єм 2-го сейфу="+mySafe2.safeVolume());
    }
}
Як бачимо код програми спростився. Тепер набагато легше модифікувати програму, додаючи нові сейфи. Крім того можна наприклад вивід повідомлення з інформацією про об’єм розмістити метод safeVolume() або в окремий метод, наприклад, printVolume().
Слід зауважити, щодо назв змінних-параметрів. Так для висоти, широти та глибини в методі safeValue() вибрані назви aWidth, aHeight, aDepth. Вони могли б мати назви і просто width, height, depth, але тоді б вони перекрили б доступ до однойменних змінних класу. В такому випадку, щоб звернутися до змінних класу з методу необхідно вживати ключове слово this. Наприклад: this.height=height - тут ми присвоюємо змінній класу this.height одержаний методом параметр height.

Конструктори

Замість методу safeValue(), який в нас заповнює змінні об’єкту значеннями ми можемо створити метод, який буде мати назву таку ж як і клас, тобто Safe(aWidth, aHeight, aDepth). Це дасть нам можливість ще скоротити програму, оскільки при створенні об’єкту ми зможемо зразу ж задавати розміри сейфу.
Safe mySafe1=new Safe(10.0, 15.0, 20.0)
Такі методи носять назву “конструктор класу”. Коли ми писали просто new Safe(); то віртуальна машина використовувала конструктор по замовчуванню без параметрів, який практично нічого корисного для нас не робив. Тепер же ми можемо використовувати новий створений нами конструктор.
Таким чином, новий варіант програми:
class Safe {
    final double width;
    final double height;
    final double depth;
 
    // конструктор
    Safe(double pWidth, double pHeight, double pDepth) {
        width = pWidth;
        height = pHeight;
        depth = pDepth;
    }
 
    // обчислюємо об'єм сейфу
    double getVolume() {
        return width * height * width;
    }
 
}
 
public class CoinsVolume {
    public static void main(String[] args) {
        double width1 = 10, height1 = 20, depth1 = 40;
        Safe safe1 = new Safe(width1, height1, depth1); // створюємо 1-й сейф
        Safe safe2 = new Safe(10.0, 15.0, 20.0); // створюємо 2-й сейф
        Safe safe3 = new Safe(10.3, 15.4, 20.5); // створюємо 3-й сейф
        Safe safe4 = new Safe(20.0, 30.0, 20.0); // створюємо 4-й сейф
 
        printSafeVolume(safe1, 1); // виводимо об'єм 1-го сейфу
        printSafeVolume(safe2, 2);
        printSafeVolume(safe3, 3);
        printSafeVolume(safe4, 4);
    }
 
    // вивід об'єму сейфу
    // safe - сейф
    // number - номер сейфу
    static void printSafeVolume(Safe safe, int number) {
        System.out.println("Об'єм " + number + "-го сейфу=" + safe.getVolume());
    }
 
}
Результат виконання:
Об'єм 1-го сейфу=2000.0
Об'єм 2-го сейфу=1500.0
Об'єм 3-го сейфу=1633.786
Об'єм 4-го сейфу=12000.0 
В наведеному прикладі, щоб обчислити об’єм нового сейфу, нам потрібно додати лише два рядочки тексту (дві інструкції). Щоправда навіть це можна автоматизувати за допомогою використання іншого типу даних – масивів, які будуть розглядатися пізніше. Можна також додати клас Coin, в якому був би метод для обчислення сукупного об’єму різноманітних монет. Ви можете спробувати зробити таку програму зараз. Це буде корисним для засвоєння викладеного матеріалу.
Тема класів та методів значно комплексніша, тому основне, що Ви повинні винести з даного розділу -це розуміння того, як використовуються методи класів. Java надає великий набір уже готових класів та методів, які значно спрощують роботу програміста.

Повний варіант книги знаходиться на Вікіпідручнику

неділя, 15 січня 2012 р.

Як створити блог. Де завести?

Зацікавилися блогами і блогуванням. Тоді ця стаття для Вас. Як показує власний досвід переважно більшість блогерів проходять наступну еволюцію:

  1. виникає бажання щось написати і розмістити де небуть
  2. виникає бажання створити повноцінний блог з власним інтерфейсом та інтернет адресою
  3. виникає бажання заробити на блозі


Якщо ви просто хочете писати статті не переживати про оформлення вашого блогу, то тут вибір доволі обширний, багато сайтів запрошують авторів до співпраці заради наповнення власного вмісту і навіть блогери практикують таке, оскільки самому писати статті і розкручувати блог доволі трудомістка задачі. Можна завести блог наприклад на Живому журналі (http://www.livejournal.com). Якщо ви цікавитися політикою можна писати на (http://politiko.ua).   Але рано чи пізно, ви скоріше за все задумаєтеся створити повноцінний блог із своїм оформлення, або ж навіть з метою заробітку. Тут уже потрібно більш серйозніше підійти до справи. І тут у вас два шляхи:

1) безкоштовний блог
2) платний блог

Другий варіант дає найбільшу свободу, але одночасно і найбільш трудомістий. Ви наприклад можете створити повністю блог з нуля придбавши місце на котромусь сервері та інтернет адресу, потім або написати його самому або використати якусь із популярних систем керування вмістом (CMS) з готовими шаблонами (Wordpress, Joomla, Drupal ). Якщо вам звичайно це не лякає і вам не шкода 400-500 грн в рік, то вперед. Але здебільшого викинути таку суму зразу ж шкода. Цей варіант найбільш прийнятний для досвідчених блогерів і коли ви впевнені, що Ваш блог приноситиме відчутну користь Вам. Існують і доволі непогані сервіси платних блогів за невелику ціну. Проте, якщо ви просто хочете спробувати вести свій блог, то можна обійтися цілком і безплатними сервісами.

В інтернеті ви зустрінете чимало статей з розповідями як створити блог на конкретному ресурсі. Проте, чимало таких статей часто пишуть власники цих же самих місць, з метою приваблення потенційних клієнтів. Крім того здебільшого при створені блогу перед вами ставлять певну вимогу, наприклад, що на ваших блогах буде обов'язкова реклама або прийдеться платити за певні додаткові можливості. Особливо такі обмеження стають відчутні при спробі заробити на власному блозі. Тому при вибору місця розміщення вашого блогу зверніть увагу на обмеження, платні послуги і чи маєте ви доступ до початкового коду сторінки або чи ви хоча б можете запускати ДжаваСкрипти і в яких місцях їх розміщувати.  Адже при розміщенні реклами, наприклад, від Google AdSense вам прийдеться розміщувати невеликий JavaScript у місці появи рекламного банера.  Інколи Вас можуть і не попереджувати про певні обмеження, проте після написання кількох дописів ви можете виявити ці обмеження.  В такому випадку сміло заводьте блог на іншому ресурсі. Буде дуже школа, коли ви потратите кілька місяців, розкрутити власний блог до пів тисячі відвідувань в день, вирішите монетизувати свій блог, а тоді виявиться, що вам бракує вільного місця для нових дописів, або ви не можете розмістити рекламу і за це потрібно платити. Сам на власній шкурі пережив таке..

Випробувавши кілька безкоштовних місць для ведення блогу, можу заявити, що найкращими для цього є wordpress.com та blogger.com.  Щоправда на wordpress.com заборонено розміщувати рекламу при безплатному сервісі. Проте там практично відсутні обмеження, плюс ви освоїте можлиовсті однієї з найпотужніших систем керування вмістом Wordpress, яку можна окремо поставити на власному хостінгу і плюс якої велика кількість готових шаблонів сайтів. Тому для тих хто не планує заробляти на блозі, це найкращий варіант. Особливо для інформаційних ресурсів.

Другий варіант - blogger.com від компанії google, поступається wordpress.com в плані зручності. Проте великим плюсом є можливості встановлення реклами, наявність шаблонів хоч і не такої кількості як на wordpress, проте їх можна налаштувати під власні смаки і головне є доступ до початкового коду і можливість запускання JavaScript, відсутні чужі рекламні банери. Для першого блогу для заробітку доволі хороший варіант, де ви зможите освоїти усі аспекти блогінгу від створення до розкрутки і монетизації.

В наступній статті я розкажу як створити і налаштувати блог на blogger.com.