Создание прогресс бара

Автор Тема: Создание прогресс бара  (Прочитано 21903 раз)

0 Пользователей и 4 Гостей просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Павел55Автор темы

  • ADN OPEN
  • ***
  • Сообщений: 106
  • Карма: 3
Создание прогресс бара
« : 18-04-2019, 13:26:41 »
пытаюсь создать прогресс бар, но выдает ошибки  в тех местах, где в качестве аргумента передается база данных
я так понимаю это что то связанное с потоками, потому что если вызывать только метод work (коммандой ss), то все работает


Код - C# [Выбрать]
  1.     public class Class1
  2.     {
  3.  
  4.         MainWindow mw = new MainWindow();
  5.         Document curenntdoc;
  6.         [CommandMethod("ss")]
  7.         public void CreateFromTin()
  8.         {
  9.             curenntdoc = Application.DocumentManager.MdiActiveDocument;
  10.             mw.bworker.DoWork += work;
  11.             mw.bworker.RunWorkerAsync();
  12.  
  13.         }
  14.         public void work(object sender, DoWorkEventArgs e)
  15.         {
  16.             Editor ed = curenntdoc.Editor;
  17.             using (Transaction ts = curenntdoc.Database.TransactionManager.StartTransaction())
  18.             {
  19.  
  20.                 Database db = curenntdoc.Database;
  21.                 CivilDocument civil_doc = CivilApplication.ActiveDocument;
  22.                 ObjectId surface_id1 = civil_doc.GetSurfaceIds()[1];
  23.                 Autodesk.Civil.DatabaseServices.TinSurface tin_surface1 = surface_id1.GetObject(OpenMode.ForRead) as Autodesk.Civil.DatabaseServices.TinSurface;
  24.  
  25.                 ObjectId newSurfid = TinSurface.Create(db, "Surf1");
  26.  
  27.                 TinSurface newtin = newSurfid.GetObject(OpenMode.ForWrite) as TinSurface;
  28.                 newtin.CopyFrom(tin_surface1);
  29.                 newtin.RaiseSurface(5);
  30.                 ObjectId borderId = newtin.ExtractBorder(Autodesk.Civil.SurfaceExtractionSettingsType.Plan)[0];
  31.                 Polyline3d border = borderId.GetObject(OpenMode.ForRead) as Polyline3d;
  32.                
  33.                 Point3dCollection vertexInPoly = new Point3dCollection();
  34.                 foreach (ObjectId acObjIdVert in border)
  35.                 {
  36.                     PolylineVertex3d acPolVer3d;
  37.                     acPolVer3d = ts.GetObject(acObjIdVert,
  38.                                                    OpenMode.ForRead) as PolylineVertex3d;
  39.                    
  40.                     vertexInPoly.Add(acPolVer3d.Position);
  41.                 }
  42.                 Point3dCollection offsetline = new Point3dCollection();
  43.                 List<string> angle = new List<string>();
  44.                 for (int i = 0; i < vertexInPoly.Count-1; i++)
  45.                 {
  46.                     int k = i - 1;
  47.                     if (k < 0)
  48.                     {
  49.                         k = vertexInPoly.Count - 2;
  50.                     }
  51.                     int j = i + 1;
  52.                     if (j > vertexInPoly.Count - 2)
  53.                     {
  54.                         j = 0;
  55.                     }
  56.                     Mpoint m = new Mpoint(vertexInPoly[k], vertexInPoly[i], vertexInPoly[j], 5);
  57.  
  58.                     //////////////////////////////////////////////
  59.                     Thread.Sleep(1000);
  60.                     mw.bworker.ReportProgress(1);
  61.  
  62.                     if (m.SharpAngle == false)//если угол больше 180 - строим дугу между перпендикулярами
  63.                     {
  64.                         offsetline.Add(m.OrthoPointFromEdge1);
  65.                         foreach (Point3d item in m.PointInAngle)
  66.                         {
  67.                             offsetline.Add(item);
  68.                         }
  69.                         offsetline.Add(m.OrthoPointFromEdge2);
  70.                     }
  71.                     else if (m.SharpAngle == true)// если угол меньше 180 - строим одну точку(угол)
  72.                     {
  73.                      
  74.                         if (m.GetDist(vertexInPoly[k], vertexInPoly[j]) > 10)// если расстояние между двумя(крайними) точками меньше расстояния подобия*2 то не строим угловую точку
  75.                         {
  76.                             offsetline.Add(m.Intersect);
  77.                         }
  78.                        
  79.                     }
  80.                    
  81.                     //////////////////////////////////////////////
  82.                    
  83.                     string s = "угол " + i.ToString() + " " + m.Angle.ToString() + " " + m.SharpAngle.ToString() + "  Кол-во точек для угла: " + m.CountPointInAngle.ToString();
  84.                     angle.Add(s + "\n");
  85.                 }
  86.  
  87.                 BlockTable acBlkTbl;
  88.                 acBlkTbl = ts.GetObject(db.BlockTableId,
  89.                                              OpenMode.ForRead) as BlockTable;
  90.  
  91.                 // Open the Block table record Model space for write
  92.                 BlockTableRecord acBlkTblRec;
  93.                 acBlkTblRec = ts.GetObject(acBlkTbl[BlockTableRecord.ModelSpace],
  94.                                                 OpenMode.ForWrite) as BlockTableRecord;
  95.                 Polyline3d newpoly = new Polyline3d();
  96.                 newpoly.SetDatabaseDefaults();
  97.                 newpoly.ColorIndex = 1;
  98.  
  99.                 // Add the new object to the block table record and the transaction
  100.                 acBlkTblRec.AppendEntity(newpoly);
  101.                 ts.AddNewlyCreatedDBObject(newpoly, true);
  102.  
  103.                 for (int i = 0; i < offsetline.Count; i++)
  104.                 {
  105.                     newpoly.AppendVertex(new PolylineVertex3d(offsetline[i]));
  106.                 }
  107.                 newpoly.Closed = true;
  108.                 foreach (string s in angle)
  109.                 {
  110.                     ed.WriteMessage(s);
  111.                 }
  112.                 foreach (Point3d p in vertexInPoly)
  113.                 {
  114.                     ed.WriteMessage(p.X.ToString() + " / " + p.Y.ToString());
  115.                 }
  116.                 ts.Commit();
  117.             }
  118.  
  119.         }
  120.  
  121.         }            
  122.  
