2010-09-20 19 views
53

Estoy jugando con Qt, y quiero crear una pausa simple entre dos comandos. Sin embargo, no parece permitirme usar Sleep(int mili);, y no puedo encontrar ninguna función de espera obvia.¿Cómo creo una función de pausa/espera usando Qt?

Básicamente estoy haciendo una aplicación de consola para probar algún código de clase que luego se incluirá en una GUI de Qt adecuada, así que por ahora no me molesta romper todo el modelo impulsado por eventos.

+0

¿Qué exactamente estás probando? ¿Qué significa agregar 'wait()' o 'sleep()'? –

+0

Estoy creando una clase para conducir una bomba peristáltica utilizando comandos serie RS232. He creado una GUI en QT, pero mientras tanto solo estoy probando las funciones que he creado desde una función main() dentro de la consola. Por lo tanto, quiero que la clase sea compilada por QT pero al mismo tiempo quiero mypump.startpump(); dormir (1000); mypump.stoppump(); por ejemplo. solo para probarlo funciona – Zac

+0

A pesar de compilar con QT, estoy usando la consola CONFIG + = para ejecutar y enviar cadenas de depuración a la consola. – Zac

Respuesta

28

Este previous question menciona el uso de qSleep() que se encuentra en el módulo QtTest. Para evitar la vinculación de gastos generales en el módulo QtTest, al buscar la fuente para esa función puede simplemente hacer su propia copia y llamarla. Utiliza define para llamar a Windows Sleep() o Linux nanosleep().

#ifdef Q_OS_WIN 
#include <windows.h> // for Sleep 
#endif 
void QTest::qSleep(int ms) 
{ 
    QTEST_ASSERT(ms > 0); 

#ifdef Q_OS_WIN 
    Sleep(uint(ms)); 
#else 
    struct timespec ts = { ms/1000, (ms % 1000) * 1000 * 1000 }; 
    nanosleep(&ts, NULL); 
#endif 
} 
+0

Gracias, el incluir windows.h habilita el uso de Sleep(); Esto funcionará por ahora ya que entiendo que no utilizaré este código en el programa final porque rompe el modelo impulsado por el evento, pero por ahora esto me permite probar el programa tal como está. – Zac

+0

¿Dónde encontraste la fuente? –

+0

Ahora son seis años después y algunas personas cambiaron de manos, pero puede encontrar la versión de código abierto de Qt en https://www.qt.io/download-open-source. Hay enlaces allí que conducirán al código fuente. No tengo idea si el código anterior aún existe. –

5

Puesto que usted está tratando de "probar algo de código de clase," Yo realmente recomiendo aprender a usar QTestLib. Proporciona un QTest namespace y un QtTest module que contienen una serie de funciones y objetos útiles, incluido QSignalSpy, que puede usar para verificar que se emitan ciertas señales.

Dado que eventualmente se integrará con una GUI completa, el uso de QTestLib y la prueba sin dormir ni esperar le dará una prueba más precisa, una que representa mejor los verdaderos patrones de uso. Pero, si decide no seguir esa ruta, puede usar QTestLib::qSleep para hacer lo que ha solicitado.

ya que sólo se necesita una pausa entre el comienzo de la bomba y apagarlo, se puede utilizar fácilmente un único temporizador de disparo:

class PumpTest: public QObject { 
    Q_OBJECT 
    Pump &pump; 
public: 
    PumpTest(Pump &pump):pump(pump) {}; 
public slots: 
    void start() { pump.startpump(); } 
    void stop() { pump.stoppump(); } 
    void stopAndShutdown() { 
     stop(); 
     QCoreApplication::exit(0); 
    } 
    void test() { 
     start(); 
     QTimer::singleShot(1000, this, SLOT(stopAndShutdown)); 
    } 
}; 

int main(int argc, char* argv[]) { 
    QCoreApplication app(argc, argv); 
    Pump p; 
    PumpTest t(p); 
    t.test(); 
    return app.exec(); 
} 

Pero qSleep() sin duda sería más fácil si todo lo que le interesa es verificar un par de cosas en la línea de comando.

EDIT: Según el comentario, aquí se muestran los patrones de uso necesarios.

En primer lugar, es necesario modificar el archivo .pro para incluir qtestlib:

CONFIG += qtestlib 

En segundo lugar, es necesario incluir los archivos necesarios:

  • Para el espacio de nombres QTest (que incluye qSleep) : #include <QTest>
  • Para todos los elementos en el módulo QtTest: #include <QtTest>. Esto es funcionalmente equivalente a agregar una inclusión para cada elemento que existe dentro del espacio de nombres.
+0

¿Cómo incluyo QTestlib? El #include no parece poder encontrarlo. – Zac

+0

buen punto. No entendí que estaba realmente probando :) –

8

Hemos estado utilizando la clase de abajo -

class SleepSimulator{ 
    QMutex localMutex; 
    QWaitCondition sleepSimulator; 
public: 
    SleepSimulator::SleepSimulator() 
    { 
     localMutex.lock(); 
    } 
    void sleep(unsigned long sleepMS) 
    { 
     sleepSimulator.wait(&localMutex, sleepMS); 
    } 
    void CancelSleep() 
    { 
     sleepSimulator.wakeAll(); 
    } 
}; 

QWaitCondition está diseñado para coordinar mutex de espera entre diferentes hilos. Pero lo que hace que esto funcione es que el método de espera tiene un tiempo de espera excedido. Cuando se lo llama de esta manera, funciona exactamente como una función de reposo, pero utiliza el ciclo de eventos de Qt para el tiempo. Por lo tanto, ningún otro evento o la IU están bloqueados como lo hace la función normal de reposo de Windows.

Como una ventaja, hemos agregado la función CancelSleep para permitir que otra parte del programa cancele la función "dormir".

