Jump to content

SUBIECTE NOI
« 1 / 5 »
RSS
Merita un Termostat Smart pentru ...

Sfat achizitie MTB Devron Riddle

Problema mare cu parintii= nervi ...

switch microtik
 Permis categoria B la 17 ani

Sfaturi pentru pregatirea de eval...

Crapaturi placa

cum imi accesez dosarul electroni...
 Momentul Aprilie 1964

Sursa noua - zgomot ?

A fost lansat Ubuntu 24.04 LTS

Pareri apartament in zona Berceni?
 Free streaming SkyShowtime de la ...

Skoda Fabia 1.0 TSI (110 CP)- 19 ...

Mezina familiei, Merida BigNine

The Tattooist of Auschwitz (2024)
 

Crearea meniurilor unei aplicatii [C, Text Based]

- - - - -
  • Please log in to reply
No replies to this topic

#1
dani.user

dani.user

    Guru Member

  • Grup: Senior Members
  • Posts: 30,238
  • Înscris: 24.02.2007
Foarte multe probleme scolaresti, si nu numai, cer la un moment dat crearea unui meniu care prezinta utilizatorului mai multe optiuni, utilizatorul urmand sa aleaga una din ele.

Astfel, un cod tipic ajunge sa arate cam asa:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int value = 0;
	int choice = 0;

	while (choice != 3)
	{
		printf("1. Aduna o unitate\r\n");
		printf("2. Scade o unitate\r\n");
		printf("3. Iesire\r\n");
		scanf("%d", &choice);

		switch (choice)
		{
		case 1:
			value += 1;
			printf("Dupa adunare, value = %d\r\n", value);
			break;
		case 2:
			value -= 1;
			printf("Dupa scadere, value = %d\r\n", value);
			break;
		}
	}

	return 0;
}


Chiar daca inca nu arata asa rau, daca sunt multe optiuni, treaba se complica:
  • Dezvoltatorul trebuie sa fie atent ce indice introduce pentru fiecare optiune pentru a nu le incurca
  • Cand apare o noua optiune, trebuie deobicei decalate altele
  • A scrie mult cod intr-un switch nu e recomandat
  • Multi uita, la un moment dat, sa introduca break peste tot

Asadar, cum se poate imbunatatii? Folosind functii si pointeri :D

Definim un tip de pointer la functii
typedef void(*optionCallback)(void* data);
Fiecare optiune va avea asociata o functie. Acea functie va fi apelata cand utilizatorul alege optiunea in cauza. Pentru a nu folosi variabile globale, functia va primi drept parametru un pointer la orice.

Definim o structura de date pentru a pastra toate optiunile
typedef struct
{
	const char* displayText;
	optionCallback callback;
	int triggersExit;
} option;


Definim un vector de optiuni
Fiecare optiune va avea un nume, o functie ce va fi apelata, si un parametru care indica daca loop-ul va fi intrerupt sau nu.
option options[] =
{
	{ "Aduna o unitate", addUnit, 0 },
	{ "Scade o unitate", subtractUnit, 0 },
	{ "Iesire", NULL, 1 }
};


Apelam o functie ce se ocupa de afisarea efectiva a meniului

displayMenu(options, sizeof(options) / sizeof(options[0]), &value);

Pare complicat?
Este usor mai complicat, dar:

  • Definesc intr-un loc toate optiunile
  • Nu mai trebuie sa fiu atent la ordinea lor
  • Am separat codul ce trateaza fiecare optiune
  • Pot crea oricand o functie de afisare mai buna

Codul complet:
#include <stdio.h>
#include <stdlib.h>

typedef void(*optionCallback)(void* data);

typedef struct
{
	const char* displayText;
	optionCallback callback;
	int triggersExit;
} option;

void displayMenu(const option options[], size_t nrOptions, void* data)
{
	size_t i = 0;
	size_t choice = 0;
	int exit = 0;

	while ( ! exit)
	{
		for (i = 0; i < nrOptions; i++)
		{
			printf("%d. %s\r\n", i + 1, options[i].displayText);
		}
		scanf("%u", &choice);
		choice -= 1;
		if (choice >= nrOptions)
		{
			printf("Alegere gresita\r\n");
		}
		else
		{
			if (options[choice].callback)
			{
				options[choice].callback(data);
			}
			exit = options[choice].triggersExit;
		}
	}
}

void addUnit(void* data)
{
	int* value = (int*)data;
	*value += 1;
	printf("Dupa adunare, value = %d\r\n", *value);
}

void subtractUnit(void* data)
{
	int* value = (int*)data;
	*value -= 1;
	printf("Dupa scadere, value = %d\r\n", *value);
}

int main(void)
{
	int value = 0;

	option options[] =
	{
		{ "Aduna o unitate", addUnit, 0 },
		{ "Scade o unitate", subtractUnit, 0 },
		{ "Iesire", NULL, 1 }
	};

	displayMenu(options, sizeof(options) / sizeof(options[0]), &value);

	return 0;
}