« Последнее редактирование: 18-04-2019, 13:56:52 от Александр Ривилис »

Оффлайн Алексей Терно

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: Создание прогресс бара
« Ответ #1 : 18-04-2019, 13:37:33 »
Создание прогресс бара:
Код - C# [Выбрать]
  1. ProgressMeter pm = new ProgressMeter();
  2. pm.SetLimit(max_len);
  3. pm.Start("текст");
  4. System.Windows.Forms.Application.DoEvents();

В цикле для увеличения счетчика:
Код - C# [Выбрать]
  1. pm.MeterProgress();
  2. System.Windows.Forms.Application.DoEvents();

Убрать прогресс бар после выполнения:
Код - C# [Выбрать]
  1. pm.Stop();
  2. System.Windows.Forms.Application.DoEvents();

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Создание прогресс бара
« Ответ #2 : 18-04-2019, 13:58:18 »
Павел55,
Внимательно прочитайте у меня в подписи как следует форматировать код для форума и соблюдайте это правило!
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Создание прогресс бара
« Ответ #3 : 18-04-2019, 13:59:54 »
я так понимаю это что то связанное с потоками, потому что если вызывать только метод work (коммандой ss), то все работает
Правильно понимаешь. AutoCAD не потокобезопасный. Обращаться к его API безопасно можно только из основного потока.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Павел55 27-07-2019, 08:47:51

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Создание прогресс бара
« Ответ #4 : 18-04-2019, 15:50:59 »
Создание прогресс бара:
Код - C# [Выбрать]
  1. ProgressMeter pm = new ProgressMeter();
  2. pm.SetLimit(max_len);
  3. pm.Start("текст");
  4. System.Windows.Forms.Application.DoEvents();

В цикле для увеличения счетчика:
Код - C# [Выбрать]
  1. pm.MeterProgress();
  2. System.Windows.Forms.Application.DoEvents();

Убрать прогресс бар после выполнения:
Код - C# [Выбрать]
  1. pm.Stop();
  2. System.Windows.Forms.Application.DoEvents();
Иногда стандартный прогресс-бар лучше не использовать. Например, когда к нему параллельно внутренние механизмы обращаются. Тогда можно сделать свой на любой вкус и цвет с помощью WPF. В общем случае, даже писать ничего не надо - примеры реализации есть в сети.
Недавно, например, вот такой сделал:

Ещё примерчик:

Кстати, а что эта тема делает в Civil 3D?
« Последнее редактирование: 18-04-2019, 16:27:12 от Дмитрий Загорулькин »

Оффлайн Павел55Автор темы

  • ADN OPEN
  • ***
  • Сообщений: 106
  • Карма: 3
