Qt 求两个多边形组合后的凸包,Qt里的排序方法

本文介绍了在Qt中如何求取两个多边形组合后的凸包,并强调了unique步骤的重要性,以避免重合点问题。同时,文章提到在排序过程中可以利用内置方法,无需额外编写cmp函数,简化了代码实现。

unique是很关键的一步,不可省略,一般的题目都给定了不会有重合点,但是实际项目应用里保不准。

可以证明,交点不会出现在凸包上。

这里的排序方法非常好用,不用单独写一个cmp函数了,相当于直接把这个函数写在sort下面



qreal DataConvert::getCrossProduct(const QPointF &iPointA,const QPointF &iPointB,const QPointF &iPointC){
  
  //获得a->b和a->c的叉积
    //x1y2-x2y1
    return ((iPointB.x()-iPointA.x())*(iPointC.y()-iPointA.y())-(iPointC.x()-iPointA.x())*(iPointB.y()-iPointA.y()));
}
QPolygonF DataConvert::getPolysConvexHull(const QPolygonF &iFirstPoly, const QPolygonF &iSecondPoly){
  
  //获取两个poly的凸包
    if(iFirstPoly.size()==0)return iSecondPoly;
    if(iSecondPoly.size()==0)return iFirstPoly;
    int Size1=iFirstPoly.size();
    int Size2=iSecondPoly.size();
    //第一步把所有结点取出来
    QVector<QPointF>AllPoints;
    
<think>嗯,用户现在遇到了在MFC框架下动态创建CEdit控件时需要自动监测内容修改的问题。ta希望避免手动为每个控件添加ON_EN_CHANGE消息映射函数,这种需求确实很实际,特别是当需要创建大量编辑框时,逐个添加处理函数会非常繁琐。回顾之前的对话,我已经解释了基本实现方法,但用户现在需要更智能的解决方案。用户可能正在开发一个需要动态生成多个输入字段的应用,比如数据录入系统或表单生成器。ta的真实需求应该是:在保持代码简洁性的同时确保功能完善。这个问题有几个关键点:首先,动态创建的控件需要唯一ID;其次,如何统一处理消息而不写重复代码;最后,还要考虑资源管理和线程安全。用户提供的引用材料很有帮助,特别是引用[5]提到的ON_CONTROL_RANGE宏,这正是解决问题的核心。让我思考实现方案。主要有两种技术路线:一是使用控件ID范围的消息映射,通过ON_CONTROL_RANGE宏批量处理所有控件事件;二是通过控件子类化技术(SubclassWindow)让每个控件实例自带消息处理能力。考虑到用户需要"自动监测"的特性,子类化方案可能更优雅,但实现起来稍复杂。第一种方案中,我们可以这样设计:定义连续的ID范围,比如从0x8000到0x8FFF。创建控件时分配这些ID,然后使用ON_CONTROL_RANGE(EN_CHANGE,ID_START,ID_END,OnEditChange)来捕获整个范围内所有控件的修改事件。在处理函数里通过参数区分具体是哪个控件发出的消息。这样只需要一个处理函数就能管理所有动态编辑框。不过用户可能需要更灵活的解决方案,特别是当控件ID不连续时。这就引出了第二个方案:创建CEdit的派生类,重写其虚函数,比如PreTranslateMessage或WindowProc,直接在里面处理EN_CHANGE通知。这样每个动态创建的控件都能自主处理消息,完全不需要在父窗口中添加消息映射。考虑到用户的技术水平,这个方案虽然高效但可能需要更深入的MFC知识。权衡之后,我决定优先介绍第一种方案,因为它更容易理解且代码改动小。但为了完整性,我也会简要提及其他的方案思路,确保用户有选择余地。在文档结构上,我会先展示ID范围管理方案的具体代码实现,从定义ID范围到处理函数的细节处理。然后介绍子类化方案作为备选,最后提及反射消息方案作为补充。特别要注意提醒用户资源释放问题,动态创建的控件需要手动销毁,很多人容易忽略这点。用户可能还会关心性能问题,特别是当有大量编辑框时。需要说明消息机制本身的负荷很小,但获取文本内容这种操作可能成为瓶颈。建议在处理函数中避免立即进行复杂操作,可以考虑延迟处理或缓冲机制。对了,引用[3]提到GetWindowText这个重要方法,必须在使用时特别注意内存分配和线程安全。特别是如果用户在辅助线程中创建这些控件(虽然不推荐),需要强调跨线程调用的限制。</think> 在MFC框架中,动态创建多个`CEdit`控件并自动监测内容修改可通过以下方案实现,避免为每个控件单独添加`ON_EN_CHANGE`消息映射: ### 方法一:使用控件ID范围映射 (推荐) 通过`ON_CONTROL_RANGE`宏批量处理同一类事件[[^5]]: 1. **定义控件ID范围** ```cpp #define IDC_EDIT_START 1000 #define IDC_EDIT_END 1050 // 支持最多50个动态编辑框 ``` 2. **动态创建控件** ```cpp for(int i = 0; i < nEditCount; i++) { CEdit* pEdit = new CEdit; pEdit->Create(WS_CHILD | WS_VISIBLE | WS_BORDER, rect, this, IDC_EDIT_START + i); // 分配连续ID m_edits.Add(pEdit); // 加入控件数组 } ``` 3. **添加统一消息映射** 在消息映射表中添加: ```cpp BEGIN_MESSAGE_MAP(CYourDialog, CDialog) ON_CONTROL_RANGE(EN_CHANGE, IDC_EDIT_START, IDC_EDIT_END, OnEditChanged) END_MESSAGE_MAP() ``` 4. **实现统一处理函数** ```cpp void CYourDialog::OnEditChanged(UINT nID) { int nIndex = nID - IDC_EDIT_START; // 计算控件索引 CEdit* pEdit = (CEdit*)GetDlgItem(nID); CString strText; pEdit->GetWindowText(strText); TRACE(_T("Edit %d modified: %s\n"), nIndex, strText); } ``` ### 方法二:子类化CEdit控件 创建派生类自动处理修改事件: ```cpp class CAutoEdit : public CEdit { public: DECLARE_MESSAGE_MAP() afx_msg void OnEnChange() { TRACE(_T("Edit content changed!\n")); // 添加自定义处理逻辑 } }; BEGIN_MESSAGE_MAP(CAutoEdit, CEdit) ON_EN_CHANGE(10000, OnEnChange) // 10000为伪ID,实际不需真实ID END_MESSAGE_MAP() // 动态创建 CAutoEdit* pEdit = new CAutoEdit; pEdit->Create(WS_VISIBLE | WS_CHILD, rect, this, nAnyID); ``` ### 方法三:使用反射消息(Reflection) 在父窗口处理反射消息: ```cpp BEGIN_MESSAGE_MAP(CYourDialog, CDialog) ON_NOTIFY_REFLECT(EN_CHANGE, OnEditReflected) END_MESSAGE_MAP() void CYourDialog::OnEditReflected(NMHDR* pNMHDR, LRESULT* pResult) { CEdit* pEdit = (CEdit*)FromHandle(pNMHDR->hwndFrom); // 处理修改事件 *pResult = 0; } ``` ### 关键注意事项 1. **内存管理** 动态创建的控件必须手动销毁: ```cpp for(int i = 0; i < m_edits.GetCount(); i++) delete m_edits[i]; ``` 2. **线程安全** 控件操作需在UI线程执行,工作线程中修改文本应使用`PostMessage` 3. **性能优化** 高频修改场景建议: ```cpp // 批量修改前禁用通知 pEdit->SetRedraw(FALSE); // ...批量文本操作... pEdit->SetRedraw(TRUE); ``` > **方案对比** > - ✅ `ON_CONTROL_RANGE`:适合固定数量编辑框 > - ✅ **子类化方案**:最适合动态增删控件的场景 > - ✅ 反射消息:适合需要集中处理的简单场景 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值