Взаимодействие с ITableRange

Автор Sprinter500, 25.12.19, 11:07:30

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

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

Sprinter500

Добрый день! Не получается задать массив текстов в tableRange.Texts. Считывание массива текстов при этом работает. Вот пример кода:

        void RENTable2(IDrawingTable drawingTable, string A, string B) // Переименование в таблицах
        {
            if (drawingTable != null)
            {
                ITable table = (ITable)drawingTable;
                if (table != null)
                {
                    ITableRange tableRange = (ITableRange)table.Range[0, 0, table.RowsCount - 1, table.ColumnsCount - 1];
                    if (tableRange != null)
                    {
                        Array textsArray = (Array)tableRange.Texts;
                        for (long w = 0; w < textsArray.LongLength; w++)
                        {
                            string s = textsArray.GetValue(w).ToString();
                            s = s.Replace(A, B);
                            textsArray.SetValue(s, w);
                        }
                        tableRange.Texts = textsArray;  // ТУТ ВЫЛАЗИТ ОШИБКА !!!!!!!!!!!
                    }
                    drawingTable.Update();
                }
                table = null;
            }
            drawingTable = null;
        }


Вот на этой обратной функции вылазит ошибка:
System.Runtime.InteropServices.COMException
  HResult=0x80010105
  Сообщение = Ошибка на сервере. (Исключение из HRESULT: 0x80010105 (RPC_E_SERVERFAULT))


Вероятно требуется преобразование типа объекта textsArray в тип соответствующий tableRange.Texts, только как?

DesignЯR

В справке четко написано:
Документ 2D  > Таблица  > Интерфейс ITableRange  > ITableRange - свойства
Texts - Получить тексты из ячеек в виде массива VT_ARRAY | VT_BSTR
О том что можно записать речи вроде как и не идет.
Текст ячейки представляет собой структуру IText, поэтому, возможно можно передать массив именно такого типа данных, а не строк. Возможно просто не предусмотрено автоматическое преобразование строки в IText.


Sprinter500

Цитата: DesignЯR от 26.12.19, 10:58:21В справке четко написано:
Документ 2D  > Таблица  > Интерфейс ITableRange  > ITableRange - свойства
Texts - Получить тексты из ячеек в виде массива VT_ARRAY | VT_BSTR
О том что можно записать речи вроде как и не идет.
Текст ячейки представляет собой структуру IText, поэтому, возможно можно передать массив именно такого типа данных, а не строк. Возможно просто не предусмотрено автоматическое преобразование строки в IText.

Visual Studio отображает, что у метода TableRange.Texts есть и GET (получить) и SET (задать). И так как есть SET значит все таки записать новые значения в массив текстов TableRange.Texts как-то можно.



DesignЯR

Тогда вот так-вот можно поменять значения, только нужно добавить перебор ITextLines и ITextItems
 
            GetKompas();//функция получения компаса из приложения
            #region Получение выделенных объектов
            IApplication Application = kompas.ksGetApplication7();
            IKompasDocument KompasDocument = (IKompasDocument)Application.ActiveDocument;
            IKompasDocument2D KompasDocument2D = (IKompasDocument2D)KompasDocument;
            if (KompasDocument2D == null) { kompas.ksMessage("Нет активного 2D документа"); return; }
            IKompasDocument2D1 KompasDocument2D1 = (IKompasDocument2D1)KompasDocument2D;
            ISelectionManager SelectionManager = KompasDocument2D1.SelectionManager;
            #endregion
            int type = GetObjectType(SelectionManager.SelectedObjects);//функция определения типа выделенного объекта

            if (type == 25) // если выделена таблица
            {
                ITable Table = (ITable)SelectionManager.SelectedObjects;
                IDrawingTable DrawingTable = (IDrawingTable)Table;
                for (int i = 0; i < Table.RowsCount; i++)
                {
                    for (int j = 0; j < Table.ColumnsCount; j++)
                    {
                        ITableCell TableCell = Table.Cell[i, j];
                        ICellFormat CellFormat = (ICellFormat)TableCell;
                        IText Text = (IText)TableCell.Text;
                        ITextLine TextLine = Text.TextLine[0];//нужен перебор
                        ITextItem TextItem = TextLine.TextItem[0];//нужен перебор
                        Log.AppendText(TextItem.Str + Environment.NewLine); //Log - это TextBox
                        TextItem.Str = "new" + TextItem.Str; //здесь изменение текста Item'а Line'а TableCell'а
                        TextItem.Update();
                    }
                }
               DrawingTable.Update();
            }

