Սկիզբ » Ուսումնական նյութեր » Ծրագրավորում » Ծրագրավորման լեզուներ » Java » Ինչպե՞ս Java ծրագիրն ընդլայնել սկրիպտերով

Ինչպե՞ս Java ծրագիրն ընդլայնել սկրիպտերով

| Սեպտեմբեր 22, 2012 | Մեկնաբանված չէ |

Ներածություն

Իմ նպատակն է ցուցադրել, թե ինչես կարելի է Java լեզվով գրված ծրագրի ֆունկցիոնալությունն ընդլայնել սկրիպտային մեխանիզմի միջոցով՝ օգտագործողին տալով գործողությունների մեծ ազատություն: Որպես մոդել դիտարկում եմ JPanel-ի վրա հատվածների միջոցով տարբեր երկրաչափական պատկերների ստացման խնդիրը:

Եթե չօգտագործվեր սկրիպտային մեխանիզմը, ապա կամայական պատկեր ստանալու համար կան հետևյալ եղանակները.

  • Նախատեսել ստանդարտ գործողություններ, որոնք օգտագործողին մատչելի կլինեն որպես մենյուի կամ գործիքների տողի գործողություններ: Այս դեպքում օգտագործողը ստիպված կլինի մկնիկով բազմաթիվ գործողություններ կատարել, իսկ կառուցված պատկերի համար մեծ ճշտություն ստանալն էլ դժվար կլինի:
  • Նախագծել մի նոր, հատկապես տվյալ խնդիրը սպասարկելու համար նախատեսված լեզու, որն իր հրամանների համակարգում կունենա գրաֆիկական պրիմիտիվներ (տվյալ դեպքում՝ հատված) պատկերելու հրամաններ: Այս դեպքում էլ ստիպվալ կլինենք գրաֆիկական պրիմիտիվներից բացի իրականացնել ալգորիթմներ կազմելու համար անգրաժեշտ հրահանգները՝ պայման, ցիկլ, ֆւնկցիաներ կամ պրոցեդուրաներ և այլն:

Իմ կարծիքով, նպատակահարմար է Java-ի գրաֆիկական միջոցներով (այս դեպքում՝ Swing) իրականացնել տրված սկզբնակետի ու վերջնակետի կոորդինատներ ունեցող հատված պատկերման կոդը (ես դա արել եմ JPanel-ի ընդլայնմամբ), ապա սկրիպտային լեզվով (այս դեպքում՝ Armed Bear Common Lisp) իրականացնել մյուս բոլոր անհրաժեշտ գրաֆիկական հրամանները:

Հատվածների պատկերում

Հատվածները պատկերելու համար ընդլայնվել է JPanel դասը: Եթե խոսենք ավելի հասկանալի տերմիններով, ապա paintComponent մեթոդում իրականացված է գրաֆիկական հրամանների վիրտուալ մեքենա, որը կատարում է երկու հրաման՝ հատվածի պատկերում և գույնի ընտրություն:

package jrobot;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

public class RobotField extends JPanel {
    /**/
    private CommandList commands = null;

    /**/
    public RobotField()
    {
        setBackground(Color.white);
    }

    /**/
    public void draw(CommandList com)
    {
        commands = com;
        repaint();
    }

    /**/
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if( null == commands ) return;
        int index = 0;
        while( index < commands.size() ) {
            if( commands.get(index) == CommandList.O_LINE ) {
                g.drawLine(commands.get(index+1), commands.get(index+2), commands.get(index+3), commands.get(index+4));
                index += 5;
            }
            else if( commands.get(index) == CommandList.O_COLOR ) {
                g.setColor(new Color(commands.get(index+1), commands.get(index+2), commands.get(index+3)));
                index += 4;
            }
        }
    }
}

paintComponent մեթոդը ենթադրում է, որ commands ցուցակում հանդիպող թվերից առաջինը գործողությանա կոդն է, իսկ նրան հաջորդողներն արգումենտներն են՝ համապատասխան քանակով: Այս իրականացման մեջ հատվածի (O_LINE) գործողությունն օգտագործում է իրեն հաջորդող չորս թվերը, իսկ գույնի (O_COLOR) ընտրման գործողությունը՝ իրեն հաջորդող երեք թվերը:

commands-ը CommandList դասին պատկանող օբյեկտ է: Այդ դասը ArrayList<Integer> ցուցակի ընդլայնումն է, որտեղ ավելացրած են երկու մեթոդներ՝ addLine և addColor, պարզապես աշխատանքի հարմարության համար:

package jrobot;

import java.util.ArrayList;

public class CommandList extends ArrayList<Integer> {
    public static final int O_LINE = 0x01;
    public static final int O_COLOR = 0x02;

    /**/
    public void addLine(int x0, int y0, int x1, int y1)
    {
        add(Integer.valueOf(O_LINE));
        add(Integer.valueOf(x0));
        add(Integer.valueOf(y0));
        add(Integer.valueOf(x1));
        add(Integer.valueOf(y1));
    }

    /**/
    public void addColor(int r, int g, int b)
    {
        add(Integer.valueOf(O_COLOR));
        add(Integer.valueOf(r));
        add(Integer.valueOf(g));
        add(Integer.valueOf(b));
    }
}

Ահա այսքանը բավարար է հատվածների պատկերումն ապահովելու համար:

JSR-223 մեխանիզմի օգտագործումը

JSR-223 մեխանիզմը հնարավորություն է տալիս Java ծրագրերում օգտագործել ստրիպտային լեզուների ամբողջ հզորությունը: Բնականաբար այստեղ ես չեմ ներկայացնի այդ մեխանիզմի բոլոր հնարավորությունները, այլ կպատմեմ, թե ինչպես է օգտագործվել Armed Bear Common Lisp (ABCL) լեզուն գրաֆիկական հրամաններ ստեղծելու համար:

ABCL-ի ինտերպրետատորը ծրագրում օգտագործելու համար MainWindow դասում նախատեսված է հետևյալը.

private ScriptEngine engine = null;

engine օբյեկտը ստեղծվում է createInterpreter մեթոդով, որը նախ ստեղծում է Lisp-ի ինտերպրետատորը, ապա բեռնում է համակարգի ինիցալիզացիայի drawersetup.lisp ֆայլը (այդ ֆայլի մասին՝ ստորև).

private void createInterpreter()
{
    ScriptEngineManager factory = new ScriptEngineManager();
    engine = factory.getEngineByName("ABCL");
    try {
        engine.eval(new FileReader("drawersetup.lisp"));
    }
    catch(Exception ex) { 
        System.err.println(ex.getMessage()); 
    }
}

ScriptEngineManager դասի getEngineByName մեթոդը ստեղծում է տրված անունով լեզվի ինտերպրետատոր այն դեպքում, երբ համակարգին հասանելի է համապատասխան լեզվի իրականացման jar ֆայլը. տվյալ դեպքում դա abcl.jar ֆայլն է:

Երբ օգտագործողը սկրիպտի համար նախատեսված տեքստային դաշտում հավաքում է Lisp ծրագիրը, կամ բացում է նախապես պատրաստված ֆայլը, և ընտրում է Script մենյուի Draw հրամանը, ապա կատարվում է runLispScript մեթոդը, որը.
  1. ստեղծում է նոր CommandList օբյեկտ,
  2. այդ օբյեկտը հասանելի է դառնում Lisp-ի ինտերպրետատորին *commands* անունով,
  3. ինտերպրետատորին կատարման է տալիս սկրիպտի դաշտի պարունակությունը,
  4. JPanel-ի նմուշին է փոխանցվում արժեքներով լցված ցուցակը:

private void runLispScript()

