Reject Message 实现-1

本文介绍了一款简单的拒接短信App开发过程,包括使用ListView展示预设短信、添加删除功能实现等。涉及布局管理器使用、BaseAdapter自定义及ActionBar样式重写等内容。

Reject Message(拒接短信) 使用ListView存储用户预设的短信,在来电中可以使用,较为简单也常用。

本文主要介绍Layout及简单实现添加和删除,并未涉及存储及应用(待完善)。

涉及到的基本知识:各种布局管理器的使用、ListView使用BaseAdapter的实现、ActionBar样式的重写等等

 

直接上代码:

(1) java 文件

package com.xx.myrejectmessageapp;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;


public class MyRejectMessageActivity extends Activity {
    public final String LOG_TAG = "MyRejectMessageActivity";
    private List<RejectMessageData> data = new ArrayList<RejectMessageData>();
    private RejectMessageAdapter adapter = new RejectMessageAdapter();
    private ListView listView;
    private ImageButton addButton;
    //private ImageButton delButton;
    private EditText inputNumber;
    private TextView emptyTextView;

    private ActionBar actionBar;

    public class RejectMessageData{
        private String number;
        private String name;

        public RejectMessageData(String number, String name) {
            this.number = number;
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_reject_message);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        listView = (ListView) findViewById(R.id.rejectMessageListView);
        addButton = (ImageButton) findViewById(R.id.addButton);
        inputNumber = (EditText) findViewById(R.id.enterNumber);
        emptyTextView = (TextView) findViewById(R.id.empty);

        addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String number = null;
                number = inputNumber.getText().toString();
                if(number != null){
                    RejectMessageData inputData = new RejectMessageData(number, "no name");
                    data.add(inputData);
 //                   emptyTextView.setVisibility(View.GONE);
 //                   listView.setVisibility(View.VISIBLE);
 //                   listView.setAdapter(adapter);
                    updateRejectMessage();
                }
            }
        });

        actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
}


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //getMenuInflater().inflate(R.menu.menu_my_reject_message, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }
        if(id == android.R.id.home){
            onBackPressed();
        }

        return super.onOptionsItemSelected(item);
    }

    public class RejectMessageAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return data.size();
        }

        @Override
        public Object getItem(int position) {
            return data.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewGroup rootView = null;
            LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rootView = (ViewGroup) inflater.inflate(R.layout.reject_message_list_item, rootView, true);
            TextView numberText;
            TextView nameText;
            ImageButton delButton;
            numberText = (TextView) rootView.findViewById(R.id.reject_message_item_number);
            nameText = (TextView) rootView.findViewById(R.id.reject_message_item_name);
            delButton = (ImageButton) rootView.findViewById(R.id.delete);
            numberText.setText(data.get(position).getNumber());
            nameText.setText(data.get(position).getName());

            delButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    data.remove(position);
                    updateRejectMessage();
                }
            });

            return rootView;
        }
    }

    public void updateRejectMessage(){
        if(data.size() != 0) {
            emptyTextView.setVisibility(View.GONE);
            listView.setVisibility(View.VISIBLE);
        }else{
            emptyTextView.setVisibility(View.VISIBLE);
            listView.setVisibility(View.GONE);
        }

        listView.setAdapter(adapter);
    }
}

(2)界面主要布局文件:activity_my_reject_message.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="15dp"
    android:paddingRight="15dp"
    android:orientation="vertical"
    tools:context=".MyRejectMessageActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="87dp"
        android:paddingTop="18dp">
        <ImageButton
            android:id="@+id/addButton"
            android:layout_width="@dimen/add_delete_button_width"
            android:layout_height="@dimen/add_delete_button_height"
            android:src="@drawable/tw_list_icon_create_mtrl"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true" />
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_marginRight="48dp">
            <TextView
                android:id="@+id/editTextTitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Add call-reject message" />
            <EditText
                android:id="@+id/enterNumber"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:hint="Enter number" />
        </LinearLayout>
    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_marginTop="3dp"
        android:layout_marginBottom="16dp"
        android:orientation="horizontal">
        <Button
            android:id="@+id/logButton"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="Logs" />
        <Button
            android:id="@+id/contactsButton"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="contacts" />
    </LinearLayout>

    <View
        android:id="@+id/reject_divider"
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:background="@color/list_divider_color"/>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/empty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:text="empty"
            android:textColor="@color/empty_text_color"
            android:visibility="visible" />
        <ListView
            android:id="@+id/rejectMessageListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"></ListView>
    </FrameLayout>

