• Добро пожаловать на Форум пользователей ПО АСКОН. Пожалуйста, авторизуйтесь.
 

Уважаемые пользователи,

Хотим проинформировать вас о режиме работы регистрации на нашем сайте.

Зарегистрироваться возможно в рабочие дни, с 8:00 до 20:00 (мск).

Если у вас возникнут вопросы или потребуется дополнительная информация, не стесняйтесь обращаться к нашей службе поддержки. Вы можете связаться с нами по указанным контактным данным на нашем сайте.

Благодарим вас за понимание и сотрудничество. Мы ценим ваше терпение и стремимся предоставить вам лучший опыт использования нашего сервиса.

С уважением,
Команда Ascon

Спецификация. Стандартные изделия. Табличный атрибут.

Автор midreyk, 21.01.22, 08:30:27

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

midreyk

Здравствуйте.
Пытаюсь сделать свои стандартные изделия 3D. Каждый экземпляр - отдельный файл с внешним объектом спецификации.
Подскажите как добраться до табличного атрибута объекта спецификации стандартного изделия. API7
Есть деталь с единственным объектом спецификации, вставленным шаблоном.
Теперь нужно изменить параметры и сохранить под другим именем.
добрался до базового объекта, даже номер атрибута есть. А как сам атрибут-то открыть?
Вот код на питоне 3.10
# -*- coding: utf-8 -*-

import pythoncom
from win32com.client import Dispatch, gencache


# Получить интерфейсы API 7 КОМПАС
def get_kompas_api7():
        module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
        api = module.IKompasAPIObject(Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(module.IKompasAPIObject.CLSID, pythoncom.IID_IDispatch))
        const = gencache.EnsureModule("{75C9F5D0-B5B8-4526-8681-9903C567D2ED}", 0, 1, 0)
        return module, api, const.constants

module_7,  i_kompas_api_object, const_7 = get_kompas_api7()
application = i_kompas_api_object.Application
iKompasDocument = application.ActiveDocument
iSpecificationDescription = iKompasDocument.SpecificationDescriptions.Active
BaseObject = iSpecificationDescription.BaseObjects.Item(0)
print(BaseObject.AttributeNumber)

midreyk

Есть подозрение, что это можно сделать так:
iAttribute = iKompasDocument1.Attributes(0, 0, 0, 0, 0, BaseObject)
Но нет, ничего не передается. Наверное вместо нулей что-то другое надо? Или это вообще не то...

graphdark

Вот интерфейс IProperty и IPropertyKeeper. Просто я как-то без этого обошелся и у меня для молели раздел либо стандартные, либо детали.

Посмотрите функцию, там много чего.
function Create3D(name, design, path, filename: string): boolean;
var
  iDoc3D: ksDocument3D;
  ColorParam: ksColorParam;
  iPart, phantom: ksPart;
  EntityCollection, ecoll: ksEntityCollection;
  EntityConcentric, EntityConcidence, EntityConcentric2, EntityConcidence2
    : ksEntity;
  EntityFaceDistance1, EntityFaceDistance2: ksEntity;
  iRequestInfo3D: ksRequestInfo3D;
  ikompas: KompasObject;
  Place: ksPlacement;
  iUserParam: ksUserParam;
  VarCol: ksVariableCollection;
  variable: ksVariable;
  strPromt, strPromt1: string;
  i, count: integer;
begin
  ikompas := KompasObject(GetActiveOleObject('Kompas.Application.5'));
  if ikompas = nil then
    Exit;

  iDoc3D := ksDocument3D(ikompas.ActiveDocument3D);
  if iDoc3D = nil then
    Exit;
  iPart := ksPart(iDoc3D.GetPart(pNew_Part));
