Bonjour
J'ai un dessin contenant un Xref. Ce dernier a pour particularité qu'il change de nom assez souvent.
Ma question est la suivante : comment faire pour garder le lien entre les 2, sans tenir compte du nom ?
Pour être honnête, je ne sais même pas si cela est possible mais on sait jamais.
Cordialement,
CM
Le titre du sujet a été modifié par un modérateur pour faciliter la recherche. Titre original:
Garder le lien vers un Xref même si le nom de ce dernier change
Résolu ! Accéder à la solution.
Résolu par Y.AUBRY. Accéder à la solution.
Une programmation lisp est toujours imaginable du genre : "trouve-moi le seul dwg contenu dans ce dossier" pour en faire une xref à chaque appui ou lancement d'une instruction au clavier (voire à l'ouverture de chaque dessin) sur un bouton est possible.
MAis as-tu déjà utilisé la rubrique détails de la palette des xrefs pour repointer manuellement ? Je suppose que oui 🙂
Bonjour, merci pour votre réponse
Oui j'ai déjà essayé mais le problème est que je n'ai pas qu'un seul fichier..j'en ai au moins une centaine. Donc un automatisme serait pas de refus. Je ne connais pas le Lisp hélas...
Bonjour @martin.cappe,
Lorsque tu dis que ton XREF change de nom assez souvent c'est un changement de date (voir exemple ci-dessous) ou c'est un changement complet de nommage?
Ex : NOM_FICHIER_20220502.dwg --> NOM_FICHIER_20221027.dwg
Si c'est une changement de date, c'est surement possible via programmation, sinon je ne vois pas comment AutoCAD pourrait savoir qu'un XREF a changé de nom.
A+ Yoan
Yoan AUBRY
Bonjour,
C'est un changement de "numéro" par exemple : "40-xxxx.dwg" => "45-xxxx.dwg"
Du coup, le XXXX reste toujours identique?
Le séparateur entre ton numéro et le XXXX est toujours un "-"?
Les fichiers renommés restent dans le même dossier? (Le chemin du dossier présent dans l'ancien XREF reste inchangé)
Sinon, tu travailles sur un AutoCAD complet ou une version LT (Si c'est LT je ne pourrai rien te faire) ?
Quelle est ta version d'AutoCAD (pour la génération de DLL, la version de Framework change en fonction de la version d'AutoCAD)
A+ Yoan
Yoan AUBRY
Re-bonjour
Le séparateur est et sera toujours un "-". Je travaille avec la version complète d'AutoCAD 2021 et 2022.
EDIT : Oui le dossier est le même que le fichier de base
Cordialement,
CM
OK, dans ces cas-là je vais pouvoir te faire quelque-chose.
A+ Yoan
Yoan AUBRY
Je viens de finir le code, peux-tu me faire un e-transmit d'un plan pour les tests (ici ou en MP)
Yoan
Yoan AUBRY
Re-bonjour,
Voici des fichiers afin de tester la macro. Merci d'avance.
Cordialement,
CM
Tu ne m'as envoyé qu'un zip de plusieurs fichiers d'un dossier en non des e-transmits (je n'ai pas les XREF du coup)
Yoan AUBRY
Du coup tu trouveras dans le zip ci-joint une DLL nommée RELOAD_XREF.dll.
Il se peut que tu ais besoin de la débloquer car transmise par internet.
Pour le savoir faire un clic-droit dessus, puis propriétés, s'il y a le bouton "Débloquer" (ou case à cocher selon la version de Windows)
Exemple :
Une fois débloquer, elle se charge dans AutoCAD via la commande NETLOAD
Tu auras ensuite accès à la commande RELOAD_XREF
Je te conseille de créer un dossier dans lequel tu mets cette DLL et d'ajouter ce dossier dans les "Chemins de recherche des fichiers de support de travail" ainsi que dans les "Emplacements approuvés" (Outils\Options onglet fichier)
Nota , les fichiers envoyés n'étaient pas des e-transmit et donc ne permettaient pas de faire des tests car je n'avais pas les XREF associés.
Ci-dessous le code :
Option Compare Text
Imports System.IO
Imports System.Linq
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Public Class CmdXREF
<CommandMethod("RELOAD_XREF")>
Public Sub RELOAD_XREF()
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim FpDWG As String = doc.Name
Dim FnDWG As String = FpDWG.Split("\").Last
Dim FpDoss As String = Microsoft.VisualBasic.Left(FpDWG, Len(FpDWG) - Len(FnDWG))
Dim TMP() As String
TMP = FpDWG.Split("\")
Dim TMP_X() As String
Dim collection As ObjectIdCollection = New ObjectIdCollection()
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim bt As BlockTable = TryCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
For Each btrId As ObjectId In bt
Dim btr As BlockTableRecord = TryCast(tr.GetObject(btrId, OpenMode.ForRead), BlockTableRecord)
If btr.IsFromExternalReference Then
btr.UpgradeOpen()
Dim oldPath As String = btr.PathName
Dim oldFN As String = oldPath.Split("\").Last
Dim FpDossXREF As String = ""
If oldPath Like "..\*" Then
TMP_X = oldPath.Split("\")
Dim NbRetour As Integer = 0
For i As Integer = 0 To UBound(TMP_X)
If TMP_X(i) = ".." Then NbRetour += 1
Next
Dim TmpPath As String = ""
For i As Integer = 0 To UBound(TMP) - (NbRetour + 1)
If TmpPath = "" Then
TmpPath = TMP(i)
Else
TmpPath = TmpPath & "\" & TMP(i)
End If
Next
For i As Integer = 0 To UBound(TMP_X) - 1
If TMP_X(i) <> ".." Then
TmpPath = TmpPath & "\" & TMP_X(i)
End If
Next
FpDossXREF = TmpPath & "\"
ElseIf oldPath Like ".\*" Then
FpDossXREF = FpDoss & Microsoft.VisualBasic.Right(oldPath, Len(oldPath) - 2)
FpDossXREF = Microsoft.VisualBasic.Left(FpDossXREF, Len(FpDossXREF) - Len(oldFN))
Else
FpDossXREF = Microsoft.VisualBasic.Left(oldPath, Len(oldPath) - Len(oldFN))
End If
If Not Directory.Exists(FpDossXREF) Then
MsgBox("Le dossier " & FpDossXREF & " n'a pas été trouvé", MsgBoxStyle.Exclamation, "Annulation")
Exit Sub
End If
Dim newFN As String = ""
Dim newPath As String = ""
Dim Texte_a_trouver = Microsoft.VisualBasic.Right(oldFN, Len(oldFN) - Len(oldFN.Split("-").First))
Dim di As System.IO.DirectoryInfo = New System.IO.DirectoryInfo(FpDossXREF)
For Each fi As System.IO.FileInfo In di.GetFiles
If fi.Name Like "*" & Texte_a_trouver Then
newFN = fi.Name
Exit For
End If
Next
If newFN <> "" Then
newPath = oldPath.Replace(oldFN, newFN)
btr.PathName = newPath
btr.Name = Microsoft.VisualBasic.Left(newFN, Len(newFN) - 4) ' -4 pour ".dwg"
collection.Add(btrId)
ed.WriteMessage(String.Format("{0}Ancien chemin : {1} Nouveau Chemin : {2}", Environment.NewLine, oldPath, newPath))
End If
End If
Next
tr.Commit()
End Using
If collection.Count > 0 Then
db.ReloadXrefs(collection)
End If
db.SaveAs(db.OriginalFileName, True, db.OriginalFileVersion, db.SecurityParameters)
End Sub
End Class
A+ Yoan
Yoan AUBRY
Désolé je ne suis pas très à l'aise avec les e-transmits, il faudrait que je trouve un tutoriel pour ça.
Je test le code et je vous tiens au courant 🙂
Merci,
CM
J'ai testé et cela marche parfaitement à 1 détail près. Si mon Xref contient des calques gelés, après avoir utilisé la commande, tous les calques reviennent.
Est-il possible de garder les calques gelés même après le changement ?
Question au passage : Est-il possible de faire des "commandes" en un autre langage que le Lisp ?
Cordialement,
CM
Re-bonjour,
Je vais regarder si c'est possible pour les histoires de calques gelés (mais étant donné que l'on change le nom de l'XREF c'est normal qu'actuellement tous reviennent à l'état non gelé).
Sinon oui, c'est possible de faire des commande avec d'autres langages : J'ai utilisé le VB.NET pour cette commande mais c'est également possible de C#. Il est également possible de créer une interaction entre Excel et AutoCAD via programmation VBA, mais cela ne permet pas de faire uniquement du traitement, pas de création de commande.
Pour VB.NET et C#, il faut installer Visual Studio (je te conseille la version Community qui est gratuite)
Ensuite tu as pas mal de forums dédiés et de posts dédiés au développement .NET et C# pour AutoCAD
Il est également possible (généralement) de convertir des morceaux de codes C# en .NET (et vice-versa) via des pages comme https://converter.telerik.com/
Ci-dessous des exemples de pages dédiés à l'interaction Visual Basic / AutoCAD:
https://gilecad.azurewebsites.net/Resources/Template_Csharp.pdf
http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%20.NET%20Developer%27s%20Guide/index.html
https://www.keanw.com/autocad_net/
Je me suis auto-formé sur le sujet et j'avoue que ca a complètement changé ma manière de voir les traitements réalisables sur un dwg. En tout cas bon courage si tu te lance la dedans.
A+ Yoan
Yoan AUBRY
Ci-joint la DLL mise à jour.
...et le code associé
Option Compare Text
Imports System.IO
Imports System.Linq
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.Runtime
Public Class CmdXREF
Public Class ClCalque
Public LayerName As String
Public _IsOff As Boolean
Public _IsFrozen As Boolean
Public _IsLocked As Boolean
Public _Plottable As Boolean
End Class
Public Class ClXREF_MAJ
Public OldPath As String
Public NewPath As String
Public OldFN As String
Public NewFN As String
End Class
<CommandMethod("RELOAD_XREF")>
Public Sub RELOAD_XREF()
Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
Dim db As Database = doc.Database
Dim ed As Editor = doc.Editor
Dim LstCalque As New List(Of ClCalque)
Dim LstXREF As New List(Of ClXREF_MAJ)
Dim FpDWG As String = doc.Name
Dim FnDWG As String = FpDWG.Split("\").Last
Dim FpDoss As String = Microsoft.VisualBasic.Left(FpDWG, Len(FpDWG) - Len(FnDWG))
Dim TMP() As String
TMP = FpDWG.Split("\")
Dim TMP_X() As String
Dim collection As ObjectIdCollection = New ObjectIdCollection()
Dim newFN As String = ""
Dim newPath As String = ""
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim idLay As ObjectId = db.LayerTableId
Dim lt As LayerTable = tr.GetObject(idLay, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)
For Each id As ObjectId In lt
Dim ltr As LayerTableRecord = DirectCast(tr.GetObject(id, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead), LayerTableRecord)
Dim Calque As New ClCalque With {
.LayerName = ltr.Name,
._IsOff = ltr.IsOff,
._IsFrozen = ltr.IsFrozen,
._IsLocked = ltr.IsLocked,
._Plottable = ltr.IsPlottable
}
LstCalque.Add(Calque)
Next
Dim bt As BlockTable = TryCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
For Each btrId As ObjectId In bt
Dim btr As BlockTableRecord = TryCast(tr.GetObject(btrId, OpenMode.ForRead), BlockTableRecord)
If btr.IsFromExternalReference Then
btr.UpgradeOpen()
Dim oldPath As String = btr.PathName
Dim oldFN As String = oldPath.Split("\").Last
Dim FpDossXREF As String = ""
If oldPath Like "..\*" Then
TMP_X = oldPath.Split("\")
Dim NbRetour As Integer = 0
For i As Integer = 0 To UBound(TMP_X)
If TMP_X(i) = ".." Then NbRetour += 1
Next
Dim TmpPath As String = ""
For i As Integer = 0 To UBound(TMP) - (NbRetour + 1)
If TmpPath = "" Then
TmpPath = TMP(i)
Else
TmpPath = TmpPath & "\" & TMP(i)
End If
Next
For i As Integer = 0 To UBound(TMP_X) - 1
If TMP_X(i) <> ".." Then
TmpPath = TmpPath & "\" & TMP_X(i)
End If
Next
FpDossXREF = TmpPath & "\"
ElseIf oldPath Like ".\*" Then
FpDossXREF = FpDoss & Microsoft.VisualBasic.Right(oldPath, Len(oldPath) - 2)
FpDossXREF = Microsoft.VisualBasic.Left(FpDossXREF, Len(FpDossXREF) - Len(oldFN))
Else
FpDossXREF = Microsoft.VisualBasic.Left(oldPath, Len(oldPath) - Len(oldFN))
End If
If Not Directory.Exists(FpDossXREF) Then
MsgBox("Le dossier " & FpDossXREF & " n'a pas été trouvé", MsgBoxStyle.Exclamation, "Annulation")
Exit Sub
End If
newFN = ""
newPath = ""
Dim Texte_a_trouver = Microsoft.VisualBasic.Right(oldFN, Len(oldFN) - Len(oldFN.Split("-").First))
Dim di As System.IO.DirectoryInfo = New System.IO.DirectoryInfo(FpDossXREF)
For Each fi As System.IO.FileInfo In di.GetFiles
If fi.Name Like "*" & Texte_a_trouver Then
newFN = fi.Name
Exit For
End If
Next
If newFN <> "" Then
newPath = oldPath.Replace(oldFN, newFN)
btr.PathName = newPath
btr.Name = Microsoft.VisualBasic.Left(newFN, Len(newFN) - 4) ' -4 pour ".dwg"
collection.Add(btrId)
ed.WriteMessage(String.Format("{0}Ancien chemin : {1} Nouveau Chemin : {2}", Environment.NewLine, oldPath, newPath))
End If
Dim XREF_MAJ As New ClXREF_MAJ With {
.OldPath = oldPath,
.OldFN = oldFN,
.NewFN = newFN,
.NewPath = newPath
}
LstXREF.Add(XREF_MAJ)
End If
Next
tr.Commit()
End Using
If collection.Count > 0 Then
db.ReloadXrefs(collection)
End If
db.SaveAs(db.OriginalFileName, True, db.OriginalFileVersion, db.SecurityParameters)
Using tr As Transaction = db.TransactionManager.StartTransaction()
Dim idLay As ObjectId = db.LayerTableId
Dim lt As LayerTable = tr.GetObject(idLay, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead)
For Each id As ObjectId In lt
Dim ltr As LayerTableRecord = DirectCast(tr.GetObject(id, Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite), LayerTableRecord)
If ltr.Name Like "*|*" Then 'Nommage des calques des XREF avec un |
Dim NomCalque As String = ltr.Name
Dim NomXREF As String = NomCalque.Split("|").First
Dim XREF_MAJ As ClXREF_MAJ = LstXREF.Find(Function(f) f.NewFN = NomXREF & ".dwg")
If Not XREF_MAJ Is Nothing Then
Dim OldNomXREF As String = Microsoft.VisualBasic.Left(XREF_MAJ.OldFN, Len(XREF_MAJ.OldFN) - 4)
Dim OldNomCalque As String = NomCalque.Replace(NomXREF, OldNomXREF)
Dim Calque As ClCalque = LstCalque.Find(Function(f) f.LayerName = OldNomCalque)
If Not Calque Is Nothing Then
ltr.IsOff = Calque._IsOff
ltr.IsFrozen = Calque._IsFrozen
ltr.IsLocked = Calque._IsLocked
ltr.IsPlottable = Calque._Plottable
End If
End If
End If
Next
tr.Commit()
End Using
End Sub
End Class
A+ Yoan
Yoan AUBRY
Merci beaucoup ! Le code fonctionne parfaitement.
J'ai des bases de VBA et de C#. Je vais me pencher sur les commandes pour voir ce qu'on peut faire.
Merci beaucoup encore une fois.
Cordialement,
CM
Content d'avoir pu t'aider.
Bon courage pour la suite 😉
A+ Yoan
Yoan AUBRY
Vous n'avez pas trouvé ce que vous recherchiez ? Posez une question à la communauté ou partagez vos connaissances.