如何通过鼠标单击选择性地使QWidget接受焦点?

时间:2014-06-03 19:13:02

标签: c++ qt user-interface qwidget

我正在创建一个应用程序,它提供节点和将它们连接在一起的线的可视化表示。节点和行都由自定义QWidgets,WidgetNode和WidgetLine表示,比如说。

我已经将WidgetLine实现为一个透明的小部件,它足够大,可以包含该行的起点和终点,以及一个自定义函数来绘制行本身。

我希望如果用户点击该行旁边或右侧,则WidgetLine会获得焦点,但如果他们点击更远的线(但仍然在WidgetLine的几何体所覆盖的矩形区域上),那么点击被WidgetLine完全忽略并传递给下面的小部件。

我首先尝试在WidgetLine上使用自定义focusInEvent()函数执行此操作,但发现鼠标单击没有在下面传播。然后我尝试将焦点策略设置为Qt::NoFocus并使用mousePressEvent()使用setFocus()在适当的时候手动设置焦点,但鼠标事件仍未传播到上面的小部件,即使我打电话给ignore()

最后,我尝试使用此事件过滤器函数

安装事件过滤器来拒绝鼠标事件
bool WidgetLineFilter::eventFilter(QObject* object, QEvent* event)
{
    assert(object == mCord);
    if (event->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent* e = dynamic_cast<QMouseEvent*>(event);
        assert(e);
        if (e)
        {
            QPoint mouseRelativeToParent = mCord->mapToParent(e->pos());
            // calculate distance of mouse click to patch cord
            QLineF line(mCord->line());
            float distance = distanceFromPointToLine(QVector2D(line.p1()), QVector2D(line.p2()), QVector2D(mouseRelativeToParent));
            qDebug() << distance;
            const float distanceThreshold = 2.f;
            if (distance < distanceThreshold)
            {
                qDebug() << "consuming mouse click for focus";
                mCord->setFocus(Qt::MouseFocusReason);
                return true;
            }
            else{
                qDebug() << "mousepressevent too far for focus";
                return QObject::eventFilter(object, event);
            }
        }
    }
    return false;
}

但是这仍然没有将鼠标事件传播给“mousepressevent太远焦点”案例中的父节点。我也试过从这里返回false和true,并在ignore上调用e,但下面的小部件没有收到点击。

(注意上述方法在WidgetLine仅在正确的时间获得焦点的意义上起作用,只是下面的小部件在没有获得焦点时没有接收到新闻事件。)

有关如何解决此问题的任何想法?

2 个答案:

答案 0 :(得分:0)

将鼠标位置存储在全局变量中。让所有小部件都进入/离开以下事件,并使用它来检查运行func时您所在/附近的小部件。

void QGLWidget::enterEvent(QEvent *)
{
    setFocus();
}

void QGLWidget::leaveEvent(QEvent *)
{
    clearFocus();
}

答案 1 :(得分:0)

最后,我创建了一个事件过滤器,用于有选择地拦截鼠标事件并将其安装在基本窗口上,并递归地放在基本窗口的每个子窗口小部件上(在创建它们时将其安装在新的子窗口小部件上)。此过滤器使用每个鼠标按下事件调用基本窗口,然后迭代每个WidgetLine,测试是否应该通过此鼠标按下选择它们并在需要时设置焦点。如果它们都测试为false,则过滤器会释放事件,否则过滤器会消耗它。

然后使用

将WidgetLine设置为对鼠标事件透明
setAttribute(Qt::WA_TransparentForMouseEvents);

实现这个目标应该比实现这个目标更加麻烦。但是这样做。