Recommended Posts

Posted

Chcę zrobić blok dynamiczny pręta do zbrojenia płyty. Pręt ma określoną długość, którą mogę rozciągać (a więc zmieniać jego długość) a prostopadle do niego mam linię wymiarową określającą jego rozstaw, którą też mogę rozciągać (też mam długość rozkładu). Po środku stoi blok z atrybutami. 

Czy mogę powiązać atrybuty bloku ze zmiennymi atrybutami? Aby blok wiedział, że zmieniła się długość pręta i wciągała do siebie jego wartość?

Macie jakiś pomysł czy można to zautomatyzować?

Posted

Nie nie, nie o to chodzi. 

No dobrze.. a można wczytać wartość długości rozciąganych elementów do VBA?

To znaczy, mam blok dynamiczny, w którym rozciągam dwie prostopadłe linie. Wartości te są edytowalne i można je zmieniać poprzez kliknięcie myszką lub wpisanie wartości. Te wartości są sobie tożsame. Czy można stworzyć makro VBA w którym to klikamy na blok i np. msgbox podaje nam wartości długości tych dwóch linii?

Posted

OK, więc w pliku blok dynamiczny, który posiada parametry rozciągania długości o nazwach Rozstaw i Dlugosc_preta (na zdjęciu w czerwonej ramce), blok będzie posiadał również atrybuty do przechowywania informacji itp. (niebieska ramka), ale o nich proszę nie myśleć - wiem jak się do nich dostać przez VBA.

Teraz pytanie, czy mogę wczytać wartości z czerwonej ramki z pod VBA i wyświetlić je w msgBox, a może mogę je też podmienić?

PS. Na początku chodziło mi o to, żeby któryś z atrybutów (z niebieskiej ramki) podczytywał na żywo po każdej zmianie długości (z czerwonej ramki)

test_blok.png

forum_cad_blok.dwg

Posted

Tak na szybko to odczytać właściwości (z niebieskiej ramki) można tak:

Public Sub test()
    Dim ss As ZcadSelectionSet
    Dim ent As ZcadEntity
    Dim bname As String
    Dim props() As ZcadDynamicBlockReferenceProperty
    Dim pvalue As Variant
    Dim blkref As ZcadBlockReference
    With ThisDrawing.SelectionSets
        While .Count > 0
              .Item(0).Delete
        Wend
        Set ss = .Add("$DynBlocks$")
    End With

    Dim ftype(0 To 1) As Integer
    Dim fdata(0 To 1) As Variant

    ftype(0) = 0: ftype(1) = 66
    fdata(0) = "INSERT": fdata(1) = 1
    ss.SelectOnScreen ftype, fdata
     
    If ss.Count = 0 Then
        MsgBox "Nie wybrano bloku...Kończymy"
        Exit Sub
    End If

    Set blkref = ss.Item(0)
    Dim i As Integer
    props = blkref.GetDynamicBlockProperties
 
    Dim prop As ZcadDynamicBlockReferenceProperty
    For i = LBound(props) To UBound(props)
        Set prop = props(i)
        pvalue = prop.Value
        Dim asTxt As String
        asTxt = CStr(pvalue)
        MsgBox (asTxt)
    Next i

End Sub

Dalej powinno już być łatwo.

Posted

Aha, elegancko.

Teraz jak już mam dostęp do bloku dynamicznego, jego parametrów i atrybutów to chodzi mi po głowie takie makro, które byłoby wczytywane wraz z oknem zwcada i śledziłoby zmianę któregokolwiek parametru (lub atrybutu) bloku o nazwie "Test_blok" i za każdym razem wyrzucałoby Msgbox typu "parametr bloku o współrzędnych x,y został zmieniony" lub "atrybut bloku o współrzędnych x,y został zmieniony". Byłby to blok superdynamiczny, który mógłby reagować na każdą zmianę :)

Jest to w ogóle możliwe? Czy takie makro ciągle działające w tle nie zajmowałoby za dużo zasobów? Co o tym myślicie? 

Posted

Tak na pierwszy rzut oka wygląda na możliwe. Ale jak zwykle diabeł tkwi w szczegółach.

Mechanizm reakcji można zrealizować przy użyciu reaktorów. Tylko nigdy nie używałem ich w VBA, nie jestem pewien czy są dostępne. Jeśliby nie były, to można taki reaktor uruchamiać w LISP a on uruchamiałby odpowiednią funkcję w VBA.

