QTimer становится быстрее с каждым запуском/остановкой

Я использую QTimer для плавного изменения размера метки: она должна медленно увеличиваться, когда я навожу указатель мыши на кнопку, и медленно сворачиваться (уменьшать ее размер до тех пор, пока она не исчезнет), когда мышь покидает кнопку.

У меня есть два таймера в классе моей формы:

QTimer oTimer, cTimer;//oTimer for expanding, cTimer for collapsing

В конструкторе моей формы я устанавливаю значения таймера и подключаю сигналы кнопок mouseOver и mouseOut к слотам моей формы:

oTimer.setInterval( 25 );
cTimer.setInterval( 25 );

connect( ui.Button, 
         SIGNAL(mouseEntered(QString)), 
         this, 
         SLOT(expandHorizontally(QString)) );
connect( ui.Button, 
         SIGNAL(mouseLeft(QString)), 
         this, 
         SLOT(compactHorizontally(QString)) );

Теперь в этих слотах подключаю соответствующий таймер к слоту, который будет постепенно менять размер, а потом запускаю таймер:

void cForm::expandHorizontally(const QString & str)
{
    ui.Text->setText( str ); 
    connect( &oTimer, SIGNAL(timeout()), this, SLOT(increaseHSize()) );
    cTimer.stop();//if the label is collapsing at the moment, stop it
    disconnect( &cTimer, SIGNAL(timeout()) );
    oTimer.start();//start expanding
}

void cForm::compactHorizontally(const QString &)
{
    connect( &cTimer, SIGNAL(timeout()), this, SLOT(decreaseHSize()) );
    oTimer.stop();
    disconnect( &oTimer, SIGNAL(timeout()) );
    cTimer.start();
}

После этого метка начинает менять свой размер:

void cForm::increaseHSize()
{
    if( ui.Text->width() < 120 )
    {
        //increase the size a bit if it hasn't reached the bound yet
        ui.Text->setFixedWidth( ui.Text->width() + 10 );
    }
    else
    {
        ui.Text->setFixedWidth( 120 );//Set the desired size
        oTimer.stop();//stop the timer
        disconnect( &oTimer, SIGNAL(timeout()) );//disconnect the timer's signal
    }
}

void cForm::decreaseHSize()
{
    if( ui.Text->width() > 0 )
    {
        ui.Text->setFixedWidth( ui.Text->width() - 10 );
    }
    else
    {
        ui.Text->setFixedWidth( 0 );
        cTimer.stop();
        disconnect( &cTimer, SIGNAL(timeout()) );
    }
}

Проблема: Сначала все работает гладко, этикетка медленно открывается и закрывается. Однако, если он делает это пару раз, то с каждым разом начинает менять размер все быстрее и быстрее (как если бы интервал таймера становился все меньше и меньше, но это явно не так). В конце концов после пары открытий/закрытий он просто начинает сразу увеличивать свой размер до границы, когда я навожу указатель мыши на кнопку, и сразу сворачивается до нулевого размера когда мышь уходит от кнопки.

Что может быть причиной этого?


person SingerOfTheFall    schedule 21.09.2012    source источник
comment
Можем ли мы увидеть метод compactHorizontally(QString) и метод «усадки» соответствующего размера? У меня есть подозрение, что это не QTimer, а что-то связанное с логикой размеров. Кроме того, QPropertyAnimation был разработан именно для этой цели и значительно облегчает жизнь.   -  person cmannett85    schedule 21.09.2012
comment
@ cmannett85, обновил вопрос. Я делаю это скорее в учебных целях, поэтому сам реализую   -  person SingerOfTheFall    schedule 21.09.2012
comment
какой класс обеспечивает сигнал mouseEntered??   -  person UmNyobe    schedule 21.09.2012
comment
@UmNyobe, мой класс унаследован от QPushButton, его единственная цель - сделать это: void cHoverButton::enterEvent(QEvent *) { emit mouseEntered( accessibleName() ); }   -  person SingerOfTheFall    schedule 21.09.2012
comment
это важное замечание. добавить это   -  person UmNyobe    schedule 21.09.2012


Ответы (2)


Я бы предположил, что события ожидают обработки, и количество событий в очереди увеличивается со временем. Возможно, потому что событие не полностью обрабатывается между двумя событиями таймера или из-за других частей программы.

Почему бы вам не использовать только один таймер? Вы можете пойти еще дальше, используя только слот для событий изменения размера. Другие слоты предназначены только для изменения типа изменений:

void cForm::connectStuff(){
    connect( &oTimer, SIGNAL(timeout()), this, SLOT(changeSize()) );
    connect( 
          ui.Button, 
          SIGNAL(mouseEntered(QString)), 
          this, 
          SLOT(expandHorizontally()) 
    );
    connect( 
          ui.Button, 
          SIGNAL(mouseLeft(QString)), 
          this, 
          SLOT(compactHorizontally()) 
    );
}

void cForm::expandHorizontally(){
      shouldExpand = true;
}

void cForm::compactHorizontally(){
      shouldExpand = false;
}

void cForm::changeSize(){
     if(shouldExpand)
        increaseHSize();//call the function which expand
     else
        decreaseHSize();//call the function which compact
}
person UmNyobe    schedule 21.09.2012
comment
Спасибо, переход на 1 таймер помог. Это довольно интересно, хотя я не ожидал, что он может так себя вести... - person SingerOfTheFall; 21.09.2012
comment
Я согласен. Мне тоже нужно сделать домашнее задание по событиям qt, для меня это все еще серая зона. - person UmNyobe; 21.09.2012

Согласно вашему коду, сигнал timeout() QTimer несколько раз подключается к одному и тому же слоту, а несколько подключений означают, что при испускании сигнала слот также будет вызываться несколько раз, что может показаться ускорением таймера.

Чтобы избежать этого, вы можете сделать соединение уникальным с помощью:

connect( &oTimer, SIGNAL(timeout()), this, SLOT(increaseHSize()), Qt::UniqueConnection);
person alexisdm    schedule 21.09.2012