333

Для замены текста в текстах объектов компас лучше использовать функцию
IText::Replace

333

В ячейках таблиц может быть также вертикальный текст который нужно находить и менять отдельно

333

bool EditText( ksAPI7::ITextPtr & text, bool addData )
{
  bool change = false;
  if ( text && text->Replace( oldStr, newStr, true/*Case*/, false/*WordOnly*/, true/*ReplaceAll*/ ) )
    change = true;
  if ( addData && EditAdditionDataTex(text) )
    change = true;
  return change;
}

bool EditAdditionDataTex( ksAPI7::ITextPtr & text )
{
  bool change = false;
  for ( long i = 0, count = text->Count; i < count; i++ )
  {
    ksAPI7::ITextLinePtr line( text->TextLine );
    if ( line )
    {
      ksTextLineType lineType = line->TextLineType;
      switch ( lineType )
      {
        case  ksTLVerticalText: // Вертикальный текст
        {
          ksAPI7::ITextPtr vertText( line->TextLineData );
          if ( EditText( vertText ) )
            change = true;
          break;
        }
        case ksTLTable: // Таблица в тексте текстового документа
        {
          ksAPI7::ITablePtr textTable( line->TextLineData );
          if ( EditTable( textTable ) )
            change = true;
          break;
        }
      }
    }
  }
  return change;
}

333

bool EditTable( ksAPI7::ITablePtr & table )
{

  bool change = false;
  if ( table )
  {
    long rCount = table->RowsCount;
    long cCount = table->ColumnsCount;

    for ( long i = 0; i < rCount; i ++ )
    {
      for ( long j = 0; j < cCount; j++ )
      {
        ksAPI7::ITableCellPtr cell = table->Cell[j];
        if ( cell )
        {
          ksAPI7::ITextPtr text( cell->Text );
          if ( EditText( text, true/*AddData*/ ) )
            change = true;
        }
      }
    }
  }
  return change;
}

Sprinter500

Уважаемые DesignЯR и 333, обычное хождение по ячейкам таблицы путем перебора строк и столбцов с двумя циклами уже реализовал и даже в параллельной ветке обсуждение было. Тут другой момент - такое хождение ячейка за ячейкой и получение текста почему-то работает медленно, особенно если таблица большая - занимает около минуты. Поэтому хотелось бы попробовать сделать тоже самое именно через ITableRange то есть всем скопом сразу, и сравнить скорость работы. Методы Get и Set у ItableRange.texts есть, поэтому надо как-то применить Set без поиска обходных путей.

Slaviation

Появилась информация, что в групповой установке текста в ячейки таблицы через ITableRange::Texts была недоработка, касающаяся C# и Python (может и каких других ЯП) и которая будет исправлена или в экспресс-обновлении или в 19-ой версии.
+ Благодарностей: 1

Sprinter500

Цитата: Slaviation от 27.12.19, 06:58:32Появилась информация, что в групповой установке текста в ячейки таблицы через ITableRange::Texts была недоработка, касающаяся C# и Python (может и каких других ЯП) и которая будет исправлена или в экспресс-обновлении или в 19-ой версии.

Спасибо, ясно. Будем ждать 19й версии. А экспресс-обновления к какой версии выходили?

