Προς το περιεχόμενο

"Loading..." screen σε C


Dark_Sage

Προτεινόμενες αναρτήσεις

Δημοσ.

γεια σε όλους

 

εχω ενα προγραμμα που φτιαχνω σε C και σε καποιο σημειο εχει μια μεγαλη εργασία και δεν εκτυπωνει τπτ... θα ήθελα εκεινη τη περιοδο να εμφανίζω ενα μήνυμα σαν "Loading ..."

δηλαδή:

Loading

Loading.

Loading..

Loading...

Loading

 

Δεν θέλω το αποπάνω μιας και ειναι εύκολο απλα το έκανα έτσι για να σας το περιγραψω. Θέλω το Loading σταθερό και να εναλλάσονται οι κουκίδες λες και φορτώνει κατι... οσο και αν προσπάθησα δεν βρήκα τροπο! καμία ιδέα?

 

ευχαριστώ!!!

Δημοσ.

Το παρακάτω Console Application είναι γραμμένο σε Visual C++ Express Studio 2008 και δεν είναι τίποτα άλλο παρά μόνο η εμφάνιση ενός μηνύματος loading με κάποιες τελείες στο τέλος του μηνύματος να δηλώνουν την διαδικασία φορτώματος. Το όλο concept λειτουργεί χρησιμοποιώντας την συνάρτηση clock() μέσα σε ένα while βρόχο. Κατά τα άλλα αυτό είναι όλο το trick, τα υπόλοιπα ήταν απλά. Προσοχή μπορεί να υπάρχουν bugs αφού έχω να γράψω C κώδικα εδώ και 6 μήνες λόγω στρατού. Για να δούμε λοιπόν:

 

>
/* Loading message screen by BokDB-Bokarinho.*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

#define LOAD_FACTOR_DOTS 6

/* Functions Used in this Console App. */

void Wait(unsigned int _msec)
{
clock_t endWait = clock() + _msec * CLOCKS_PER_SEC;
while(clock() < endWait)
{
	/* Just Do nothing....*/
}
}

int main(int argc, char *argv[])
{
static int Idx = 0;
char *LoadingBuf = (char*)calloc(BUFSIZ, sizeof(char));
if(!LoadingBuf)
{
	printf("Memory Error:%s\n", strerror(errno));
	return EXIT_FAILURE;
}
/* Firstly create the loading message. */
strcpy(LoadingBuf, "Loading");
/* Print the initial message of loading process. */
printf("%s", LoadingBuf);
/* Generate a loop displaying the loading.... message. */
for(Idx = 0; Idx < LOAD_FACTOR_DOTS; Idx++)
{
	if(strlen(LoadingBuf) < BUFSIZ-1)
	{
		strcat(LoadingBuf,".");
		if(Idx)
			printf("%s", &LoadingBuf[strlen(LoadingBuf)-1]);
		Wait(3);
	}
	else
	{
		printf("Buffer Overflow....\n");
		return EXIT_FAILURE;
	}
}
/* Free memory used. */
free(LoadingBuf);
printf("\nHit enter to continue....\n");
getchar();
return EXIT_SUCCESS;
}

 

Καλή συνέχεια...

Δημοσ.

Bokarinho:

Απ'ότι κατάλαβα θέλει να εμφανίζονται εως 3 τελείες και μετά πάλι μόνο loading. Δηλαδή κάτι τέτοιο: (Ελπίζω να μη σε πειράζει που χρησιμοποίησα την Wait σου)

>
#include <stdio.h>
#include <time.h>
#include <string.h>

void Wait(unsigned int _msec)
{
   clock_t endWait = clock() + _msec * CLOCKS_PER_SEC;
   while(clock() < endWait)
   {
       /* Just Do nothing....*/
   }
} 

int main(int argc,char *argv[]) {
char loadingmsg[11];
int i,l;
strcpy(loadingmsg,"Loading");
loadingmsg[10]=0;
for (i=0;i<10;i++) {
	for (l=0;l<3;l++) {
		loadingmsg[l+7]=(i%4)>l?'.':' ';
	}
	printf("\r%s",loadingmsg);
	Wait(1);
}
printf("\nPress enter to continue");
getchar();
return 0;
}

Δημοσ.

Μπορείς να κάνεις την διαδικασία μετακίνησης των χαρακτήρων με την βοήθεια της memmove η οποία μετακινεί ολόκληρο το string προς την πλευρά που επιθυμείς λαμβάνοντας αυτόματα υπόψη της, τις πιθανότητες buffer overlap.

 

