Reactor e Xdata; Coisas de doido

Por estes dias me perguntaram como usar reactors. Bem, não é complicado, mas o help não ajuda muito... enfim... Considere o exemplo abaixo:

;nome da xdata
(setq xdata:nome "TESTEXDATAREACTOR")

;carrega funções vl*
(vl-load-com)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para adicionar xdata na entidade
;ent -> ename, por exemplo: <Entity name: 7ffff4104e0>
;xdappname -> string, nome da xdada
;xdata elista da xdata, formato:
;((ExtendDataDxfCode . Valor) ... (ExtendDataDxfCode . Valor))
(defun xdata->put  (ent xdappname xdata / elist)
  ;garanta que o nome da xdata esta no banco de dados do cad
  (regapp xdappname)
  

  ;adiciona a xdata no elist da entidade
  (setq elist (entget ent)
    elist (cons (list -3 (cons xdappname xdata)) elist))

  ;atualiza a entidade
  (entmod elist)
  (
entupd ent)
  )


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;reactor para ação da linha sendo modificada
;note que este reactor não causa modificações na LINHA, apenas no texto
;se fazemos um reactor causar modificações em algo que dispara reactors,
;temos de desabilitar eles antes de modificar
;parametros:
;linha, é o objeto que notificou o reactor, no caso a linha
;rea, é o ponteiro para o objeto do reactor
;par, são parâmetros adicionais que podem ser passados ao reactor
;na hora que o criamos, no caso, não passamos nenhum dado extra
;então não usamos o seu valor, que será nil
(defun reactor->modified (linha rea par / params texto)
  ;obter os dados do reactor. note que não seria necessario
  ;pois poderiamos encontrar o texto pelo xdata.
  ;no caso é só para mostrar o uso da função vlr-data
  ;para obter o texto pela xdata, veja a subrotina reactors->aciona
  (setq params (vlr-data rea)
    texto  (car params))

  ;atualizar o conteudo do texto:
  (vla-put-textstring
    texto
    (strcat "l=" (rtos (vla-get-length linha) 2 2)))

  (
vla-put-insertionpoint texto (vla-get-startpoint linha))
  )


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;subrotina para "ligar" os reators para as linhas já desenhadas
;em um desenho com o nosso novo comando "teste"
(defun reactors->aciona (/ ss ent linha xdata texto)
  ;seleção das linhas que tem a nossa xdata
  (setq ss (ssget "X" (list
            '(0 . "LINE")
            (
list -3 (list xdata:nome)))))

  ;se ela existir, processa as linhas
  (if ss
    (repeat (sslength ss)

      ;pega a primeira linha
      (setq ent   (ssname ss 0) ;ename
        linha (vlax-ename->vla-object ent) ;ename para vla
        xdata (assoc -3 (entget ent (list xdata:nome))) ;xdata da linha
        ;agora, pega o handle, que é string, acha o ename e obtem o vla
        texto (vlax-ename->vla-object (handent (cdr (cadadr xdata))))
        )



      ;cria o reactor para a linha
      (vlr-object-reactor
          (list linha) ;objeto modificado que notifica o reactor
          (list texto) ;parametros a serem passados
          '((:vlr-modified . reactor->modified)))

      ;tira a linha da seleção e reinicia o looping
      (ssdel ent ss)
      )
    )

  ;perfumaria:
  (princ "\nReactors criados")
  )




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;função principal
(defun c:teste (/ linha texto pa pb thisdrawing model xdata)

  ;desenha uma lina e um texto no modelspace:
  (setq pa          (getpoint "\nPa")
    pb          (getpoint pa "\nPb")
    

    ;obtem o ponteiro para o modelspace
    thisdrawing (vla-get-activedocument(vlax-get-acad-object))
    model       (vla-get-modelspace thisdrawing)

    ;cria uma linha no model
    linha       (vla-addline model
              (vlax-3d-point pa)
              (
vlax-3d-point pb))

    ;cria um texto no model
    texto       (vla-addtext model
              (strcat "l=" (rtos (vla-get-length linha) 2 2))
              (
vlax-3d-point pa)
              4)
     )


  ;vincula a linha ao texto usando um xdata
  ;1005 é o dxfcode de xdata para "handle" da entidade
  (xdata->put
    (vlax-vla-object->ename linha) ;ename da linha
    xdata:nome ;nome da xdata
    (list (cons 1005 (vla-get-handle texto))) ;a xdata propriamente dita
    )
  


  ;cria um reactor para linha, associando ao evento de modificar a linha
  (vlr-object-reactor
          (list linha) ;objeto modificado que notifica o reactor
          (list texto) ;parametros a serem passados
          '((:vlr-modified . reactor->modified) ;evento a ser chamado ao disparar o reactor
        ))

  ;perfumaria
  (princ "\nFeito")
  )



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;sempre que a lisp for carregada com APPLOAD,
;será acionada a função 'reactors->aciona' para "ligar" os reactors nas linhas criadas
;com o comando que criamos
(reactors->aciona)


O exemplo pede dois pontos, por ele faz passar uma linha e cria um texto no inicio da linha.

Na linha, cria um vinculo com o texto atravez de xdata.

Por fim, cria um reactor, que é um evento. Este evento modifica o conteúdo e a posição do texto conforme modificamos a linha. Simples, não?

O evento que você informa no reactor é monitorado pelo cad e quando acontece o evento, o reactor dispara uma função que informamos.

Igual aos eventos do VBA ou VB. Claro que o exemplo é bem simples, ainda falta monitorar o que acontece se apagamos o texto por exemplo.

O reactor não teria o que atualizar e um erro seria mostrado.

Outro exemplo: Se copiássemos a linha, o texto também poderia ser copiado.....

Outro exemplo: Se editássemos o texto, o reactor não faria nada até modificar a linha.
Neste caso, poderíamos monitorar edições no texto.

Se o fizermos, temos de ter em mente que se precisar modificar o texto, o reactor que o monitora precisa ser desligado antes de editar ele....

Para esta situação, procure por reactor no meu blog. Tem algumas rotinas bem legais!!!

Nenhum comentário:

Postar um comentário