Re: Создание прогресс бара
« Ответ #5 : 19-04-2019, 22:24:56 »
И все равно не понимаю как заставить работать прогресс бар.
Получатся у меня 2 потока - один это в AutoCAD, второй - прогресс бар. после запуска происходит следующее:
открывается окно с прогресс баром, выполняются все вычисления в цикле, а потом (по завершению цикла )
в прогресс бар передается последнее значение цикла. То есть он срабатывает, когда все вычисления закончены. Как заставить его работать синхронно с циклом?
Код - C# [Выбрать]
  1. namespace PtogressBar
  2. {
  3.     /// <summary>
  4.     /// Логика взаимодействия для MainWindow.xaml
  5.     /// </summary>
  6.     public partial class MainWindow : Window
  7.     {
  8.         private object threadLock = new object();
  9.         public MainWindow()
  10.         {
  11.             InitializeComponent();
  12.             System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(updadingThread));
  13.             t.Start();
  14.         }
  15.         public delegate void Update(int value);
  16.         public void updadeBar(int value)
  17.         {
  18.            
  19.             this.PG.Value = value;
  20.         }
  21.  
  22.         public void updadingThread(object sender)
  23.         {
  24.             Update update = new Update(updadeBar);
  25.  
  26.         }
  27.     }
  28. }


               
Код - C# [Выбрать]
  1.  MainWindow mw = new MainWindow();
  2.                 mw.Show();
  3.                 for (int i = 0; i < vertexInPoly.Count-1; i++)
  4.                 {
  5.                         Thread.Sleep(500);
  6.                         mw.updadeBar(i * 5);
  7.                         int k = i - 1;
  8.                         if (k < 0)
  9.                         {
  10.                             k = vertexInPoly.Count - 2;
  11.                         }
  12.                         int j = i + 1;
  13.                         if (j > vertexInPoly.Count - 2)
  14.                         {
  15.                             j = 0;
  16.                         }
  17.                         Mpoint m = new Mpoint(vertexInPoly[k], vertexInPoly[i], vertexInPoly[j], 5);
  18.  
  19.                         //////////////////////////////////////////////
  20.  
  21.                         if (m.SharpAngle == false)//если угол больше 180 - строим дугу между перпендикулярами
  22.                         {
  23.                             offsetline.Add(m.OrthoPointFromEdge1);
  24.                             foreach (Point3d item in m.PointInAngle)
  25.                             {
  26.                                 offsetline.Add(item);
  27.                             }
  28.                             offsetline.Add(m.OrthoPointFromEdge2);
  29.                         }
  30.                         else if (m.SharpAngle == true)// если угол меньше 180 - строим одну точку(угол)
  31.                         {
  32.  
  33.                             if (m.GetDist(vertexInPoly[k], vertexInPoly[j]) > 10)// если расстояние между двумя(крайними) точками меньше расстояния подобия*2 то не строим угловую точку
  34.                             {
  35.                                 offsetline.Add(m.Intersect);
  36.                             }
  37.  
  38.                         }
  39.                 }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Создание прогресс бара
« Ответ #6 : 20-04-2019, 01:27:09 »
Есть куча готовых прогрессбаров. Зачем изобретать велосипед?
Ну например: http://drive-cad-with-code.blogspot.com/2015/04/showing-progress-for-long-code.html
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Создание прогресс бара
« Ответ #7 : 22-04-2019, 07:49:38 »
Создание прогресс бара:
Код - C# [Выбрать]
ProgressMeter pm = new ProgressMeter();
pm.SetLimit(max_len);
pm.Start("текст");
System.Windows.Forms.Application.DoEvents();
Не совсем так ;-)

Как ни странно сначала
pm.Start("текст");
а потом
pm.SetLimit(max_len);

Иначе в AutoCAD progressbar идет скачками, а кое-где(что мы тут не обсуждаем)  pm.Start("") сбрасывает счетчик на 100.

