Логин:   Пароль:




Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100

Java: СтатьиПостроение графиков простых функций

Построение графиков простых функций

Глава 3.1 из монографии Жмайлова Б.Б."Моделирование технических систем на Java 2"

В начале рассмотрим построение графиков простых функций:y=x, y=x2 и y=x3 на примере разработки простого приложения. Для того чтобы немного усложнить задачу, реализуем так же следующие функциональные возможности: перемещение осей по экрану, изменение шага табуляции, что в конечном итоге изменяет масштаб изображения. Исходя из этого, окно приложения будет состоять из трех областей, в первой разместим, кнопки для реализации возможности задания типа графика функции, во второй – кнопки для масштабирования, в третьей будет осуществляться вывод графика функции. Главное окно приложения представлено на рисунке 1.


Рисунок 1. Окно приложения "Построение графика функции"

Исходя из этого код класса главного окна приложения выглядит следующим образом, листинг 1 :

Листинг 1

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

public class DirPan extends JFrame 
{
PaintGraph pg; // класс вывода графика функции
ButPan bp; // класс управляющих масштабом кнопок
RadPan rp; // класс задания функции
            public DirPan()
            {
            super("Построение графика функции");
            Container c = getContentPane();
            c.setLayout(new BorderLayout()); // установка менеджера размещения
            pg = new PaintGraph(); // инициализация класса построения графика функции
            pg.setSize(600,430); // задание размеров
            c.add(pg,BorderLayout.CENTER); // задание размещения
            bp = new ButPan(pg); // инициализация класса кнопок масштаба
            c.add(bp,BorderLayout.WEST);
            rp = new RadPan(pg); 
            c.add(rp,BorderLayout.NORTH);// инициализация класса выбора графика функции
            setSize(700,430); // задание размеров
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // задание параметров
                                                            // главного окна при закрытии
            setVisible(true);
            }
  public static void main(String[] args)
 {
  new DirPan();
 }
}

Теперь рассмотрим каждый класс, исходя из его функциональности. Класс для масштабирования графика функции, содержит восемь кнопок, с помощью которых можно перемещать оси вверх – вниз, влево – вправо, увеличивать – уменьшать шаг табуляции, уменьшать - увеличивать количество делений. Класс реализован на базе класса JPanel и интерфейса ActionListener, с помощью которого обрабатываются события "нажатия " кнопок. Также необходимо, чтобы по достижению, каких либо критических значений, касающихся параметров построения, кнопка становилась не активной, т.е. отслеживать эти параметры.

Листинг 2. Класс управляющих кнопок

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

public class ButPan extends JPanel implements ActionListener
{
 private JButton jbt1,jbt2,jbt3,jbt4,jbt5,jbt6,jbt7,jbt8;
 PaintGraph pg;
 public void actionPerformed(ActionEvent e)
 {
  if (e.getSource().equals(jbt1))
  {
   if( pg.getNy()= = 5 ) jbt2.setEnabled( true );
   pg.setNy(pg.getNy() + 5);
   pg.repaint();
  }
  if (e.getSource().equals(jbt2))
  {
   pg.setNy(pg.getNy() - 5);
   pg.repaint();
   if(pg.getNy() = = 5) jbt2.setEnabled(false);
  }
  if (e.getSource().equals(jbt3)) 
  {
   if(pg.getKy() < 1 ) jbt4.setEnabled(true);
   pg.setKy(pg.getKy() - (float)0.1);
   pg.repaint();
   if(pg.getKy()<= 0.05) jbt3.setEnabled(false);
  }
  if (e.getSource().equals(jbt4))
  {
   if(pg.getKy() >= 0) jbt3.setEnabled(true);
   pg.setKy(pg.getKy() + (float)0.1);
   pg.repaint();
   if(pg.getKy() >= 0.95) jbt4.setEnabled(false);
  }
  if (e.getSource().equals(jbt5))
  {
   if(pg.getKx() <1;) jbt6.setEnabled(true);
   pg.setKx(pg.getKx() - (float)0.01);
   pg.repaint();
   if(pg.getKx() <=0.05) jbt5.setEnabled(false);
  }
  if (e.getSource().equals(jbt6))
  {
   if(pg.getKx() >0;) jbt5.setEnabled(true);
   pg.setKx(pg.getKx() + (float)0.01);
   pg.repaint();
   if(pg.getKx() >= 0.99) jbt6.setEnabled(false);
  }
  if (e.getSource().equals(jbt7))
  {
   if(pg.getHx() >=0.01) jbt8.setEnabled(true);
   pg.setHx( pg.getHx()+(float)0.01);
   pg.repaint();
   if(pg.getHx() >= 1) jbt7.setEnabled(false);
  }
  if (e.getSource().equals(jbt8))
  {
   if(pg.getHx() <=1) jbt7.setEnabled(true);
   pg.setHx( pg.getHx()-(float)0.01);
   pg.repaint();
   if(pg.getHx() <=0.01) jbt8.setEnabled(false);
  }
 }
 public ButPan(PaintGraph p)
 {
  setLayout(new GridLayout(8,1));// Установка табличного менеджера размещения
  pg=p ;
  jbt1 = new JButton("Scale -");
  jbt2 = new JButton("Scale +");
  jbt3 = new JButton("|^");
  jbt4 = new JButton("|_");
  jbt5 = new JButton("<—");
  jbt6 = new JButton("—>");
  jbt7 = new JButton("hx+");
  jbt8 = new JButton("hx-");
  jbt1.addActionListener(this);
  jbt2.addActionListener(this);
  jbt3.addActionListener(this);
  jbt4.addActionListener(this);
  jbt5.addActionListener(this);
  jbt6.addActionListener(this);
  jbt7.addActionListener(this);
  jbt8.addActionListener(this);
  add(jbt1);
  add(jbt2);
  add(jbt3);
  add(jbt4);
  add(jbt5);
  add(jbt6);
  add(jbt7);
  add(jbt8);
 }
}

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


