@Alexv Non intendo forzare nessuno a cambiare, davo solo un contributo alla conoscenza e il perché si usa uno o un altro linguaggio, poi dal mio punto di vista che non deve essere per forza condiviso.
@Rosmarino Non conosco le wxWidgets e non ti posso aiutare, ho sperimentato QT5 che permette la creazione di interfacce multipiattaforma a dir poco fantastiche, usato anche dalle case automobilistiche per la creazione dei nuovi cruscotti interattivi (un pachiderma) e FLTK farraginoso un po' datato ma ancora supportato.
Resto in ascolto anche io, sono interessato ad una soluzione per gestire un'interfaccia grafica con Il C/C++, con la mia scarsa esperienza per ora ho trovato soluzioni che poi sono risultate obsolete e/o deprecate che risolvevano dei problemi ma poi non funzionavono con win10 o delle librerie aggiuntive indispensabili erano sparite, oppure ide sterminati dove l'installazione configurazione e uso comporta un'impegno equivalente ad imparare a programmare da zero.
Un link dove trovare come installare ed usare una libreria valida ancora oggi per gestire un'interfaccia senza grandi pretese in C/C++ è gradito.
Il C++ supporta la sintassi del C, non avrai nessun problema ad usarlo, i nuovi tipi di dato e la gestione della console permette di usare il C++ come un C corredato di qualche comoda istruzione in più. Ma è un uso riduttivo del C++, che invece contempla le classi e la programmazione ad oggetti.
Programmo in C da pochi mesi per curiosità, di proposito evito il C++ (conosco C# e VB.Net non sento il bisogno del C++), a scopo didattico dalla console sono riuscito a speremere qualcosina in più, per la posizione del mouse ho scritto un programma: il gioco del 15:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <ctype.h>
/*************************************
* GIOCO DEL 15 *
* Si gioca in console con il mouse *
* il puzzle è sempre risolvibile *
*************************************/
// **** costanti
const char RigSopra[]={(CHAR)201,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)203,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)203,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)203,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)187,'\0'};
const char RigheCentro[]={(CHAR)204,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)206,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)206,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)206,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)185,'\0'};
const char RigSotto[]={(CHAR)200,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)202,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)202,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)202,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)205,(CHAR)188,'\0'};
// in aControllo, gli indici in base zero del vettore iSequenza che devono essere esplorati, in base alla casella cliccata
const unsigned int aControllo[16][4]={{1, 4, 0, 0}, {0, 2, 5, 1}, {1, 3, 6, 2}, {2, 7, 3, 3}, {0, 5, 8, 4}, {4, 1, 6, 9}, {5, 2, 7, 10}, {11, 3, 6, 7}, {4, 9, 12, 8}, {8, 5, 10, 13}, {14, 9, 6, 11}, {15, 10, 7, 11}, {8, 13, 12, 12}, {12, 9, 14, 13}, {13, 10, 15, 14}, {14, 11, 15, 15}};
const char Titolo[]="Gioco del15 CB2021";
// **** pubbliche
struct {
unsigned int riga; // base 1
unsigned int colonna; // base1
unsigned int casella; // base 0
unsigned int mosse;
unsigned int MouseButton; // 1 = tasto sinistro, 2 = tasto destro
unsigned char iSequenza[16]; // contiene sempre lo stato del gioco
}GiocoDel15;
// **** prototipi
int Schermo(HANDLE Cons); // disegna lo schema con i numeri
int SeqValida(); // 0 = la sequenza non è risolvibile, 1 = la sequenza è risolvibile
void MenuScelta();
void GenSequenza(); // genera la sequenza ordinata
void mescola(HANDLE Cons);
void TrovaCasella(int x, int y, HANDLE Cons); // aggiorna la struct GiocoDel15 in base alla casella cliccata
int main()
{
SetConsoleTitle(Titolo);
POINT pCoor;
HWND hwnd=0;
//attende la creazione della finestra per prelevare hwnd
while (hwnd==0)
hwnd=FindWindow(NULL, Titolo); // handle della finestra
//------------------------------------------------------
HANDLE console=GetStdHandle(STD_OUTPUT_HANDLE); // handle del processo
MenuScelta();
GenSequenza(); // sequenza ordinata
Schermo(console); // prima visualizzazione schema
while(1){ // loop infinito mouse
Sleep(50); // lascia la CPU libera, limita i cicli in 1000/50=20 al secondo
if((GetKeyState(GiocoDel15.MouseButton) & 0x8000) != 0){ // bottone mouse
GetCursorPos(&pCoor); // coordinate assolute cursore
ScreenToClient(hwnd, &pCoor); // coordinate relative cursore
TrovaCasella(pCoor.x, pCoor.y, console); // TrovaCasella modifica la struct GiocoDel15
if (GiocoDel15.riga!=0 && GiocoDel15.colonna!=0){ // click dentro lo schema
for (int i=0; i<4; i++){ // controllo in 4 direzioni predefinite in aControllo
if (GiocoDel15.iSequenza[aControllo[GiocoDel15.casella][i]]==0){ // è la casella vuota, swap
GiocoDel15.iSequenza[aControllo[GiocoDel15.casella][i]]=GiocoDel15.iSequenza[GiocoDel15.casella]; // scrivo il valore della casella cliccata nella casella vuota
GiocoDel15.iSequenza[GiocoDel15.casella]=0; // nella casella cliccata metto zero, lo swap è completo
GiocoDel15.mosse++; // incremento le mosse
/* per test
printf("\n\nCasella = %d", GiocoDel15.casella+1);
printf(" Vuota = %d", aControllo[GiocoDel15.casella][i]+1);*/
break;
}
}
int risolto=Schermo(console); // aggiorno lo schermo, la funzione restituisce se c'è soluzione
printf("\n\n ");
if (risolto==1){
SetConsoleTextAttribute(console, 0x0E); // 0xE giallo 0x0 nero
printf(" Risolto,");
SetConsoleTextAttribute(console, 0x0A); // 0xA verde 0x0 nero
}
printf(" mosse = %d",GiocoDel15.mosse); // visualizzo le mosse
}
Sleep(200); // Ritardo evita doppio click, al massimo vengono rilevati 5 click al secondo
}
}
}
int Schermo(HANDLE Cons){
system("cls");
int i=0;
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
if (GiocoDel15.MouseButton==1)
printf("\n GIOCO DEL15 W7 LBUTTON\n");
else
printf("\n GIOCO DEL15 W10 RBUTTON\n");
printf("\n ");
// disegno schema con sequenza ***************
SetConsoleTextAttribute(Cons, 0xCF); // 0xF bianco 0xC rosso
printf(" ");
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
printf("\n ");
SetConsoleTextAttribute(Cons, 0xCF); // 0xF bianco 0xC rosso
printf(" %s ",RigSopra);
for (i=0; i<16; i+=4){
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
printf("\n ");
SetConsoleTextAttribute(Cons, 0xCF); // 0xF bianco 0xC rosso
// il numero zero viene sostituito con gli spazi (casella vuota)
for (int ind=0; ind<4; ind++){
printf(" %c ", (CHAR)186);
if (GiocoDel15.iSequenza[ind+i]==0) printf(" "); else printf("%02d", GiocoDel15.iSequenza[ind+i]);
}
printf(" %c ", (CHAR)186);
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
printf("\n ");
SetConsoleTextAttribute(Cons, 0xCF); // 0xF bianco 0xC rosso
if (i==12) printf(" %s ", RigSotto); else printf(" %s ", RigheCentro);
}
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
printf("\n ");
SetConsoleTextAttribute(Cons, 0xCF); // 0xF bianco 0xC rosso
printf(" ");
SetConsoleTextAttribute(Cons, 0x0B); // 0xB ciano 0x0 nero
printf("\n ");
printf("\n [MESCOLA] [ESCI]");
SetConsoleTextAttribute(Cons, 0x0A); // 0xA verde 0x0 nero
//****************************************
/* per test*/
printf("\n\n Sequenza = [");
for (i=0; i<16; i++){
printf("%02d", GiocoDel15.iSequenza[i]); // mostra lo stato della sequenza
}
printf("]");
if (GiocoDel15.iSequenza[15]==0 ){
printf(" SeqValida = %d", SeqValida()); // verifica se la sequenza è risolvibile: 1=si, 0=no
}
for (i=0; i<15; i++){
if (GiocoDel15.iSequenza[i] != i+1) return 0; // non risolto
}
return 1; // risolto
}
int SeqValida(){ // usata in fase di test
unsigned int coppie = 0;
for (int i=0; i<15;i++){
for (int y=i+1; y<15;y++){
if (GiocoDel15.iSequenza[i] < GiocoDel15.iSequenza[y]) coppie++;
}
}
return coppie%2;
}
void MenuScelta(){
GiocoDel15.MouseButton=0;
while(GiocoDel15.MouseButton==0){
system("cls");
printf("\n ***** GIOCO DEL15 *****\n");
printf("\n si gioca con il mouse, le coordinate cambiano in base al S.O.\n");
printf("\n 1) Win 7 tasto sinistro mouse");
printf("\n 2) Win10 tasto destro mouse\n");
printf("\n 0) Esci\n");
printf("\n Tua scelta : ");
char scelta=getchar();
switch (scelta){
case '1': // Win7
GiocoDel15.MouseButton = 1; // VX_LBUTTON
break;
case '2': // Win10
GiocoDel15.MouseButton = 2; // VX_RBUTTON
break;
case '0': // esci
printf("\n");
exit(0);
}
}
}
void GenSequenza(){
// riempimento vettore ordinato
for (int i=0; i<15; i++)GiocoDel15.iSequenza[i]=i+1;
GiocoDel15.iSequenza[15]=0;
}
void mescola(HANDLE Cons){
GenSequenza(); // si parte con la sequenza ordinata con zero finale
// mescolamento vettore
srand((unsigned) time(NULL)); // init random
for (int i=0; i<30; i++){ // se la sequenza ordinata viene mescolata un numero pari di volte(es 30), è sempre valida
int ind = rand() % 14 + 1 ; // (1/14), non sposto mai lo zero finale
unsigned char tmp = GiocoDel15.iSequenza[ind]; // inizio swap
GiocoDel15.iSequenza[ind] = GiocoDel15.iSequenza[0];
GiocoDel15.iSequenza[0] = tmp; // fine swap
}
GiocoDel15.mosse = 0;
Schermo(Cons); // visualizzazione
}
void TrovaCasella(int x, int y, HANDLE Cons){ // controllo coordinate mouse
GiocoDel15.riga = 0; // base 1
GiocoDel15.colonna = 0; // base 1
GiocoDel15.casella = 0; // base zero
if (GiocoDel15.MouseButton==1){ // Win7
if (x>39 && x<73) GiocoDel15.colonna = 1; // casella 0
if (x>79 && x<113) {GiocoDel15.colonna = 2; GiocoDel15.casella = 1;}
if (x>119 && x<153) {GiocoDel15.colonna = 3; GiocoDel15.casella = 2;}
if (x>158 && x<193) {GiocoDel15.colonna = 4; GiocoDel15.casella = 3;}
if (y>55 && y<76) GiocoDel15.riga = 1;
if (y>79 && y<100) {GiocoDel15.riga = 2; GiocoDel15.casella +=4;}
if (y>103 && y<123) {GiocoDel15.riga = 3; GiocoDel15.casella +=8;}
if (y>129 && y<148) {GiocoDel15.riga = 4; GiocoDel15.casella +=12;}
if (x>37 && x<100 && y>180 && y<190) mescola(Cons);
if (x>149 && x<188 && y>180 && y<190) {printf("\n"); exit(0);}
}
else{ // Win10
if (x > 39 && x < 74) GiocoDel15.colonna = 1; // casella 0
if (x > 78 && x < 112) { GiocoDel15.colonna = 2; GiocoDel15.casella = 1; }
if (x > 119 && x < 154) { GiocoDel15.colonna = 3; GiocoDel15.casella = 2; }
if (x > 158 && x < 192) { GiocoDel15.colonna = 4; GiocoDel15.casella = 3; }
if (y > 76 && y < 103) GiocoDel15.riga = 1;
if (y > 107 && y < 135) { GiocoDel15.riga = 2; GiocoDel15.casella += 4; }
if (y > 140 && y < 167) { GiocoDel15.riga = 3; GiocoDel15.casella += 8; }
if (y > 173 && y < 197) { GiocoDel15.riga = 4; GiocoDel15.casella += 12; }
if (x > 37 && x < 100 && y>240 && y < 251) mescola(Cons);
if (x > 149 && x < 188 && y>240 && y < 251) { printf("\n"); exit(0); }
}
// printf( "\nPosizione x = %d y = %d rig = %d col = %d cas = %d",x ,y, GiocoDel15.riga, GiocoDel15.colonna, GiocoDel15.casella);
}
Per la posizione del cursore e i colori, ho scritto un programma che replica alcune istruzioni presenti in alcune versioni della libreria conio.h:
#include <stdio.h>
#include <windows.h>
/****************************************************************************
codice che replica le istruzioni:
gotxy(); textcolor(); textbackground(); clrscr();
presenti nella libreria <conio.h> del compilatore Borland C/C++ e simili
Didattico direttamente usabile, o adatto a compatibilizzare i codici che usano
tali istruzioni ma non presenti nella conio.h fornita con i compilatori:
CGwin, MinGW, MSVC e altri, è sufficiente eseguire le seguenti modifiche:
1) aggiungere le variabili globali: fore, back e handle
2) aggiungere nel main(): handle=GetStdHandle(STD_OUTPUT_HANDLE);
3) modificare tutti i cprintf() in printf()
4) aggiungere le quattro void:
gotxy(int x, int y)
textcolor(int f)
textbackground(int b)
clrscr()
*****************************************************************************/
int fore = 7; // variabile globale colore primo piano
int back = 0; // variabile globale colore secondo piano
HANDLE handle; // variabile globale che contiene l'HANDLE della console
void gotoxy(int x, int y){ // equivalente in Borland C/C++
COORD cursore; // angolo superiore sinistro = 0,0
cursore.X=x-1; // i codici Borland usano la base 1
cursore.Y=y-1; // i codici Borland usano la base 1
SetConsoleCursorPosition(handle, cursore);
}
COORD getxy(){ // può far comodo
CONSOLE_SCREEN_BUFFER_INFO buff; // buffer info schermo
GetConsoleScreenBufferInfo(handle, &buff); // lettura info console
/* info disponibili:
dwCursorPosition COORD
dwMaximumWindowSize COORD
dwSize COORD
srWindow SMALL_RECT
wAttributes WORD
*/
return buff.dwCursorPosition; // angolo superiore sinistro = 0,0
}
void textcolor(int f){ // equivalente in Borland C/C++
// se f non è compreso tra 0 e 15, i colori ciclano
fore=f; // right 4 bit
SetConsoleTextAttribute(handle, fore+back*16);
}
void textbackground(int b){ // equivalente in Borland C/C++
// se b non è compreso tra 0 e 15, i colori ciclano
back=b; // left 4 bit
SetConsoleTextAttribute(handle, fore+back*16);
}
void clrscr(){
system("cls");
}
// Test routine
int main(){
handle=GetStdHandle(STD_OUTPUT_HANDLE); // lettura dell'HANDLE
for (int i=0; i<16; i++) printf("foba "); // intestazione fo=foreground, ba=background
for (int ba=0; ba<16; ba++){ // 16 colori di background
for (int fo=0; fo<16; fo++){ // 16 colori di foreground
gotoxy(ba*5+1,fo+2); // ogni colore al suo posto
textcolor(fo); textbackground(ba);
printf("%02d%02d", fo, ba);
}
}
textcolor(7); textbackground(0); // colori default
printf("\n");
COORD cursore=getxy(); // lettura coordinate cursore in base 0
printf("_<- qui il cursore e' in colonna %d riga %d ", cursore.X, cursore.Y);
cursore=getxy(); // lettura coordinate cursore in base 0
printf("_<- qui colonna %d riga %d \n\n", cursore.X, cursore.Y);
system("pause");
return 0;
}
entrambi sono per progetti:
console application, scritti in C con Code::Blocks e compilatore GCC. (funzionano anche con progetto console application C++).
I codici sopra esposti sono frutto del mio primo approcio al C.
EDIT: concordo con Weierstrass