Показаны сообщения с ярлыком решения. Показать все сообщения
Показаны сообщения с ярлыком решения. Показать все сообщения

пятница, 19 октября 2012 г.

Маленькие Заметки о проблемах и их решениях


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

Читать дальше......

среда, 3 октября 2012 г.

Python+OpenCv распознавание лиц и определение расстояния до них (версия простая )

Все знают такую функцию в фото-аппаратах, как распознавание лиц? Никогда не задумывались, как она работает? Никогда не хотелось сделать что-то подобное? Например, чтобы ваш компьютер выходил из спящего режима, как только кто-то к нему сел? Применений можно найти море, а тут я расскажу как это сделать.


Мы живём в счастливую для лентяев эпоху - вам уже не нужно купаться в сложной математической теории. Всё сделано за вас, по крайней мере на таком элементарном уровне. Распознавание лиц происходит по признакам Хаара. "Эталон" лица уже давно создан и хорошо обучен, находится он в файле haarcascade_frontalface_alt.xml . Там находится, так называемая, модель лица, а именно "Идеальное" лицо в виде примитивов Хаара :

Это бинаризированая диаграмма яркостей. У любого лица посередине светло(нос), а по краям уходит в тёмное, а потом снова на светлое( щеки). Таких признаков у лица много, и они перечислены в haarcascade_frontalface_alt.xml. А наша программка будет их искать.

 Первый бой (вывод видео на экран) :

  Для начала давайте на экран выведем видео поток. С помощью OpenCV это делается элементарно.




import cv2

cam = cv2.VideoCapture(0)
while 1:
     _,frame =cam.read()
     cv2.imshow("features", frame)
     if cv2.waitKey(10) == 0x1b: # ESC
         print 'ESC pressed. Exiting ...'
         break

Работает? Классно!
Код прост:
Я создаю объект камеры, которая подхватит первую попавшуюся(ваша web-ка)
И всё последующее время я буду читать 1 кадр из камеры и выводить его на экран, каждые десять миллисекунд опрашивать клавиатуру, и, если нажата клавиша с кодом 27(Esc) ,то выйду из бесконечного цикла прямо в ОС.



Битва вторая( использование микроскопа по назначению):

Использовать OpenCV для вывода видео на экран - забивание гвоздей микроскопом. Не будем столь брутальны - начнём  распознавание лиц:



import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')

def detect(image):
 bitmap = cv.fromarray(image)
 faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
 if faces:
  for (x,y,w,h),n in faces:
   pass
   cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),2)
 return image

if __name__ == "__main__":
    cam = cv2.VideoCapture(0)
    while 1:
        _,frame =cam.read()
        frame = numpy.asarray(detect(frame))
        cv2.imshow("features", frame)
        if cv2.waitKey(10) == 0x1b: # ESC
            print 'ESC pressed. Exiting ...'
            break

HaarDetectObjects принимает 3 параметра ( где_искать,что искать, где_хранить_промежуточные_данные)
где_хранить_промежуточные_данные - область памяти, которую можно выделить функцией CreateMemStorage.

Уже что-то.

Последний бой ( проявите каплю своего творчества):

Если, проделав это всё, вы гордо скажите, что вы программист, я плюну вам в лицо. Что вы сделали? Ну хоть малость своих мыслей тут? Мы использовали стандартные функции для совершения достаточно тривиальных действий - ни капли математического аппарата. Давайте-же прибавим! А что тут можно сделать? Определим расстояние до лица!
Попытаемся понять, как работает наша камера:



Обратите внимание, что треугольники ACB и DCE подобны. Что это значит?
Уберём из рисунка лишнее и добавим необходимое:

А значит это то , что отношение DE/CH равно отношению AB/FC. Поднеся линейку в 10 сантиметров к веб-камере так, чтоб она поместилась полностью, и измерив расстояние до веб-камеры от линейки, мы можем узнать отношение высоты матрицы нашей камеры к её фокусному расстоянию.( у меня это 1.6) .
Средняя высота лица человека - 15 сантиметров.