Рисунок 2. Выполнение граничных условий (кнопки неактивны)

Класс задания графика функции состоит из трех радио кнопок объединенных в группу, при нажатии которых вызывается метод setSw(int sw) класса PaintGraph, задающий вид функции. Данный класс реализован также на базе JPanel и размещается в верхней части главного окна, листинг приведен ниже:

Листинг 3. Класс задания графика функции

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

public class RadPan extends JPanel implements ActionListener
{
 private JRadioButton jrb1,jrb2,jrb3,;
 private ButtonGroup bg;
 PaintGraph pg;
 public void actionPerformed(ActionEvent e)
 {
// Проверяется источник генерации события, и в зависимости от него задается вид 
// графика функции
  if (e.getSource().equals(jrb1)){
   pg.setSw(1) ;
   pg.repaint();// перерисовка графика функции
  }
  if (e.getSource().equals(jrb2)) {
   pg.setSw(2) ;
   pg.repaint();
  }
  if (e.getSource().equals(jrb3)) {
   pg.setSw(3);
   pg.repaint();
  }
 }
 public RadPan(PaintGraph p)
 {
  setLayout(new FlowLayout());
  pg=p ;
  jrb1 = new JRadioButton("Линия",true);
  jrb2 = new JRadioButton("Парабола",false);
  jrb3 = new JRadioButton("Гипербола",false);
  jrb1.addActionListener(this);
  jrb2.addActionListener(this);
  jrb3.addActionListener(this);
  bg = new ButtonGroup();
  bg.add(jrb1);
  bg.add(jrb2);
  bg.add(jrb3);
  add(jrb1);
  add(jrb2);
  add(jrb3);
 }
}

Класс, который выводит график функции на экран можно условно разделить на следующие части, первая это конструктор, в котором собственно инициализируются переменные этого класса. Вторая часть – метод класса paint(), в котором выполняются основные графические построения, рисуются оси делаются под ними подписи и наносятся деления, вызываются методы рисующие график функции, в зависимости от выбора с помощью радиокнопки. Третья часть – методы, которые строят график функции. Четвертая часть – методы setXXX(), getXXX(), с помощью которых реализуется инкапсуляция, т.е. обеспечивается защита внутренних переменных класса от несанкционированного доступа из других классов. В данном случае рисование графика осуществляется отрезками, когда конец одного отрезка является началом другого. Кроме того, в связи с тем, что центр осей может перемещаться, построение выполняется в двух интервалах первый интервал – отрицательные значения по Х до 0, второй 0 – положительные значения по шкале Х, при этом абсолютные длины осей не меняются.

Листинг 5. Класс, выводящий графики функций

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

public class PaintGraph extends JPanel
{
 private int ny , nx , oyn , oyk , oyx , oxn , oxk , oxy , ly , lx , sw , xln , l2;
 private    float xng , kx , ky , hx , yg , xk;

 public PaintGraph()
 {
  ny = 10;// цена деления  по шкалам
  ky = (float)0.5; // коэф шкалы по у
  kx = (float)0.5; // коэф шкалы по x
  oyn = 50; // начальный отступ по y
  oxn = 50 ; //начальный отступ по х
  ly = 400; // длина оси у
  lx = 600; // длина оси х
  // по умолчанию в начале на экран выводится график y=x
  sw = 1; // свич для переключения графика функции
  hx = (float)0.011;//шаг табуляции
 }