Еще момент - конечно я это уже затрагивал в другой теме: в стандартной библиотеке RTW "сервисные инструменты" замена текста работает одинаково быстро как для таблиц так и для прочих объектов. И это без временного отключения графического интерфейса КОМПАСа. Я же пишу EXE-приложения. Мне объяснили, что возможно дело в маршаллинге и в межпроцессном взаимодействии. Так вот для прочих объектов замена текста из под моего приложения тоже работало медленно, пока не попробовал отключение графического интерфейса (дало прирост скорости в 5-10 раз) и использование функции Replace в самом объекте IText (прирост по скорости в 1,5 раза). После внесенных изменений скорость работы приложения сравнялась а в некоторых случаях стала чуть выше чем у стандартной библиотеки. Но не в случае с таблицами. Хождение по ячейкам работает ужасающе медленно. Значит раз в одном случае скорости равные, значит дело не в том, что у меня не RTW а EXE. Я прав?  Но ведь как то же в "сервисных инструментах" реализовали же быструю работу с таблицей! Еще один важный момент: в стандартной библиотеке посе ее работы постоянно вылазит сообщение "Неверный указатель массива" и также она не может работать с вертикальным текстом в ячейках таблицы (по состоянию на версии Компаса 15.2). Вот бы увидеть исходный код по части работы с таблицей у библиотеки "Сервисные инструменты".

P.S. Скорость работы мерил не "на глазок", а инструментально - встроенным в приложение таймером, то есть измерял время от начала до конца выполнения алгоритма.

Slaviation

ЦитироватьХождение по ячейкам работает ужасающе медленно. Значит раз в одном случае скорости равные, значит дело не в том, что у меня не RTW а EXE. Я прав?
Групповая замена текста в таблицах работала и сейчас работает, если написана на C++, и эта библиотека возможно написана на C++ и использует групповую замену.

Sprinter500

Цитата: Slaviation от 27.12.19, 12:40:30Групповая замена текста в таблицах работала и сейчас работает, если написана на C++, и эта библиотека возможно написана на C++ и использует групповую замену.


А можете пример на C++ привести как это примерно выглядит? Попробую сделать внешнюю DLL на С++ с одной единственной функцией, принимающей как аргумент ITableRange.

Vi2

Нужно, наверное, в техподдержку написать, что эта функция не работает.

Dim trange As KompasAPI7.ITableRange
Dim v, ss() As String
...
  ss = trange.Texts
  ss(0) = Replace(ss(0), "4", "7")
 
  trange.Texts = ss
  trange.Texts = (ss)
 
  v = ss
  trange.Texts = v
  trange.Texts = (v)

Ни один из этих методов не работает, значит, просто бага при работе этого свойства. Вряд ли С++ тут поможет.

Sprinter500

Цитата: Vi2 от 28.12.19, 12:12:02Нужно, наверное, в техподдержку написать, что эта функция не работает.

Dim trange As KompasAPI7.ITableRange
Dim v, ss() As String
...
  ss = trange.Texts
  ss(0) = Replace(ss(0), "4", "7")
 
  trange.Texts = ss
  trange.Texts = (ss)
 
  v = ss
  trange.Texts = v
  trange.Texts = (v)

Ни один из этих методов не работает, значит, просто бага при работе этого свойства. Вряд ли С++ тут поможет.


Я так понимаю работа API возможна 2 разными способами: Automation и COM. Я в программировании почти чайник, и не улавливаю между ними разницу. Знаю лишь, что C# работает только с Automation, а С++ (студия и билдер) и Delphi могут как с Automation работать, так и с COM. Вот наверно с ITableRange только через COM реально полноценно взаимодействовать.

Vi2

Цитата: Sprinter500 от 30.12.19, 11:15:31Я так понимаю работа API возможна 2 разными способами: Automation и COM. Я в программировании почти чайник, и не улавливаю между ними разницу. Знаю лишь, что C# работает только с Automation, а С++ (студия и билдер) и Delphi могут как с Automation работать, так и с COM. Вот наверно с ITableRange только через COM реально полноценно взаимодействовать.
Автоматизацию и СОМ можно считать синонимами, как объяснение разным людям одного и того же подхода. Вот описание из Вики: Microsoft OLE Automation. По мне разница - только в используемых типах данных. Например, в C++ можно использовать типы, которые не поддерживает VB или другие скриптовые движки. И, наоборот, механизмы, реализованные в VB и скриптах очень тяжело реализовать в C++.

