Pomoc pro ztracené programátory - práce s reaktorem

Vytvoření dialogového okna

Při tvorbě uživatelského rozhraní využívejte maximálně obrázku výsledného dialogového okna. Všímejte si hlavně hierarchického uspořádání jednotlivých prvků. Uspořádání vám pomůže při vlastní tvorbě dialogu.

Návod pro tvorbu jednotlivých částí aplikace

Aplikaci je výhodné rozdělit na několik funkcí. Každá funkce bude plnit ucelenou činnost. Jednotlivé funkce budou plnit následující úlohu:

Další doporučení:

Vysvětlený kód funkce

Pro uživatele, kteří zabloudili při tvorbě kódu uvádíme jednotlivé ucelené části kódu. Pokud si nebudete jisti funkcí některého příkazu, stačí kliknout nad příkazem a zobrazí se Vám referenční příručka se zobrazeným příkazem.

Kód dialogového okna

Při tvorbě dialogového okna si pozorně prostudujte obrázek výsledného dialogu!

  dialogBox:dialog {                       // jméno dialogového boxu
    label = "Dialog - parametry kvádru";   // popis dialogového prvku
    :boxed_column {                        // organizováno do sloupců
      label = "Nastavení parametrů prvku"; // popis orámované oblasti
      :boxed_column {                 // organizace do sloupců
        label = "Nastavení středu";   // popis 
        :edit_box {                   // prvek edit_box
          label = "Souřadnice x: ";   // popisek
          key = "stredx";             // klíč
          edit_width = 10;            // šířka prvku
        }
        :edit_box {                   // prvek edit_box
          label = "Souřadnice y: ";   // popisek
          key = "stredy";             // klíč
          edit_width = 10;            // šířka prvku
        }
        :edit_box {                   // prvek edit_box
          label = "Souřadnice z: ";   // popisek
          key = "stredz";             // klíč
          edit_width = 10;            // šířka prvku
        }
        :button  {                    // prvek tlačítko
          label = "Ruční nastavení";  // popisek
          key = "stred_but";          // klíč
          fixed_width = true;         // použít fixní velikost
          width = 10;                 // šířka prvku
          alignment = centered;       // centrovat na střed
        }
      }
      :edit_box {                     // prvek edit_box
        label = "Délka kvádru: ";     // popisek
        key = "delka";                // klíč
        edit_width = 10;              // šířka prvku
      }
      :edit_box {
        label = "Šířka kvádru: ";     // popisek
        key = "sirka";                // klíč
        edit_width = 10;              // šířka prvku
      }       
      :edit_box {
        label = "Výška kvádru: ";     // popisek
        key = "vyska";                // klíč	
        edit_width = 10;              // šířka prvku
      } 
    }
    ok_cancel;                        // tlačítka OK a Cancel
  }

Kód aplikace reaktorBox

Funkce výsledné aplikace uvádíme v pořadí, v jakém je nutné uvést funkce v souboru. V jiném pořadí uložení funkcí by mohlo dojít k výskytu chyb.

Na začátku souboru musíme aktivovat podporu funkcí ActiveX a reaktorů:

    (vl-load-com)            ;;; nahrání podpory reaktorů


První funkcí uvedenou v souboru je obslužná funkce reaktoru. Reaktor bude typu object reaktor. Hlavička funkce musí obsahovat:

V těle funkce musíme pro jistotu otestovat (pomocí funkce vlax-property-available-p) zda objekt předaný reaktorem (volajObj) obsahuje vlastnost, kterou potřebujeme využívat. Pokud objekt vlastnost obsahuje určíme objem nového a původního objektu. Původní objem máme uložený v paměti reaktoru reactorObj. Nakonec funkce vypočítá kolikrát je nový objekt menší nebo větší než objekt původní. Výsledek zobrazí pomocí jednoduchého dialogového prvku.

  (defun  rb:infoBox(volajObj reactorObj paramList 
     / objemNovy objemStary)
         ;;; obslužná funkce reaktoru, reagující na změnu rozměrů 
         ;;; kvádru
    (if (vlax-property-available-p volajObj "Volume")
         ;;; kontrola, zda objekt, který způsobil vyvolání 
         ;;; obslužné fce. obsahuje vlastnost obsah
      (progn
        (setq objemNovy (vla-get-volume volajObj))  
           ;;; zjistí se nový obsah
        (setq objemStary (vlr-data reactorObj))
           ;;; zjistí se starý obsah
        (if (> objemNovy objemStary)    
                             ;;; určí se zda jde o zvětšení/zmenšení
          (alert         ;;; zobrazí se zpráva
            (strcat "Objem krychle se zvětšil "
              (rtos (/ objemNovy objemStary)) " krát."
            )
          )
          (alert
            (strcat "Objem krychle se zmenšil "
              (rtos (/ objemStary objemNovy)) " krát."
            )
          )
        )
        (vlr-data-set reactorObj objemNovy)  
              ;;; nakonec se aktualizuje hodnota v datech reaktoru
              ;;; pro další použití
      )
    )
  )