</LinearLayout>



(3) list item 布局文件 reject_message_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/reject_message_item_height"
    android:minHeight="?android:attr/listPreferredItemHeight" >

    <ImageButton
        android:id="@+id/delete"
        android:layout_width="@dimen/add_delete_button_width"
        android:layout_height="@dimen/add_delete_button_height"
        android:src="@drawable/tw_list_icon_minus_mtrl"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginRight="48dp"
        android:orientation="vertical"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true" >

        <TextView
            android:id="@+id/reject_message_item_number"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:textSize="@dimen/reject_message_item_text_size1"
            android:textColor="@color/reject_message_item_text_color1"/>

        <TextView
            android:id="@+id/reject_message_item_name"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:textSize="@dimen/reject_message_item_text_size2"
            android:textColor="@color/reject_message_item_text_color2"/>
    </LinearLayout>
</RelativeLayout>

 

(4)  AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xx.myrejectmessageapp" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/RejectMessageApp" >
        <activity
            android:name=".MyRejectMessageActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

(5) styles.xml

<resources>

    <!-- Base application theme, if using AppTheme, not work -->
    <style name="RejectMessageApp" parent="@android:style/Theme.DeviceDefault.Light">
        <!-- Customize your theme here. -->

        <item name="android:statusBarColor">@color/status_bar_color</item>
        <item name="android:colorPrimary">@color/action_bar_color</item>
        <item name="android:textColorPrimary">@color/action_bar_text_color</item>
    </style>

    <style name="reject_message_actionbar_style" parent="@android:style/Theme.DeviceDefault.Light">
        <item name="android:background">@color/action_bar_color</item>
    </style>

    <!-- tmp theme. -->
    <style name="Theme.Setting" parent="@android:style/Theme.DeviceDefault.Light">
        <!-- Customize your theme here. -->
        <item name="android:statusBarColor">@color/status_bar_color</item>
        <item name="android:actionBarStyle">@style/reject_message_actionbar_style</item>
    </style>

</resources>

 

(6) colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="empty_text_color">#47952b</color>
    <color name="action_bar_color">#4fa630</color>
    <color name="status_bar_color">#3f8526</color>
    <color name="action_bar_text_color">#fafafa</color>
    <color name="reject_message_item_text_color1">#000000</color>
    <color name="reject_message_item_text_color2">#838688</color>
    <color name="list_divider_color">#cecece</color>
</resources>

(7) dimens.xml

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="reject_message_item_height">80dp</dimen>
    <dimen name="add_delete_button_height">32dp</dimen>
    <dimen name="add_delete_button_width">32dp</dimen>
    <dimen name="reject_message_item_text_size1">17sp</dimen>
    <dimen name="reject_message_item_text_size2">14sp</dimen>
</resources>

 

 总结点:

1.  在item的layout文件中,用android:layout_height设置item的高度。 运行,高度设置无效。
解决办法:给item设定minHeight,即可.
e.g : android:minHeight="?android:attr/listPreferredItemHeight"

2. 更改statusbar / actionbar 背景颜色
AndroidManifest.xml -> application 对应的android.theme="@style/MyAppTheme"

-> styles.xml 定义的AppTheme 改为:
<style name="MyAppTheme" parent="@android:style/Theme.DeviceDefault.Light" >
    <item name="android:statusBarColor">#3f8526</item>
 <item name="android:ActionBarStyle">@style/my_actionbar_style</item>
</style>

<style name="my_actionbar_style" parent="@android:style/Theme.DeviceDefault.Light >
    <item name="android:background">#4fa630</item>
</style>

// 注意尽量不要使用AppTheme命名,可能会修改无效!!!

PS: 更改ActionBar颜色
android:colorPrimary
android:textColorPrimary -->标题

 

next : 实现可以存储,即退出应用再进入能保存之前设置的数据。

