Qt C ++:在两个spinbox中连接值的变化

问题描述 投票:0回答:2

我有一个带有两个旋转框的表格,由于纵横比的宽度和高度,必须连接。当我点击第一个旋转框并增加/减少值时,另一个第二个旋转框应该将其值更改为与第一个旋转框的比率。我已经完成了比率连接,但是有问题,因为我在SLOT valueChanged(int)上连接两个spinbox并且这个方法阻止整个程序,因为无限循环。这意味着当我将值增加到第一个spinbox时,首先为此值更改值,然后为第二个再次调用第一个值。

我想解决这个问题,所以当我点击其中一个spinbox时,以正确的方式改变这两个值而不用无限循环。

所以有代码:

void MainWindow::on_sbHeight_valueChanged(int arg1)
{
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbWidth->setValue((arg1/8)*2);
    } else if (ui->radioRatio2->isChecked()) {
        ui->sbWidth->setValue((arg1/14)*3);
    }
    } else {
    ui->sbWidth->setValue(arg1);
    }
}

void MainWindow::on_sbWidth_valueChanged(int arg1)
{
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbHeight->setValue((arg1/2)*8);
    } else if (ui->radioRatio2->isChecked()) {
        ui->sbHeight->setValue((arg1/3)*14);
    }
    } else {
    ui->sbHeight->setValue(arg1);
    }
}
c++ qt qt-creator signals-slots qspinbox
2个回答
1
投票

我认为,在改变槽中的值之前,这里最好的解决方案是来自spinboxes的block signals

我通常使用这样的助手类:

class SignalsBlocker
{
public:
    SignalsBlocker(QObject* ptr):
    _ptr(ptr)
    {
        _b = ptr->blockSignals(true);
    }
    ~SignalsBlocker()
    {
        _ptr->blockSignals(_b);
    }

private:
    QObject* _ptr;
    bool _b;
};

所以你可以写

void MainWindow::on_sbHeight_valueChanged(int arg1)
{
    SignalsBlocker block(ui->sbWidth);
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbWidth->setValue((arg1/8)*2);
    //.....
}

void MainWindow::on_sbWidth_valueChanged(int arg1)
{
    SignalsBlocker block(ui->sbHeight);
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbHeight->setValue((arg1/2)*8);
    //....
}

人们可以提供的直接解决方案是

void foo(QObject* object)
{
    object->blockSignals(true); 
    // some stuff
    object->blockSignals(false);
}

但是,这种解决方案并不正确:想象一下以下情况

QObject* obj;
obj->blockSignals(true);
foo(obj);
//some other stuff
obj->blockSignals(false);

人们可能希望信号在some otherstuff之后被解锁,但实际上它们将在foo函数内被解锁,这不是预期的行为。这就是为什么你应该保存块状态然后恢复它。

但同样,RAII助手类是降低代码复杂性的最方便的解决方案。


还要注意,你用整数计算,比如

(arg1/8)*2

根本不准确。

例如,让arg1 = 6。然后arg1/80,而(arg1/8)*2导致0

只是改变计算顺序可以提高准确性:

 (arg1 * 2) / 8

 arg1 = 6
 arg1 * 2 = 12
 (arg1 * 2 / 8) = 1

0
投票

@ lol4t0解决方案现在使用QSignalBlocker从5.3版开始在Qt中。含义QSignalBlocker可以像@ lol4t0中的SignalsBlocker一样使用。它会在创建时阻止信号,并在销毁时恢复先前的块状态。

来自@ lol4t0的示例,但是使用Qt类:

void MainWindow::on_sbHeight_valueChanged(int arg1)
{
    QSignalBlocker block(ui->sbWidth);
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbWidth->setValue((arg1/8)*2);
    //.....
}

void MainWindow::on_sbWidth_valueChanged(int arg1)
{
    QSignalBlocker block(ui->sbHeight);
    if (arg1 != 0) {
    if (ui->radioRatio1->isChecked()) {
        ui->sbHeight->setValue((arg1/2)*8);
    //....
}

http://doc.qt.io/qt-5/qsignalblocker.html

© www.soinside.com 2019 - 2024. All rights reserved.