Hlavní funkce musí být deklarovaná s prefixem c: (c:reaktorBox). Prefix zajistí možnost spuštění funkce v prostředí AutoCADu jako příkazu (nemusí se uvádět závorky). Ve funkci c:reactorBox() deklarujeme globální proměnnou gl_pam_hodnoty typu asociační seznam. Do globální proměnné uložíme inicializační hodnoty dialogových prvků. Dále otestujeme jestli byly hodnoty v dialogovém boxu zadány korektně. Jestli ano (funkce rb:dialog vrací true) zavolá se funkce rb:kresli_box. Jakmile funkce dokončí činnost, zobrazí informaci o aktivaci reaktoru.

  (defun c:reaktorBox ()
      ;;; definice nové funkce spustitelné jako příkaz AutoCADu
      ;;; funkce vykreslí kvádr a přidruží k němu reaktor 
      ;;; odchytávající změnu velikosti kvádru
    (setq	gl_pam_hodnoty	   ;;; globální proměnná uchovávající 
                               ;;; jednotlivá nastavení, proměnná
                               ;;;  je typu asociační seznam
      (list
        (cons "stredx" "0.0")  ;;; x-ova souřadnice středu kvádru
        (cons "stredy" "0.0")  ;;; y-ova souřadnice středu kvádru
        (cons "stredz" "0.0")  ;;; z-ova souřadnice středu kvádru
        (cons "delka"    "1")   ;;; délka kvádru
        (cons "sirka"    "1")    ;;; sirka kvádru
        (cons "vyska"    "1")  ;;; vyska kvádru
      )
    )
    (if	(= (rb:dialog) T) ;;; je-li dialogový box řádně ukončen,
      (rb:kresli_box)           ;;; zavolej funkci pro vykreslení
                                             ;;; požadovaného objektu
    )
    (princ "Funkce dokončila činnost, reaktor je aktivní.")
    (princ)                   ;;; výpis informací o ukončení funkce
  )

Funkce rb:dialog nejprve načte dialog ze souboru dialogBox.dcl. Ukazatel na dialog si uloží do proměnné id. Dále je funkcí nastavena proměnná co_delat na hodnotu 2 (znamená setrvej ve smyčce). Program vstoupí do smyčky while, otestuje zda načtený soubor obsahuje dialog se jménem "dialogBox". Pokud ne program skončí. Dále jsou v programu nastaveny pomocí funkce set_tile všechny prvky dialogového panelu. Získání hodnot z dialogových prvků zajišťují funkce action_tile vyvolané při akci na dialogovém prvku. Při stisku tlačítka je zavolán příkaz done_dialog s parametrem určujícím další činnost. Příkaz star_dialog je zastaven a do proměnné co_dělat vrátí hodnotu, s kterou byl vyvolán příkaz done_dialog. Podle hodnoty uložené v proměnné co_dělat se určí další činnost.