Получив из OpenCV размер квадрата лица, просто вычислить, сколько процентов всей высоты кадра оно занимает. Несложно додуматься, что Если лицо влезает в камеру всеми своими 15 сантиметрами , то до веб-камеры - (AB/FC)*12. Если лицо занимает меньше 100% пространства, то оно более удалено. Давайте определим , насколько...





Из рисунка видно, что переместив объект из точек CD в точки EF, его отображение(GH) будет занимать не 100% , а N%(где N<=100). Из свойства подобия треугольников видно, что отношение GH/AB = KL/CD. А ,значит, для наглядности ,я могу упростить модель до треугольника и трапеции:
Что нам отсюда известно?
Мы знаем, отношение AB/FE - это есть наше фокальное расстояние, обозначим его как focal.
реальные размеры AB.

Нам надо узнать расстояние FG.
Треугольники AFB и DFC подобны, значит FE/FG=AB/DC. Из этого равенства видно, что если FG увеличивается в M раз, то либо DC увеличивается в M раз, либо AB уменьшается в M раз. AB уменьшится не может - это реальный размер лица, он всегда 15 сантиметров, А вот DC - может, это размер лица на фотографии, чем лицо дальше, тем размер его меньше. Исходя из этого, можно сделать вывод, что если DC уменьшилось в M раз( или на N%) ,то и FG уменьшилось так же в M раз( или на N%). Если DC у нас равно AB, то GF = EF, если DC меньше AB в M раз (илиN%),то и FG


Теперь ближе к коду:

import sys
import cv,cv2
import numpy
cascade = cv.Load('haarcascade_frontalface_alt.xml')
c=1.6
Sr=15

def detect(image):
 bitmap = cv.fromarray(image)
 faces = cv.HaarDetectObjects(bitmap, cascade, cv.CreateMemStorage(0))
 if faces:
  for (x,y,w,h),n in faces:  
   k=float(w)/bitmap.cols
   S = Sr*c/k
   cv2.rectangle(image,(x,y),(x+w,y+h),(255,255,255),3)
   cv2.putText(image,'S=%s'%(S),(x,y-10), cv2.FONT_HERSHEY_PLAIN, 1.0,(255,255,255))
 return image

if __name__ == "__main__":
    cam = cv2.VideoCapture(0)
    while 1:
        _,frame =cam.read()
        frame = numpy.asarray(detect(frame))
        cv2.imshow("features", frame)
        if cv2.waitKey(1) == 0x1b: # ESC
            print 'ESC pressed. Exiting ...'
            break





Как видите, я задаю отношение размера матрицы к фокальному расстоянию и размер лица человека, и, исходя из этого, считаю его удалённость, в зависимости от процентов занимаемого им места на экране.

Вот и все пироги, ничего сложного. В следующий раз я предоставлю программу для детектирования любого объекта, стоит вам его выделить мышкой.

Читать дальше......

пятница, 1 июня 2012 г.

Больше гибкости!!! И прыгающие шарики.

Прошла пара дней с тех пор,как я выпустил свою первую библиотеку. И вот, я выпускаю первое к ней обновление, и програмку “Скачущие шарики”, иллюстрирующую её применение . Если интересно, прошу под кат.
Если вы посмотрите в исходный код, то теперь там найдёте новый класс ExeptionMiscarriage.
public class ExeptionMiscarriage extends Throwable{
    private String info ="Object didn't ready";
    public ExeptionMiscarriage(String info){
        this.info =info;
    }

    public ExeptionMiscarriage() {
       
    }
    /**
     * @return the info
     */
    public String getInfo() {
        return info;
    }