{
    CommandList test = new CommandList();
    engine.put("*commands*", test);
    try { 
        engine.eval(scriptCode.getText());
    }
    catch(Exception ex) { 
        JOptionPane.showMessageDialog(this, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    }
    robotField.draw(test);
}

Գրաֆիկական հրամանները Common Lisp լեզվով

Քանի որ վիրտուալ մեքենան “հասկանում” է միայն հատվածի պատկերման և գույնի ընտրության հրամանները, ապա մնացած ամբողջ աշխատանքը, այն է՝ տարատեսակ գրաֆիկական նրամանների կաուցումը, պետք իրականացնել Lisp-ով:
drawersetup.lisp ֆայլում սահմանված են ստրուկտուրաներ, ֆունկցիաներ ու մակրոսներ, որոնք օգտագործողին հնարավորություն են տալիս երկրաչափական (գրաֆիկական) պատկերներ կառուցել աշխատանքի համար ավելի հարմար տեսքով: Այն էլեմենտները, որոնք կողմնակի ազդեցություն չեն թողնում, սահմանված են որպես ֆունկցիաներ, մյուսները՝ որպես մակրոսներ:
Եվ այսպես, նախ սահմանենք դեկարտյան կետը մոդելավորող ֆունկցիան.
(defstruct point x y)
+start-point+ հաստատունով նշենք (0,0) կետը.
(defconstant +start-point+ (make-point :x 0 :y 0))
Սահմանենք նաև երկու ֆունկցիաներ, որոնցից առաջինը վերադարձնում է տրված կետի շեղումը ըստ dx և dy դեկարտյան տարբերության,
(defun point-translate-cart (p dx dy)
  (make-point :x (+ dx (point-x p)) :y (+ dy (point-y p))))
Իսկ մյուսը վերադարձնում է տրված կետի շեղումը ըստ angle և dist բևեռային տարբերության (անկյունները տրվում են աստիճաններով).
(defun point-translate-polar (pos angle dist)
  (let* ((rad (/ (* pi angle) 180))
  (dx (truncate (* dist (cos rad))))
  (dy (truncate (* dist (sin rad)))))
  (point-translate-cart pos dx (* -1 dy))))
Գույնի մոդելը պարզապես կարմիր, կանաչ և կապույտ գույների միավորումն է.
(defstruct color red green blue)
(defconstant +black+ (make-color :red 0 :green 0 :blue 0))
(defconstant +white+ (make-color :red 255 :green 255 :blue 255))
Հատվածի մոդելը ներկայացված է նրա ծայրակետերի կոորդինատներով
(defstruct segment begin end)
segment-from-turn-go ֆունկցիան վերադարձնում է մի հատված, որի սկզբնակետը տրված է, իսկ վերջնակետը համընկնում է սկզբնակետը տրված անկյամբ ու հեռավորությամբ տեղաշարժած կետին.
(defun segment-from-turn-go (pos ang dis)
  (make-segment :begin pos :end (point-translate-polar pos ang dis)))

;;;
;;; Position and direction.
;;;
(defvar *position* +start-point+)
(defvar *direction* 0)

;;;
;;; Drawing commands (predefined primitives).
;;;

(defmacro reset ()
  `(progn (setf *position* +start-point+)
   (setf *direction* 0)))

(defmacro pen-up ()
  `(jcall "addColor" *commands* 255 255 255))

(defmacro pen-down ()
  `(jcall "addColor" *commands* 0 0 0))

(defmacro set-angle (alpha)
  `(setf *direction* ,alpha))

(defmacro turn (alpha)
  `(set-angle (rem (+ *direction* ,alpha) 360)))

(defmacro jump-to (nx ny)
  `(setf *position* (make-point :x ,nx :y ,ny)))

(defmacro move (dist)
  `(let* ((seg (segment-from-turn-go *position* *direction* ,dist))
          (be (segment-begin seg))
          (en (segment-end seg)))
     (jcall "addLine" *commands* (point-x be) (point-y be) (point-x en) (point-y en))
     (setf *position* en)))

(defmacro turn-and-go (ang dis)
  `(progn (set-angle ,ang) (move ,dis)))
(defmacro right (dist)
  `(turn-and-go 0 ,dist))
(defmacro left (dist)
  `(turn-and-go 180 ,dist))
(defmacro up (dist)
  `(turn-and-go 90 ,dist))
(defmacro down (dist)
  `(turn-and-go 270 ,dist))
(defmacro down-right (dist)
  `(turn-and-go 315 ,dist))
(defmacro up-right (dist)
  `(turn-and-go 45 ,dist))
(defmacro down-left (dist)
  `(turn-and-go 225 ,dist))
(defmacro up-left (dist)
  `(turn-and-go 135 ,dist))
Ինչպե՞ս Java ծրագիրն ընդլայնել սկրիպտերով, 10.0 out of 10 based on 6 ratings

Նշագրեր: , , ,

Բաժին: Java, Lisp և Common Lisp

Կիսվել , տարածել , պահպանել

VN:F [1.9.20_1166]
Rating: 10.0/10 (6 votes cast)

Մեկնաբանեք

Կհաստատվեն միայն մեսրոպատառ հայերենով գրած մեկնաբանությունները

234