//  ColorParam := ksColorParam(ipart.ColorParam);
//  ColorParam.Color := StUnit.ColorVar; // 15387420-голубой;//16744448-синий;
//  iPart.SetAdvancedColor(ColorParam.Color, 0.5, 0.6, 0.5, 0.8, 0.8, 1);
//  iPart.Update;
  iUserParam := ksUserParam(ikompas.GetParamStruct(ko_UserParam));
  iUserParam.number := 1;
  iPart.standardComponent := true;
  iPart.name := Name;
  iPart.filename := path + filename;
  iRequestInfo3D := ksRequestInfo3D(iDoc3D.GetRequestInfo(iPart));
  iRequestInfo3D.prompt := 'Укажите положение стандартного изделия';
  iRequestInfo3D.SetCallBack('SELECTCALLBACKPROC', hinstance, nil);
  iRequestInfo3D.SetFilterCallBack('SELECTFILTERPROC', hinstance, nil);
  iRequestInfo3D.CreatePhantom;
  phantom := ksPart(iRequestInfo3D.GetIPhantom);
  phantom.standardComponent := true;
//  iDoc3D.drawMode := vm_Shaded;
//  phantom1 := ksFeatureCollection(iRequestInfo3D.GetIPhantom);
  VarCol := ksVariableCollection(phantom.VariableCollection);
//      ShowMessage('here');
  count := VarCol.GetCount();
//        ShowMessage(intToStr(count));
  if StUnit.DBGrid2.Visible = false then
  begin
    for i := 0 to count - 1 do
    begin
      variable := ksVariable(VarCol.GetByIndex(i));
      if variable.name = 'h' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('h').AsFloat;
      // ShowMessage(StUnit.DBGrid1.DataSource.DataSet.FieldByName('h').AsString);
      if variable.name = 'h1' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('h1').AsFloat;
      if variable.name = 'l' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('l').AsFloat;
      if variable.name = 'l1' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('l1').AsFloat;
      if variable.name = 'a' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('a').AsFloat;
      if variable.name = 'd' then
        variable.value := StUnit.DBGrid1.DataSource.DataSet.FieldByName
          ('d').AsFloat;
    end;
    // kompas.ksExecuteKompasCommand(prMovePart, True);
  end
  else
  begin
    for i := 0 to count - 1 do
    begin
      // ShowMessage('here');
      variable := ksVariable(VarCol.GetByIndex(i));
      if variable.name = 'd1' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('d1').AsFloat;
      if variable.name = 'D' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('D').AsFloat;
      if variable.name = 'k' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('k').AsFloat;
      if variable.name = 'r1' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('r1').AsFloat;
      if variable.name = 'h' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('h').AsFloat;
      if variable.name = 'b' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('b').AsFloat;
      if variable.name = 'l' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('Lenght').AsFloat;
      if variable.name = 'S' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('S').AsFloat;
      if variable.name = 'e' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('e').AsFloat;
      if variable.name = 'fas' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('fas').AsFloat;
      if variable.name = 'h' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('h').AsFloat;
      // ShowMessage(DBGrid2.DataSource.DataSet.FieldByName('h').AsString);
      if variable.name = 'h1' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('h1').AsFloat;
      if variable.name = 'i' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('i').AsFloat;
      if variable.name = 'l1' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('l1').AsFloat;
      if variable.name = 'a' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('a').AsFloat;
      if variable.name = 'd' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('d').AsFloat;
      if variable.name = 't' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('t').AsFloat;
      if variable.name = 'r' then
        variable.value := StUnit.DBGrid2.DataSource.DataSet.FieldByName
          ('r').AsFloat;
    end;
    phantom.RebuildModel;
  end;