    /**
     * @param info the info to set
     */
    public void setInfo(String info) {
        this.info = info;
    }
    public void addInfo(String info) {
        this.info =  this.info   info;
    }   
}
Не сложно догадаться, что это Исключение “выкидыша”. Что это значит? Теперь, если пользователь не заполнил все необходимые поля в панели создания объекта и нажал на кнопочку “ОК”, вы можете сформировать это исключение, и наполнить его информаицией. И пользователю будет выдано модальное окошко ошибки, в котором будет ваша информация.
Диалог не прекратится, а продолжит действовать, пока пользователь не введёт всю необходимую информацию для формирования вашего объекта, или же не нажмёт “Отмена”. Второе улучшение библиотеки касается расширяемости.  По ходу написания программы “Скачущие шарики”, мне понадобилось использовать мою библиотеку не совсем в стандартной ситуации. Я хотел сделать диалог выбора цвета. Панель выбора цвета существует - JColorChooser. И вот ведь незадача: я не могу сообщить её в конструктор своего диалога, так как она не является наследником FactoryPanel. Вот он, камень преткновения и проектировочный тупик. Наследовать от 2-х классов в Java нельзя. Даже, если я наследую от JColorChooser и реализую интерфейс ObjectFactory. То это не сможет явно привести к FactoryPanel во -первых :потому, что так делать нельзя. Если у нас есть:
 
class A{}
interface I{}
class B extends A,implements I{}
class С extends A,implements I{}
Мы не можем Объект класса C явно привести к B. Но, даже, если бы это было возможно-в конкретной ситуации этого сделать было бы нельзя, так как у JColorChooser нет в потомках JPanel. Но зато, у него есть JComponent. JComponent является наследником всех Swing UI элементов. Поэтому, я пересмотрел свою библиотеку и в свой диалог я буду принимать JComponent. Конечно, в целях обратной совместимости, я оставил FactoryPanel, но переименовал её в FactoryComponent. Это не вызовет проблем при разработке панели в визуальном редакторе. Вы по-прежнему, после разработки переопределяете наследника с JPanel на FactoryComponent. Но из за мухи в супе, описанной выше, такой фокус не пройдёт с JColorChooser. Поэтому, я решил, сделать ещё один конструктор в ComplexDialog. ComplexDialog(JFrame parent, Object mainpanel, String title, boolean modal); Как видите - Тип главной панели-настройщика – Object. То есть , я могу сообщить туда всё, что душе угодно. Но в самом конструкторе я проверяю:
 
        settingscomponent = (JComponent)mainpanel;
        objectFactory = (ObjectFactory)mainpanel;
Если вы скормили моему диалогу какое-то непотребство - вывалится исключение о несоответствии типов.  Вернёмся к задаче: Нам надо скормить JColorChooser в ComplexDialog. Если скормим без приправы, ComplexDialog- выплюнет исключение, как я и описывал выше. Поэтому, мы наследуем от JColorChooser и при этом реализуем интерфейс ObjectFactory.
 
    public class MyColorChoser extends JColorChooser implements complexdialog.ObjectFactory{

        @Override
        public Object getResult() throws ExeptionMiscarriage {
           return getColor();
   }
Видите, как классно! Теперь мы можем создать объект типа MyСolorСhoser и успешно скормить его моему диалогу в качестве Object. Так как JColorChooser потомок JComponent, а MyСolorСhoser ещё и реализовывает ObjectFactory- значит диалог скушает этот объект с большим удовольствием. Здесь, в папке examples/example2 ,лежит программа “Скачущие мячики” ,в которой реализованы 2 диалоговых окна моей библиотеки. Первое окно (добавления мячика) показывает, как работают исключения-выкидыши. Второе- показывает, как скормить чужие компоненты моей библиотеке. Дабы вам не было сильно скучно - в самой програмке скачут шарики, как в реальной жизни: с ускорением, вязкостью воздуха, коэффициентом упругости и прочими вкусностями. Для добавления шарика-нажмите кнопочку “Add”,она вызовет мой диалог, и вы не сможете нажать OK, пока не заполните все поля и не выберете цвет. Если вы читаете эту статью, наверно вы - программист. А ,значит , вас не испугает перспектива залезть в код и посмотреть, как добавляются шарики. Я специально, сразу кинул в цикле 20 шариков с разной начальной скоростью и прочим. Поэкспериментируйте с разным количеством шариков, динамической начальной скоростью(очень интересны получаются функциональные зависимости), меняющимися цветами, динамическим коэффициентом упругости.Попробуйте изменить вязкость среды, время обновления рассчётов, временной коэффициент- я специально создал его, чтобы при очень больших масштабах( я сбрасывал мячик с 10 километров на начальной скорости 100 метров в секунду) всё происходило немного быстрей, чем в реальной жизни. Ибо скучно. Только осторожно! Меня эта штука затянула на целый вечер, поэтому, я и пишу статью сегодня, а не вчера :-) Всем спасибо. Постараюсь радовать вас новыми интересными идеями, библиотеками, програмками и прочим. И ,конечно, до бесконечности совершенствовать библиотеку ComplexDialog.