Ακολουθεί ένα απλό υπόδειγμα για το πώς θα μπορούσε να γίνει κάτι τέτοιο σε Windows κονσόλα:

 

>
//-Directx Text Scrolling Left -> Right--------------------------------------

#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <string.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
#ifdef __BORLANDC__
#pragma argsused
#endif

void _AnimateStr(char *pszInput);

int main(int argc, char* argv[])
{
char *pszWaiting = ".  ";

while(!kbhit())
 {
	gotoxy(1,1); cprintf("Please wait%s", pszWaiting);
	_AnimateStr(pszWaiting);
	Sleep(100);
 }

return 0;
}
//---------------------------------------------------------------------------
void _AnimateStr(char *pszInput)
{
// Push pszInput chars from left to right
char Char;
// pszInput should not be empty!
if(!strlen(pszInput))
	return;

Char = pszInput[strlen(pszInput) - 1];
memmove(&pszInput[1], &pszInput[0], strlen(pszInput) - 1);
pszInput[0] = Char;
}

 

* Οι εντολές gotoxy και cprintf βασίζονται στην βιβλιοθήκη conio.h του compiler μου (CodeGear Turbo C++) ώστε να κρατούν σταθερό το κείμενο στις συντεταγμένες της κονσόλας, το kbhit επιστρέφει != 0 αν πατηθεί κάποιο πλήκτρο οπότε ξεφεύγουμε από το while loop. Τέλος το Sleep είναι μια απλή Windows API εντολή που διακόπτει την εκτέλεση του loop για ms. Προφανώς κάποιες ανάλογες εντολές υπάρχουν και σε άλλα περιβάλλοντα ανάπτυξης -αλλά το θέμα μας εδώ είναι το animation των τελειών.

 

Το _AnimateStr κάνει την μετακίνηση των χαρακτήρων ενός string από τα αριστερά προς τα δεξιά. Το τρικ είναι η αποθήκευση του τελευταίου χαρακτήρα στο Char και η μετακίνηση ολόκληρου του string ύστερα προς τα δεξιά με την βοήθεια της memmove, επαναφέροντας το Char στην αρχή.

 

Σε δεύτερο επίπεδο δηλώνουμε τις κουκκίδες ως ". " για να πετύχουμε την ψευδαίσθηση του animation στην κονσόλα, εκ τυπώνοντας τις ύστερα δίπλα από το Please wait με %s.

 

Για την ιστορία, πρόκειται ουσιαστικά για ένα οπτικό τρικ (text scrolling) από την εποχή των 8-bit υπολογιστών (home computers), όταν η μετακίνηση ενός μεγάλου bitmap κόστιζε μεγάλα ποσά μνήμης.

Φυσικά μπορεί να υπάρχουν αβλεψίες στον κώδικα,

Καλή συνέχεια!

Δημοσ.

Σωστός ο DirectX, είναι μία λύση χρησιμοποιώντας το WinApi, άλλο ένα recital προγραμματισμού έλαβε χώρα στο section του insomnia όπου για το ίδιο θέμα δόθηκαν 3 διαφορετικές εκδοχές - απαντήσεις. Άντε καλημέρα σε όλους...

:-):-)

Δημοσ.

Αντιθέτως θεωρώ κάπως "specific" τη λύση του συμφορουμίτη μας Directx, ειδικά αφού χρησιμοποιεί WinAPI και μια συγκεκριμένη βιβλιοθήκη (για το gotoxy). Φυσικά ο σκοπός είναι να δείξει τί πρέπει να αναζητήσει ο Dark_Sage προκειμένου να φτιάξει τέτοια "εφέ", δεδομένου πως δεν υπάρχουν στάνταρ κλήσεις που να σε διευκολύνουν για κάτι τέτοιο.

 

Πάντως μια σχετική βιβλιοθήκη για τέτοια παιχνίδια στην κονσόλα είχα βρει και στον lcc-win32 compiler με την οποία είχα φτιάξει πολλά τέτοια στο παρελθόν (χρωματιστή progress bar στην κονσόλα και άλλα).

Δημοσ.

@bokarinho:

Thx! ;)

 

@PCharon:

Σκοπός μου είναι να δείξω στον Dark_Sage πως μπορεί να κάνει μετακίνηση χαρακτήρων εύκολα και γρήγορα από τα αριστερά προς τα δεξιά, συνεπώς εδώ ο πρωταγωνιστής μας είναι η ρουτίνα _AnimateStr που έγραψα για αυτό τον σκοπό σε ANSI C.

 