 public void paint(Graphics g)
 {
  super.paint(g);
  //Разбиваем каждую ось на две части для удобства переноса центра координат
  // Ось Y
  g.drawLine( ( int ) ( lx * kx + oxn ) , oyn ,
              ( int ) ( lx * kx+ oxn ) , ly + oyn );
  // Стрелки
  g.drawLine( ( int ) ( lx * kx + oxn) , oyn ,
              ( int ) ( lx * kx + oxn ) - 3 , oyn + 10 );
  g.drawLine( ( int ) ( lx * kx + oxn) , oyn ,
              ( int ) ( lx * kx + oxn) + 3 , oyn + 10 );
  // Надпись
  g.drawString( "Y" , ( int ) ( lx * kx + oxn) - 10 , oyn + 10 );
  g.drawString( "0" , ( int ) ( lx * kx + oxn ) - 10 , ( int) ( ly * ky+ oyn) + 10 );
  //Деления
  int l1 = ( int ) (ly*ky);
  l2 = ly - l1;
  int k1 = ( int ) l1 / ny ;
  int k2 = ( int ) l2 / ny ;
  for ( int i = 1; i < k1 + 1 ; i++)
  {
   g.drawLine( ( int )(lx * kx - 2 + oxn) , l1 - ny+ oyn ,
               ( int ) ( lx * kx + 2+ oxn ) , l1 - ny+ oyn );
   l1 = l1 - ny ;
  }
  l1 = ly - l2;
  for ( int i = 1; i < k2 + 1 ; i++)
  {
   g.drawLine( ( int )(lx * kx - 2 + oxn) , l1 + ny+ oyn ,
               ( int )(lx * kx + 2+ oxn ) , l1 + ny+ oyn );
   l1 = l1 + ny ;
  }
  // Ось Х
  g.drawLine( oxn , ( int ) ( ly * ky + oyn) , lx + oxn,  ( int ) ( ly * ky + oyn)  );
  g.drawLine( lx+ oxn , ( int ) ( ly * ky + oyn ) , lx+ oxn - 10 ,
                        ( int ) ( ly * ky + oyn) - 3 );
  g.drawLine( lx + oxn, ( int ) ( ly * ky + oyn) , lx+ oxn - 10 ,
                        ( int ) ( ly * ky+ oyn ) + 3 );
  // Надпись
  g.drawString( "Х" , lx+ oyn -10 , ( int ) ( ly * ky+ oyn ) - 10 );
  // Деления
  l1 = ( int ) ( lx * kx );
  l2 = lx - l1;
  k1 = ( int ) l1 / ny ;
  k2 = ( int ) l2 / ny ;
  for ( int i = 1; i <  k1 + 1 ; i++)
  {
   g.drawLine( l1 - ny + oxn ,( int ) ( ly * ky - 2+ oyn) ,
               l1 - ny + oxn , ( int ) ( ly * ky + 2 + oyn )  );
   l1 = l1 - ny ;
  }
  l1 = lx - l2;
  double xl = l1/ny;
  double xl1 = l2/ny;
  for ( int i = 1; i < k2 + 1 ; i++)
  {
   g.drawLine( l1 + ny+ oxn ,( int )(ly* ky - 2+ oyn) ,
   l1 + ny + oxn , ( int )(ly * ky + 2+ oyn )  );
   l1 = l1 + ny ;
  }
  // Выбор метода для рисования функции
  switch (sw)
  {
   case 1 :
   funcLine(g);
   break;
 
   case 2 :
   funcPar(g);
   break;

   case 3 :
   funcGip(g);
   break;
  }
 }

 // группа методов рисующих графики функций
 // Метод рисующий линию
 
 void funcLine(Graphics g)
 {
  xln = ( lx - l2 ) ;
  xk = 0 ;
  yg = 0;
  while(   ( xk + hx )  * ny < xln  &&  ( xk + hx )* ny < ly - ly * ky )
  {
   yg =  xk  ;
   g.drawLine( ( int ) ( xln - xk * ny+ oxn ) ,
               ( int ) ( ly * ky + yg * ny + oyn),
               ( int ) ( xln -  ( xk + hx ) * ny + oxn ),
               ( int ) ( ly * ky + ( xk + hx )  * ny )+ oyn) ;
   xk = xk + hx ;
  }
  xk = 0 ;
  yg = 0;
  while(   ( xk + hx )  * ny < l2 &&  ( xk + hx )  * ny < ly * ky )
  {
   yg =  xk  ;
   g.drawLine( ( int ) ( xln + xk * ny+ oxn ) ,
               ( int ) ( ly * ky - yg * ny+ oyn ),
               ( int ) ( xln +  ( xk + hx ) * ny+ oxn ),
               ( int ) ( ly * ky - ( xk + hx )  * ny  )+ oyn) ;
   xk = xk + hx ;
  }
 }