За редакцию хочется выразить благодарность,Алисе Брыль. 
Читать дальше......

понедельник, 28 мая 2012 г.

Моя первая библиотека, или Сложные Диалоги в Java (SWING)

Добрый вечер. Сегодня я хочу предоставить на ваш суд свою первую библиотеку. Прошу не судить строго, но буду рад конструктивной критике и предоложениям по развитию. Если же кто-то захочет помочь в модификации, буду только счастлив. Теперь про библиотеку. Она позволяет вам создавать сложные диалоговые окна. Что это? Зачем? Стандартная библиотека позволяет создавать простые диалоговые окна(выбор Да\Нет, ввод строки, выдор варианта из списка). А что, если вам требуется диалоговое окно, результатом котого будет целый объект. Например, Диалоговое окно выбора места на карте, а результатом будет объект адреса, на котоый кликнул пользователь. Вот, с помошью моей библиотеки, вы сможете это сделать быстро и просто.
Скачать сие творение можно от сюда ComplexDialog . Там же можно присоедениться к разработке.

Теперь про то, как ей пользоваться. Подключив библиотеку(Есть много способов это сделать. Зависит от среды разработки и ваших вкусовых предпочтений) ,вы получаете 2 класса и 1 интерфейс.

Интрфейс ObjectFactory имеет один единственный метод, который возврашает значение указаного вами типа.

Первый класс - ComplexDialog. Это, непосредственно ,класс диалога. Он насделуется от JDialog .Для работы с ним, вы должны указать тип который диалог обязан вернуть. После вызова его конструктора и вызова метода show\setVisible(true) ,можно смело вызывать метод getReturnedStatus(), который вернёт сформированный пользователем объект. Программа приостановится, пока пользователь не нажмёт на OK или Canel. Если Пользователь жмёт Canel, getReturnedStatus возвращает нулевой указатель.

Для того, чтоб детальнее понять ComplexDialog, стоит изучить FactoryPanel. Это абстрактный класс. Он абсолютно пустой. Наследуется от JPanel и реализует интерфейс ObjectFactory. От него вам стоит наслелдовать панель, в которой будет вестись настройка вашего объекта. Обратите внимание, класс нетипизирован и дать ему тип вы должны такой же, как и в ComplexDialog. Потому что ComplexDialog использует метод getResult() для возвращения значения. На самом деле, вы можете создать панельку и в визуальном редакторе, но потом подредактировать код, изменив extends высшей панельки на FactoryPanel, и реализовать метод getResult(),как того требует интерфейс ObjectFactory.

Для создания ComplexDialog нужно:
JFrame parent - окно -родитель(осталось от JDialog);
FactoryPanel mainpanel - панелька, в которой происходит настройка необходимого вам типа; 
String title - надпись на окошке (осталось от JDialog) ; 
boolean modal - модальность окна (осталось от JDialog); 


Для более наглядного объяснения, хочу привести пример практического использования этой библиотеки. Одним из самых простых и достаточно часто необхидимых примеров ,наверное, будет DatePicker, то есть Диалог, в котором пользователь выберет какую- либо дату. 


Наш "ХелоВорлд" будет просить пользователя ввести дату его рождения и подсчитает количество дней прожитых пользователем. Для начала, Создадим формочку, которая наследуется от FactoryPanel. Для подтверждения своих слов, я создал её в визуальном редакторе, позже реализовал внутри необходимый функционал и реазиловал метод getResult() ,который возвращает объект типа java.util.Date, сформированный пользователем. FactoryPanel:
package alexkutsan_blogspot;

import complexdialog.FactoryPanel;
import java.util.Calendar;
import java.util.Date;
import javax.swing.DefaultComboBoxModel;
/**
 *
 * @author alex
 */