Dále je testována podmínka cond . Spustí se přiřazená funkce . Po jejím skončení se běh programu vrátí na začátek smyčky, je zkontrolována správnost načteného dialogu a dialog je opět zobrazen příkazem start_dialog. Tato činnost se opakuje do té doby než je vyvolána funkce done_dialog s parametrem < 2. Dialog je odstraněn z paměti a je vrácena návratová hodnota.

  (defun rb:dialog (/ id co_delat vysledek)
         ;;; funkce pro obsluhu dialogového boxu
    (setq id (load_dialog "D:/dialogBox.dcl"))	
                           ;;; předání jména dialogového boxu
    ;;; CESTU K UMÍSTĚNÍ DIALOGU  JE NUTNO AKTUALIZOVAT PODLE 
    ;;; AKTUALNÍHO UMÍSTĚNÍ
       
    (setq co_delat 2)
    (while (>= co_delat 2) ;;; opakuj pokud nenastane zmena
      (if	(not (new_dialog "dialogBox" id))
        (exit)             ;;; není-li jméno dialogu vyber tak skonči
      )
                             ;;; nastavení hodnot dialogových prvků
      (set_tile "delka"  (cdr (assoc "delka"  gl_pam_hodnoty)))
      (set_tile "sirka"  (cdr (assoc "sirka"  gl_pam_hodnoty)))
      (set_tile "vyska"  (cdr (assoc "vyska"  gl_pam_hodnoty)))
      (set_tile "stredx" (cdr (assoc "stredx" gl_pam_hodnoty)))
      (set_tile "stredy" (cdr (assoc "stredy" gl_pam_hodnoty)))
      (set_tile "stredz" (cdr (assoc "stredz" gl_pam_hodnoty)))

      ;;; získání hodnot z dialogových prvků a 
      ;;; jejich uložení do globální proměnné gl_pam_hodnoty
      (action_tile "stredx"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"stredx\" $value)
            (assoc \"stredx\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "stredy"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"stredy\" $value)
            (assoc \"stredy\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "stredz"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"stredz\" $value)
            (assoc \"stredz\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "delka"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"delka\" $value)
            (assoc \"delka\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "sirka"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"sirka\" $value)
            (assoc \"sirka\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "vyska"
        "(setq gl_pam_hodnoty
          (subst
            (cons \"vyska\" $value)
            (assoc \"vyska\" gl_pam_hodnoty)
            gl_pam_hodnoty
          )
        )"
      )
      (action_tile "stred_but" "(done_dialog 4)")
          ;;; je-li zmáčknuto tlačítko "stred_but" zavolej
          ;;; funkci done_dialog s hodnotou 4
      (action_tile "accept" "(done_dialog 1)")
          ;;; je-li zmáčknuto tlačítko "accept"
          ;;; zavolej funkci done_dialog s hodnotou 1
      (action_tile "cancel" "(done_dialog 0)")
          ;;; je-li zmáčknuto tlačítko "cancel"
          ;;; zavolej funkci done_dialog s hodnotou 0
  
      (setq co_delat (start_dialog))
              ;;; nastaví proměnnou na hodnotu získanou 
              ;;; od funkce start_dialog (hodnota s kterou
              ;;; končí funkce done_dialog)
      (cond	  ;;; určení další činnosti
        ((= co_delat 0) (setq vysledek nil))	
              ;;; uživatel stornoval dialog,
              ;;; ukonči funkci s hodnotou nil
        ((= co_delat 1) (setq vysledek T))	
              ;;; uživatel potvrdil dialog, 
              ;;; ukonči funki s hodnotou T
        ((= co_delat 4) (rb:nastav_stred 
                           (getpoint "\nVýběr bodu:")
                        )
        )      ;;; uživatel zmáčkl tlačítko pro zadání 
               ;;; souřadnic středu zavolej funkci 
               ;;; rb:nastav_stred
      )
    )
    (unload_dialog id)	;;; odstraň dialog id z paměti
    vysledek  ;;; návratová hodnota funkce (T = uživatel zadal
                        ;;; hodnoty a potvrdil dialog, jinak se vrací nil)
  )

Funkce rb:nastav_stred zajistí nastavení hodnot souřadnic středu tělesa po zadání středu pomocí tlačítka Ruční nastavení. Nejprve jsou získány hodnoty jednotlivých souřadnic z proměnné stred. Každá souřadnice je převedena na řetězec a uložena do globální proměnné gl_pam_hodnoty.

  (defun rb:nastav_stred (stred / stredx stredy stredz)
        ;;; funkce nastavující hodnoty jednotlivých
        ;;; souřadnic při stisku tlačítka pro zadání
        ;;; středu do globální proměnné gl_pam_hodnoty
    (setq stredx (strcat (vl-princ-to-string (car stred))))
    (setq stredy (strcat (vl-princ-to-string (cadr stred))))
    (setq stredz (strcat (vl-princ-to-string (caddr stred))))

    (setq gl_pam_hodnoty
      (subst
        (cons  "stredx" stredx)
        (assoc "stredx" gl_pam_hodnoty)
        gl_pam_hodnoty
      )
    )
    (setq gl_pam_hodnoty
      (subst
        (cons  "stredy" stredy)
        (assoc "stredy" gl_pam_hodnoty)
        gl_pam_hodnoty
      )
    )
    (setq gl_pam_hodnoty
      (subst
        (cons  "stredz" stredz)
        (assoc "stredz" gl_pam_hodnoty)
        gl_pam_hodnoty
      )
    )
  )

Funkce rb:kresli_box zajišťuje vykreslení kvádru a vytvoření objektu reaktoru, který reaguje na změny velikosti kvádru. Ve funkci nejdříve zjistíme pointr na objekt application AutoCAD. Abychom mohli přidávat do modelového prostoru výkresu objekty, musíme nejprve zjistit pointer na aktivní dokument a poté pointer do modelového prostoru. Před vytvořením objektu kvádr musíme zjistit všechny potřebné parametry (stred, delka, sirka a vyska). Všechny parametry zjistíme z globální proměnné gl_pam_hodnoty. Vytvoříme nový objekt kvádru a pointer na vytvořený objekt přiřadíme do proměnné objBox. Pomocí pointru na nový objekt zjistíme objem nového kvádru. Vykreslený objekt (kvádr) zvětšíme, aby byl dobře viditelný. Nakonec funkce vytvoříme objekt reaktoru.

  (defun rb:kresli_box (/ stred delka vyska sirka objBox objemPuvodni)
         ;;; funkce vytvářející kvádr a objekt reaktoru
    (setq acadObjekt (vlax-get-acad-object)) 
         ;;; nastavení pointru na objekt application AutoCAD
    (setq acadDokument (vla-get-ActiveDocument acadObjekt))
         ;;; nastavení pointru na aktivní dokument
    (setq modelProstor (vla-get-ModelSpace acadDokument)) 
         ;;; nastavení pointru na modelový prostor dokumentu

    (setq stred
      (list
        (atof (cdr (assoc "stredx" gl_pam_hodnoty)))
        (atof (cdr (assoc "stredy" gl_pam_hodnoty)))
        (atof (cdr (assoc "stredz" gl_pam_hodnoty)))
      )
    )	  ;;; převod tří řetězců reprezentujících souřadnice
        ;;; do proměnné stred (položky stred jsou typu float)
    (setq delka (atof (cdr (assoc "delka" gl_pam_hodnoty))))
        ;;; získání délky krychle z asoc. seznamu gl_pam_hodnoty  
    (setq sirka (atof (cdr (assoc "sirka" gl_pam_hodnoty))))
        ;;; získání šířky krychle z asoc. seznamu gl_pam_hodnoty  
    (setq vyska (atof (cdr (assoc "vyska" gl_pam_hodnoty))))
        ;;; získání výšky krychle z asoc. seznamu gl_pam_hodnoty  

    (command)	;;; ukončení všech předchozích příkazů
    (setq objBox
      (vla-addBox modelProstor
        (vlax-3d-point stred) delka sirka vyska
      )
    )          ;;; vykreslení kvádru v modelovém prostoru

    (setq objemPuvodni (vla-get-volume objBox))
               ;;; získání objemu kvádru, objem je následně
               ;;; uložen do reaktoru jako doplňková data
    (command "_zoom" "M")     ;;; zvětšení výkresu
    (setq boxReaktor (vlr-object-reactor (list objBox)
      objemPuvodni '((:vlr-modified . rb:infoBox)))
    )          ;;; vytvoření objektu reaktoru, reagujícího
               ;;; na modifikaci kvádru
  )

Na konci souboru, který je nahrán jako poslední, je výhodné uvést informaci, jak spustit aplikaci v AutoCADu. Informace se zobrazí po nahrání funkce v příkazovém řádku.

  ;;; nakonec zobrazíme informaci pro uživatele
  (princ "\nNezapomeňte nastavit správnou cestu 
          k dialogu ve funkci rb:dialog!!!"
  )
  (princ "\nFunkce se spustí příkazem
          (c:reaktorBox) v IDE Visual LISPu"
  )
  (princ "\nFunkce se spustí příkazem 
          reaktorBox v AutoCADu"
  )

Zdrojové kódy