//  phantom := kspart(iRequestInfo3D.GetIPhantom);
  if StUnit.mate then
  begin
    EntityCollection := ksEntityCollection(ipart.EntityCollection(o3d_face));
    EntityConcentric := ksEntity(phantom.GetDefaultEntity(o3d_axisOZ));
    EntityConcidence := ksEntity(phantom.GetDefaultEntity(o3d_planeXOY));
    strPromt := 'Укажите отверстие';
    strPromt1 := 'Укажите плоскость совпадения';
    EntityConcentric2 := ksEntity(iDoc3D.UserSelectEntity(nil,
      'SELECTFILTERPROC', strPromt, hinstance, nil));
    EntityConcidence2 := ksEntity(iDoc3D.UserSelectEntity(nil,
      'SELECTFILTERPROC', strPromt1, hinstance, nil));

    if iDoc3D.UserGetPlacementAndEntity(2) then
    begin
      iPart.SetPlacement(iRequestInfo3D.GetPlacement);
      iDoc3D.SetPartFromFile(path + filename, iPart, true);
      iDoc3D.AddMateConstraint(mc_Concentric, EntityConcentric,
        EntityConcentric2, integer(StUnit.direction), 1, 0);
      iDoc3D.AddMateConstraint(0, EntityConcidence, EntityConcidence2,
        integer(StUnit.direction), 1, 0);
      iPart.UpdatePlacement;
    end;
    iPart.SetUserParam(iUserParam);
    iPart.marking := design;
    // iPart.useColor := 3;
  end
  else
  begin
    if iDoc3D.UserGetPlacementAndEntity(0) then
    begin
      iPart.SetPlacement(iRequestInfo3D.GetPlacement);
      iDoc3D.SetPartFromFile(path + filename, iPart, true);
      iPart.UpdatePlacement;
    end;
    iPart.SetUserParam(iUserParam);
    iPart.marking := design;
    // iPart.useColor := 3;
  end;
//  ColorChange(iPart);
  iPart.useColor := 0;
  ColorParam := ksColorParam(ipart.ColorParam);
//  ipart.marking := 'test';
  ColorParam.Color := StUnit.ColorVar; // 15387420-голубой;//16744448-синий;
//  iPart.SetAdvancedColor(ColorParam.Color, 0.5, 0.6, 0.5, 0.8, 0.8, 1);
  iPart.Update;
end;

midreyk

Спасибо за ответ. Попробую посмотреть когда время будет.  :w:

Denis78

Подскажите, пожалуйста, а как извлечь Атрибуты Документа?

attr.jpg

Я делаю так:
...
IKompasDocument3DPtr doc3D(newKompasAPI->ActiveDocument);
res = doc3D.QueryInterface(IID_IKompasDocument1, &kd1);
_variant_t at = kd1->GetAttributes(0, 0, 0, 0, 0, NULL); // Здесь получаю атрибуты
PrintAttr(at);

Собственно, функция PrintAttr:

void PrintAttr(const _variant_t& varArr)
{
    if (varArr.vt == (VT_ARRAY | VT_DISPATCH))
    {
        int count = varArr.parray->rgsabound[0].cElements - varArr.parray->rgsabound[0].lLbound; // Здесь все прекрасно, у меня 2 атрибута и count = 2, ура
        if (varArr.parray->cDims == 1)
        {
            HRESULT hr;
            LPDISPATCH HUGEP *pvar;
            hr = ::SafeArrayAccessData(varArr.parray, (void HUGEP* FAR*)&pvar);
            if (!FAILED(hr) && pvar)
            {
                for (int i = 0; i < count; i++)
                {
                    long idx = i;
                    // Хочется вызвать SafeArrayGetElement, но что я получу? Какого типа будет этот атрибут?
                    hr = SafeArrayGetElement(varArr.parray, &idx, ????); // [1]
                }
                hr = ::SafeArrayUnaccessData(varArr.parray);
            }
        }
    }
}

Хочется вызвать SafeArrayGetElement, но что я получу? Какого типа будет этот атрибут?
Никакого IAttribute я не нашел.
Далее, у меня один атрибут строковый, другой числовой. Это как-то можно различить? Ну, то есть, тип его получить (строковый/числовой).

Denis78

Был не прав, IAttribute есть. Теперь цикл for выглядит так:

for (int i = 0; i < count; i++)
{
    long idx = i;
    IAttributePtr attr;
    IDispatchPtr dis;
    hr = SafeArrayGetElement(varArr.parray, &idx, &attr);
    dis = attr;
    GetType(dis);

    // Ну, и вызываем любой метод объекта IAttribute, например, GetType():
    KompasAPIObjectTypeEnum type = attr->GetType();
}

