Ошибка работы спецификации в компас 18.1.13-18.1.15

Автор SerGoVec, 15.07.19, 15:02:23

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

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

SerGoVec

Всем привет!

Столкнулся с такой вот проблемой: недавно нужно было получить значение из колонки "Кол." из спецификации (Простая спецификация ГОСТ 2.106-96.) и если значение не удовлетворяет некому критерию записать свое значение. Все прекрасно работало - https://forum.ascon.ru/index.php/topic,30427.msg238976.html#msg238976 под КОМПАСом версии 18.1.9.

Обновился до 18.1.13 и...вместо ожидаемого результата получил повисший КОМПАС, выполняющий какую-то работу. Закрыть КОМПАС можно только через "убийство" процесса. Стал разбираться, отлаживать код своего приложения
procedure ChangeColumnCountSPW();
var
  doc: IKompasDocument;
  ks_spcDoc: ksSpcDocument;
  ks_spec: ksSpecification;
  ks_iter: ksIterator;
  ks_spcColumnParam: ksSpcColumnParam; //параметры колонки таблицы спецификации
  objID: Integer;
  countColumn: Integer;
  I: Integer;

begin
  doc := K7.ActiveDocument;

  //работа со спецификацией api 5
  try
    ks_spcDoc := ksSpcDocument(K5.SpcActiveDocument);
    ks_spec := (ks_spcDoc.GetSpecification as ksSpecification);
    countColumn := ks_spec.ksGetSpcTableColumn('',0,0);
    ks_iter := (K5.GetIterator as ksIterator);  //общий итератор
    ks_iter.ksCreateSpcIterator('',0,3);           //итератор для работы с объектами спецификации
   
    if ks_iter = nil then
      Exit;
 
    objID := ks_iter.ksMoveIterator('F');   
   
    if objID = 0 then
      Exit;
   
    //перебор объектов спецификации (вертикаль)
    while objID <> 0 do
    begin
      for I := 1 to countColumn do         //номера колонок начинаются с 1
      begin
        ks_spcColumnParam := (k5.GetParamStruct(ko_SpcColumnParam) as ksSpcColumnParam);
        ks_spec.ksGetSpcColumnType(objID, i, ks_spcColumnParam);

        var colType := ks_spcColumnParam.columnType;
//        if colType = SPC_CLM_COUNT then
//        begin
          var isp := ks_spcColumnParam.ispoln;
          var blok := ks_spcColumnParam.block;
          var txt := ks_spec.ksGetSpcObjectColumnText(objID, colType,isp,blok);

          ...
          ks_spec.ksSpcObjectEdit(objID);
          ks_spec.ksSetSpcObjectColumnText(SPC_CLM_COUNT,isp,blok,'5'); //как пример
          ks_spec.ksSpcObjectEnd;
//        end;
      end;

      objID := ks_iter.ksMoveIterator('N');
    end;

  finally
    ks_spcDoc := nil;
    //TODO дописать
  end;
end;


и вот что я увидел: перебор объектов спецификации (while objID <> 0 do) выполняется ВЕЧНО (зацикленно).

ObjID вначале получается как objID := ks_iter.ksMoveIterator('F'), а после прохода очередной итерации objID := ks_iter.ksMoveIterator('N'),  то есть objID проходится по всем объектам спецификации (в зависимости от ksCreateSpcIterator), последовательно, сверху-вниз. Казалось бы, все нормально, НО как только в спецификации встречается не базовый объект, например прочие изделия, внесенные в спецификацию руками, objID принимает значение первого базового объекта в спецификации и итерациия цикла начинается сначала, цикл становится зациклен.

Обновил КОМПАС до версии 18.1.15, проблема не исчезла!

Кто встречался с данной проблемой и как ее можно обойти?       

Вират Лакх

На кой сдался вам этот апи 5? У меня сложилось впечатление, что он медленнее седьмого. Я к "старому" обращаюсь, если нет такого в "новом" апи. Или если новый глючно работает. Попробуйте седьмой. На нем код короче должен быть. Цикл for вместо этих итераторов...

SerGoVec

да апи 5 я использовал только для спецификации, не видел примера под апи 7 для спецификации.
Буду благодарен если поделитесь примером работы со спецификацией под апи 7. :)

Вират Лакх

Вот пара функций из программы "Обозначение компонентов и тел" на питоне (см. вложение): копирование всех видимых внутренних ОС во внешние и удаление всех внешних ОС. Открывайте в редакторе, который корректно отображает табуляции.
+ Благодарностей: 1

SerGoVec

Использовал апи 7, вроде заработало:


...
doc.Active := True;
var spcDescrip := doc.SpecificationDescriptions;
var activeDescription := spcDescrip.Active;

var spcObjects := activeDescription.Objects;      //состав списка видимых объектов
//    for i in spcObj do //это в delphi не катит!
//    begin
//
//    end;

//вот delphi style
    var i := -1;
    //несколько объектов
    if VarType(spcObjects) = (VT_ARRAY or VT_DISPATCH) then
      i := VarArrayHighBound(spcObjects, 1)
    //один объект
    else if VarType (spcObjects) = VT_DISPATCH then
      i := 0;

    var Obj1: IDispatch;
    var j := 0;
    while j <> i+1 do
    begin
      if (i=0) and (VarType(spcObjects) = VT_DISPATCH) then
        Obj1 := spcObjects
      else
        Obj1 := spcObjects[j];

      if Obj1 <> nil then
      begin
        var pObject := Obj1 as ISpecificationObject;
        if pObject <> nil then
        begin
          //0- неизвестный тип 1- базовый объект 2- комментарий
          if pObject.ObjectType in [0,1,2] then
          begin
            //разбор колонок
            var colums  := pObject.Columns;
            var number  := string.Empty;
            var name  := string.Empty;
            var count   := string.Empty;

            for var a := 0 to (colums.Count - 1) do
            begin
              var column := colums.Item[a];
              var text    := column.Text;
              var str     := text.Str;

              if column.ColumnType = ksSColumnMark then
                number := str;

              if column.ColumnType = ksSColumnName then
                name   := str;

              if column.ColumnType = ksSColumnCount then
              begin
                count := str;
                if count  = string.Empty then
                  Continue;

                //...тут какая-то логика вычисления...

                text.str := string.Empty;      //если этого не делать, то значения как-то криво записываются.
                pObject.Update;                  //обязательно, иначе записи не будет.

                text.Str := c;                        //с некое вычисленное значение из логики вычисления
              end;
            end;
          end;
          pObject.Update;                        //обязательно, иначе записи не будет.
        end;
      end;
      Inc(j);
    end;
...
+ Благодарностей: 1

Neelliguino

Вы попали в самую точку. В этом что-то есть и это хорошая идея. Я Вас поддерживаю.