public class DatePickerPanel extends FactoryPanel<Date>{

    /**
     * Creates new form DatePickerPanel
     */
    public DatePickerPanel() {
        super();
        initComponents();
        myinitUI();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {

        YearBox = new javax.swing.JComboBox();
        MonthBox = new javax.swing.JComboBox();
        DayBox = new javax.swing.JComboBox();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        jLabel3 = new javax.swing.JLabel();

        YearBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        YearBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                YearBoxActionPerformed(evt);
            }
        });

        MonthBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        MonthBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                MonthBoxActionPerformed(evt);
            }
        });

        DayBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

        jLabel1.setText("%u0413%u043E%u0434");

        jLabel2.setText("%u041C%u0435%u0441%u044F%u0446");

        jLabel3.setText("%u0414%u0435%u043D%u044C");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(YearBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(6, 6, 6)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(MonthBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(DayBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(27, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(25, 25, 25)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(YearBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(MonthBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(DayBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2)
                    .addComponent(jLabel3))
                .addContainerGap(35, Short.MAX_VALUE))
        );
    }// </editor-fold>

    private void YearBoxActionPerformed(java.awt.event.ActionEvent evt) {                                        
       int m = MonthBox.getSelectedIndex()   1;
                    int y = YearBox.getSelectedIndex()   (Calendar.getInstance().get(Calendar.YEAR) - CountYears);
                    int n = m != 2 ? m > 7 ? 30   m % 2 == 1 ? 0 : 1 : 30   m % 2 : y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
                    Integer[] Days = new Integer[n];
                    for (int i = 1; i < n   1; i  ) {
                        Days[i - 1] = i;
                    }
                    DayBox.setModel(new DefaultComboBoxModel(Days));
    }                                       

    private void MonthBoxActionPerformed(java.awt.event.ActionEvent evt) {                                         
                    int m = MonthBox.getSelectedIndex()   1;
                    int y = YearBox.getSelectedIndex()   (Calendar.getInstance().get(Calendar.YEAR) - CountYears);
                    int n = m != 2 ? m > 7 ? 30   m % 2 == 1 ? 0 : 1 : 30   m % 2 : y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
                    Integer[] Days = new Integer[n];
                    for (int i = 1; i < n   1; i  ) {
                        Days[i - 1] = i;
                    }
                    DayBox.setModel(new DefaultComboBoxModel(Days));
    }                                        

    // Variables declaration - do not modify
    private javax.swing.JComboBox DayBox;
    private javax.swing.JComboBox MonthBox;
    private javax.swing.JComboBox YearBox;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    // End of variables declaration

    private void myinitUI() {
     Date cur = new Date(System.currentTimeMillis());
            int curentYear = Calendar.getInstance().get(Calendar.YEAR);
            Integer[] Years = new Integer[CountYears];
            for (int i = curentYear - CountYears; i < curentYear; i  ) {
                Years[i - (curentYear - CountYears)] = i;
            }
            Integer[] Month = new Integer[12];
            for (int i = 1; i <= 12; i  ) {
                Month[i - 1] = i;
            }
            Integer[] Data31 = new Integer[31];
            Integer[] Data30 = new Integer[30];
            Integer[] Data29 = new Integer[29];
            Integer[] Data28 = new Integer[28];
            for (int i = 1; i < 32; i  ) {
                if (i < 31) {
                    Data30[i - 1] = i;
                }
                if (i < 30) {
                    Data29[i - 1] = i;
                }
                if (i < 29) {
                    Data28[i - 1] = i;
                }
                Data31[i - 1] = i;
            }
            int m = Month[0];
            int y =Years[0];
            int n = m != 2 ? m > 7 ? 30   m % 2 == 1 ? 0 : 1 : 30   m % 2 : y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
            Integer[] Days = new Integer[n];
            for (int i = 1; i < n   1; i  ) {
                Days[i - 1] = i;
            }
            YearBox.setModel(new DefaultComboBoxModel(Years));
            MonthBox.setModel(new DefaultComboBoxModel(Month));
            DayBox.setModel(new DefaultComboBoxModel(Days));
    }
    int CountYears = 100;

    @Override
    public Date getResult() {
            Integer y =(Integer) YearBox.getSelectedItem();
            Integer m =(Integer) MonthBox.getSelectedItem();
            Integer d =(Integer) DayBox.getSelectedItem();
            Date date = new Date(y-1900, m-1, d);
            return date;
    }
}
Вот такая панелька
У неё незамысловатый функционал .Внимания заслуживает лишь моя функция рассчёта количества дней в месяце.
 int n = m != 2 ? m > 7 ? 30 m % 2 == 1 ? 0 : 1 : 30 m % 2 : y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28; где 
m - месяц(1..12)
y - год.

 Как видите, в функции getResult() формируется и возвращается Дата, введённая пользователем. Теперь главный класс:
 


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package alexkutsan_blogspot;
import complexdialog.ComplexDialog;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
/**
 *
 * @author alex
 */
public class Alexkutsan_blogspot {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws ParseException, IOException, URISyntaxException {


        // Date today = new Date(System.currentTimeMillis());
        Date today = new Date(System.currentTimeMillis());
        DatePickerPanel p = new DatePickerPanel();
        ComplexDialog<Date> dp = new ComplexDialog<Date>(null,p,"%u0412%u0432%u0435%u0434%u0438%u0442%u0435 %u0434%u0430%u0442%u0443 %u0432%u0430%u0448%u0435%u0433%u043E %u0440%u043E%u0436%u0434%u0435%u043D%u0438%u044F", true);
        dp.setVisible(true);
        Date born = dp.getReturnedStatus();
        if (born != null) {
            long difference = today.getTime() - born.getTime();
            long daycount = TimeUnit.MILLISECONDS.toDays(difference);
            JOptionPane.showMessageDialog(dp, String.format("%u0417%u0435%u043C%u043B%u044F %u0432%u0430%u0441 %u043D%u043E%u0441%u0438%u0442 %u0432%u0441%u0435%u0433%u043E-%u0442%u043E %s %u0434%u043D%u0435%u0439 ", daycount), "%u0412%u044B %u0442%u0430%u043A %u043C%u043E%u043B%u043E%u0434%u044B", JOptionPane.INFORMATION_MESSAGE);
        }
        //URLLabel myEgo = new URLLabel(new URI("http://alexkutsan.blogspot.com/"),"%u041F%u0440%u043E%u0433%u0440%u0430%u043C%u043C%u0443 %u0440%u0430%u0437%u0440%u0430%u0431%u043E%u0442%u0430%u043B %u0410%u043B%u0435%u043A%u0441%u0430%u043D%u0434%u0440 %u041A%u0443%u0446%u0430%u043D");
        //JLabel mersi = new JLabel("%u0411%u043B%u0430%u0433%u043E%u0434%u0430%u0440%u043D%u043E%u0441%u0442%u0438:\n \t %u0410%u043B%u0435%u043A%u0441%u0430%u043D%u0434%u0440 %u041A%u0438%u043B%u0438%u043C%u043D%u0438%u043A \t \n %u0410%u043B%u0438%u0441%u0430 %u0411%u0440%u044B%u043B%u044C");
        JOptionPane.showMessageDialog(dp,new About(), "%u0410%u0432%u0442%u043E%u0440: ", JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
    }
}

Я тут создаю панельку, котороую описал выше, вычисляю сегодняшнюю дату, создаю диалог и жду, пока пользователь не нажмёт что-то.
 

        ComplexDialog<Date> dp = new ComplexDialog<Date>(null,p,"%u0412%u0432%u0435%u0434%u0438%u0442%u0435 %u0434%u0430%u0442%u0443 %u0432%u0430%u0448%u0435%u0433%u043E %u0440%u043E%u0436%u0434%u0435%u043D%u0438%u044F", true);
        dp.setVisible(true);
        Date born = dp.getReturnedStatus();
Выглядит диалог Так:
По нажатию, у меня в born лежит либо дата, которую выбрал пользователь, либо null. Если Дата != null, то выскочит сообщение c подсчитаными днями. Работать это будет только ,если вы ещё создадите эти классы. Они не нуждаются в дополнительном описании, разве что URLLable. Но о ней я расскажу позже. Скачать пример можно по этой ссылке ComplexDialog , в каталоге Examples.
 

//The contents of this file are subject to the Mozilla Public License Version 1.1
//(the "License"); you may not use this file except in compliance with the 
//License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
//
//Software distributed under the License is distributed on an "AS IS" basis,
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
//for the specific language governing rights and
//limitations under the License.
//
//The Original Code is "The Columba Project"
//
//The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003. 
//
//All Rights Reserved.
package alexkutsan_blogspot;


import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URI;
import javax.swing.JLabel;

public class URLLabel extends JLabel {

  boolean entered = false;

  boolean mousehover;
  private  URI site ;
  public URLLabel(URI uri) {
    this(uri, uri.toString());
  }

  public URLLabel(URI uri, String str) {
    super(str);
    this.site = uri;
    setForeground(Color.blue);
    mousehover = false;
    setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    this.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() > 0) {
                    if (Desktop.isDesktopSupported()) {
                        Desktop desktop = Desktop.getDesktop();
                        try {
                          
                            desktop.browse(site);
                            System.exit(0);
                        } catch (IOException ex) {
                            
                        }
                    } 

                }
            }
        });
  }

  public void mouseEntered(MouseEvent e) {
    entered = true;
    if (mousehover) {
      repaint();
    }
  }

  public void mouseExited(MouseEvent e) {
    setCursor(Cursor.getDefaultCursor());
    entered = false;

    if (mousehover) {
      repaint();
    }
  }

  public void mousePressed(MouseEvent e) {
  }

  public void mouseReleased(MouseEvent e) {
  }

    @Override
  public void paint(Graphics g) {
    super.paint(g);

    if (entered || !mousehover) {
      Rectangle r = g.getClipBounds();

      g.drawLine(0, r.height - this.getFontMetrics(this.getFont()).getDescent(), this
          .getFontMetrics(this.getFont()).stringWidth(this.getText()), r.height
          - this.getFontMetrics(this.getFont()).getDescent());
    }
  }
}


}


 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package alexkutsan_blogspot;

