Разработка собственных объектов.
В большинстве случаев, при разработки приложений, необходимо создавать собственные объекты. Это обусловлено тем, что язык Java является объектно-ориентированным и вся обработка информации происходит на уровне объекта. В общем случае описание объекта имеет следующий вид:
package имя пакета;
// Подключение библиотек, используемых новым компонентом
class имя компонента extends имя базового компонента
{
// свойства и методы нового компонента
};
Объекты могут быть визуальными, то есть видимыми на форма и невидимыми, то есть хранящиеся в только в памяти.
Рассмотри построение собственного визуального компонента на примере объекта вывода графика функции. В качестве базового компонента будем использовать класс JPanel.
package имя пакета;
// Библиотека базового класса нашего компонента
import javax.swing.JPanel;
// Библиотека класса графических примитивов
import java.awt.Graphics;
// Библиотека сервисных функций шрифтов
import java.awt.FontMetrics;
// Библиотека палитры.
import java.awt.Color;
// Библиотека математических функций
import java.lang.Math;
// Создаем компонент.
class имя компонента extends JPanel
{
// Определение переменных
// Определяем массив для хранения значений оси X.
private double val_x[]=null;
// Определяем массив для хранения значений оси Y.
private double val_y[]=null;
// Определяем переменные ограничивающие размеры графика
// по оси X и Y.
private double Xmin=0;
private double Xmax=0;
private double Ymin=0;
private double Ymax=0;
};
// Конструктор класса
public имя компонента() {
// Устанавливаем цвет фона данного компонента
this.setBackground(Color.white);
}
// Установка и первичная обработка данных
// для построения графика
void setDataGraph(double _val_x[],double _val_y[])
{
// Устанавливаем значения массивов
val_x=_val_x;
val_y=_val_y;
// Вычисляем диапазон по оси X
if(vay_x!=null)
{
Xmin=val_x[0];
Xmax=val_x[0];
For(int i=0;i<val_x.length;i++)
{
if(Xmin>val_x[i])Xmin=val_x[i];
if(Xmax<val_x[i])Xmax=val_x[i];
}
}
else
{
Xmin=0;
Xmax=0;
}
// Вычисляем диапазон по оси Y
if(val_y!=null)
{
Ymin=val_y[0];
Ymax=val_y[0];
for(int i=1;i<val_y.length;i++)
{
if(Ymin>val_y[i])Ymin=val_y[i];
if(Ymax<val_y[i])Ymax=val_y[i];
}
}
else
{
Ymin=0;
Ymax=0;
}
// Увиличиваем диапазон, для предотвращения выхода
// за пределы окна по оси X
double delta=Math.abs(Xmax-Xmin)*0.05;
Xmin-=delta;
Xmax+=delta;
// Увиличиваем диапазон, для предотвращения выхода
// за пределы окна по оси Y
delta=Math.abs(Ymax-Ymin)*0.05;
Ymin-=delta;
Ymax+=delta;
// Вызываем перерисовку, для отображения полученных результатов
this.repaint();
}
// В большинстве случаем при построении каких либо графиков или диаграмм
// необходимо преобразовывать (приводить) исходные данные к пространству
// компонентов. Для этого необходимо вычислить коэффициенты
// масштабирования (множители) приведения и положение нулевой точки
// координат.
// По оси X коэффициент приведения вычисляется как отношение ширины
// компонента к диапазону X, а по оси Y как отношение высоты компонента
// к диапазону по оси Y
// Определение коэффициента масштабирования
// по оси X
private double GetKmX()
{
double space_x=Xmax-Xmin;
if(space_x==0)return 0;
return (double)this.getWidth()/space_x;
}
// Определение коэффициента масштабирования
// по оси Y
private double GetKmY()
{
double space_y=Ymax-Ymin;
if(space_y==0)return 0;
return (double)this.getHeight()/space_y;
}
// Определение положения нулевой точки
// по оси X
private int GetCenterX()
{
double tmp=0;
if(Xmin<0 && Xmax>0)tmp=-Xmin*GetKmX();
else if(Xmax<0)tmp=(double)this.getWidth();
return (int)tmp;
}
// Определение положения нулевой точки
// по оси Y
private int GetCenterY()
{
double tmp=0;
if(Ymin<0 && Ymax>0)tmp=this.getHeight()-(-Ymin*GetKmY());
else if(Ymax<0)tmp=(double)this.getHeight();
return (int)tmp;
}
// Далее идет описание функций определения положения точки
// приведенной к размерам окна и положению центра координат
// Получение значения абсциссы приведенной к размерам окна
private int GetX(int idx)
{
if(val_x==null)return 0;
int i_pos=(int)(double)(val_x[idx]*GetKmX());
return GetCenterX()+i_pos;
}
// Получение значения ординаты приведенной к размерам окна
private int GetY(int idx)
{
if(val_y==null)return 0;
int i_pos=(int)(double)(val_y[idx]*GetKmY());
return GetCenterY()-i_pos;
}
// Поскольку в языке Java пока отсутствуют функции форматированного
// ввода-вывода то необходимо описать функцию преобразования
// вещественного числа в строку по указанному формату.
// Функция преобразования вещественного числа в строку.
private String float_to_str(double val,String format)
{
int idx_dec=format.indexOf('.');
if(idx_dec==-1)return String.valueOf(val);
String dec_str=format.substring(idx_dec+1);
int cnt_dec=0;
for(int i=0;i<dec_str.length();i++)
{
if(dec_str.charAt(i)!='0')break;
cnt_dec++;
}
double prepare_f=val;
double delta=0.5;
for(int i=0;i<cnt_dec;i++)delta/=10;
prepare_f+=delta;
String fl_str=String.valueOf(prepare_f);
int idx_int=fl_str.indexOf(',');
if(idx_int==-1)idx_int=fl_str.indexOf('.');
String base=fl_str;
String expn="";
if(idx_int!=-1)base=fl_str.substring(0,idx_int);
if(idx_int!=-1)expn=fl_str.substring(idx_int+1);
while(expn.length()<cnt_dec)
{
expn+="0";
}
fl_str=base+","+expn.substring(0,cnt_dec)+dec_str.substring(cnt_dec);
return fl_str;
}
// Далее идет функция рисования координатных осей
private void draw_coord(Graphics g,int mode)
{
Color save_color=g.getColor(); // Сохраняем текущий цвет
g.setColor(Color.black); // Устанавливаем черный цвет осей
double delta_x=0;
double delta_y=0;
FontMetrics fm=g.getFontMetrics(); // Определяем параметры шрифта
if(mode==0)
{
// Рисование оси Y
g.drawLine(GetCenterX()-1,4,GetCenterX()-1,this.getHeight()-3);
g.drawLine(GetCenterX(),3,GetCenterX(),this.getHeight()-3);
g.drawLine(GetCenterX()+1,4,GetCenterX()+1,this.getHeight()-3);
g.drawLine(GetCenterX()-5,13,GetCenterX(),3);
g.drawLine(GetCenterX()+5,13,GetCenterX(),3);
// Вывод заголовка метки оси Y
g.drawString("Y",GetCenterX()+10,fm.getHeight()+3);
delta_y=Math.max(Math.abs(Ymin),Math.abs(Ymax))/10;
delta_y=Math.ceil(delta_y*10)/10;
}
else
{
// Рисование оси X
g.drawLine(3,GetCenterY()-1,this.getWidth()-4,GetCenterY()-1);
g.drawLine(3,GetCenterY(),this.getWidth()-3,GetCenterY());
g.drawLine(3,GetCenterY()+1,this.getWidth()-4,GetCenterY()+1);
g.drawLine(this.getWidth()-13,GetCenterY()-5,
this.getWidth()-3,GetCenterY());
g.drawLine(this.getWidth()-13,GetCenterY()+5,
this.getWidth()-3,GetCenterY());
// Вывод заголовка метки оси X
g.drawString("X",this.getWidth()-fm.charWidth('X')*2,
GetCenterY()+fm.getHeight());
delta_x=Math.max(Math.abs(Xmin),Math.abs(Xmax))/10;
delta_x=Math.ceil(delta_x*10)/10;
}
// Вывод масштабных линий
double tmp_x=delta_x;
double tmp_y=delta_y;
for(int i=0;i<10;i++)
{
if(delta_x!=0)
{
int i_pos=(int)((double)tmp_x*GetKmX());
String txt=float_to_str(tmp_x,"0.0");
if(tmp_x<Math.abs(Xmin))
{
g.drawLine(GetCenterX()-i_pos,GetCenterY()-5,
GetCenterX()-i_pos,GetCenterY()+5);
if((i%2)==0)
{
g.drawString("-"+txt,GetCenterX()-i_pos-
fm.stringWidth("-"+txt)/2,GetCenterY()+fm.getHeight());
}
}
if(tmp_x<Math.abs(Xmax))
{
g.drawLine(GetCenterX()+i_pos,GetCenterY()-5,
GetCenterX()+i_pos,GetCenterY()+5);
if((i%2)==0)
{
g.drawString(txt,GetCenterX()+i_pos-
fm.stringWidth(txt)/2,GetCenterY()+fm.getHeight());
}
}
}
if(delta_y!=0)
{
int i_pos=(int)((double)tmp_y*GetKmY());
String txt=float_to_str(tmp_y,"0.0");
if(tmp_y<Math.abs(Ymin))
{
g.drawLine(GetCenterX()-5,GetCenterY()+i_pos,
GetCenterX()+5,GetCenterY()+i_pos);
if((i%2)==0)
{
g.drawString("-"+txt,GetCenterX()-5-
fm.stringWidth("-"+txt),
GetCenterY()+i_pos+fm.getHeight()/2);
}
}
if(tmp_y<Math.abs(Ymax))
{
g.drawLine(GetCenterX()-5,GetCenterY()-i_pos,
GetCenterX()+5,GetCenterY()-i_pos);
if((i%2)==0)
{
g.drawString(txt,GetCenterX()-5-
fm.stringWidth(txt),
GetCenterY()-i_pos+fm.getHeight()/2);
}
}
}
tmp_x+=delta_x;
tmp_y+=delta_y;
}
g.setColor(save_color);
if(mode==0)draw_coord(g,1);
}
// Функция рисования графика. Функция paint является виртуальной
// функцией класса JPanel. При определении виртуальной функции, вызов
// будет происходить аналогично языку C++
public void paint(Graphics g)
{
super.paint(g);
if(val_x==null || val_y==null)return;
draw_coord(g,0);
Color save_color=g.getColor();
g.setColor(Color.red);
int save_x=GetX(0);
int save_y=GetY(0);
for(int i=1;i<val_x.length-1;i++)
{
g.drawLine(save_x,save_y,GetX(i),GetY(i));
save_x=GetX(i);
save_y=GetY(i);
}
g.setColor(save_color);
}
}
7.1. Объекты управления
К объектам управления в языке Java относятся все компоненты, имеющие обработчики событий. В большинстве случаев в качестве объектов управления используются кнопки, меню, панели управления. В общем случае управление поведением программы имеет структуру приведенную на рисунке 1:
Рис. 1. Структурная схема обработки событий
На данном рисунку К.У. – компонент управления, а О– управляемый объект. Из рисунка видно, что компонент управления передает команду форме, а форма уже распределяет эти команды в зависимости от принадлежности соответствующим компонентам.
Стандартные компоненты управления приведены в таблице 4.
Таблица 4. Стандартные компоненты управления.
Компонент | Комментарии |
JButton | Кнопка библиотеки SWING. Событие генерируется при нажатии кнопки. |
JRadioButton | Кнопка выбора варианта библиотеки SWING. Событие генерируется при изменении состояния кнопки. |
JCheckBox | Кнопка флага библиотеки SWING. Событие генерируется при изменении состояния кнопки. |
JMenuItem | Строка меню SWING. Событие генерируется при выборе пункта меню. |
Button | Кнопка библиотеки AWT. Событие генерируется при нажатии кнопки. |
RadioButton | Кнопка выбора варианта библиотеки AWT. Событие генерируется при изменении состояния кнопки. |
CheckBox | Кнопка флага библиотеки AWT. Событие генерируется при изменении состояния кнопки. |
MenuItem | Строка меню AWT. Событие генерируется при выборе пункта меню. |
В общем случае любой компонент может генерировать события, в зависимости от его назначения. Язык Java позволяет обрабатывать все события мыши и клавиатуры, в зависимости от их необходимости.
Так рассмотрим обработку событий формы на примере формы построения графика функции. Предположим, что нам задана функция:
и в результате мы хотим получить приложение выполняющее построение графика этой функции следующего вида:
Рис.2.
На данной форме расположены окна редактирования, в которые вводятся исходные параметры для построения графика, компонент управления (кнопка «Обработать») и управляемый объект (область построения графика). Целью формы является связь визуальных компонентов (управляющих и управляемых) между собой. Программа связи компонентов будет иметь следующий вид:
package имя пакута;
// Подключение необходимых библиотек:
// Подключаем стандартную библиотеку работы с окнами
import java.awt.*;
// Подключаем стандартную библиотеку обработки событий
// окон, она необходима для обработки системных сообщений
import java.awt.event.*;
// Подключаем расширенную библиотеку работы с окнами
import javax.swing.*;
// Подключаем библиотеку позиционирования
import com.borland.jbcl.layout.*;
// Класс-оболочку для преобразования вещественных чисел
import java.lang.Double;
// Класс математических функций
import java.lang.Math;
// Описываем класс формы, используя базовым классом
// класс расширенной библиотеки работы с окнами.
public class имя формы extends JFrame {
JPanel contentPane; // Переменная связанная с корневой панелью формы
// Создаем объект позиционирования компонентов на форме
BorderLayout borderLayout1 = new BorderLayout();
// Создаем объект, на котором будут располагать компоненты управления
JPanel tool_panel = new JPanel();
// Объект позиционирования компонентов на контейнере управления
XYLayout xYLayout1 = new XYLayout();
// Создаем метки и поля редактирования для ввода исходных данных.
JLabel a_label = new JLabel();
JTextField a_text = new JTextField();
JLabel b_label = new JLabel();
JTextField b_text = new JTextField();
JLabel c_label = new JLabel();
JTextField c_text = new JTextField();
JLabel xn_label = new JLabel();
JTextField xn_text = new JTextField();
JLabel xk_label = new JLabel();
JTextField xk_text = new JTextField();
JLabel dx_label = new JLabel();
JTextField dx_text = new JTextField();
// Создаем компонент управления
JButton update_btn = new JButton();
// Создаем объект отображения графической информации, в нашем
// случае управляемый объект описанный выше.
Имя класса graph=new Имя класса();
// Описываем переменные для ввода исходных данных
double val_x[]=null;
double val_y[]=null;
// Конструктор класса
public имя формы() {
// Устанавливаем перехватчик событий окон, в нашем случае необходим
// для обработки системной команды закрытия окна.
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
// Инициализируем компоненты.
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
// Функция инициализации компонентов
private void jbInit() throws Exception {
// Получаем корневую панель формы
contentPane = (JPanel) this.getContentPane();
// Устанавливаем способ позиционирования компонентов на форме
contentPane.setLayout(borderLayout1);
// Устанавливаем размеры окна и его заголовок
this.setSize(new Dimension(550, 400));
this.setTitle("Построение графиков функций");
// Устанавливаем параметры контейнера компонентов управления
tool_panel.setBorder(BorderFactory.createEtchedBorder());
tool_panel.setMinimumSize(new Dimension(10, 27));
tool_panel.setPreferredSize(new Dimension(10, 27));
tool_panel.setLayout(xYLayout1);
// Определяем параметры меток и полей ввода исходных данных
a_label.setText("A:");
a_text.setMinimumSize(new Dimension(35, 21));
a_text.setPreferredSize(new Dimension(35, 21));
a_text.setText("100");
b_label.setText("B:");
b_text.setText("5");
b_text.setPreferredSize(new Dimension(35, 21));
b_text.setMinimumSize(new Dimension(35, 21));
c_label.setText("C:");
c_text.setMinimumSize(new Dimension(35, 21));
c_text.setPreferredSize(new Dimension(35, 21));
c_text.setText("150");
xn_label.setText("Xнач:");
xn_text.setText("-20");
xn_text.setPreferredSize(new Dimension(35, 21));
xn_text.setMinimumSize(new Dimension(35, 21));
xk_label.setText("Xкон:");
xk_text.setMinimumSize(new Dimension(35, 21));
xk_text.setPreferredSize(new Dimension(35, 21));
xk_text.setText("30");
dx_text.setText("1");
dx_text.setPreferredSize(new Dimension(35, 21));
dx_text.setMinimumSize(new Dimension(35, 21));
dx_label.setText("DX:");
// Определяем параметры компонента управления
update_btn.setBorder(BorderFactory.createEtchedBorder());
update_btn.setMaximumSize(new Dimension(75, 23));
update_btn.setMinimumSize(new Dimension(75, 23));
update_btn.setPreferredSize(new Dimension(73, 23));
update_btn.setText("Обработать");
// Устанавливаем компоненту управления, класс обработки события нажатия
// на него.
update_btn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
update_btn_actionPerformed(e);
}
});
// Закрепляем панель управления на форме
contentPane.add(tool_panel, BorderLayout.NORTH);
// Закрепляем компоненты ввода исходных данных на панели управления
tool_panel.add(a_label, new XYConstraints(2, 2, -1, -1));
tool_panel.add(a_text, new XYConstraints(16, 0, -1, -1));
tool_panel.add(b_label, new XYConstraints(54, 2, -1, -1));
tool_panel.add(c_text, new XYConstraints(123, 0, -1, -1));
tool_panel.add(b_text, new XYConstraints(69, 0, -1, -1));
tool_panel.add(c_label, new XYConstraints(107, 2, -1, -1));
tool_panel.add(xn_label, new XYConstraints(161, 2, -1, -1));
tool_panel.add(xn_text, new XYConstraints(195, 0, -1, -1));
tool_panel.add(xk_label, new XYConstraints(233, 2, -1, -1));
tool_panel.add(xk_text, new XYConstraints(267, 0, -1, -1));
tool_panel.add(dx_label, new XYConstraints(305, 2, -1, -1));
tool_panel.add(dx_text, new XYConstraints(328, 0, -1, -1));
// Закрепляем компонент управления на парели управления
tool_panel.add(update_btn, new XYConstraints(368, 0, -1, -1));
// Устанавливаем параметры компонента отображения информации
graph.setBorder(BorderFactory.createEtchedBorder());
// Закрепляем компонент отображения информации на форме
contentPane.add(graph, BorderLayout.CENTER);
}
// Создаем обработчик системных событий, в нашем случае для обработки
// события закрытия окна
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
// Создаем функцию получения исходных данных в требуемом формате
private double get_float_field(JTextField fld)
{
return Double.valueOf(fld.getText()).doubleValue();
}
// Описываем реакцию на нажатие кнопки (компонента управления)
void update_btn_actionPerformed(ActionEvent e) {
// Получаем исходные данных
double a=get_float_field(a_text);
double b=get_float_field(b_text);
double c=get_float_field(c_text);
double xn=get_float_field(xn_text);
double xk=get_float_field(xk_text);
double dx=get_float_field(dx_text);
// вычисляем значения функции
if(dx==0)
{
graph.setDataGraph(null,null);
JOptionPane.showMessageDialog(this,"Интервал не может равняться нулю!",
this.getTitle(),JOptionPane.ERROR_MESSAGE);
return;
}
if((xn>xk && dx>0) || (xn<xk && dx<0))
{
graph.setDataGraph(null,null);
JOptionPane.showMessageDialog(this,"Интервал или приращение заданы неверно!"+
" Бесконечный цикл!",
this.getTitle(),JOptionPane.ERROR_MESSAGE);
return;
}
int count=(int)Math.abs((xk-xn)/dx);
val_x=new double[count];
val_y=new double[count];
if(val_x==null || val_y==null)
{
graph.setDataGraph(null,null,0,0);
JOptionPane.showMessageDialog(this,"Ошибка выделения памяти!",
this.getTitle(),JOptionPane.ERROR_MESSAGE);
return;
}
double x=xn;
if(xn>xk)
{
double tmp=xn;
xk=xn;
xn=tmp;
dx*=-1;
}
int i=0;
boolean null_flag;
while(x<=xk && i<(val_x.length-1))
{
null_flag=false;
val_x[i]=x;
if(b<15 && x!=0)val_y[i]=a-b*x;
else
{
if(b>15 && x==0)
{
if((c-b*x)==0)
{
null_flag=true;
}
else val_y[i]=a*(b+x)/(c-b*x);
}
else
{
if(c==0)
{
null_flag=true;
}
else val_y[i]=(c+x)/(-1*c);
}
}
if(null_flag)
{
JOptionPane.showMessageDialog(this,
"Функция имеет точку разрыва. Система остановлена!",
this.getTitle(),JOptionPane.ERROR_MESSAGE);
return;
}
x+=dx;
i++;
}
// передаем параметры компоненту отображения информации.
graph.setDataGraph(val_x,val_y);
}
}
Структурная схема работы данной формы имеет следующий вид:
Рис.3.
На данной схеме видно, что вся работа приложения представляет собой цикл, состоящий из четырех состояний:
ü Ожидание команды (ожидание действий пользователя, определенных в программе в нашем случае нажатия кнопки);
ü Обработка получение исходных данных;
ü Обработка исходных данных;
ü Вывод результатов.
Дата добавления: 2016-01-03; просмотров: 718;