[c++] Fermare una funzione ricorsiva

valentino861
Devo far andare una funzione finchè non premo un determinato tasto ma non so come. Pensavo di usare GOTO e poi di far leggere da tastiera la pressione di quel determinato tasto e se non ci fosse entro 3 secondi di continuare con la ricorsione, o una cosa del genere. Che ne dite?

Risposte
apatriarca
Il modo più semplice credo sia quello di utilizzare una qualche API in grado di gestire gli eventi inviati dal sistema operativo. Se stai lavorando in Windows puoi usare ad esempio le Win32 API oppure qualcosa come le SDL. Quando un tasto viene premuto, un evento viene generato e inserito in una specie di lista. Dopo la tua attesa di 10 secondi puoi a questo punto leggere tutti gli eventi ricevuti dalla tua applicazione e se non ci sono eventi del tipo voluto continui con la tua applicazione.

valentino861
si il senso l'ho capito. Mi servirebbe un mini codice al volo...non sono un campioni in informatica.

apatriarca
Appena ho tempo vedo se riesco a scrivertelo.

valentino861
grazie :)

valentino861
ragazzi basta che mi date qualche consiglio su cosa usare e poi me le vado a vedere io

apatriarca
Scusa, ma sono in periodo esami e quindi occupatissimo. Devi decidere una libreria che permetta di gestire gli eventi inviati alla tua applicazione dal sistema operativo. Con le SDL ad esempio è sufficiente scrivere:

SDL_Event event;

while (SDL_PollEvent(&event)) {
    if (event.type == SDL_KEYUP) {
        // un tasto è stato premuto...
    }
}


Il problema principale, motivo per cui non ho risposto prima, è che l'uso degli eventi richiede in molti casi la creazione di una finestra grafica di Windows (non so se questo è un problema per te) e quindi una struttura del codice un po' diversa da quella che probabilmente hai attualmente.

valentino861
no in effetti una finestra grafica di windows non sono proprio capace, e quindi come lo utilizzo il codice che hai postato?

grazie davvero per la disponibilità :)

valentino861
Ho un pò smanettato con sorgenti trovati in rete e sono arrivato a questo:

#include "SDL.h"
#include <stdio.h>
#include "stdlib.h"

//Function prototypes
void DisplayState(SDL_KeyboardEvent *key);
void DisplayModifiers(SDL_KeyboardEvent *key);
void DisplayKey(SDL_KeyboardEvent *key);

int main(int argc, char *argv[])
{
	SDL_Surface *screen;
	SDL_Event event;
	int running = 1;
	
	//We must first initialize the SDL video component, and check for success
	if (SDL_Init(SDL_INIT_VIDEO) != 0) {
		printf("Unable to initialize SDL: %s\n", SDL_GetError());
		return 1;
	}
	
	//When this program exits, SDL_Quit must be called
	atexit(SDL_Quit);
	
	//Set the video mode to anything, just need a window
	screen = SDL_SetVideoMode(320, 240, 0, SDL_ANYFORMAT);
	if (screen == NULL) {
		printf("Unable to set video mode: %s\n", SDL_GetError());
		return 1;
	}
	
	//Keep looping until the user closes the SDL window
	while(running) {
		//Get the next event from the stack
		while(SDL_PollEvent(&event)) {
			//What kind of event has occurred?
			switch(event.type){
				case SDL_KEYDOWN:	//A key has been pressed
				case SDL_KEYUP:		//A key has been released
					DisplayState(&event.key);	//Print out the key state
					break;
				case SDL_QUIT:		//The user has closed the SDL window
					running = 0;
					break;
			}
		}
	}	
	//Return success!
	return 0;
}

void DisplayState(SDL_KeyboardEvent *key)
{
	//What type of keypress was this?
	if (key->type != SDL_KEYUP)
		printf("PRESSED: %s\n", SDL_GetKeyName(key->keysym.sym));
	
}


Mi crea una piccola finestra e riconosce il comando da tastiera. Ora dovrei solo integrare questo codice con il mio e fare in modo che quando premo ad esempio escape, il programma si chiuda...giusto?

valentino861
Ok ci dovrei essere. La funzione test verifica se viene spinto un tasto e se è cosi viene chiuso il ciclo.

#include "SDL.h"
#include <stdio.h>
#include "stdlib.h"
#include "time.h"

SDL_Surface *image;	//This pointer will reference our bitmap sprite