Что поделаешь, такое API.

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Создание прогресс бара
« Ответ #8 : 22-04-2019, 10:30:42 »
И все равно не понимаю как заставить работать прогресс бар.
Получатся у меня 2 потока - один это в AutoCAD, второй - прогресс бар. после запуска происходит следующее:
открывается окно с прогресс баром, выполняются все вычисления в цикле, а потом (по завершению цикла )
в прогресс бар передается последнее значение цикла. То есть он срабатывает, когда все вычисления закончены. Как заставить его работать синхронно с циклом?
Делал тестовый пример, код пока не нашел, но примерно так:
1. Всю работу с AutoCAD делаешь в основном потоке AutoCAD. Не пытайся вынести в другой поток.
2. Окно progressbar запускаешь в другом потоке.
3. Из основного потока вызываешь методы progressbar. Только методы progressbar должны менять состояние progressbar.
4. Периодически выполняешь System.Windows.Forms.Application.DoEvents(); чтобы интерфейс обновлялся.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Создание прогресс бара
« Ответ #9 : 22-04-2019, 13:03:35 »
Привалов Дмитрий,
Зачем второй поток? Пункта 4 должно быть достаточно. Или речь про нестандартный прогрессбар?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Создание прогресс бара
« Ответ #10 : 22-04-2019, 13:09:38 »
Делал нестандартные, но второй поток не запускал. Так что, это необязательная процедура.
4. Периодически выполняешь System.Windows.Forms.Application.DoEvents(); чтобы интерфейс обновлялся.
А вот без этого, да, согласен - прогрессбар не обновляется, пока автокад не закончит работу с циклом.

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Создание прогресс бара
« Ответ #11 : 22-04-2019, 13:27:49 »
Зачем второй поток?
Я сделал некий тестовый проект и пока ни разу не применил.

Задумка была такая, что пока в AutoCAD обрабатывается основной поток пользователь в WPF окне мог смотреть информацию по обработке, например переключать вкладки. Т.е. случай, если информации больше, чем может уместиться на экране, и процесс обработки длительный.

А так да, если взаимодействия пользователя не требуется, то и второй поток не нужен.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Создание прогресс бара
« Ответ #12 : 30-03-2021, 11:42:50 »
Сначала накатал пост, потом стер его и еще три дня экспериментировал и все таки напишу, вдруг кому сэкономит время.

В общем, не нужно использовать штатный прогресс бар при создании и изменении динамических блоков, так как
вызов метода System.Windows.Forms.Application.DoEvents(); чтобы интерфейс обновлялся, одновременно как бы отменяет
using (App.DocumentLock docLock = doc.LockDocument()) и появляется куча разных ошибок в произвольных местах программы.

« Последнее редактирование: 05-04-2021, 14:34:43 от Владимир Шу »

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 546
  • Карма: 119
Re: Создание прогресс бара
« Ответ #13 : 05-04-2021, 15:53:24 »
вызов метода System.Windows.Forms.Application.DoEvents(); чтобы интерфейс обновлялся, одновременно как бы отменяет
using (App.DocumentLock docLock = doc.LockDocument()) и появляется куча разных ошибок в произвольных местах программы.

Я использую стандартный прогресс бар с DoEvents() и подобных ошибок не возникало.
Возможно в другом месте ошибка, и DoEvents() ускоряет ее появление?

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Создание прогресс бара
« Ответ #14 : 05-04-2021, 16:22:44 »
Привалов Дмитрий, схема программы примерно следующая:

1. Открыть в редакторе документ
2. Сделать его активным
3. Блокируем документ
4. Базу этого документа так же делаем активной ( HostApplicationServices.WorkingDatabase)
5. Создаем блоки и заносим их ID в списочек
6. Проходим по созданному списку и назначаем созданным блокам нужные параметры
7. Прописываем доп. данные в XData (нужно сгруппировать блоки и записываются номера групп)
8. Перемещаем блоки в нужные позиции по группам (по простому, через метод Transform)
9. Сохраняем базу
10. Тут заканчивается блокировка документа
11. Оставляем чертеж открытым

Так же были вариации на работу с ReadDwd и всякими разными комбинациями открытия файла, разные последовательности создания и редактирования дин. свойств блока, использование или не использование транзакцимй и их вариантов, я говорю, больше трех дней плотно занимался этим кодом, порой полностью переписывая методы и общую схему работы программы, но итог один, использование прогресс бара в любом месте, пока документ заблокирован, приводит к вылету. Редко, может проскочить при одном двух блоках... но редко.

Иногда вылет с фаталом, иногда просто закрывается автокад, как будто и не запускался, иногда это ошибка записи в динамические свойства блока, иногда ошибка записи XData, иногда фатал с сообщением о попытке записи в запрещенную область памяти, иногда ошибка с тем, что открытое для записи вхождение блока выдает ошибку сообщая, что это блок открыт только для чтения, но я же вижу в коде, что двумя строчками выше открывал этот блок для записи. И это все может быть в любой момент и на любой выборке данных, хоть 10, хоть 3.
НО, если прогресс бар убрать, то ни одна из перечисленных ошибок не появляется, хоть вставляй десяток тысяч блоков и при непрерывной работе больше часа, я проверял, больше 15 т. блоков вставляются нормально и стабильно, много раз... долго только, но все работает.
И да, все эти же ошибки будут если не блокировать документ вовсе.

Так не бывает.