Co do zasobów to raczej byłbym spokojny, choć oczywiście wszystko zależy od stopnia skomplikowania makra i wielkości pliku. Ale to lepiej sprawdzić w boju niż zakładać że będzie zbyt obciążające. Dla każdego użytkownika taki próg bólu może być w innym miejscu.

 

Posted (edited)

LISP-em można sterować parametrami bloku dynamicznego podczas aktywności okna dialogowego. Pozwala to kontrolować wizualnie dokonane zmiany. Tutaj na szybko tylko jeden parametr:

dynamicblockdialog.gif

Edited by kojacek
Posted

Witam

kiedyś napisałem taki program który odczytuje parametry bloku dynamicznego:

sub program()

On Error Resume Next

Dim z As Double

Dim x As Double

Dim ent As ZcadEntity

Dim blk1 As ZcadBlockReference

Dim ContextData As Variant

Dim sset1 As ZcadSelectionSet

Dim dynblk As ZcadDynamicBlockReferenceProperty

Set sset1 = ThisDrawing.SelectionSets.Add("grupa1")

ThisDrawing.Utility.Prompt ("wybierz bloki dynamiczne :")
sset1.SelectOnScreen
z = ThisDrawing.Utility.GetInteger("wybierz nr. zmiennej bloku dyn : ")
z = z - 1
For Each ent In sset1
If ent.ObjectName = "AcDbBlockReference" Then
Set blk1 = ent
If blk1.IsDynamicBlock = True Then
ContextData = blk1.GetDynamicBlockProperties
Set dynblk = ContextData(z)
x = x + dynblk.Value
End If
End If
Next

ThisDrawing.Utility.Prompt ("calkowita suma współczynnika (" & dynblk.PropertyName & ") wynosi = " & x)
ThisDrawing.Utility.Prompt (" ")

end sub

teraz wystarczy go tylko przerobić do potrzeb.

zrobiłem też taki blok dynamiczny powiązany z wymiarem z nudów, może taka wersja będzie wystarczająca ??

informacja o długości pręta i rozstawienia jest wyświetlona.

pozdrawiam

 

blok_pret.dwg

Posted

Dzięki wszystkim za odpowiedzi. 

Ten etap już mamy ogarnięty. Teraz chciałem wywoływać jakąś funkcję (choćby MsgBox) VBA za każdym razem jak ten właśnie blok zmodyfikuję (rozszerzę, wydłużę)

  • 6 months later...
Posted

No dobra, pomożecie powalczyć z reaktorem? Plik z blokiem dynamicznym - bohaterem w załączniku

Procedura:

Private Sub ZcadDocument_ObjectModified(ByVal Object As Object)

    Dim ATT As ZcadAttributeReference
    Dim atts As Variant
           
        If TypeOf Object Is ZcadBlockReference Then
            Set blk = Object
            If blk.EffectiveName = "Konstruktor_dozbrojenia" Then
                atts = blk.GetAttributes
                For j = 0 To UBound(atts)
                    Set att = atts(j)
                    If j = 0 Then MsgBox "Udało się" & att.TextString
                Next

            End If
        End If
End Sub

OK, trochę dziwnie wygląda odniesienie się do atrybutu tego bloku, ale działa..  Procedura powoduje wywalenie msgboxa z pokazaniem atrybutu po każdorazowej zmianie bloku.

Zmieniona procedura:

Private Sub ZcadDocument_ObjectModified(ByVal Object As Object)

    Dim att As ZcadAttributeReference
    Dim atts As Variant
           
        If TypeOf Object Is ZcadBlockReference Then
            Set blk = Object
            If blk.EffectiveName = "Konstruktor_dozbrojenia" Then
                atts = blk.GetAttributes
                For j = 0 To UBound(atts)
                    Set att = atts(j)
                    'If i = 0 Then MsgBox "Udało się" & att.TextString
                    
                    
                    
                    
                    
                        Dim ss As ZcadSelectionSet
                        Dim ent As ZcadEntity
                        Dim bname As String
                        Dim props() As ZcadDynamicBlockReferenceProperty
                        Dim pvalue As Variant
                        Dim blkref As ZcadBlockReference
                        With ThisDrawing.SelectionSets
                            While .Count > 0
                                  .item(0).Delete
                            Wend
                            Set ss = .Add("$DynBlocks$")
                        End With
                    
                        Dim ftype(0 To 1) As Integer
                        Dim fdata(0 To 1) As Variant
                    
                        ftype(0) = 0: ftype(1) = 66
                        fdata(0) = "INSERT": fdata(1) = 1
                        ss.SelectOnScreen ftype, fdata
                         
                        If ss.Count = 0 Then
                            MsgBox "Nie wybrano bloku...Kończymy"
                            Exit Sub
                        End If
                    
                        Set blkref = ss.item(0)
                        'Dim i As Integer
                        props = blkref.GetDynamicBlockProperties
                        MsgBox props(0).Value
                        Dim prop As ZcadDynamicBlockReferenceProperty
                        'For i = LBound(props) To UBound(props) - 1
                            Set prop = props(0)
                            pvalue = prop.Value
                            Dim asTxt As String
                            asTxt = CStr(pvalue)
                            MsgBox (asTxt)
                        'Next i
                    

                Next

            End If
        End If
End Sub

Na chama wrzucone to co Kruszynski wymyślił. Tym razem procedura pokazuje długość pręta po każdorazowej zmianie. Niestety mogę się odnieść jedynie do pierwszej długości props(0), wyłączyłem pętle, bo przy props(1) wywala już błąd.

 

CEL: Po zmianie długości pręta lub wymiaru, chcę podmienić atrybut. Czuję, że jestem już blisko, ale działam na ślepo. Pomożecie?

blok.dwg

Posted

Wiem że czegoś tu nie rozumiem, ale też jeszcze nie wiem czego.

Z eksperymentu wyszło mi, że tablica

Dim prop As ZcadDynamicBlockReferenceProperty

Zwraca 8 elementów.
Te o indeksach 1,3,5,7 mają taką samą nazwę "Origin" Nie wiem dlaczego, i nie wnikam,
ale jak zmieniłem pętlę, żeby przechodziła indeksem co 2

For i = LBound(props) To UBound(props) - 1 Step 2
	Set prop = props(i)
	pvalue = prop.Value
	Dim asTxt As String
	asTxt = CStr(pvalue)
	MsgBox (asTxt)
Next i

To wyświetliło poprawnie i kulturalnie 4 wartości.

Posted

A jednak jeszcze trochę głębiej w to wniknąłem i wyszło mi że tam gdzie jest Origin

asTxt = CStr(pvalue)

Wyrzuca błąd

Run-time error '13' :

Type mismatch

w linijce

asTxt = CStr(pvalue)

Co w sumie miałby sens, bo w tym przypadku pvalue jest variantem - tablicą trzyelementową. To chyba jest jakiś punkt, A z takimi CStr może sobie nie poradzić.

Teraz pytanie co dalej z tym ma się dziać. o jeśli maa to być tylko wyświetlone, to pewnie wystarczy odwołać się do każdego elementu variantu, i poskładać to w jeden tekst. Ale to już pozostawiam, powinno być łatwe.

Posted

Tak jak pisałem, chcę odczytać tę wartość i zapisać ją w atrybucie bloku (odczytywać to, co jest w czerwonej ramce i zapisywać w niebieskiej - patrz 9 post) za każdym razem, gdy blok zostanie zmieniony.

Posted

Chyba najłatwiej tak:

Dim attribs As Variant
attribs = blkref.GetAttributes
; tu trzeba wybrać odpowiedni atrybut wybierając w pętli po TagString

For i = LBound(props) To UBound(props) - 1
	Set prop = props(i)
    If prop.PropertyName = "Rozstaw" Then
    	; a tu ustawić wartość (TextString) atrybutu
    End If
Next i

 

 

Posted

Tak też o tym myślałem. Tak będę kombinował

Do stworzenia superbloku potrzebne mi jeszcze kilka patentów.

1. Jaka komenda vba poda mi współrzędne zaznaczonego bloku?

2. Czy istnieje możliwość podania współrzędnych w jakiejś funkcji a funkcja zwróci nazwy wszystkich bloków występujących w tym punkcie i je zaznaczy?

3. Czy jest możliwość zaingerowania w blok nie edytując go. Na przykład po spełnieniu określonego warunku wszystko co jest wewnątrz bloku zmieni kolor na żółty.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...