<think>我们遇到了一个编译错误,提示“PromptSelectionOptions”未包含“RejectMessage”的定义。这是因为在AutoCAD .NET API中,`PromptSelectionOptions`类确实没有名为`RejectMessage`的属性。可能是混淆了其他选项类(如`PromptEntityOptions`有`RejectMessage`)。因此,我们需要移除这个无效的属性设置。 ### 修复步骤: 1. **移除无效的`RejectMessage`属性设置**:在`SelectCurves`方法中,删除对`RejectMessage`的赋值。 2. **使用其他方式提供拒绝消息**:可以通过设置`MessageForAdding`和`Keywords`等来引导用户正确选择。 ### 修改后的代码(仅修改选择部分): ```csharp private List<Curve> SelectCurves(Editor ed) { var res = ed.GetSelection(new PromptSelectionOptions { MessageForAdding = "\n选择线段、圆弧或多段线: ", AllowDuplicates = false, // 移除 RejectMessage 属性 AllowSubSelections = true }, new SelectionFilter(new[] { new TypedValue(0, "LINE"), new TypedValue(0, "ARC"), new TypedValue(0, "LWPOLYLINE"), new TypedValue(0, "POLYLINE") })); if (res.Status != PromptStatus.OK) return null; // 用户取消 return res.Value.GetObjectIds() .Select(id => id.GetObject(OpenMode.ForRead) as Curve) .Where(curve => curve != null) .ToList(); } ``` ### 完整修复代码: 由于只修改了选择部分,其他部分保持不变,这里只展示修改后的方法,但为了完整性,下面提供完整的类代码(其他方法保持不变): ```csharp using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Collections.Generic; using System.Linq; namespace LineExtensionPlugin { public class Commands { [CommandMethod("SCDDX_BIHEDUODUANXIAN")] public void CloseShapeCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; try { // 获取最大允许间隙 double maxGap = GetMaxGap(ed); if (maxGap < 0) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // 选择对象 - 添加重试机制 List<Curve> selectedCurves = SelectCurvesWithRetry(ed, 3); if (selectedCurves == null || selectedCurves.Count == 0) { ed.WriteMessage("\n未选择有效对象,命令终止。"); return; } // 清理小弧 CleanupSmallArcs(ed, selectedCurves, maxGap / 10); // 处理单条多段线 if (selectedCurves.Count == 1 && selectedCurves[0] is Polyline pline) { ProcessSinglePolyline(ed, pline, maxGap); return; } // 处理多条曲线 if (selectedCurves.Count < 3) { ed.WriteMessage($"\n至少需要选择3条线段或1条多段线(当前:{selectedCurves.Count})。"); return; } // 合并小线段 List<Line> consolidatedLines = ConsolidateSmallLines(selectedCurves, maxGap / 10); // 检查合并后是否有有效线段 if (consolidatedLines.Count < 3) { ed.WriteMessage($"\n合并后有效线段不足({consolidatedLines.Count}),无法形成闭合路径。"); return; } // 排序和连接线段 List<Line> sortedLines = SortLines(consolidatedLines, maxGap); if (sortedLines == null) { ed.WriteMessage("\n线段无法形成连续路径。"); return; } // 计算交点 List<Point3d> vertices = CalculateIntersections(sortedLines, maxGap); // 验证顶点数 if (vertices.Count < 3 || vertices.Count > 1000) { ed.WriteMessage($"\n错误:无效顶点数({vertices.Count}),应为3-1000"); return; } // 创建三维多段线 Polyline3d poly3d = Create3dPolyline(vertices, maxGap); // 添加到模型空间 BlockTableRecord btr = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite); ObjectId polyId = btr.AppendEntity(poly3d); tr.AddNewlyCreatedDBObject(poly3d, true); // 添加顶点 foreach (Point3d vertex in vertices) { poly3d.AppendVertex(new PolylineVertex3d(vertex)); } // 删除原始线段 foreach (Line line in sortedLines) { if (!line.IsErased) { line.UpgradeOpen(); line.Erase(); } } tr.Commit(); ed.WriteMessage($"\n成功创建{(poly3d.Closed ? "闭合" : "开放")}三维多段线,包含{vertices.Count}个顶点!"); } } catch (System.Exception ex) { ed.WriteMessage("\n错误: " + ex.Message); } } // 带重试机制的选择曲线 private List<Curve> SelectCurvesWithRetry(Editor ed, int maxAttempts) { int attempts = 0; while (attempts < maxAttempts) { List<Curve> curves = SelectCurves(ed); if (curves == null) // 用户取消 return null; if (curves.Count > 0) // 成功选择对象 return curves; attempts++; ed.WriteMessage($"\n未选择任何对象,请重新选择(剩余尝试次数:{maxAttempts - attempts})。"); } return new List<Curve>(); // 返回空列表表示失败 } // 清理小弧 private void CleanupSmallArcs(Editor ed, List<Curve> curves, double minSize) { int deletedCount = 0; foreach (Curve curve in curves.ToList()) { if (curve is Arc arc && arc.Radius < minSize) { arc.UpgradeOpen(); arc.Erase(); curves.Remove(curve); deletedCount++; } } if (deletedCount > 0) { ed.WriteMessage($"\n已清理{deletedCount}个小弧(半径<{minSize:F4})"); } } // 处理单条多段线 private void ProcessSinglePolyline(Editor ed, Polyline pline, double maxGap) { if (pline.Closed) { ed.WriteMessage("\n多段线已经闭合。"); return; } double gap = pline.StartPoint.DistanceTo(pline.EndPoint); if (gap <= maxGap) { pline.UpgradeOpen(); pline.Closed = true; ed.WriteMessage($"\n多段线已成功闭合(间隙:{gap:F4})"); } else { ed.WriteMessage($"\n首尾点距离({gap:F4})超过最大允许间隙({maxGap:F4})"); } } // 创建三维多段线 private Polyline3d Create3dPolyline(List<Point3d> vertices, double maxGap) { double closureGap = vertices[0].DistanceTo(vertices[vertices.Count - 1]); return new Polyline3d { Closed = closureGap <= maxGap }; } // 获取最大允许间隙 private double GetMaxGap(Editor ed) { var res = ed.GetDouble(new PromptDoubleOptions("\n输入最大允许间隙: ") { AllowNegative = false, DefaultValue = 0.1, UseDefaultValue = true }); return res.Status == PromptStatus.OK ? res.Value : -1; } // 选择曲线对象(已修复:移除RejectMessage属性) private List<Curve> SelectCurves(Editor ed) { var res = ed.GetSelection(new PromptSelectionOptions { MessageForAdding = "\n选择线段、圆弧或多段线: ", AllowDuplicates = false, // 注意:PromptSelectionOptions没有RejectMessage属性,已移除 AllowSubSelections = true }, new SelectionFilter(new[] { new TypedValue(0, "LINE"), new TypedValue(0, "ARC"), new TypedValue(0, "LWPOLYLINE"), new TypedValue(0, "POLYLINE") })); if (res.Status != PromptStatus.OK) return null; // 用户取消 return res.Value.GetObjectIds() .Select(id => id.GetObject(OpenMode.ForRead) as Curve) .Where(curve => curve != null) .ToList(); } // 合并小线段 private List<Line> ConsolidateSmallLines(List<Curve> curves, double minLength) { var result = new List<Line>(); foreach (var curve in curves) { if (curve is Line line && line.Length > minLength) { result.Add(line); } else if (curve is Arc arc && arc.Radius > minLength) { result.Add(new Line(arc.StartPoint, arc.EndPoint)); } else if (curve is Polyline poly) { for (int i = 0; i < poly.NumberOfVertices - 1; i++) { Point3d start = poly.GetPoint3dAt(i); Point3d end = poly.GetPoint3dAt(i + 1); if (start.DistanceTo(end) > minLength) { result.Add(new Line(start, end)); } } } } return result; } // 排序和连接线段 private List<Line> SortLines(List<Line> lines, double maxGap) { var sorted = new List<Line> { lines[0] }; lines.RemoveAt(0); var current = sorted[0]; while (lines.Count > 0) { bool found = false; for (int i = 0; i < lines.Count; i++) { if (CheckConnection(current, lines[i], maxGap, ref sorted, ref current)) { lines.RemoveAt(i); found = true; break; } } if (!found && !FindExtendedConnection(lines, maxGap, ref sorted, ref current)) return null; } // 验证闭合 double closureGap = sorted[0].StartPoint.DistanceTo(sorted[sorted.Count - 1].EndPoint); if (closureGap > maxGap * 2) throw new InvalidOperationException($"路径未闭合(首尾间隙: {closureGap:F4})"); return sorted; } // 四向连接检测 private bool CheckConnection(Line current, Line testLine, double maxGap, ref List<Line> sorted, ref Line currentLine) { // 1. 当前终点 -> 测试起点 if (current.EndPoint.DistanceTo(testLine.StartPoint) <= maxGap) { sorted.Add(testLine); currentLine = testLine; return true; } // 2. 当前终点 -> 测试终点 if (current.EndPoint.DistanceTo(testLine.EndPoint) <= maxGap) { ReverseLine(testLine); sorted.Add(testLine); currentLine = testLine; return true; } // 3. 当前起点 -> 测试起点 if (current.StartPoint.DistanceTo(testLine.StartPoint) <= maxGap) { ReverseLine(current); sorted[sorted.Count - 1] = current; sorted.Add(testLine); currentLine = testLine; return true; } // 4. 当前起点 -> 测试终点 if (current.StartPoint.DistanceTo(testLine.EndPoint) <= maxGap) { ReverseLine(current); sorted[sorted.Count - 1] = current; ReverseLine(testLine); sorted.Add(testLine); currentLine = testLine; return true; } return false; } // 反转线段方向 private void ReverseLine(Line line) { if (line.IsWriteEnabled) { (line.StartPoint, line.EndPoint) = (line.EndPoint, line.StartPoint); } else { line.UpgradeOpen(); (line.StartPoint, line.EndPoint) = (line.EndPoint, line.StartPoint); } } // 延长连接检测 private bool FindExtendedConnection(List<Line> lines, double maxGap, ref List<Line> sorted, ref Line current) { Line closestLine = null; double minDistance = double.MaxValue; int closestIndex = -1; bool reverseClosest = false; bool reverseCurrent = false; for (int i = 0; i < lines.Count; i++) { var testLine = lines[i]; double[] distances = { current.EndPoint.DistanceTo(testLine.StartPoint), current.EndPoint.DistanceTo(testLine.EndPoint), current.StartPoint.DistanceTo(testLine.StartPoint), current.StartPoint.DistanceTo(testLine.EndPoint) }; double minDist = distances.Min(); if (minDist < minDistance && minDist <= maxGap * 5) { minDistance = minDist; closestLine = testLine; closestIndex = i; if (minDist == distances[0]) { reverseClosest = false; reverseCurrent = false; } else if (minDist == distances[1]) { reverseClosest = true; reverseCurrent = false; } else if (minDist == distances[2]) { reverseClosest = false; reverseCurrent = true; } else { reverseClosest = true; reverseCurrent = true; } } } if (closestLine == null) return false; // 翻转当前线段 if (reverseCurrent) { ReverseLine(current); sorted[sorted.Count - 1] = current; } // 翻转测试线段 if (reverseClosest) { ReverseLine(closestLine); } sorted.Add(closestLine); current = closestLine; lines.RemoveAt(closestIndex); return true; } // 交点计算 private List<Point3d> CalculateIntersections(List<Line> lines, double maxGap) { var vertices = new List<Point3d>(); for (int i = 0; i < lines.Count; i++) { var current = lines[i]; var next = lines[(i + 1) % lines.Count]; if (current.EndPoint.DistanceTo(next.StartPoint) <= maxGap) { vertices.Add(current.EndPoint); } else { var intersection = Find3dIntersection(current, next); vertices.Add(intersection ?? new Point3d( (current.EndPoint.X + next.StartPoint.X) / 2, (current.EndPoint.Y + next.StartPoint.Y) / 2, (current.EndPoint.Z + next.StartPoint.Z) / 2)); } } return vertices; } // 三维空间线段交点计算 private Point3d? Find3dIntersection(Line line1, Line line2) { var l1 = new Line3d(line1.StartPoint, line1.EndPoint); var l2 = new Line3d(line2.StartPoint, line2.EndPoint); // 检查是否共面 var normal = l1.Direction.CrossProduct(l2.Direction); if (normal.Length < 1e-9) return null; return l1.IntersectWith(l2).FirstOrDefault(); } } } ``` ### 修复说明: - 移除了`PromptSelectionOptions`中不存在的`RejectMessage`属性设置。 - 其他功能保持不变,包括重试机制、小弧清理、单条多段线处理、线段合并、排序连接和交点计算等。 ### 注意事项: - 在AutoCAD .NET API中,`PromptSelectionOptions`确实没有`RejectMessage`属性。该属性通常存在于`PromptEntityOptions`等类中。 - 如果需要在选择时提供拒绝消息,可以考虑使用其他方式,例如在`MessageForAdding`中说明选择要求。 此修复确保代码能够编译通过,并保持原有功能不变。 §§相关问题§§ 1. AutoCAD .NET API中PromptSelectionOptions类支持哪些常用属性? 2. 如何为选择操作添加自定义过滤条件(如特定图层或颜色)? 3. 当用户取消选择时如何提供更友好的提示? 4. 如何优化选择性能处理大量对象? 5. 怎样实现选择集预览功能让用户确认选择?</think>我注意到错误提示表明`PromptSelectionOptions`类没有`RejectMessage`属性。在AutoCAD .NET API中,`PromptSelectionOptions`确实没有这个属性,您可能将其与`PromptEntityOptions`混淆了。以下是修复后的代码: ```csharp using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Collections.Generic; using System.Linq; namespace LineExtensionPlugin { public class Commands { [CommandMethod("SCDDX_BIHEDUODUANXIAN")] public void CloseShapeCommand() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; try { // 获取最大允许间隙 double maxGap = GetMaxGap(ed); if (maxGap < 0) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // 选择对象 - 添加重试机制 List<Curve> selectedCurves = SelectCurvesWithRetry(ed, 3); if (selectedCurves == null || selectedCurves.Count == 0) { ed.WriteMessage("\n未选择有效对象,命令终止。"); return; } // 清理小弧 CleanupSmallArcs(ed, selectedCurves, maxGap / 10); // 处理单条多段线 if (selectedCurves.Count == 1 && selectedCurves[0] is Polyline pline) { ProcessSinglePolyline(ed, pline, maxGap); return; } // 处理多条曲线 if (selectedCurves.Count < 3) { ed.WriteMessage($"\n至少需要选择3条线段或1条多段线(当前:{selectedCurves.Count})。"); return; } // 合并小线段 List<Line> consolidatedLines = ConsolidateSmallLines(selectedCurves, maxGap / 10); // 检查合并后是否有有效线段 if (consolidatedLines.Count < 3) { ed.WriteMessage($"\n合并后有效线段不足({consolidatedLines.Count}),无法形成闭合路径。"); return; } // 排序和连接线段 List<Line> sortedLines = SortLines(consolidatedLines, maxGap); if (sortedLines == null) { ed.WriteMessage("\n线段无法形成连续路径。"); return; } // 计算交点 List<Point3d> vertices = CalculateIntersections(sortedLines, maxGap); // 验证顶点数 if (vertices.Count < 3 || vertices.Count > 1000) { ed.WriteMessage($"\n错误:无效顶点数({vertices.Count}),应为3-1000"); return; } // 创建三维多段线 Polyline3d poly3d = Create3dPolyline(vertices, maxGap); // 添加到模型空间 BlockTableRecord btr = (BlockTableRecord)tr.GetObject( SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite); ObjectId polyId = btr.AppendEntity(poly3d); tr.AddNewlyCreatedDBObject(poly3d, true); // 添加顶点 foreach (Point3d vertex in vertices) { poly3d.AppendVertex(new PolylineVertex3d(vertex)); } // 删除原始线段 foreach (Line line in sortedLines) { if (!line.IsErased) { line.UpgradeOpen(); line.Erase(); } } tr.Commit(); ed.WriteMessage($"\n成功创建{(poly3d.Closed ? "闭合" : "开放")}三维多段线,包含{vertices.Count}个顶点!"); } } catch (System.Exception ex) { ed.WriteMessage("\n错误: " + ex.Message); } } // 带重试机制的选择曲线 private List<Curve> SelectCurvesWithRetry(Editor ed, int maxAttempts) { int attempts = 0; while (attempts < maxAttempts) { List<Curve> curves = SelectCurves(ed); if (curves == null) // 用户取消 return null; if (curves.Count > 0) // 成功选择对象 return curves; attempts++; ed.WriteMessage($"\n未选择任何对象,请重新选择(剩余尝试次数:{maxAttempts - attempts})。"); } return new List<Curve>(); // 返回空列表表示失败 } // 清理小弧 private void CleanupSmallArcs(Editor ed, List<Curve> curves, double minSize) { int deletedCount = 0; foreach (Curve curve in curves.ToList()) { if (curve is Arc arc && arc.Radius < minSize) { arc.UpgradeOpen(); arc.Erase(); curves.Remove(curve); deletedCount++; } } if (deletedCount > 0) { ed.WriteMessage($"\n已清理{deletedCount}个小弧(半径<{minSize:F4})"); } } // 处理单条多段线 private void ProcessSinglePolyline(Editor ed, Polyline pline, double maxGap) { if (pline.Closed) { ed.WriteMessage("\n多段线已经闭合。"); return; } double gap = pline.StartPoint.DistanceTo(pline.EndPoint); if (gap <= maxGap) { pline.UpgradeOpen(); pline.Closed = true; ed.WriteMessage($"\n多段线已成功闭合(间隙:{gap:F4})"); } else { ed.WriteMessage($"\n首尾点距离({gap:F4})超过最大允许间隙({maxGap:F4})"); } } // 创建三维多段线 private Polyline3d Create3dPolyline(List<Point3d> vertices, double maxGap) { double closureGap = vertices[0].DistanceTo(vertices[vertices.Count - 1]); return new Polyline3d { Closed = closureGap <= maxGap }; } // 获取最大允许间隙 private double GetMaxGap(Editor ed) { var res = ed.GetDouble(new PromptDoubleOptions("\n输入最大允许间隙: ") { AllowNegative = false, DefaultValue = 0.1, UseDefaultValue = true }); return res.Status == PromptStatus.OK ? res.Value : -1; } // 选择曲线对象(修复了RejectMessage问题) private List<Curve> SelectCurves(Editor ed) { var filter = new SelectionFilter(new[] { new TypedValue(0, "LINE"), new TypedValue(0, "ARC"), new TypedValue(0, "LWPOLYLINE"), new TypedValue(0, "POLYLINE") }); var options = new PromptSelectionOptions { MessageForAdding = "\n选择线段、圆弧或多段线: ", MessageForRemoval = "\n移除不需要的对象: ", AllowDuplicates = false, AllowSubSelections = true }; // 添加自定义拒绝消息 options.Keywords.Add("Cancel"); options.KeywordInput += (sender, e) => { if (e.Input == "Cancel") ed.WriteMessage("\n选择已取消。"); }; var res = ed.GetSelection(options, filter); if (res.Status != PromptStatus.OK) return null; // 用户取消 return res.Value.GetObjectIds() .Select(id => id.GetObject(OpenMode.ForRead) as Curve) .Where(curve => curve != null) .ToList(); } // 合并小线段 private List<Line> ConsolidateSmallLines(List<Curve> curves, double minLength) { var result = new List<Line>(); foreach (var curve in curves) { if (curve is Line line && line.Length > minLength) { result.Add(line); } else if (curve is Arc arc && arc.Radius > minLength) { result.Add(new Line(arc.StartPoint, arc.EndPoint)); } else if (curve is Polyline poly) { for (int i = 0; i < poly.NumberOfVertices - 1; i++) { Point3d start = poly.GetPoint3dAt(i); Point3d end = poly.GetPoint3dAt(i + 1); if (start.DistanceTo(end) > minLength) { result.Add(new Line(start, end)); } } } } return result; } // 排序和连接线段 private List<Line> SortLines(List<Line> lines, double maxGap) { var sorted = new List<Line> { lines[0] }; lines.RemoveAt(0); var current = sorted[0]; while (lines.Count > 0) { bool found = false; for (int i = 0; i < lines.Count; i++) { if (CheckConnection(current, lines[i], maxGap, ref sorted, ref current)) { lines.RemoveAt(i); found = true; break; } } if (!found && !FindExtendedConnection(lines, maxGap, ref sorted, ref current)) return null; } // 验证闭合 double closureGap = sorted[0].StartPoint.DistanceTo(sorted[sorted.Count - 1].EndPoint); if (closureGap > maxGap * 2) throw new InvalidOperationException($"路径未闭合(首尾间隙: {closureGap:F4})"); return sorted; } // 四向连接检测 private bool CheckConnection(Line current, Line testLine, double maxGap, ref List<Line> sorted, ref Line currentLine) { // 1. 当前终点 -> 测试起点 if (current.EndPoint.DistanceTo(testLine.StartPoint) <= maxGap) { sorted.Add(testLine); currentLine = testLine; return true; } // 2. 当前终点 -> 测试终点 if (current.EndPoint.DistanceTo(testLine.EndPoint) <= maxGap) { ReverseLine(testLine); sorted.Add(testLine); currentLine = testLine; return true; } // 3. 当前起点 -> 测试起点 if (current.StartPoint.DistanceTo(testLine.StartPoint) <= maxGap) { ReverseLine(current); sorted[sorted.Count - 1] = current; sorted.Add(testLine); currentLine = testLine; return true; } // 4. 当前起点 -> 测试终点 if (current.StartPoint.DistanceTo(testLine.EndPoint) <= maxGap) { ReverseLine(current); sorted[sorted.Count - 1] = current; ReverseLine(testLine); sorted.Add(testLine); currentLine = testLine; return true; } return false; } // 反转线段方向 private void ReverseLine(Line line) { if (line.IsWriteEnabled) { (line.StartPoint, line.EndPoint) = (line.EndPoint, line.StartPoint); } else { line.UpgradeOpen(); (line.StartPoint, line.EndPoint) = (line.EndPoint, line.StartPoint); } } // 延长连接检测 private bool FindExtendedConnection(List<Line> lines, double maxGap, ref List<Line> sorted, ref Line current) { Line closestLine = null; double minDistance = double.MaxValue; int closestIndex = -1; bool reverseClosest = false; bool reverseCurrent = false; for (int i = 0; i < lines.Count; i++) { var testLine = lines[i]; double[] distances = { current.EndPoint.DistanceTo(testLine.StartPoint), current.EndPoint.DistanceTo(testLine.EndPoint), current.StartPoint.DistanceTo(testLine.StartPoint), current.StartPoint.DistanceTo(testLine.EndPoint) }; double minDist = distances.Min(); if (minDist < minDistance && minDist <= maxGap * 5) { minDistance = minDist; closestLine = testLine; closestIndex = i; if (minDist == distances[0]) { reverseClosest = false; reverseCurrent = false; } else if (minDist == distances[1]) { reverseClosest = true; reverseCurrent = false; } else if (minDist == distances[2]) { reverseClosest = false; reverseCurrent = true; } else { reverseClosest = true; reverseCurrent = true; } } } if (closestLine == null) return false; // 翻转当前线段 if (reverseCurrent) { ReverseLine(current); sorted[sorted.Count - 1] = current; } // 翻转测试线段 if (reverseClosest) { ReverseLine(closestLine); } sorted.Add(closestLine); current = closestLine; lines.RemoveAt(closestIndex); return true; } // 交点计算 private List<Point3d> CalculateIntersections(List<Line> lines, double maxGap) { var vertices = new List<Point3d>(); for (int i = 0; i < lines.Count; i++) { var current = lines[i]; var next = lines[(i + 1) % lines.Count]; if (current.EndPoint.DistanceTo(next.StartPoint) <= maxGap) { vertices.Add(current.EndPoint); } else { var intersection = Find3dIntersection(current, next); vertices.Add(intersection ?? new Point3d( (current.EndPoint.X + next.StartPoint.X) / 2, (current.EndPoint.Y + next.StartPoint.Y) / 2, (current.EndPoint.Z + next.StartPoint.Z) / 2)); } } return vertices; } // 三维空间线段交点计算 private Point3d? Find3dIntersection(Line line1, Line line2) { var l1 = new Line3d(line1.StartPoint, line1.EndPoint); var l2 = new Line3d(line2.StartPoint, line2.EndPoint); // 检查是否共面 var normal = l1.Direction.CrossProduct(l2.Direction); if (normal.Length < 1e-9) return null; return l1.IntersectWith(l2).FirstOrDefault(); } } } ``` ### 主要修复: 1. **移除了无效的`RejectMessage`属性**: ```csharp // 错误代码(已移除) options.RejectMessage = "\n请选择线段、圆弧或多段线。"; // 修复后(使用标准属性) options.MessageForAdding = "\n选择线段、圆弧或多段线: "; options.MessageForRemoval = "\n移除不需要的对象: "; ``` 2. **添加了关键字处理作为替代方案**: ```csharp // 添加自定义取消选项 options.Keywords.Add("Cancel"); options.KeywordInput += (sender, e) => { if (e.Input == "Cancel") ed.WriteMessage("\n选择已取消。"); }; ``` 3. **保留了所有核心功能**: - 选择重试机制 - 小弧清理功能 - 单条多段线处理 - 线段合并与排序 - 三维多段线创建 ### 关于`PromptSelectionOptions`的说明: 在AutoCAD .NET API中,`PromptSelectionOptions`类没有`RejectMessage`属性。有效属性包括: - `MessageForAdding`:选择对象时的提示 - `MessageForRemoval`:移除对象时的提示 - `AllowDuplicates`:是否允许重复选择 - `AllowSubSelections`:是否允许子选择 - `Keywords`:添加自定义关键字选项 此修复确保代码能够编译通过,同时保持了原有的用户交互体验。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值