Добрый день! Пытаюсь написать код для массового переименования обозначений позиций (скажем сдвиг нумерации или приписка/удаление буквы), но ничего не выход. Нашел в SDK два кода на Visual Basic: один для перебора объектов, а другой - для создания и редактирования позиции. Думаю они должны подойти. Но как их объединить? Все мои попытки не увенчались успехом.
Вот примеры кодов:
1.
Sub WalkFromView(doc As Object) ' хождение по виду
' в текущем документе и виде создадим итератор для хождения по всем элементам
Dim obj As Long
Dim count As Integer
count = 0
Dim iIter As Object ' ksIterator
Set iIter = iKompasObject.GetIterator
iIter.ksCreateIterator ALL_OBJ, 0
If iIter.reference Then
obj = iIter.ksMoveIterator("F")
If doc.ksExistObj(obj) Then
Do
doc.ksLightObj obj, 1
count = count + 1
iKompasObject.ksMessage "номер = " & count
doc.ksLightObj obj, 0
obj = iIter.ksMoveIterator("N")
Loop Until doc.ksExistObj(obj) = 0
End If
End If
End Sub
2.
Sub DrawPosLeader(doc As Object)
Dim ilead As Object ' ksPosLeaderParam
Set ilead = iKompasObject.GetParamStruct(ko_PosLeaderParam)
Dim itLinePar As Object ' ksTextLineParam
Set itLinePar = iKompasObject.GetParamStruct(ko_TextLineParam)
Dim iItemPar As Object ' ksTextItemParam
Set iItemPar = iKompasObject.GetParamStruct(ko_TextItemParam)
Dim itFont As Object ' ksTextItemFont
Set itFont = iItemPar.GetItemFont()
Dim itMathPoint As Object ' ksMathPointParam
Set itMathPoint = iKompasObject.GetParamStruct(ko_MathPointParam)
If Not ilead Is Nothing And Not itLinePar Is Nothing And Not iItemPar Is Nothing And Not itFont Is Nothing And Not itMathPoint Is Nothing Then
ilead.Init
itLinePar.Init
iItemPar.Init
itFont.Init
itMathPoint.Init
'ilead.Style = INDICATIN_TEXT_LINE_ARR
itFont.SetBitVectorValue NEW_LINE, True
itLinePar.Style = 0
Dim iptext As Object ' ksDynamicArray
Set iptext = ilead.GetpTextline()
Dim iTextItemArr As Object ' ksDynamicArray
Set iTextItemArr = itLinePar.GetTextItemArr()
iItemPar.s = "1"
iTextItemArr.ksAddArrayItem -1, iItemPar
iptext.ksAddArrayItem -1, itLinePar
Dim ipPolyLin As Object ' ksDynamicArray
Set ipPolyLin = ilead.GetpPolyline
Dim ipMathPoint As Object ' ksDynamicArray
Set ipMathPoint = iKompasObject.GetDynamicArray(POINT_ARR)
If Not ipPolyLin Is Nothing And Not ipMathPoint Is Nothing Then
itMathPoint.x = 10
itMathPoint.y = 10
ipMathPoint.ksAddArrayItem -1, itMathPoint
ipPolyLin.ksAddArrayItem -1, ipMathPoint
itMathPoint.x = 30
itMathPoint.y = 10
ipMathPoint.ksClearArray
ipMathPoint.ksAddArrayItem -1, itMathPoint
ipPolyLin.ksAddArrayItem -1, ipMathPoint
ilead.SetpPolyline ipPolyLin
End If
' заполним параметры
ilead.x = 50 ' координаты базовой точки ( начало полки )
ilead.y = 50
ilead.arrowType = 1
ilead.dirX = -1
Dim obj As Long
obj = doc.ksPositionLeader(ilead)
If obj Then
doc.ksGetObjParam obj, ilead, ALLPARAM
ilead.x = 100
iKompasObject.ksMessage "Поменяем параметры"
doc.ksSetObjParam obj, ilead, ALLPARAM
End If
End If
End Sub
Неужели никто подсказать не может?
ИМХО
за чем такие сложности
через API7 - все достаточно просто
Виды - Вид - Контейнер условных обозначений - Линии-Выноски - Линия-выноска -
Линия-выноска для обозначения позиции -
смотрим 2 свойства:
Positions
UnderPositionText
Получаете от вида ISymbols2DContainer контейнер условных обозначений, далее коллекцию линий-выносок Leaders, получаете IBaseLeader от свойства ILeaders.Leader, приводите интерфейс IBaseLeader к IDrawingObject и проверяете свойство DrawingObjectType , если равно ksDrPosLeader, то приводите интерфейс IBaseLeader к IPositionLeader - интерфейс параметров линии-выноски для обозначения позиции и редактируете его.
Второй вариант, получаете от вида(IView) контейнер объектов вида графического документа IDrawingContainer, далее получаете массив SAFEARRAY объектов Air:=IDrawingContainer.Objects[ksDrPosLeader] линий-выносок для обозначения позиций, входящих в состав данного объекта вида.
Спасибо. Теперь знаю направление дальнейшего поиска. Было бы конечно лучше увидеть образец кода, хотя бы выполнящего не в точности то что мне нужно, а например смежную или схожую функцию.
Добрый день! На VB я так и не решил задачу. Теперь перешел на программирование в Delphi. На нем даже решилась проблема из соседней, основанной мною ветки о работе с переменными в 3D.
Но по данной теме как решить? Я смотрю куда больше знатоков Delphi, чем VB. Может кто чем помочь?
Надо сделать следующее:
1. Пройтись по всем видам, или только по текущему, или только по выделенным элементам (всего 3варианта) по тексту в линиях-выносках, позиционных линиях выносках и текстовым надписям (тоже три варианта).
2. И соответственно изменить один текст на другой в линиях-выносках, позиционных линиях выносках и текстовым надписям.
И еще доп. вопрос: Как произвести замену в вертикальном тексте таблиц?
В прицепе, но на Python (для его популяризации среди уважаемых форумчан :))
Должны быть установлены:
КОМПАС-3D V13 или новее, Python, расширение PyWin32 для Python.
Запускаем компас, открываем чертеж с выносками и текстами, запускаем тест.
ЦитироватьИ соответственно изменить один текст на другой
Добавил в тест заменяемый текст
Вот набросал такой код:
procedure RENM();
var
newKompasAPI : IApplication;
disp : IDispatch;
pDocuments : iDocuments;
pDocument : IKompasDocument;
pKompasDocument2D : IKompasDocument2D;
pViewsAndLayersManager : IViewsAndLayersManager;
pViews : IViews;
pView : IView;
pSymbols2DContainer : ISymbols2DContainer;
// pDrawingContainer : IDrawingContainer;
pLeaders : ILeaders;
pBaseLeader : IBaseLeader;
begin
disp := IDispatch( CreateKompasApplication );
newKompasAPI := disp As IApplication;
pDocuments := newKompasAPI.Documents;
pDocument := pDocuments.Add(1,true);//(doc tupe,visible-regim)
pKompasDocument2D := pDocument as iKompasDocument2D;
pViewsAndLayersManager := pKompasDocument2D.ViewsAndLayersManager;
pViews := pViewsAndLayersManager.Views;
pView := pViews.ViewByNumber[1];
pView.Current := true;
//pDrawingContainer := pView as iDrawingContainer;
pSymbols2DContainer := pView as iSymbols2DContainer;
pLeaders:= pSymbols2DContainer.Leaders;
pBaseLeader := pLeaders.Leader;
//Дальше что делать?
end;
Дальше что нужно делать? В Питоне есть код, но как в Delphi перевести?:
if self.__context != 2:
viewsAndLayersManager =activeDoc2D.ViewsAndLayersManager
views = viewsAndLayersManager.Views
context = []
if self.__context == 0:
for i in range(views.Count):
context.append(views.View(i))
else:
context.append(views.ActiveView)
if self.__target != 2:
for i, view in enumerate(context):
symbols2DContainer = module.ISymbols2DContainer(view._oleobj_.QueryInterface(module.ISymbols2DContainer.CLSID, pythoncom.IID_IDispatch))
leaders = symbols2DContainer.Leaders
for j in range(leaders.Count):
baseLeader = leaders.Leader(j)
if self.__target == 0 and baseLeader.DrawingObjectType == 20: #Простая линия-выноска
leader = module.ILeader(baseLeader._oleobj_.QueryInterface(module.ILeader.CLSID, pythoncom.IID_IDispatch))
if leader != None and leader.TextOnShelf.Str == self.__oldValue:
leader.TextOnShelf.Str = self.__newValue
if self.__target == 1 and baseLeader.DrawingObjectType == 21: #Линия-выноски для обозначения позиции
positionLeader = module.IPositionLeader(baseLeader._oleobj_.QueryInterface(module.IPositionLeader.CLSID, pythoncom.IID_IDispatch))
if positionLeader != None and positionLeader.Positions.Str == self.__oldValue:
positionLeader.Positions.Str = self.__newValue
baseLeader.Update()
else:
for i, view in enumerate(context):
drawingContainer = module.IDrawingContainer(view._oleobj_.QueryInterface(module.IDrawingContainer.CLSID, pythoncom.IID_IDispatch))
drawingTexts = drawingContainer.DrawingTexts
for j in range(drawingTexts.Count):
drawingText = drawingTexts(j)
text = module.IText(drawingText._oleobj_.QueryInterface(module.IText.CLSID, pythoncom.IID_IDispatch))
if text.Str == self.__oldValue:
text.Str = self.__newValue
drawingText.Update()
else:
activeDoc2D1 = module.IKompasDocument2D1(activeDoc2D._oleobj_.QueryInterface(module.IKompasDocument2D1.CLSID, pythoncom.IID_IDispatch))
selectionManager = activeDoc2D1.SelectionManager
selectedObjects = selectionManager.SelectedObjects
if isinstance(selectedObjects, tuple):
for item in selectedObjects:
drawingObject = module.IDrawingObject(item._oleobj_.QueryInterface(module.IDrawingObject.CLSID, pythoncom.IID_IDispatch))
if self.__target == 0 and drawingObject.DrawingObjectType == 20: #Простая линия-выноска
leader = module.ILeader(drawingObject._oleobj_.QueryInterface(module.ILeader.CLSID, pythoncom.IID_IDispatch))
if leader != None and leader.TextOnShelf.Str == self.__oldalue:
leader.TextOnShelf.Str = self.__newValue
elif self.__target == 1 and drawingObject.DrawingObjectType == 21: #Линия-выноски для обозначения позиции
positionLeader = module.IPositionLeader(drawingObject._oleobj_.QueryInterface(module.IPositionLeader.CLSID, pythoncom.IID_IDispatch))
if positionLeader != None and positionLeader.Positions.Str == self.__oldValue:
positionLeader.Positions.Str = self.__newValue
elif self.__target == 2 and drawingObject.DrawingObjectType == 4: #Текст на чертеже
drawingText = module.IDrawingText(drawingObject._oleobj_.QueryInterface(module.IDrawingText.CLSID, pythoncom.IID_IDispatch))
if drawingText != None:
text = module.IText(drawingText._oleobj_.QueryInterface(module.IText.CLSID, pythoncom.IID_IDispatch))
if text.Str == self.__oldValue:
text.Str = self.__newValue
drawingObject.Update()
else:
drawingObject = module.IDrawingObject(selectedObjects._oleobj_.QueryInterface(module.IDrawingObject.CLSID, pythoncom.IID_IDispatch))
if self.__target == 0 and drawingObject.DrawingObjectType == 20: #Простая линия-выноска
leader = module.ILeader(drawingObject._oleobj_.QueryInterface(module.ILeader.CLSID, pythoncom.IID_IDispatch))
if leader != None and leader.TextOnShelf.Str == self.__oldValue:
leader.TextOnShelf.Str = self.__newValue
elif self.__target == 1 and drawingObject.DrawingObjectType == 21: #Линия-выноски для обозначения позиции
positionLeader = module.IPositionLeader(drawingObject._oleobj_.QueryInterface(module.IPositionLeader.CLSID, pythoncom.IID_IDispatch))
if positionLeader != None and positionLeader.Positions.Str == self.__oldValue:
positionLeader.Positions.Str = self.__newValue
elif self.__target == 2 and drawingObject.DrawingObjectType == 4: #Текст на чертеже
drawingText = module.IDrawingText(drawingObject._oleobj_.QueryInterface(module.IDrawingText.CLSID, pythoncom.IID_IDispatch))
if drawingText != None:
text = module.IText(drawingText._oleobj_.QueryInterface(module.IText.CLSID, pythoncom.IID_IDispatch))
if text.Str == self.__oldValue:
text.Str = self.__newValue
drawingObject.Update()
Кто поможет эту процедуру довести до рабочего состояния - тому отправлю готовое приложение для переименования позиций и текста, в различных вариациях.
Вы наверное пошутили? В коде ни одного коментария... Ни смысла кода... Т.е. посмотри и догадайся сам что я хочу сделать.... Называется нагрузить кого то работой по расшифровке)
Коды не мои. Взял подходящие участки из других примеров. В них не было изначально коментариев. А разбираюсь я в SDK компаса плохо. Была бы хорошая литература, где описывался бы весь SDK (и API5 и API7), наверно бы и вопросов не было. А Справка по SDK не помощник, все по спартански для "джедаев" программирования, но не для чайников.
ЦитироватьpBaseLeader := pLeaders.Leader;
//Дальше что делать?
Меняем на:
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item
;
if pDrawingObject<>nil then
begin
if pDrawingObject.DrawingObjectType=ksDrLeader then
begin // Простая линия-выноска
pLeader:=pDrawingObject as ILeader;
if pLeader<>nil then
begin
if pLeader.TextOnShelf.Str=oldValue then
begin
pLeader.TextOnShelf.Str=newValue;
pDrawingObject.Update;
end;
pLeader:=nil;
end;
end
else if pDrawingObject.DrawingObjectType=ksDrPosLeader then
begin // Линия-выноска для обозначения позиции
...
end
else if pDrawingObject.DrawingObjectType=ksDrBrandLeader then
begin // Линия-выноска для для обозначения клеймения
...
end
else if pDrawingObject.DrawingObjectType=ksDrMarkerLeader then
begin // Линия-выноска для обозначения маркирования
...
end
else if pDrawingObject.DrawingObjectType=ksDrChangeLeader then
begin // Знак изменения
...
end;
pDrawingObject:=nil;
end;
end;
для ... делаем аналогично в зависимости от типа.
Спасибо большое!!!!
Но нарисовалась новая проблема. Delphi при компиляции выдает: "запуск программы не возможен, так как на компьютере отсутствует kAPI7.DLL". Но она точно есть и лежит на своем месте. Куда эту библиотеку скопировать или где мне размещать проект, чтобы было видно библиотеку? Может что в подключаемых модулях стоит поменять?
Там, где всегда лежит.
Да, да. И у меня там же. Просто что то делаю не так и Delphi ругается, не может найти библиотеку. Даже ругается на примеры SDK по API7. С API5 все хорошо.
Как Вы подключаете API7 в Delphi ? Через ksAPI7.pas или через TLB. Может адрес где лежит библиотека надо где то прописывать? Или что то не так объявляю. Если не трудно можете какой-нибудь простейший пример проекта на API7 (пускай в нем даже ничего не будет) ?
Запустите KOMPAS.Exe /register
Подключаю через ksAPI7.pas, но все ссылки на kAPI7.DLL находятся в ksAuto.pas.
Прописал полный путь. Помогло (почему относительные пути у меня не работают?). Но теперь kSys1.DLL не может найти. В каком файле его путь задать? Напасть какая то.
Вы регистрацию компонентов делали? - KOMPAS.Exe /register
Что у Вас неправильно, я сказать не могу, я не телепат, скорее всего криво Компас стоит.
По поводу dll, они все взаимно завязаны, стоит зацепить одну и они друг друга начнут тянуть.
Нет. Не делал. Как она делается? Куда эту команду вбивать? Возможно и в правду Компас криво стоит. Вечерком попробую переустановить. И почему то запрещены изменения в папке где Компас установлен, убираешь галочку "только для чтения", а потом она опять появляется. Может антивирус это делает.
И как вариант то что Delphi позже Компаса ставилось, может из-за этого?
В Total или из командной строки, когда ставилось Delphi на регистрацию не влияет.
Спасибо. Попробовал - пишет: "Ошибка регистрации. обратитесь к администратору". Странно ведь у меня учетка - администратор )))))
В общем понял, что надо переустанавливать. И пробовать снова. Как все это проделаю отпишусь, что получилось.
Еще пара вопросов:
1. После того как Компас переустановлю, надо ли будет регистрировать компоненты, или автоматом все пройдет?
2. Далее просто в Uses прописываю kAPI7 и все?
Надеюсь все получится
Компас их при установке зарегистрирует.
В Uses прописать ksAPI7, но всё зависит от кода.
Переустановил проблема осталась. Разобрался только с одной - снял запрет с редактирования папки Ascon - наделил правами учетку. Скидываю сам проект. Может в нем ошибка?. Примеры в SDK по API7 не хотят работать, точнее вообще ни один не компилится в RTW.
А через API5 никак нельзя все это реализовать? Пускай даже код немного сложнее будет.
Вы делаете Exe файл, попробуйте сделать так для получения Api7:
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
PS. Лучше всё сделать библиотекой dll или rtw, проще и меньше подводных камей.
Спасибо большое! Заработало. Осталось только код настроить.
На счет библиотек: у каждого свои вкусы и привычки. Мне в виде приложений exe нравится делать так как:
1. Не надо подключать. Открыл нужное приложение и вперед
2. Вроде бы форма и все элементы в библиотеке задаются кодом, а не конструктором форм как для exe. Хотя может я ошибаюсь.
Вот код процедуры:
procedure RENM();
var
newKompasAPI : IApplication;
disp : IDispatch;
pDocuments : iDocuments;
pDocument : IKompasDocument;
pKompasDocument2D : IKompasDocument2D;
pViewsAndLayersManager : IViewsAndLayersManager;
pViews : IViews;
pView : IView;
pSymbols2DContainer : ISymbols2DContainer;
pDrawingContainer : IDrawingContainer;
pLeaders : ILeaders;
pBaseLeader : IBaseLeader;
pLeader : ILeader;
pDrawingObject : IDrawingObject;
I:integer;
oldValue, newValue: string;
begin
//disp := IDispatch( CreateKompasApplication );
//newKompasAPI := disp As IApplication;
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
pDocuments := newKompasAPI.Documents;
pDocument := pDocuments.Add(1,true);//(doc tupe,visible-regim)
pKompasDocument2D := pDocument as iKompasDocument2D;
pViewsAndLayersManager := pKompasDocument2D.ViewsAndLayersManager;
pViews := pViewsAndLayersManager.Views;
pView := pViews.ViewByNumber[1];
pView.Current := true;
pDrawingContainer := pView as iDrawingContainer;
pSymbols2DContainer := pView as iSymbols2DContainer;
pLeaders:= pSymbols2DContainer.Leaders;
oldValue:='2';
newValue:='5';
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item;
if pDrawingObject<>nil then
begin
if pDrawingObject.DrawingObjectType=ksDrLeader then
begin // Простая линия-выноска
pLeader:=pDrawingObject as ILeader;
if pLeader<>nil then
begin
if pLeader.TextOnShelf.Str=oldValue then
begin
pLeader.TextOnShelf.Str:=newValue;
pDrawingObject.Update;
end;
pLeader:=nil;
end;
end;
end;
end;
end;
При нажатии на кнопку, вызывающую эту процедуру - почему то открывает новый документ при уже отрытом, вместо того чтобы поменять и выдает ошибку.
Для этого отладчик существует.
хотя pDrawingObject:=pLeaders.Item; ???
pDrawingObject:=pLeaders.Item[J];
А если попытаться нажать кнопку с процедурой снова то новая ошибка:
Вы создаёте документ pDocument := pDocuments.Add(1,true); откуда там вид с номером 1 pView := pViews.ViewByNumber[1];, Вы хотябы в код немного вникните.
Почему то вставился старый код. Ты прав там ошибка была - я поменял (то есть добавил индекс итерации):
....
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item;
....
Ошибка возникала на свежем коде. Прикладываю обновленный проект. См. модуль WKMPS.
Цитата: Sabahs от 13.04.14, 17:14:37
Вы создаёте документ pDocument := pDocuments.Add(1,true); откуда там вид с номером 1 pView := pViews.ViewByNumber[1];, Вы хотябы в код немного вникните.
Я не знаю что эта процедура означает. Взял подходящий код из соседней ветки. Очень хочу вникнуть во все тонкости. Можете посоветовать что почитать? Кроме встроенного Хелпа - он настолько краткий, что чайнику такому как я многое не понятно.
Добавил в чертеж Вид с номером 1. Теперь новый документ не создается, но вылазит ошибка как на 4.PNG.
Что надо сделать с этим кодом чтобы он годился для редактирования открытых документов?:
....
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
pDocuments := newKompasAPI.Documents;
pDocument := pDocuments.Add(1,true);//(doc tupe,visible-regim)
pKompasDocument2D := pDocument as iKompasDocument2D;
....
pDocument := pDocuments.Add(1,true); меняете на pDocument := newKompasAPI.ActiveDocument
pKompasDocument2D := pDocument as iKompasDocument2D; - здесь не вылетит, если активный документ 2D.
В V15 справка по Api полное говно, можно пользоваться старой.
Цитата: Sprinter500 от 13.04.14, 17:17:21
Почему то вставился старый код. Ты прав там ошибка была - я поменял (то есть добавил индекс итерации):
....
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item;
....
Ошибка возникала на свежем коде. Прикладываю обновленный проект. См. модуль WKMPS.
Чудеса "I" в квадратных скобках исчезает через некоторое время, причем ее снова видно в цитате пока я писал этот текст.
Потому, что это тег, поставьте вместо I - J.
У тебя меняется pDocument на pDocuments. Не понятно. Сделал так:
//disp := IDispatch( CreateKompasApplication );
//newKompasAPI := disp As IApplication;
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
pDocuments := newKompasAPI.Documents;
//pDocument := pDocuments.Add(1,true);//(doc tupe,visible-regim)
pDocument := newKompasAPI.ActiveDocument;
//pKompasDocument2D := pDocument as iKompasDocument2D;
pKompasDocument2D := pDocument as iKompasDocument2D;
Вылазит та же ошибка. Может pDocuments := newKompasAPI.Documents; то же поменять надо? Я наверно задолбал уже "чайникизмом". Восхищаюсь твоим терпением :)
//disp := IDispatch( CreateKompasApplication );
//newKompasAPI := disp As IApplication;
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
pDocuments := newKompasAPI.Documents;
//pDocument := pDocuments.Add(1,true);//(doc tupe,visible-regim)
pDocument := newKompasAPI.ActiveDocument;
//pKompasDocument2D := pDocument as iKompasDocument2D;
pKompasDocument2D := pDocument as iKompasDocument2D;
Строчку выделенную жирным уберите, я код не отрабатываю, поэтому пропустил букву s, а ActiveDocument возвращает интерфейс IKompasDocument.
Все равно возникает такая ошибка:
Можете проект запустить с открытым в Компасе файлом где есть линии выноски от 1 до 3, может сразу ясно станет в чем дело?
Документ должен быть открыт, проверок у Вас нет, воспользуйтесь отладчиком, он всё покажет.
И так запущен. Как этим отладчиком воспользоваться? Я недавно начал в Delphi.
Отладчик - Debugger? Выдает вот это:
Поставьте точку останова, выполняйте по шагам свою процедуру и смотрите значения получаемых переменных после каждого шага.
Что то ничего толкового с точками останова не получается. Ладно уж, и на том спасибо. Остановился буквально в шаге от цели.
Что почитать на тему API7 и в целом на тему прог-ия под КОМПАС кроме справки посоветуете? А уж если кроме справки ничего нет, то по какой версии читать?
По Api7 книг не видел.
Выяснил что вызывает ошибку. Первая же строка в разделе begin процедуры:
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
Наверно для приложений как то иначе надо подключать?
УРА!!! Наконец то заработало! Проблема решена кодом:
...
var {модуля}
KOMPAS :IApplicationDisp;
ksDocs :IDocumentsDisp;
ksDoc :IKompasDocumentDisp;
...
procedure RENM();
var
pKompasDocument2D : IKompasDocument2D;
pViewsAndLayersManager : IViewsAndLayersManager;
pViews : IViews;
pView : IView;
pSymbols2DContainer : ISymbols2DContainer;
pDrawingContainer : IDrawingContainer;
pLeaders : ILeaders;
pBaseLeader : IBaseLeader;
pLeader : ILeader;
pDrawingObject : IDrawingObject;
I:integer;
oldValue, newValue: widestring;
begin
pKompasDocument2D := ksDoc as iKompasDocument2D;
pViewsAndLayersManager := pKompasDocument2D.ViewsAndLayersManager;
pViews := pViewsAndLayersManager.Views;
pView := pViews.ViewByNumber[1];
pView.Current := true;
pDrawingContainer := pView as iDrawingContainer;
pSymbols2DContainer := pView as iSymbols2DContainer;
pLeaders:= pSymbols2DContainer.Leaders;
oldValue:='2';
newValue:='5';
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item[1];
if pDrawingObject<>nil then
begin
if pDrawingObject.DrawingObjectType=ksDrLeader then
begin // Простая линия-выноска
pLeader:=pDrawingObject as ILeader;
if pLeader<>nil then
begin
if pLeader.TextOnShelf.Str=oldValue then
begin
pLeader.TextOnShelf.Str:=newValue;
pDrawingObject.Update;
end;
pLeader:=nil;
end;
end;
end;
end;
end;
procedure STRT();
begin
TRY
//KOMPAS:=CreateOleObject('KOMPAS.Application.7') as IApplicationDisp;
//KOMPAS.Visible:=TRUE;
KOMPAS:=GetActiveOleObject('KOMPAS.Application.7') as IApplicationDisp;
ShowMessage('КОМПАС запущен');
EXCEPT
KOMPAS:=nil;
END;
end;
procedure OPF();
begin
TRY
//sDocs:=IDocumentsDisp(KOMPAS.Documents);
ksDocs:=IDocumentsDisp(KOMPAS.ActiveDocument);
//ksDoc:=IKompasDocumentDisp( ksDocs.Open('D:\Study\dr.cdw', TRUE, FALSE) );
ksDoc:=IKompasDocumentDisp(ksDocs);
RENM();
ShowMessage('Открыли документ');
EXCEPT
ksDocs:=nil;
ksDoc:=nil;
END;
end;
//запускаем сначала STRT(); потом OPF();
Необходимый участок кода взял с ветки: http://forum.ascon.ru/index.php/topic,3363.msg19673.html#msg19673 пост Olegon. Спасибо ему и Sabahs. Осталось самое приятное - написать функционал самой программа. Всем помогавшим - вышлю готовую программу.
В нем есть строка:
ksDoc :IKompasDocumentDisp;
Почему то в справке по SDK нет ничего о IKompasDocumentDisp;
:)
Однако приведенный в предыдущем посте код рабочий (хотя показан не весь - остальное можно найти в выложенном ранее проекте).
Как быть с заменой текста в линиях-выносках, решили. А вот, еще вопрос знатокам: как реализовать замену вертикального текста в таблице? да и вообще в целом любого текста в таблице.
Стандартная замена в прикладной библиотеке Компаса не работает на вертикальном тексте.
Цитата: Sprinter500 от 14.04.14, 18:08:46
Выяснил что вызывает ошибку. Первая же строка в разделе begin процедуры:
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
Наверно для приложений как то иначе надо подключать?
У меня таких проблем нет.
Это у тебя для EXE скрин (так как Form1 есть) или все таки для RTW. Я так полагаю их по разному надо подключать. Пришли пож-та тот проект, что запечатлен на скриншоте - потестирую, может и у меня без проблем запустится? ))) А так проблема решена уже в принципе. Но все таки хочется знать "почему", если у тебя работает а у меня нет.
Может для Exe надо так же настройки проекта вносить как для RTW?:
2. В настройках проекта установить выравнивание: выключить опцию
Project Options - Compiler - Code Generation - Aligned Record fields.
Это из справки.
Для Exe, для rtw делается иначе. Весь проект на первом рисунке, плюс сам проект.
Цитата: Sprinter500 от 14.04.14, 20:40:51
Как быть с заменой текста в линиях-выносках, решили. А вот, еще вопрос знатокам: как реализовать замену вертикального текста в таблице? да и вообще в целом любого текста в таблице.
Стандартная замена в прикладной библиотеке Компаса не работает на вертикальном тексте.
Вертикальный текст обсуждался здесь http://forum.ascon.ru/index.php/topic,24881.msg180076.html#msg180076
Спасибо. А по номеру строки и столбца возможно ли организовать чтение текста из ячеек таблицы Компаса? И как быть с объединенными ячейками?
Цитата: Sabahs от 14.04.14, 21:22:26
У меня таких проблем нет.
Да. Ты прав. У меня тоже нет. Ситуация прояснилась - вместо:
newKompasAPI:=CreateOleObject('Kompas.Application.7') as iApplication;
для уже запущенного Компаса (а именно так мне надо было) надо:
newKompasAPI:=GetActiveOleObject('Kompas.Application.7') as iApplication;
К тому же не надо было связываться с диспетчером iDispatch - это похоже только для библиотек.
Вот пример более простого рабочего кода с исправленными ошибками:
procedure TForm1.Button1Click(Sender: TObject);
var
newKompasAPI: iApplication;
disp : IDispatch;
pDocuments : iDocuments;
pDocument : IKompasDocument;
pKompasDocument2D : IKompasDocument2D;
pViewsAndLayersManager : IViewsAndLayersManager;
pViews : IViews;
pView : IView;
pSymbols2DContainer : ISymbols2DContainer;
pDrawingContainer : IDrawingContainer;
pLeaders : ILeaders;
pBaseLeader : IBaseLeader;
pLeader : ILeader;
pDrawingObject : IDrawingObject;
I:integer;
oldValue, newValue: widestring;
begin
newKompasAPI:=GetActiveOleObject('Kompas.Application.7') as iApplication;
pDocuments := newKompasAPI.Documents;
pDocument := newKompasAPI.ActiveDocument;
pKompasDocument2D := pDocument as iKompasDocument2D;
pViewsAndLayersManager := pKompasDocument2D.ViewsAndLayersManager;
pViews := pViewsAndLayersManager.Views;
pView := pViews.ViewByNumber[1];
pView.Current := true;
pDrawingContainer := pView as iDrawingContainer;
pSymbols2DContainer := pView as iSymbols2DContainer;
pLeaders:= pSymbols2DContainer.Leaders;
oldValue:='2';
newValue:='5';
for I:=0 to pLeaders.Count-1 do
begin
pDrawingObject:=pLeaders.Item[1];
if pDrawingObject<>nil then
begin
if pDrawingObject.DrawingObjectType=ksDrLeader then
begin // Простая линия-выноска
pLeader:=pDrawingObject as ILeader;
if pLeader<>nil then
begin
if pLeader.TextOnShelf.Str=oldValue then
begin
pLeader.TextOnShelf.Str:=newValue;
pDrawingObject.Update;
end;
pLeader:=nil;
end;
end;
end;
end;
end;
В приведенном примере происходит замена текста для одной строки, а как быть если текст состоит из нескольких строк. Если я я правильно понял надо использовать iTextLine или iTextLines. Вопрос как? Пока не могу разобраться.
ЦитироватьВ приведенном примере происходит замена текста для одной строки, а как быть если текст состоит из нескольких строк.
Разбираться из чего состоит текст.
IText - Текст, состоит из iTextLines.
iTextLines - Массив SAFEARRAY строк текста, состоит из iTextLine.
iTextLine - Интерфейс строки текста, состоит из TextItems.
iTextItems - Массив SAFEARRAY компонентов строки текста, состоит из ITextItem.
Смотрите примеры Step1_API7_2D, Step2_API7_2D, Step3_API7_2D, чтобы понять, как устроен текст.
Что то я не могу найти в этих примерах, как работать с многострочным текстом. Везде только для одной строки пример, пускай и с интерфейсами IText, ITextLine.
А мне надо провести замену части текста в одно- или многострочном тексте в: линиях-выносках, позиционных линиях выносках, в тексте на чертеже и в таблицах.
Например: двух строчный текст АБВ
БКЕ, надо заменить букву Б на М и получить: АМВ
МКЕ.
У меня тоже примеров и времени на их написание нет, пробуйте разобраться самостоятельно, как работать с вариантными массивами показано здесь http://forum.ascon.ru/index.php/topic,24894.msg180294.html#msg180294 , только другие данные из них вытягиваются.
С многострочными текстами разобрался - без всяких массивов - многострочный текст читается как обычный только с символами переноса, замена участка текста (функцией StringReplace) работает без проблем. Код для замены текста в линиях-выносках и позиционных линиях-выносках готов. А как быть обычным с текстом на чертеже? Есть примеры?
Также, текст он и в Африке, текст.
Sabahs, зайди пожалуйста на эту ветку про таблицы: http://forum.ascon.ru/index.php/topic,24881.msg180076.html#msg180076
Остался не решенным вопрос - как организовать замену текста в объектах с названием "Текст на чертеже" средствами API7.
IDrawingContainer.IDrawingTexts - Интерфейс коллекции текстов на чертеже.
IDrawingContainer содержит IDrawingTexts который в свою очередь содержит IDrawingText, имеющий свойства:
Allocation - размещение относительно точки привязки
Angle - угол наклона
Height - высота блока форматирования
HFormat - признак гориз. форматирования
Height - во втрой раз высота блока форматирования :)
VFormat - признак. вертки. форматирования
Width - ширина блока форматирвоания
X
Y - координаты точки приявзки
Где тут текст считывать и задавать? Или я чего то не понимаю?
Открываем справку и смотрим иерархию, получаем текст.
plText:=pDrawingText as IText;
Я сейчас далеко от компа где Delphi, проверить не могу, но на всякий случай спрошу заранее:
Вот это строчки будет достаточно: plText:=pDrawingText as IText; ?
Не надо ли еще дополнительно писать непонятную процедуру: IUnknown::QueryInterface (const GUID far& iid, void** pif)?
А если надо то как?
Вы уж простите меня, что столько много вопросов - я не волшебник, а только учусь :)
plText:=pDrawingText as IText; - этого достаточно.
Я так понял когда применяется "AS" работет метод: IUnknown::QueryInterface (const GUID far& iid, void** pif)?
Просто встречаются два случая, где наподобе plText:=pDrawingText as IText; и другой где (условно) ABC:=KLM.XYZ;
Пока не понятно когда что сразу ставить заранее.
Да As для приведения интерфейсов от одного типа к другому.
ЦитироватьПока не понятно когда что сразу ставить заранее.
Смотреть на типы объектов.
Спасибо, теперь и замена в "тексте на чертеже" работает.
Еще вопрос появился: как организовать перебор открытых в КОМПАСе чертежей, с целью произвести замену в каждом из них?
IDocuments.Item
Уж думал больше вопросов не будет, еще появился:
Как организовать работу с основной надписью средствами API7 ? Существующие примеры нашел только на API5. Поначалу когда я не мог подключить API7 у меня подключалась и API5, наверно они конфликтуют - после того как убрал подключение к API5 все заработало в API7. Теперь у меня весь код на API7 и подключать API5 не вариант. Хотя может я ошибаюсь.
Нашел в SDK по API7 интерфейс IStamp. У него крайне скудный набор свойств и методов. Что делать? Или так же как с таблицей?
В штампе текст, картинки скорее всего, тоже реализованы через текст, а жаловаться на интерфейс IText, что у него мало свойств и возможностей, как то не получается.
В SDK написано что в штампе IText доступен только для чтения. Наверно неправильно понял. Буду пробовать.
Написал процедуру:
procedure TForm1.Button2Click(Sender: TObject);
var
pStamp: IStamp;
pLayoutSheets : ILayoutSheets;
pLayoutSheet : ILayoutSheet;
pStampText: IText;
I : INTEGER;
begin
pLayoutSheets:= pKompasDocument2D.LayoutSheets;
pLayoutSheet:=pLayoutSheets.ItemByNumber[1];
pStamp:= pLayoutSheet as IStamp;
for I := 0 to 200 do
begin
pStampText:= pStamp.Text[pStamp.GetNextColumnId(1)];
if pStampText.Str='zz' then pStampText.Str:='dd';
end;
end;
Вылазит такая же ошибка на строке pStamp:= pLayoutSheet as IStamp; как при ....2D1. Хотя может что то не то написал в коде? Что делать?
Проверки на nil делать и в отладчике смотреть, где появляется проблема.
да в отладчике и определил - уже выше написал где. И через as пробовал и так. можно даже закомментировать то что ниже все равно ошибка. Может я принципиально неправильно делаю?
pStamp остается nil после pStamp:= pLayoutSheet as IStamp;
pStamp:= pLayoutSheet.Stamp;
так тоже делал, может проблема выше:
pLayoutSheet:=pLayoutSheets.ItemByNumber[1]; В том что для оформления с номером 1 нет штампа?
Попробуй у себя весь код процедуры с pStamp:= pLayoutSheet.Stamp; Будут у тебя ошибки или нет? Она же короткая и времени много не отнимет.
Гаданием на кофейной гуще я заниматься не хочу, у Вас есть код и есть отладчик, если pLayoutSheets=nil, то дальше код не актуален, если pLayoutSheet=nil, тоже самое.
Так я не знаю что делать чтобы nil не было. Ладно если ужа так не получается, тогда как сделать так чтобы API5 и API7 могли существовать одновременно? По API5 есть рабочий пример.
Что равно nil самое первое из всей цепочки?
Почему не сделать, так pLayoutSheet:=pLayoutSheets.Item[0]; - ?
Вот на скрине:
Должен возвращать. Вы писали, что пробовали, что то под девятый Компас, он у Вас стоит?
Уже несколько лет как не стоит 9-й, а после переустновки винды только 13-й.
Всё прекрасно получается.
Повезло Вам, а вот что у меня с изменениями в коде чтобы вашему скриншоту соответствовало:
Похоже это еще одна проблема похожа на проблему с IKompasDocument2D1. Что интересно оба этих интерфейса IStamp
и IKompasDocument2D1 появились в 12-й версии Компаса. Хотя такая у меня вообще не стояла. Похоже Delphi рассматривает библиотеки как на 11-ю версию или ранее и считает что этих интерфейсов там нет.