 // Метод рисующий параболу
 void funcPar(Graphics g)
 {
  xln = ( lx - l2 ) ;
  xk = 0 ;
  yg = 0;
  int kp = 0;
  while( ( xk + hx ) * ny < xln && Math.pow ( xk + hx , 2 ) * ny < ly * ky )
  {
   g.drawLine( ( int ) ( xln - xk * ny + oxn ) ,
               ( int ) ( ly * ky - yg * ny  + oyn),
               ( int ) ( xln -  ( xk + hx ) * ny + oxn ),
               ( int ) ( ly * ky - Math.pow ( xk + hx , 2 ) * ny+ oyn) );
   xk = xk + hx ;
   yg = (float)Math.pow ( xk , 2 ) ;
   kp++;
  }
  xk = 0 ;
  yg = 0;
  while(  ( xk + hx ) * ny < l2 && Math.pow ( xk + hx , 2 )* ny < ly * ky )
  {
   yg = (float)Math.pow ( xk , 2 ) ;
   g.drawLine( ( int ) ( xln + xk * ny + oxn) ,
               ( int ) ( ly * ky - yg * ny + oyn),
               ( int ) ( xln +  ( xk + hx ) * ny+ oxn ),
               ( int ) ( ly * ky - Math.pow ( xk + hx , 2 )  * ny  )+ oyn) ;
   xk = xk + hx;
  }
 }
 // Метод рисующий гиперболу
 void funcGip(Graphics g)
 {
  xk = 0 ;
  yg = 0;
  xln = ( lx - l2 ) ;
  while(   ( xk + hx ) * ny < xln && Math.pow ( xk + hx , 3 )* ny < ly - ly * ky )
  {
   yg = (float)Math.pow ( xk , 3 ) ;
   g.drawLine( ( int ) ( xln - xk * ny+ oxn ) ,
               ( int ) ( ly * ky + yg * ny + oyn),
               ( int ) ( xln -  ( xk + hx ) * ny+ oxn ),
               ( int ) ( ly * ky + Math.pow ( xk + hx , 3 )  * ny  )+ oyn) ;
   xk = xk + hx ;
  }
  xk = 0 ;
  yg = 0;
  while(  ( xk + hx ) * ny < l2 && Math.pow ( xk + hx , 3 )* ny < ly * ky )
  {
   yg = (float)Math.pow ( xk , 3 ) ;
   g.drawLine( ( int ) ( xln + xk * ny + oxn) ,
               ( int ) ( ly * ky - yg * ny + oyn),
               ( int ) ( xln +  ( xk + hx ) * ny+ oxn ),
               ( int ) ( ly * ky - Math.pow ( xk + hx , 3 )  * ny  )+ oyn) ;
   xk = xk + hx;
  }
 }
 // группа getXXX(), setXXX() - методов
 public int getNx() {
  return nx;
 }
 public void setNx(int nx) {
  this.nx = nx;
 }
 public int getNy() {
  return ny;
 }
 public void setNy(int ny) {
  this.ny = ny;
 }
 public float getKy() {
  return ky;
 }
 public void setKy(float ky) {
  this.ky = ky;
 }
 public float getKx() {
  return kx;
 }
 public void setKx(float kx) {
  this.kx = kx;
 }
 public float getHx() {
  return hx;
 }
 public void setHx(float hx) {
  this.hx = hx;
 }
 public int getLx() {
  return lx;
 }
 public void setLx(int lx) {
  this.lx = lx;
 }
 public int getLy() {
  return ly;
 }
 public void setLy(int ly) {
  this.ly = ly;
 }
 public int getSw() {
  return sw;
 }
 public void setSw(int sw) {
  this.sw = sw;
 }
 public int getOyn() {
  return oyn;
 }
 public void setOyn(int oyn) {
  this.oyn = oyn;
 }
 public int getOxn() {
  return oxn;
 }
 public void setOxn(int oxn) {
  this.oxn = oxn;
 }
}

Как было написано выше, данный пример рисования графиков функции реализован с помощью метода drawLine(), однако могут быть использованы и другие методы класса Graphics например drawPlyline(), который будет рассмотрен в следующих главах.



Отзывы и пожелания просьба направлять по адресу [email protected]

Автор: ЖМАЙЛОВ Борис Борисович ,
Доцент кафедры «Информатика» ДГТУ,
кандидат технических наук


Питер Дж. ДеПаскуале
"Java: Карманный справочник"
Подробнее>>
Заказать>>


Н. А. Вязовик
"Программирование на Java. Курс лекций"
Подробнее>>
Заказать>>

Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Apache Struts 2.0.11
Apache MyFaces Trinidad Core 1.2.3.
Sun переводит мобильные устройства с Java ME на Java SE
Хакерская атака!