Ну, и вызываем любой метод объекта IAttribute, например, GetType(). Можно любой другой, результат один - Access Violation. Такое впечатление, что attr указатель на какой-то иной интерфейс, а не IAttribute. Что же это тогда? Как узнать?

В попытке самостоятельно ответить на этот вопрос, написал функцию GetType():

void GetType(IDispatchPtr attr)
{
    ITypeInfoPtr pInfo;
    HRESULT hr = attr->GetTypeInfo(0, 0, &pInfo);
    TYPEATTR * ta = (TYPEATTR *)malloc(sizeof(TYPEATTR));
    pInfo->GetTypeAttr(&ta);                                   // [1]
}

На последней строчке (то есть [1]) ставлю бряку. Структура ta имеет поле guid, так вот оно равно IID_IAttribute.
То есть attr все-таки указывает на интерфейс IAttribute? Тогда почему происходит крэш (Access Violation)?

Так это выглядит

Михаил88

Screenshot_3.png
В документе создал 2 атрибута

теперь их читаю

# -*- coding: utf-8 -*-
import pythoncom
from win32com.client import Dispatch, gencache

#  Подключим описание интерфейсов API7
kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
application = kompas_api7_module.IApplication(
    Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(kompas_api7_module.IApplication.CLSID,
                                                            pythoncom.IID_IDispatch))
kompas_document = application.ActiveDocument
iAttrTypeMng = kompas_api7_module.IAttrTypeMng(application)
print(iAttrTypeMng)
attributes = iAttrTypeMng.GetAttrTypes(kompas_document)
print(attributes)
"""
ksATUnknown -1 Неизвестный
ksATString 0 Строка
ksATDouble 1 Число
ksATFixedTable 2 Таблица с фиксированным числом строк
ksATVariableTable 3 Таблица с переменным числом строк
"""
for attr in attributes:
    type_name = attr.TypeName
    print(type_name)
    attr_type = attr.AttrType
    print(attr_type)

Screenshot_4.png

вот, что получаю на выходе

0 и 1 это тип данных
0 - Строка
1 - Число
+ Благодарностей: 1

Михаил88

Можно так

# -*- coding: utf-8 -*-
import pythoncom
from win32com.client import Dispatch, gencache

#  Подключим описание интерфейсов API7
kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
application = kompas_api7_module.IApplication(
    Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(kompas_api7_module.IApplication.CLSID,
                                                            pythoncom.IID_IDispatch))
kompas_document = application.ActiveDocument
kompas_document_1 = kompas_api7_module.IKompasDocument1(kompas_document)
attributes = kompas_document_1.Attributes(0, 0, 0, 0, 0, kompas_document)
print(attributes)
for attr in attributes:
    value = attr.Value(0, 0)
    print(value)
    attribute_type = attr.AttributeType
    # print(attribute_type)
    type_name = attribute_type.TypeName
    print(type_name)
    attr_type = attribute_type.AttrType
    print(attr_type)

Screenshot_5.png

ПРивет и 140.0 это значения
Screenshot_6.png
+ Благодарностей: 1

Denis78

22.04.22, 14:22:10 #8 Последнее редактирование: 22.04.22, 15:54:00 от Denis78
Получилось. На С++, правда, все выглядит не так просто как на Питоне. Но как-то работает.
Теперь добавил еще два атрибута, один - таблица с фиксированной длиной, второй - с произвольной. И опять "забуксовал"

// Атрибут - таблица:
IAttributePtr attr(pvar[i]);
long cc = attr->GetColumnsCount();          // Тут верное кол-во строк
long rc = attr->GetRowsCount();             // Верное кол-во столбцов
VARIANT colKey = attr->GetColumnKey();
for (long i = 0; i < cc; i++)
{
    VARTYPE vt = colKey.vt;                // vt = 0x02003, то есть VT_ARRAY|VT_I4 или, по-русски говоря, массив int-ов
    if (colKey.parray)
    {
        int count = val.parray->rgsabound[0].cElements - val.parray->rgsabound[0].lLbound;  // [1] -Access Violation
        ULONG elems = val.parray->cbElements;                                               // [2] -Access Violation
       
    }
}