void DisplayState(SDL_KeyboardEvent *key){
	//What type of keypress was this?
	if (key->type != SDL_KEYUP)
		printf("PRESSED: %s\n", SDL_GetKeyName(key->keysym.sym));
}

void wait(double seconds){
	clock_t endwait;
	endwait=clock()+seconds*CLOCKS_PER_SEC;
	while (clock()<endwait);}

int test(){

int tempo=0;
SDL_Surface *screen;	//This pointer will reference the backbuffer
SDL_Surface *temp;	//This pointer will temporarily reference our bitmap sprite
SDL_Rect src, dest;	//These rectangles will describe the source and destination regions of our blit
SDL_Event event;

atexit(SDL_Quit);
screen = SDL_SetVideoMode(320, 240, 0, SDL_ANYFORMAT);
 
temp = SDL_LoadBMP("image.bmp");	
image = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);

//Construct the source rectangle for our blit
src.x = 0;
src.y = 0;
src.w = image->w;	//Use image->w to display the entire width of the image
src.h = image->h;	//Use image->h to display the entire height of the image

//Construct the destination rectangle for our blit
dest.x = 100;		//Display the image at the (X,Y) coordinates (100,100)
dest.y = 100;
dest.w = image->w;	//Ensure the destination is large enough for the image's entire width/height
dest.h = image->h;

//Blit the image to the backbuffer
SDL_BlitSurface(image, &src, screen, &dest);

//Flip the backbuffer to the primary
SDL_Flip(screen);

while(tempo<5){
	while(SDL_PollEvent(&event)) {

		switch(event.type){
			case SDL_KEYDOWN:	//A key has been pressed
				DisplayState(&event.key);	//Print out the key state
				return 0;
			case SDL_QUIT:		//The user has closed the SDL window
				return 0;
				}}				
	wait(1);
	tempo++;
	printf("%i\n",tempo);
	}
tempo=0;
SDL_FreeSurface(image);
}



int main(int argc, char *argv[])
{

while(test()){
wait(1);
printf("prova\n");
	}


printf("fine");
//Release the surface
SDL_FreeSurface(image);
return 0;
}

valentino861
si perfetto ora mentre gira la mia funzione se spingo un tasto viene registrato come un evento e prima di far ripartire l'acquisizione viene controllata la coda. Se risulta un tasto premuto si esce dall'acquisizione sennò riparte in automatico.

Fantastico è esattamente quello che volevo. L'unico neo se proprio devo fare il rompiscatole è la finestra che mi si apre che non mi serve, però me la tengo! :)

grazie

apatriarca
Sfortunatamente con le SDL (ma anche con tutte le altre librerie che conosco) per poter usare gli eventi devi avere una finestra aperta. Ovviamente la potresti usare per qualcosa. Il tuo codice fa molte più cose di quante ne siano necessarie. Io lo farei così (non ho avuto modo di provarlo):

#include "SDL.h"
#include <cstdio>
#include <cstdlib>
#include <ctime>

using namespace std;

SDL_Surface *initSDL();
void mainLoop();
void wait(double);

int main()
{
    SDL_Surface *screen = initSDL();
    if (screen == NULL) return 1;

    mainLoop();    

    SDL_Quit();

    return 0;
}

SDL_Surface *initSDL()
{
    SDL_Surface *screen = NULL;

    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("Impossibile inizializzare le SDL: %s\n", SDL_GetError());
        return NULL;
    }
 
    *screen = SDL_SetVideoMode(100, 100, 0, SDL_ANYFORMAT);
    if (*screen == NULL) {
	printf("Impossibile inizializzare la modalità video: %s\n", SDL_GetError());
	return NULL;
    }

    return screen;
}

void wait(double seconds)
{
    clock_t endwait;
    endwait=clock()+seconds*CLOCKS_PER_SEC;
    while (clock()<endwait);
}

void mainLoop()
{
    SDL_Event event;

    for(;;) {
        // elabora qui i dati

        puts("Premi un tasto entro 10 secondi per terminare.");

        wait(10.0);

        bool exit = false;
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_KEYDOWN || event.type == SDL_QUIT) {
                exit = true;
            } 
        }

        if (exit) {
            puts("Esecuzione interrotta.");
            return;
        }
    }
}

valentino861
si si infatti ho tolto anche io tutta quella parte. L'avevo inserita perchè siccome la finestra doveva essere aperta avevo pensato di metterci un logo, ma poi ho rinunciato. Meglio cosi più compatto e la finestrella piccola neanche si nota

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.