我有一个带有两个旋转盒的表单,由于宽度和高度的纵横比,必须连接它们。当我点击第一个旋转框并增加/减少值时,另一个第二个旋转框应该将其值更改为与第一个旋转框的比率。我已经完成了比率连接,但是有问题,因为我在SLOT valueChanged(int)上连接两个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);
}
}
答案 0 :(得分:1)
我认为,在更改插槽中的值之前,此处的最佳解决方案是来自spinbox的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
答案 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);
//....
}