То есть, беру атрибут таблицу. Могу получить кол-во строк и столбцов, но не знаю, как их использовать.
Могу через вызов GetColumnKey() получить массив int-ов, но не могу работать с ним как с массивом, в строках [1] и [2] будет Access Violation

Михаил88

я не совсем понял зачем вам ключи. Если надо получить все значения из таблицы то values = attr.Values
возвращается кортеж всех значений из таблицы.
для примера
(' АБВГД.001', ' АБВГД.002', ' АБВГД.003', ' Пластина', ' Кронштейн', ' Проушина', 10, 5, 1, ' Детали', ' Детали', ' Детали')
Screenshot_7.png
Если надо получить какое то определенное значение тогда так
value =attr.Value( RowNumb, ColumnNumb )
RowNumb (long) - номер строки атри­бута
ColumnNumb (long) - номер столбца атри­бута.
Для эксперимента присвоил каждому столбцу свой ключ:
Столбцу обозначение - 1
наменованию - 2
количеству - 3
разделу - 4
после выполнения
column_key = attr.ColumnKey
получил кортеж с ключами
(1, 2, 3, 4)

Vi2

Цитата: Denis78 от 21.04.22, 13:52:22Был не прав, IAttribute есть. Теперь цикл for выглядит так:
for (int i = 0; i < count; i++)
{
    long idx = i;
    IAttributePtr attr;
    IDispatchPtr dis;
    hr = SafeArrayGetElement(varArr.parray, &idx, &attr);
    dis = attr;
    GetType(dis);
...
}
Ну, и вызываем любой метод объекта IAttribute, например, GetType(). Можно любой другой, результат один - Access Violation. Такое впечатление, что attr указатель на какой-то иной интерфейс, а не IAttribute. Что же это тогда? Как узнать?
Правильно, и в хелпе написано, что тип данных - IDispatch. И ты сам проверяешь тип варианта на VT_DISPATCH в предыдущих сообщениях. Однако почему-то считаешь, что у тебя интерфейс IAttribute. С чего? Только с того, что ты так написал? А функция SafeArrayGetElement не делает преобразование интерфейсов, она просто копирует содержимое!

Вот у тебя правильно было написано (без всяких этих заморочек с HUGEP и FAR):
            LPDISPATCH *pvar;
            hr = ::SafeArrayAccessData(varArr.parray, (void**)&pvar);
Следовательно, pvar[ i ] и есть требуемый интерфейсный указатель, т.е. уже не нужно обращаться к SafeArrayGetElement, хотя можно и через эту функцию, но тогда нужно поменять местами принимаемые интерфейсы:
1)
    IAttributePtr attr = pvar[i];
2)
    IDispatchPtr dis;
    hr = SafeArrayGetElement(varArr.parray, &idx, &dis);
    IAttributePtr attr = dis; // Вот здесь будет запрошен интерфейс IAttribute и можно безопасно вызвать его методы

Vi2

Цитата: Denis78 от 22.04.22, 14:22:10int count = val.parray->rgsabound[0].cElements - val.parray->rgsabound[0].lLbound;  // [1] -Access Violation
ULONG elems = val.parray->cbElements;
Ну а что это за переменная val?

Причём поле cElements и есть число значений, не нужно из него вычитать что-либо. Вот у массива есть функции SafeArrayGetUBound и SafeArrayGetLBound, вот там нужно оперировать их разностью.

VARIANT colKey = attr->GetColumnKey();
...
if (colKey.vt == (VT_ARRAY|VT_I4))
{
   int* colItems;
   hr = ::SafeArrayAccessData(colKey.parray, (void**)&colItems);
   for(i=0; i<count; i++)
        ; // используем значение атрибута colItems[i] как целое число
   hr = ::SafeArrayUnaccessData(colKey.parray);
}