0

幅と高さのアスペクト比のために接続する必要がある 2 つのスピンボックスを含むフォームがあります。最初のスピンボックスをクリックして値を増減すると、もう一方の 2 番目のスピンボックスは、最初のスピンボックスとの比率になるように値を変更する必要があります。私はすでに比率接続を行っていますが、SLOT valueChanged(int) で両方のスピンボックスを接続し、このメソッドは無限ループのためにプログラム全体をブロックするため、問題があります。これは、最初のスピンボックスの値を増やすと、最初にこのスピンボックスの値が変更され、次に最初のスピンボックスを呼び出す 2 番目のスピンボックスの値が変更されることを意味します。

この問題を解決したいので、スピンボックスの1つをクリックすると、無限ループなしで両方の値を正しい方法で変更できます。

コードは次のとおりです。

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);
    }
}
4

2 に答える 2

1

ここでの最善の解決策は、スロットの値を変更する前に、スピンボックスからのシグナルをブロックすることだと思います。

私は通常、次のようなヘルパー クラスを使用します。

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/8になります。0(arg1/8)*20

計算の順序を変更するだけで、精度が向上します。

 (arg1 * 2) / 8

 arg1 = 6
 arg1 * 2 = 12
 (arg1 * 2 / 8) = 1
于 2013-06-08T09:48:07.267 に答える