import java.net.URI;
import java.net.URISyntaxException;

/**
 *
 * @author alex
 */
public class About extends javax.swing.JPanel {

    /**
     * Creates new form About
     */
    public About() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        try{
            jLabel2 = new URLLabel(new URI("http://alexkutsan.blogspot.com/"), "%u0410%u043B%u0435%u043A%u0441%u0430%u043D%u0434%u0440 %u041A%u0443%u0446%u0430%u043D");
            jLabel3 = new javax.swing.JLabel();
            jLabel4 = new javax.swing.JLabel();
            jLabel5 = new javax.swing.JLabel();

            jLabel1.setText("%u041F%u0440%u043E%u0433%u0440%u0430%u043C%u043C%u0443 %u0440%u0430%u0437%u0440%u0430%u0431%u043E%u0442%u0430%u043B:");

        }
        catch(URISyntaxException e){

        }
        jLabel2.setText("%u0410%u043B%u0435%u043A%u0441%u0430%u043D%u0434%u0440 %u041A%u0443%u0446%u0430%u043D");

        jLabel3.setText("%u0411%u043B%u0430%u0433%u043E%u0434%u0430%u0440%u043D%u043E%u0441%u0442%u0438:");

        jLabel4.setText("%u0410%u043B%u0435%u043A%u0441%u0430%u043D%u0434%u0440 %u041A%u0438%u043B%u0438%u043C%u043D%u0438%u043A");