Οι υπόλοιπες ρουτίνες είναι απλά για να στηθεί ο κώδικας που επιδεικνύει την χρήση της ρουτίνας και καθώς τυχαίνει να προγραμματίζω σε Windows προτίμησα μια γρήγορη λύση, αντί να χρησιμοποιώ το Console API στο οποίο κάνει “map” το conio.h ή γράφοντας ένα timer-loop αντί της Sleep.

 

Η _AnimateStr μπορεί να χρησιμοποιηθεί σε Windows Timers, σε DOS loops, σε Threads, από DOS-Windows-Linux ακόμα και CP/M (!) όπου χρειάζεται (όσο 1 char = 1 byte) – αυτή είναι η ουσία του θέματος, πως θα κάνει animation σε ένα string, το οποίο θέλει να έχει τελείες (ή κάτι άλλο στην τελική) -μπορεί κάποιος άλλος να κάνει μαζί της άλλα εφέ (vertical text scrolling για παράδειγμα).

 

Τα υπόλοιπα (ή τα απόνερα του κώδικα -το while, gotoxy κτλ) όπως καταλαβαίνεις μου είναι αδιάφορα και φυσικά είναι implementation details, απλά χρησιμοποιούνται για να δει τι μπορεί να πάρει με την _AnimateStr, τι θα κάνει μετά μαζί της και πως θα εκτυπώσει το string στην οθόνη του είναι δικό του θέμα.

Δημοσ.

>#include <stdio.h>

int main ()
{
   int i, j;
   for (i=0; i<3; i++) {
       if (i==0) printf("loading.");
       if (i==1) printf("loading..");
       if (i==2) printf("loading...");
       for (j=0; j<1000000000; j++) { }
       printf("\r");
   }
}

σκέφτηκα αυτο το κομμάτι που κανει τη δουλεια που θελω. ειναι λιγο dummy...

Δημοσ.
>#include <stdio.h>

int main ()
{
   int i, j;
   for (i=0; i<3; i++) {
       if (i==0) printf("loading.");
       if (i==1) printf("loading..");
       if (i==2) printf("loading...");
       for (j=0; j<1000000000; j++) { }
       printf("\r");
   }
}

σκέφτηκα αυτο το κομμάτι που κανει τη δουλεια που θελω. ειναι λιγο dummy...

 

Άμα κάνει την δουλεία του και σε εξυπηρετεί καλό είναι, βέβαια το for(j=0.. είναι θάνατος καθώς σχετικοποιεί την αναμονή με βάση την ταχύτητα υπολογισμού της CPU σου, οπότε καλύτερα αφαίρεσε το και βασίσου στην clock (& clock_t) ή time (& time_t) διαφορετικά πας γυρεύοντας για προβλήματα χρονισμού, εκτός και αν πρόκειται για μια εξομοίωση του loop υπολογισμού σου οπότε δεν υπάρχει πρόβλημα.

 

Εγώ θα το έγραφα κάπως έτσι:

 

>
/*-Scroll a different way---------------------------------------------------*/

#include <stdio.h>
#include <conio.h>
#include <time.h>
#ifdef __BORLANDC__
#pragma hdrstop
#endif

/*---------------------------------------------------------------------------*/

#ifdef __BORLANDC__
#pragma argsused
#endif
int main(int argc, char* argv[])
{
char *pszString[] = { "Please wait.  ",
					  "Please wait . ",
					  "Please wait  ."
					};
int nStrIdx;
clock_t ctBegin = clock();/* Μια τιμή εκκίνησης για το χρονόμετρο μας */

while(!kbhit()) /* Αν πατηθεί πλήκτρο διακόπτουμε! */
 {
	for(nStrIdx = 0; nStrIdx < 3; nStrIdx++)
	 {
		/* Σχεδιάζουμε πάνω αριστερά στην Windows κονσόλα */
		gotoxy(1,1 );
		/* Το pszString με αριθμό nStrIdx */
		printf("%s", pszString[nStrIdx]);
		/*
		 * Και περιμένουμε μέχρι να συμπληρωθούν 500ms +/- (διότι η clock είναι ευαίσθητη σε CPU utilization)
		 * ή να πατήσει πλήκτρο ο χρήστης.
		 */
		while(clock() - ctBegin < 500 && !kbhit())
		 { /* Μια ζωή περιμένω ... */ }
		/* Και ύστερα όλα από την αρχή! */
		ctBegin = clock();
	 }
 }

/* Τέλος! */
return 0;
}
/*---------------------------------------------------------------------------*/

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...