Lo que nos gustó de esto es que es liviano, reutilizable y es completamente autocontenido.

QMutex: http://doc.qt.io/archives/4.6/qmutex.html

QWaitCondition: http://doc.qt.io/archives/4.6/qwaitcondition.html

1

Si desea un método multi-plataforma de hacer esto, el patrón general es derivar de QThread y crear una función (estática, si se desea) en su clase derivada que llamará a una de las funciones de suspensión en QThread.

+0

o incluso mejor - vea el último comentario bajo la pregunta (hasta el día de hoy), gracias por inspirar eso :) – mlvljr

113

Escribí una función de retardo super simple para una aplicación que desarrollé en Qt.

Le aconsejo que use este código en lugar de la función de reposo, ya que no permitirá que su GUI se congele.

Aquí está el código:

void delay() 
{ 
    QTime dieTime= QTime::currentTime().addSecs(1); 
    while (QTime::currentTime() < dieTime) 
     QCoreApplication::processEvents(QEventLoop::AllEvents, 100); 
} 

Para retrasar un evento por n segundos - utilizar addSecs(n).

+2

¡Muchas gracias por esta hermosa función! Exactamente lo que estaba buscando, ya que no suspende el ciclo del evento principal. – Marc

+0

Este es uno de esos nuggets de código que de vez en cuando te encuentras y piensas "¿Por qué no pensé en eso?". Buen trabajo. – GPPK

+4

¿Soy solo el que experimenta una carga de CPU del 100% al poner esto en el bucle 'while' en Qt 5.7? – TranslucentCloud

32

Pequeño +1 a kshark27 's respuesta para que sea dinámica:

#include <QTime> 

void delay(int millisecondsToWait) 
{ 
    QTime dieTime = QTime::currentTime().addMSecs(millisecondsToWait); 
    while(QTime::currentTime() < dieTime) 
    { 
     QCoreApplication::processEvents(QEventLoop::AllEvents, 100); 
    } 
} 
+0

más una pequeña nota: supongo que '#include 'also' # include ' – Jack

+1

Ver comentarios arriba. Esto puede causar ocupado, espere 100% de uso de la CPU en circunstancias normales (cola de eventos vacía) y problemas mayores del reloj del sistema se ajustan cuando el ciclo se está ejecutando. – DavidJ

+0

#include nvd

2

similares a algunas respuestas aquí, pero tal vez un poco más ligero

void MyClass::sleepFor(qint64 milliseconds){ 
    qint64 timeToExitFunction = QDateTime::currentMSecsSinceEpoch()+milliseconds; 
    while(timeToExitFunction>QDateTime::currentMSecsSinceEpoch()){ 
     QApplication::processEvents(QEventLoop::AllEvents, 100); 
    } 
} 
+0

Aproximación similar a kshark27, bien también. – Jack

30

De QT5 en adelante también podemos utilizar

estáticas público Miembros de QThread

void msleep(unsigned long msecs) 
void sleep(unsigned long secs) 
void usleep(unsigned long usecs) 
+1

Esta debería ser la respuesta aceptada. Es simple, fácil de usar y no consume todos los ciclos de tu CPU. –

5

Para utilizar el estándar función del sueño añadir lo siguiente en su archivo .cpp:

#include <unistd.h> 

A partir de la versión 4.8 de Qt, las siguientes sueño funciones están disponibles:

void QThread::msleep(unsigned long msecs) 
void QThread::sleep(unsigned long secs) 
void QThread::usleep(unsigned long usecs) 

Para usarlos, simplemente agregue lo siguiente en su archivo .cpp:

#include <QThread> 

Referencia: QThread (a través de la documentación de Qt): http://doc.qt.io/qt-4.8/qthread.html

De lo contrario, realice los siguientes pasos ...

Modificar el archivo de proyecto de la siguiente manera:

CONFIG += qtestlib 

Tenga en cuenta que en las últimas versiones de Qt obtendrá el siguiente error:

Project WARNING: CONFIG+=qtestlib is deprecated. Use QT+=testlib instead. 

...Así, en lugar modificar el archivo de proyecto de la siguiente manera:

QT += testlib 

A continuación, en el archivo .cpp, asegúrese de agregar lo siguiente:

#include <QtTest> 

Y a continuación, utilizar una de las funciones del sueño, así:

usleep(100); 
+0

¡estas funciones están protegidas! – SAAD

1

@kshark27 's respuesta no funcionó para mí por alguna razón (porque uso de Qt 5.7?), así que terminó haciendo esto:

while (someCondition) { 

    // do something 

    QApplication::processEvents(); 
    QThread::sleep(1); // 1 second 

}; 

Si esto se hace en el hilo de la GUI, obviamente introduce un retraso de GUI de 1 segundo antes de responder a los eventos del usuario. Pero si puede vivir con esto, esta solución es probablemente la más fácil de implementar e incluso Qt la respalda en su artículo Threading Basics (vea Cuándo usar la sección Alternativas a los hilos).

2

A lo largo de los años he tenido muchos problemas al intentar hacer que QApplication :: processEvents funcione, como se usa en algunas de las principales respuestas. IIRC, si varias ubicaciones terminan llamándolo, puede terminar causando que algunas señales no se procesen (https://doc.qt.io/archives/qq/qq27-responsive-guis.html). Mi opción preferida habitual es utilizar un QEventLoop (https://doc.qt.io/archives/qq/qq27-responsive-guis.html#waitinginalocaleventloop).

inline void delay(int millisecondsWait) 
{ 
    QEventLoop loop; 
    QTimer t; 
    t.connect(&t, &QTimer::timeout, &loop, &QEventLoop::quit); 
    t.start(millisecondsWait); 
    loop.exec(); 
} 
Cuestiones relacionadas