        jLabel5.setText("%u0410%u043B%u0438%u0441%u0430 %u0411%u0440%u044B%u043B%u044C");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel1)
                            .addComponent(jLabel3))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel2))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(41, 41, 41)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel5)
                            .addComponent(jLabel4))))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(jLabel2))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel3)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel4)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel5))
        );
    }// </editor-fold>                        
    // Variables declaration - do not modify                     
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    // End of variables declaration                   
}


В написании статьи хочу выразить благодарность этим людям: 
    Алиса Брыль; 
    Александр Килимник;
Читать дальше......

воскресенье, 15 апреля 2012 г.

Oracle + NetBeans


Христос воскресе!!
В этоn замечательный день я хочу уменьшить ваши мучения при подключении Oracle DB к NetBeans. Предположу, что вы уже установили себе Oracle (можно XE, как у меня). И теперь вам не терпится поработать с базами данных и написать программу, которая её использует. Может быть вы даже поставили себе JDeveloper, но лично меня он пока не впечатлил. Точнее нет. Он очень крут. Но система с ним тормозит- возьми да вешайся и это на i5 проце. NetBeans тоже можно использовать на СУБД. Пусть он не настолько кликабелен  как Jdeveloper , но ничего, подучите PL/SQL. Ну что, вытаскиваем руки из задницы, ставим чуть ниже шеи и кладём на клавиатуру.




