Qt中QSpinBox调用setValue()方法会自动发送valueChanged信号问题


问题描述

我最近编写了一个可以选定视频区域的程序。用户可以通过鼠标在视频上自由绘制长方形区域。这个程序不仅可以实时跟踪并更新选中的区域,还允许用户直接操作这个长方形,比如放大、缩小或移动。所有的信息,包括选中的长方形的左上角的坐标,以及其宽度和高度,都会实时显示在编辑框中,方便用户查看和修改。

实现

使用了Qt的信号与槽机制。
当Qt中的长方形坐标改变时,会发出一个信号,并且会同步更新与之关联的编辑框的内容。相反,如果编辑框的内容发生了变化,可以直接驱动长方形进行重绘,实现两者之间的同步更新。值得注意的是,QSpinBoxvalueChanged信号具有两种重载形式,一种是接受int型参数,另一种是接受QString型参数。因此,在连接信号和槽函数时,必须使用QOverload模板来明确指定信号的参数类型,以避免出现连接错误。
代码如下:

初始化信号与槽
void Dialog::init()
{
    //绑定界面控件信号
    connect(ui->spb_x, QOverload<int>::of(&QSpinBox::valueChanged), this, &Dialog::onValueChanged);
    connect(ui->spb_y, QOverload<int>::of(&QSpinBox::valueChanged), this, &Dialog::onValueChanged);
    connect(ui->spb_w, QOverload<int>::of(&QSpinBox::valueChanged), this, &Dialog::onValueChanged);
    connect(ui->spb_h, QOverload<int>::of(&QSpinBox::valueChanged), this, &Dialog::onValueChanged);
}

//新建透明窗口
void Dialog::creatScerrn(bool flag, int x, int y, int w, int h)
{
    QPoint p = ui->video->mapToGlobal(QPoint(0, 0));
    QSize size = ui->video->size();
    if(m_screen == NULL)
    {
        m_screen = new Screen(0,p.x(),p.y(),size.width(),size.height());
        //连接信号与槽
        connect(m_screen, &Screen::rectChanged, this, &Dialog::onRectChanged);
    }
    m_screen->init(flag,x,y,w,h);
    m_screen->move(p.x(),p.y());
    m_screen->show();
}

//长方形变化槽函数
void Dialog::onRectChanged(int x, int y, int w, int h)
{
    //同步修改编辑框内容
    ui->spb_x->setValue(x);
    ui->spb_y->setValue(y);
    ui->spb_w->setValue(w);
    ui->spb_h->setValue(h);
}

//QSpinBox数值变化槽函数
void Dialog::onValueChanged()
{
    if(m_screen == NULL)
    {
        return;
    }
    int x,y,w,h;
    x = ui->spb_x->value();
    y = ui->spb_y->value();
    w = ui->spb_w->value();
    h = ui->spb_h->value();
    //将变化发送给透明窗口去重绘长方形
    m_screen->init(false,x,y,w,h);
}

我发现,QSpinBox::setValue()方法在执行结束后会触发QSpinBox::valueChanged信号的发送,而且每当其长方形被设置参数时也会进行参数计算,进一步触发信号以更新编辑框的值。这导致了信号与槽的持续触发,形成了闭合回路,导致界面出现卡顿,操作也不流畅。

为了解决这个问题,找到了bool QObject::blockSignals(bool block)方法。

看一下官方解释吧:
QObject::blockSignals(bool block)
QObject::blockSignals() 方法可以阻止一个 QObject 类的信号连接到相应的槽函数,这意味着即使信号被发射,也不会触发任何槽函数。
所以我们只需要对上面的槽函数进行改造,当对目标进行操作时,阻塞目标的信号即可打破这个闭合回路。
修改后槽函数如下:

void Dialog::onRectChanged(int x, int y, int w, int h)
{
    //阻塞信号发送
    ui->spb_x->blockSignals(true);
    ui->spb_y->blockSignals(true);
    ui->spb_w->blockSignals(true);
    ui->spb_h->blockSignals(true);
    //同步修改编辑框内容
    ui->spb_x->setValue(x);
    ui->spb_y->setValue(y);
    ui->spb_w->setValue(w);
    ui->spb_h->setValue(h);
    //恢复信号发送
    ui->spb_x->blockSignals(false);
    ui->spb_y->blockSignals(false);
    ui->spb_w->blockSignals(false);
    ui->spb_h->blockSignals(false);
}

void Dialog::onValueChanged()
{
    if(m_screen == NULL)
    {
        return;
    }
    int x,y,w,h;
    x = ui->spb_x->value();
    y = ui->spb_y->value();
    w = ui->spb_w->value();
    h = ui->spb_h->value();
    m_screen->blockSignals(true);
    m_screen->init(false,x,y,w,h);
    m_screen->blockSignals(false);
}

结果

完美实现了我们的需求。
大概效果如下:
效果图

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辣死那个胖子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值