Avand un sistem mai flexibil, putem crea o functie ce prezinta un meniu mai usor de folosit, din sageti.
#include <Windows.h>

void displayNiceMenu(const option options[], size_t nrOptions, void* data)
{
	HANDLE console, consoleInput;
	CONSOLE_SCREEN_BUFFER_INFO screenBuffer;
	INPUT_RECORD record;
	COORD screenCoords;
	int columns, rows;
	DWORD charsWritten, eventsRead;
	char buffer[1024] = {0};
	size_t i = 0, j = 0;
	size_t choice = 0;
	int exit = 0, keyPressed = 0;
	const WORD normalColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_BLUE;
	const WORD selectedColor = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | FOREGROUND_BLUE;


	console = GetStdHandle(STD_OUTPUT_HANDLE);
	consoleInput = GetStdHandle(STD_INPUT_HANDLE);
	screenCoords.X = 0;
	screenCoords.Y = 0;

	GetConsoleScreenBufferInfo(console, &screenBuffer);
	columns = screenBuffer.srwindow.Right - screenBuffer.srwindow.Left + 1;
	rows = screenBuffer.srwindow.Bottom - screenBuffer.srwindow.Top + 1;

	SetConsoleTextAttribute(console, normalColor);

	while (!exit)
	{
		//clear screen
		FillConsoleOutputCharacterA(console, ' ', rows*columns, screenCoords, &charsWritten);

		//set cursor to beginning of screen
		SetConsoleCursorPosition(console, screenCoords);

		ZeroMemory(buffer, sizeof(buffer));
		for (i = 0; i < columns; i++)
		{
			buffer[i] = 205;
		}
		buffer[0] = 201;
		buffer[columns - 1] = 187;
		WriteConsoleA(console, buffer, strlen(buffer), &charsWritten, NULL);

		for (i = 0; i < nrOptions; i++)
		{
			ZeroMemory(buffer, sizeof(buffer));
			buffer[0] = 186;
			buffer[1] = ' ';
			WriteConsoleA(console, buffer, strlen(buffer), &charsWritten, NULL);

			if (choice == i)
			{
				SetConsoleTextAttribute(console, selectedColor);
			}

			ZeroMemory(buffer, sizeof(buffer));
			strcpy(buffer, options[i].displayText);
			for (j = strlen(buffer); j < (columns - 3); j++)
			{
				buffer[j] = ' ';
			}
			WriteConsoleA(console, buffer, strlen(buffer), &charsWritten, NULL);

			if (choice == i)
			{
				SetConsoleTextAttribute(console, normalColor);
			}

			ZeroMemory(buffer, sizeof(buffer));
			buffer[0] = 186;
			WriteConsoleA(console, buffer, strlen(buffer), &charsWritten, NULL);
		}

		ZeroMemory(buffer, sizeof(buffer));
		for (i = 0; i < columns; i++)
		{
			buffer[i] = 205;
		}
		buffer[0] = 200;
		buffer[columns - 1] = 188;
		WriteConsoleA(console, buffer, strlen(buffer), &charsWritten, NULL);

		while ( ! keyPressed)
		{
			ZeroMemory(&record, sizeof(record));
			ReadConsoleInput(consoleInput, &record, 1, &eventsRead);

			if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
			{
				if (record.Event.KeyEvent.wVirtualKeyCode == 13)
				{
					if (options[choice].callback)
					{
						options[choice].callback(data);
					}
					exit = options[choice].triggersExit;
					break;
				}
				if (record.Event.KeyEvent.wVirtualKeyCode == 40)
				{
					choice = (choice + 1) % nrOptions;
					break;
				}
				else if (record.Event.KeyEvent.wVirtualKeyCode == 38)
				{
					if (choice == 0)
					{
						choice = nrOptions - 1;
					}
					else
					{
						choice = (choice - 1) % nrOptions;
					}
					break;
				}
			}
		}
	}
}


Attached File  Untitled.png   4.42K   109 downloads

Edited by dani.user, 25 January 2015 - 23:12.


Anunturi

Neurochirurgie minim invazivă Neurochirurgie minim invazivă

"Primum non nocere" este ideea ce a deschis drumul medicinei spre minim invaziv.

Avansul tehnologic extraordinar din ultimele decenii a permis dezvoltarea tuturor domeniilor medicinei. Microscopul operator, neuronavigația, tehnicile anestezice avansate permit intervenții chirurgicale tot mai precise, tot mai sigure. Neurochirurgia minim invazivă, sau prin "gaura cheii", oferă pacienților posibilitatea de a se opera cu riscuri minime, fie ele neurologice, infecțioase, medicale sau estetice.

www.neurohope.ro

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

Forumul Softpedia foloseste "cookies" pentru a imbunatati experienta utilizatorilor Accept
Pentru detalii si optiuni legate de cookies si datele personale, consultati Politica de utilizare cookies si Politica de confidentialitate