Из первоначальных требований:
   Установленная система- >=1шт.
   Установленный OracleDB(XE) = 1шт.
   Установленный NetBeans >= 1шт.
   Установленный SunJDK = 1шт.
   Мозг - 1 шт. Желательно 2 полушария.
   Руки - можно 1 но на правильном месте хоть как-то связанную с мозгом.



Ну что, в атаку. Я очень ленив, и описывать то, что описано мне не хочется. Как в NetBeans подключить BD описано здесь .Если кратко, то мы вызываем окно "службы"(Ctrl+F5). В нём кликаем правой клавишей по "Базы данных" и выбираем "новое соединение". Выбираем драйвер Oracle Thin и Нет Бианс говорит, что драйвера нет и любезно перенаправляет нас на страницу его скачивания . Загрузив драйвер ojdbc6.jar ,мы выбираем его кнопочкой «добавить» в диалоговом окне NetBeans.




Потом пред нами предстоит ввод Адреса вашей BD (скорее всего localhost) Но нет, если установленная oracle на другой машине. Так же имя пользователя и пароль. Так как аккаунт hr/hr с недавних пор по умолчанию заблокирован, мы введём system/{пароль, который вы указали при установке oracle} . Нажимаем "проверить соединение" и тут нас «Фейсом об тейбл»!ORA-12705: Cannot access NLS data files or invalid environment specified
Вот
ведь незадачка-то: Вариантов решения этой проблемы несколько. Гугл и форумчани вовсю советуют:
1)
Взять старый драйвер для oracle9( некошерно )
2)
Установить глобальную переменную NLS_LANG в en_US.utf8, в винде тоже самое, только в реестре.


1 вариант честно не пробовал. Второй - не помог, видимо он для 10 оракла или то-то типа того. Поэтому есть ещё 3-й и четвёртый варианты.  Для того, чтоб решить проблему, давайте поймём, от чего она. Если вы устанавливали и Oracle NetBeans на 1 машину, то ошибки у вас возможно и нет. Потому, что она насколько я понял из-за несоответствия кодировок сервера и клиента, Сервер БД  устанавливает внутреннюю кодировку скриптиком.
{oracle home}/product/{version}/xe/bin/nls_lang.sh . Этот скрипт анализирует кодировку вашей системы и выдаёт подходящую для БД на экран. Могу предположить, что этот скрипт выполняется при запуске OracleXE и результат его работы присваивается куда-то. Но это предположения. На стороне клиента, на сколько я понимаю, по крайней мере драйвер  ojdbc6 выполняет то же самое ,только с кодировкой системы клиента. И если кодировки разные и несовместимые, то вываливается ошибка NLS . Как же быть? Можно на стороне клиента в системе поставить кодировку, аналогичную серверу, давайте так и сделаем.
export LANG=us_US.utf8. Запускаем NetBeans в этой же консольке и мы успешно подключаемся к базе. Но способ не самый удобный, поэтому существует ещё 1.
Мы отредактируем конфигурационный файлик NetBeans.{NET BEANS HOME}/etc/netbeans.conf . И в переменную netbeans_default_options добавим ещё 1 параметр.
-J-Duser.region=US . После этого снова успешно подключаемся к базе.  В этом посте мне хотелось ещё рассказать 2 слова о подключении Oracle к java, но статья затянулась, и об этом я продолжу после.


Читать дальше......