我有一个带有两个旋转框的表格,由于纵横比的宽度和高度,必须连接。当我点击第一个旋转框并增加/减少值时,另一个第二个旋转框应该将其值更改为与第一个旋转框的比率。我已经完成了比率连接,但是有问题,因为我在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);
}
}
我认为,在改变槽中的值之前,这里最好的解决方案是来自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/8
是0
,而(arg1/8)*2
导致0
。
只是改变计算顺序可以提高准确性:
(arg1 * 2) / 8
arg1 = 6
arg1 * 2 = 12
(arg1 * 2 / 8) = 1
@ 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);
//....
}