изучаю AutoLISP с лета этого года, а VB.NET пару недель.Рекомендую бросить изучать VB.NET и начать изучать C#.
Вылетает с критической ошибкой AutoCAD.Что говорит пошаговая отладка? И что за критическая ошибка?
Я решил проблему двумя способами:Как по мне первый вариант предпочтительней, но особой разницы (особенно на VB.NET) я не вижу.
Нашёл пример использования этих методов на C# https://adndevblog.typepad.com/autocad/2014/08/set-or-get-lisp-symbol-in-net.html. И метод Set* работал отлично, но метод Get* не хотел работать, при отладке выдавало исключение, если в переменной находилось значение String.Похоже, что в статье ошибка, о чем в комментарии к ней написано. Document.GetLispSymbol возвращает Object, а не TypedValue.
Рекомендую бросить изучать VB.NET и начать изучать C#.Александр, а можете вкратце объяснить почему C# предпочтительнее? Я читал закреплённые темы Андрея Бушмана про книги и тему про изучение C#, но пока что не понял преимущества C# над VB.NET.
Похоже, что в статье ошибка, о чем в комментарии к ней написано. Document.GetLispSymbol возвращает Object, а не TypedValue.Вы правы, я в хелпе сразу видел, что он возвращает Object, но так как не имею своего опыта, понадеялся на опыт человека, написавшего статью.
Александр, а можете вкратце объяснить почему C# предпочтительнее?Вкратце - на C# значительно больше примеров, он красивее, лаконичнее, роднее для .NET
Он объявляется глобальноА где оно инициализировано? Должно быть где-то
Код - vb.net [Выбрать]
Public lxResultBuffer As ResultBuffer
А где оно инициализировано? Должно быть где-тоЯ думал, что инициализация происходит во время объявления глобальной переменной. Я добавил инициализацию перед выполнением цикла, ничего не изменилось. Хочу заметить, что AutoCAD крашится независимо от того есть ли в чертеже переменная, либо она просто пустая, либо с данными String.
Я думал, что инициализация происходит во время объявления глобальной переменной.Нет.
Хочу заметить, что AutoCAD крашится независимо от того есть ли в чертеже переменная, либо она просто пустая, либо с данными String.А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?
А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?Это я уже завтра потестирую
Какая версия и разрядность AutoCAD?Простой английский AutoCAD x64.
Где код LispExtensions.GetLispSym?Код брал вот отсюда http://www.theswamp.org/index.php?topic=35714.msg460016#msg460016 , там же и упоминается о том, что произошли изменения после 2013 версии.
Простой английский AutoCAD x64.Версия какая???
Блин, я уже сплю :) Версия 2018Простой английский AutoCAD x64.Версия какая???
Блин, я уже сплю :) Версия 2018Теоретически замена "acad.exe" на "accore.dll" должна была помочь. Завтра проверю.
Блин, я уже сплю :) Версия 2018Теоретически замена "acad.exe" на "accore.dll" должна была помочь. Завтра проверю.
Я ведь правильно понимаю, что метод Add аналогичен вот такому добавлению?Вообще-то ResultBuffer.Add работает с TypedValue, а не с ResultBuffer. В этом может быть ошибка.
Имеется вот такие две части кодаЭто потому, что, несмотря на использование .NET, Вы продолжаете думать на LISP. То есть, Вы совершенно игнорируете новые возможности и пытаетесь адаптировать .NET под логику LISP. Разумеется, что ничего хорошего из этого не выйдет.Код - vb.net [Выбрать]
Dim lxDesign As ResultBuffer = LispExtensions.GetLispSym("lxDesign") Dim lxDesignDate As ResultBuffer = LispExtensions.GetLispSym("lxDesignDate") Dim lxChecking As ResultBuffer = LispExtensions.GetLispSym("lxChecking") Dim lxCheckingDate As ResultBuffer = LispExtensions.GetLispSym("lxCheckingDate")Код - vb.net [Выбрать]Это части кода, который создаёт окно. Логика работы такая - при инициализации берутся переменные лиспа, есть они или нет в чертеже. Потом заполняются или редактируются поля, считываются и отправляются обратно в переменные лиспа. Мне интересно, возможно ли записать данные примеры циклом, чтобы было меньше строк. В автолиспе я делал это через (eval (read variable)). В VB.NET не могу найти информацию и не хватает опыта.
Dim lxArray As Array Dim lxString As String lxArray = lxDesign.AsArray lxString = lxArray(0).value TB_11.Text = lxString lxArray = lxDesignDate.AsArray lxString = lxArray(0).value TB_21.Text = lxString lxArray = lxChecking.AsArray lxString = lxArray(0).value TB_12.Text = lxString lxArray = lxCheckingDate.AsArray lxString = lxArray(0).value TB_22.Text = lxString
Конструкция типа:Код - vb.net [Выбрать]Вылетает с критической ошибкой AutoCAD.
Dim lxStringCollection = New String() {"lxDesign", "lxDesignDate", "lxChecking", "lxCheckingDate"} Dim lxTBCollection = New String() {"TB_11", "TB_21", "TB_12", "TB_22"} For lxItem = 0 To lxStringCollection.GetUpperBound(0) lxResultBuffer.Add(LispExtensions.GetLispSym(lxItem)) Next Dim lxIndex = 0 For Each lxBuffer As TypedValue In lxResultBuffer Dim lxStringBuffer As String = lxTBCollection(lxIndex) & ".text = lxBuffer.Value" Dim lxTable = New System.Data.DataTable() Convert.ToDouble(lxTable.Compute(lxStringBuffer, Nothing)) lxIndex += 1 Next
Вообще-то ResultBuffer.Add работает с TypedValue, а не с ResultBuffer. В этом может быть ошибка.Александр, я пробовал добавлять с помощью Typedvalue, но всё равно AutoCAD крашится.
Это потому, что, несмотря на использование .NET, Вы продолжаете думать на LISP. То есть, Вы совершенно игнорируете новые возможности и пытаетесь адаптировать .NET под логику LISP. Разумеется, что ничего хорошего из этого не выйдет.Дмитрий, я знаю про словари, но у меня стринговые переменные, например "lxDesign", не только читаются из чертежа, но и потом присваиваются обратно, о чём я писал в начале. Я может не понимаю Вашей мысли, Вы не могли написать пример на C#. Да и вряд ли краш AutoCAD связан с тем, что я пишу так как в начальном примере, а не с помощью словаря.
Цитата: Александр Ривилис от 22-10-2019, 22:39:17И? Какой результат?
А если вместо LispExtensions.GetLispSym() используешь lxDocument.GetLispSymbol(...) ?
Это я уже завтра потестирую
Александр, я пробовал добавлять с помощью Typedvalue, но всё равно AutoCAD крашится.Каким образом? Я не вижу кода, которым вы это делаете и поэтому не могу проверить. Создайте специальный тестовый проект, в котором будете только читать и писать lisp-переменные. Я его протестирую.
И? Какой результат?Я пока что на работе, когда дома буду, то выложу все результаты.
Каким образом? Я не вижу кода, которым вы это делаете и поэтому не могу проверить. Создайте специальный тестовый проект, в котором будете только читать и писать lisp-переменные. Я его протестирую.Делал примерно так
Делал примерно такОчевидно, что это ерунда. TypedValue - это один из элементов в ResultBuffer
Код - vb.net [Выбрать]
lxResultBuffer.Add(New TypedValue(CInt(LispDataType.Text), (LispExtensions.GetLispSym(lxStringCollection(lxItem))))
Я может не понимаю Вашей мысли, Вы не могли написать пример на C#.
Да и вряд ли краш AutoCAD связан с тем, что я пишу так как в начальном примере, а не с помощью словаря.Возможно. Я неправильно выразился. Я имел в виду, что такие сложные действия в коде являются следствием попытки реализовать операции
P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NETЯ последую Вашему совету и следующую работу выполню на C#
Я имел в виду, что такие сложные действия в коде являются следствием попытки реализовать операции через одно место через логику LISPаСогласен, что через логику лиспа, но мне интересны различные варианты реализации, для этого я и создал эту тему. Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги. У меня была задача написать скрипты для автоматической формирований связей между элементами схемы, автоматического формирования остальных документов из схемы Э4. Я сделал, времени читать книги не было, разбираюсь на ходу.
Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги. У меня была задача написать скрипты для автоматической формирований связей между элементами схемы, автоматического формирования остальных документов из схемы Э4. Я сделал, времени читать книги не было, разбираюсь на ходу.Да это, в общем-то, вполне нормальный подход: практика + теория. Главное - не пренебрегать чем-то одним. Читать книги обязательно надо, применять полученные знания на практике тоже очень важно. То, что задаёте вопросы - вообще отлично! Многие почему-то стесняются. Ну и готовьтесь к тому, что всё что вы сейчас напишете через год-два либо выкинете, либо будете переписывать заново ;)
Ну и готовьтесь к тому, что всё что вы сейчас напишете через год-два либо выкинете, либо будете переписывать зановоТак я к этому давно привык, ещё во времена, когда писал на Python и Mel интерфейсы и конвертеры шейдеров в Maya. Даже сейчас, за эти месяцы изучения и практики я нахожу более практичные реализации задач и, просматривая старый код, думаю - "Неправильно я написал, надо было делать по другому." Вообще у меня был такой план. Я пишу дополнение на лисп для создания КД шкафов РЗА, потом изучаю .NET и пишу дополнение для создания КД шкафов НКУ. Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET. VB.NET я выбрал только из-за того, что у меня были видео уроки по созданию плагинов для AutoCAD на VB.NET.
Но, к сожалению, я обычно сначала выполняю практические занятия и провожу разные эксперименты, а уже потом читаю книги.Эти эксперименты могут отнять много времени, которое можно было потратить на что-то другое более полезное. Впрочем ваше дело...
VB.NET я выбрал только из-за того, что у меня были видео уроки по созданию плагинов для AutoCAD на VB.NET.Там же были уроки по созданию плагинов на C# для AutoCAD. На каком-то из C-подобных языков вы уже что-то писали?
Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET.Так-так-так... Теперь понятны попытки скрестить лисп с нетом. То есть, нужен диалог для изменения каких-то лисповых данных? А есть уверенность, что подход выбран правильный? Я про то, что данные можно передавать по другому - не через считывание-запись лисповых переменных, а с помощью передачи аргументов в самописную лисп-функцию, которая после завершения диалога будет возвращать полученные в нём значения.
P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET+1
Функцию run-my-dialog написать на .NET. Она будет принимать строковые значения, запускать диалог по их изменению и возвращать список новых значений после закрытия диалога.Именно так. Или всё полностью пишется на .NET (C#/VB.NET) или на .NET пишется функции, к которым обращаются из lisp.
На каком-то из C-подобных языков вы уже что-то писали?Нет
Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.Но плохое поведение DCL меня поставило в такие условия, что раньше пришлось начать изучение .NET.Так-так-так... Теперь понятны попытки скрестить лисп с нетом. То есть, нужен диалог для изменения каких-то лисповых данных? А есть уверенность, что подход выбран правильный? Я про то, что данные можно передавать по другому - не через считывание-запись лисповых переменных, а с помощью передачи аргументов в самописную лисп-функцию, которая после завершения диалога будет возвращать полученные в нём значения.
Типа такого:Код - Auto/Visual Lisp [Выбрать]Функцию run-my-dialog написать на .NET. Она будет принимать строковые значения, запускать диалог по их изменению и возвращать список новых значений после закрытия диалога.
(setq res (run-my-dialog lxDesign lxDesignDate lxChecking lxCheckingDate) lxDesign (nth 0 res) lxDesignDate (nth 1 res) lxChecking (nth 2 res) lxCheckingDate (nth 3 res) )P.S.: Настоятельно рекомендую заняться изучением C# и забросить VB.NET+1
Или всё полностью пишется на .NET (C#/VB.NET) или на .NET пишется функции, к которым обращаются из lisp.Согласен, но пришлось прибегнуть к такому способу, так как чтобы переписать весь код на .net уйдёт слишком много времени.
Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.
То есть я делал конструкцию типа:Код - vb.net [Выбрать]и AutoCAD вылетал.
<LispFunction("Window")> //тут инициализовал окно
Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.Может быть. Тогда попробую реализовать окно через функции лиспа, когда буду переписывать окно для создания клемного ряда.
100% проблема в самой форме (создание, запуск, события кнопок...)Я думал о таком подходе, чтобы написать функцию лиспа на .net. Но когда вызываешь модальное окно с помощью функции лиспа, то AutoACD крашится.Причина, видимо, была где-то внутри того, что скрывается под "//тут инициализовал окно". Из лисп-функции нормально запускаются модальные диалоги.
То есть я делал конструкцию типа:Код - vb.net [Выбрать]и AutoCAD вылетал.
<LispFunction("Window")> //тут инициализовал окно
Небольшая демонстрация того, как это работает.
Лисп:Код - Auto/Visual Lisp [Выбрать].NET:
(setq data "Привет, .NET!" res (run-custom-dialog data)) (if res (setq data res)) (alert data)Код - C# [Выбрать]Весь проект для VS2019 - в приложенном архиве.
[LispFunction("run-custom-dialog")] public string RunDia(ResultBuffer rb) { string data = rb? .AsArray() .FirstOrDefault() .Value.ToString() ?? "*error*"; CustomDialog customDialog = new CustomDialog(); customDialog.Data = data; var res = Application.ShowModalDialog(customDialog); if (res != System.Windows.Forms.DialogResult.Cancel) { return customDialog.Data; } else { return null; } }
Метод лисп-функции должен иметь входной параметр типа ResultBuffer, даже если лисп-функция не будет иметь аргументов. А у Вас пустые скобки, то есть, входных параметров нет.ёмоё. Я изначально делал по примеру из хелпа по API и не работало, сюда я скопировал последний вариант пробы. Моя невнимательность.
https://knowledge.autodesk.com/search-result/caas/CloudHelp/cloudhelp/2015/ENU/AutoCAD-NET/files/GUID-3B2760FE-A0DC-4229-AEBE-5CC83290BA95-htm.html
Lemieux,Александр, в том-то и дело, что по хелпу он возвращает Object. С ResultBuffer было бы просто.
Как я понимаю lxDocument.GetLispSymbol("lmxNameTerminals") возвращает ResultBuffer
Соответственно:Код - C# [Выбрать]
object lxCollectionTB = lxDocument.GetLispSymbol("lmxNameTerminals"); TypedValue[] lxType = lxCollectionTB.AsArray();
Да именно так и следует делать:Код - C# [Выбрать]Только желательно сначала проверить не равен ли случайно lxCollectionTB null (если такой переменной нет или она nil)
TypedValue[] lxType = (TypedValue[])lxCollectionTB;
(https://live.staticflickr.com/65535/48986914917_560bed905e_o.png)
Впрочем возможен вариант, что в этой переменной не список и тогда преобразовывать в TypedValue[] нельзя.
Правильнее вот так:Код - C# [Выбрать]
[CommandMethod("GetLispVar")] public void GetLispVar() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Editor ed = doc.Editor; PromptResult rs = ed.GetString("\nУкажите имя переменной: "); if (rs.Status == PromptStatus.OK) { var o = doc.GetLispSymbol(rs.StringResult); if (o != null && o is TypedValue[]) { TypedValue[] tvs = o as TypedValue[]; foreach (TypedValue tv in tvs) { ed.WriteMessage($"\n{tv.TypeCode} - {tv.Value}"); } } else { ed.WriteMessage($"\n{o}"); } } }
Lemieux,Да, я знаю об этом, поэтому у меня перебор массива начинается не с "0" элемента, а с "1" и заканчивается на "*.length-1". А есть какое решение как более изящно избавиться от обозначения границ списка?
Кстати, ты обратил внимание что в этом списке есть не только строки, но и Autodesk.AutoCAD.Runtime.LispDataType.ListBegin и Autodesk.AutoCAD.Runtime.LispDataType.ListEnd (это как скобки в lisp)? У них TypeCode 5016 и 5017
А есть какое решение как более изящно избавиться от обозначения границ списка?Вполне изящное решение если ты уверен, что у тебя в переменной обычный линейный список строк.
Впрочем возможен вариант, что в этой переменной не список и тогда преобразовывать в TypedValue[] нельзя.В C# не-помню-какой-версии добавили удобную проверку типа с одновременным преобразованием.
Правильнее вот так:Код - C# [Выбрать]
[CommandMethod("GetLispVar")] public void GetLispVar() { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Editor ed = doc.Editor; PromptResult rs = ed.GetString("\nУкажите имя переменной: "); if (rs.Status == PromptStatus.OK) { var o = doc.GetLispSymbol(rs.StringResult); if (o != null && o is TypedValue[]) { TypedValue[] tvs = o as TypedValue[]; foreach (TypedValue tv in tvs) { ed.WriteMessage($"\n{tv.TypeCode} - {tv.Value}"); } } else { ed.WriteMessage($"\n{o}"); } } }
В C# не-помню-какой-версииДобавили в C# 7.0. Но я консервативен и использую старый синтаксис :)