Sprinter500

05.02.20, 07:07:28 #16 Последнее редактирование: 05.02.20, 07:43:10 от Sprinter500
Цитата: Vi2 от 30.12.19, 18:28:45Автоматизацию и СОМ можно считать синонимами, как объяснение разным людям одного и того же подхода. Вот описание из Вики: Microsoft OLE Automation. По мне разница - только в используемых типах данных. Например, в C++ можно использовать типы, которые не поддерживает VB или другие скриптовые движки. И, наоборот, механизмы, реализованные в VB и скриптах очень тяжело реализовать в C++.


Обнаружил, что обычный проход по строкам и столбцам большой таблицы (45х45 ячеек) из под C# занимает 15 сек, второй запуск уже работает в 10 раз быстрее за 1,5 сек. Значит Exe-программа как-то запоминает объекты (в данном случае ячейки таблицы)? Хотя в коде программы после использования объектов есть присвоение им значения NULL, то есть по идее ссылка на них должна теряться. Наверно какая-то индексация объектов происходит? Если так, то нельзя ли как-то проводить индексацию еще при старте EXE, чтобы потом не тратить время?

RTW-библиотека, написанная на DELPHI (без Automation) выполняет проход этой большой таблицы вообще за доли секунды - примерно 0,1-0,2 сек. Как-то можно не использовать Automation (он же ActiveX ???) в C#, чтобы работать наподобе? Если можно то как подключаться к КОМПАСу из под C# в таком случае?

Может что-то дополнительно с классом Marshal в C# надо делать?

Vi2

RTW библиотека грузится внутрь Компаса и не тратит время на маршаллинг. Если ты напишешь подобную на С#, то также получишь это преимущество. Главное - чтобы Компас твою модуль к себе загрузил. Иначе общение программ происходит через передачу данных между процессами.

Я не думаю, что кто-то индексирует объекты. Задержка, возможно, связана с подгрузкой сборки описания типов и выполнения запросов по СОМ. Я не думаю, что она сразу грузится, скорее, по мере запроса - ведь его может и не быть.

Vitalij Lysanov

Цитата: Sprinter500 от 05.02.20, 07:07:28Обнаружил, что обычный проход по строкам и столбцам большой таблицы (45х45 ячеек) из под C# занимает 15 сек, второй запуск уже работает в 10 раз быстрее за 1,5 сек.

Аналогичный эффект в программе Total Com.
Допустим по все машине ищем файлю. Нашли - порядок.
Запускаем поиск другого файла - ищет в 10 раз быстрее.

Кто-то запоминает список файлов?



__

В Компасе есть еще непонятное ускорение.
Допустим работает Макро.
Нажимаешь на кнопку на колесике мыши тоже ускорение раз в пять.

Когда нажимаешь кнопку мыши, Компас может отключать некоторые программы, т.к. не ждет в этом случае особых пакостей от пользователя.
Нажать кнопку - это обычно вращение.

Временно нажимать кнопку можно и программно


Sprinter500

Цитата: Vi2 от 05.02.20, 13:09:14RTW библиотека грузится внутрь Компаса и не тратит время на маршаллинг. Если ты напишешь подобную на С#, то также получишь это преимущество. Главное - чтобы Компас твою модуль к себе загрузил. Иначе общение программ происходит через передачу данных между процессами.

Я не думаю, что кто-то индексирует объекты. Задержка, возможно, связана с подгрузкой сборки описания типов и выполнения запросов по СОМ. Я не думаю, что она сразу грузится, скорее, по мере запроса - ведь его может и не быть.

Так вот как сделать подобное на C#, есть примеры?
По поводу подгрузки: только первый проход занимает 15 сек, все последующие по 1,5 сек. Можешь проверить. С чем это связано не знаю, но может быть процесс присутствующие в первом проходе и отсутствующие в остальных можно как-то "вынести за скобки" чтобы не мешал?