| 
积分19248明经币 个注册时间2015-8-18在线时间 小时威望 金钱 个贡献 激情  
 | 
 
| 本帖最后由 你有种再说一遍 于 2024-10-20 16:20 编辑 
 
 # 循环选择
 1,选择状态有夹点显示,此时缓冲区有id集合且不为0.
 2,亮显没有夹点显示.
 在Acad.net提供的手选函数,无法在缓冲区不为0时再选择,如果此时循环再手选,不会发生阻塞,而是直接就是ok的...
 
 
 问题代码展示:
 ```csharp
 [CommandMethod(nameof(LoopBug))]
 public void LoopBug() {
 Document doc = Acap.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;
 for (int i = 0; i < 5; i++) {
 // 第一次会阻塞后执行手选,第二次就不会了.
 var opts = new PromptSelectionOptions() { MessageForAdding = "\n请选择图元:" };
 var ss = ed.GetSelection(opts);
 if (ss.Status != PromptStatus.OK) {
 ed.WriteMessage("\n未选择任何图元.");
 continue;
 }
 var ids = ss.Value.GetObjectIds();
 ed.WriteMessage("\n选择了图元数:" + ids.Length);
 ed.SetImpliedSelection(ids);
 }
 }
 ```
 
 
 我们很容易想到一个解决方案,
 如果不设置缓冲区,那么是不是只能亮显了?
 但是亮显图元无法用shift剔除.
 重点:
 此时需要通过键盘钩子进行拦截shift键入,然后发送消息结束ssget.把全部图元亮显,求出鼠标矩形在哪些图元上面,暗显并ids也减去.
 shift抬起时候,恢复亮显.
 
 
 ```csharp
 [CommandMethod(nameof(Pick), CommandFlags.UsePickSet)]//记得加这个flag
 public void Pick() {
 Document doc = Application.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;
 
 
 var opts = new PromptSelectionOptions("\n请选择对象:");
 opts.AllowNone = true;
 opts.AllowArbitraryInput = true; // 允许任意输入
 //opts.SingleOnly = true;//只一个对象不回车
 opts.SelectEverythingInAperture = true;// 点击模式
 
 
 // 过滤器
 SelectionFilter fr = new (new TypedValue[] {
 new TypedValue((int)DxfCode.Start, "LINE"),
 });
 
 
 var ss = ed.SelectImplied();//预选
 if (ss.Status == PromptStatus.OK) {
 foreach(var id in ss.Value.GetObjectIds()){
 if(!fr.Contains(id)){ // 伪代码看懂就行
 _ids.Add(id);
 }
 }
 // 清空选择集
 ed.SetImpliedSelection(new ObjectId[] { });
 }
 
 
 // 循环选择,重新手选
 while(true){
 _ids.ForEach=>{ent.Highlight();}//亮显
 ss = ed.GetSelection(opts,fr);
 if (ss.Status == PromptStatus.OK) {
 _ids.ForEach=>{ent.Unhighlight();}//暗显
 _ids.AddRange(ss.Value.GetObjectIds());
 ed.SetImpliedSelection(new ObjectId[] { });
 continue;
 }
 
 if(ss.Status == PromptStatus.Cancel) {
 /* 键盘钩子发送Esc消息才到这个状态
 方案一:
 先选中ids,再开启新选择集,然后减选.
 我怀疑不行,因为选中状态(缓冲区有对象)会直接跳过手选.
 shift按着也可能不切换到新选择集的反选模式.
 释放shift也要结束这个选择集
 _ids.ForEach=>{ent.Unhighlight();}//暗显
 ed.SetImpliedSelection(_ids.ToArray());//重设选择集
 var s2 = ed.GetSelection();
 if(s2.Status == PromptStatus.OK) {
 _ids.RemoveAll(s2.Value.GetObjectIds());
 }
 方案二:
 不重设选择集,获取选择集矩形两个点ss.PickedPoint,然后直接剔除集合
 ?
 */
 }
 // 结束循环
 _ids.ForEach=>{ent.Unhighlight();}//暗显
 break;
 }
 }
 
 
 HashSet<ObjectId> _ids = new();
 
 
 void 键盘钩子(s,e) {
 if(e.Key == "shift".KeyCode()){
 Acad.Handle.Foucs().发送异步Esc消息();
 //这里_ids.事务跨线程!无法操作图元.
 }
 }
 ```
 
 
 选择集的本质:
 啊?其实可以自己实现一个两点矩形,然后通过选框范围,再触发四叉树选择.
 选框还可以利用透明winform画一个颜色,并且才用滤镜算法...很麻烦吗?
 (完)
 
 | 
 |