FreeBASIC – mouse

Nei precedenti articoli abbiamo appreso come lavorare con le finestre grafiche e come disegnare una semplice figura geometrica.

Proviamo ora a fare un piccolo passo in avanti per cercare di interagire prima con la finestra grafica e poi con le figure geometriche che disegneremo su questa.

Il primo obiettivo sarà raggiunto con questo articolo, il secondo con il prossimo.

Per interagire con la finestra grafica dovremo trovare il modo di fornire degli input che ci serviranno per far accadere delle cose. Benvenuti nella programmazione a eventi!

La libreria grafica del compilatore FreeBASIC ci mette a disposizione una serie di funzioni per gestire gli input dell’utente. Tra queste ci sono quelle per lavorare con due strumenti esterni (external devices):

  • il mouse
  • la tastiera (keyboard)

In questo articolo ci concentreremo sul mouse.

Gestire il mouse

Il compilatore FreeBASIC ci permette sia di recuperare le informazioni dal mouse, sia di impostare, per esempio, la sua posizione.

Come recuperare le informazioni dal mouse

Per intercettare lo spostamento del mouse e la pressione di uno dei tre pulsanti che vi si trovano normalmente, dobbiamo utilizzare la funzione getmouse.

La funzione getmouse ritorna un valore di tipo long che può assumere due soli valori:

  • 0 (zero) se dal mouse arrivano correttamente le informazioni
  • 1 se invece non arriva nulla (per esempio perché il puntatore è uscito fuori dai bordi della finestra grafica)

Questa funzione però non si limita soltanto a questo, ma permette di recuperare la posizione del puntatore del mouse in coordinate espresse in pixels e lo stato dei suoi pulsanti. Per farlo occorre passarle delle variabili i cui valori saranno restituiti per riferimento.

Se per qualche motivo alcune o tutte queste informazioni non vengono recuperate, le variabili coinvolte assumeranno valore -1.

Come impostare la posizione del mouse

Può essere molto utile fare in modo che all’avvio del nostro programma il puntatore del mouse si trovi in un punto specifico all’interno della finestra grafica.

Per farlo si utilizza la funzione setmouse.

Programma di esempio

Vediamo un piccolo esempio per provare queste due funzioni:

'dimensiona una variabile per ricevere il valore
'restituito dalla funzione getmouse
dim as long verifica_mouse

'dimensiona quattro variabili per ricevere le
'informazioni provenienti dal mouse
dim as integer x, y, ruota, pulsante

'imposta la finestra grafica con risoluzione dello
'schermo 800x600 pixels e dimensioni testuali 100x37
screen 19

'posiziona il puntatore del mouse al centro della
'finestra grafica
setmouse 400, 300

'ciclo per gestire le informazioni dal mouse
do
  verifica_mouse = getmouse(x, y, ruota, pulsante)
  if verifica_mouse = 0 then
    locate 1, 1
    print "Riesco a ricevere le informazioni dal mouse."
    locate 3, 1
    print "x:"; x; " y:"; y
    locate 4, 1
    print "ruota:"; ruota; " pulsante:"; pulsante
    locate 6, 1
    print "Per uscire dal ciclo porta il puntatore"
    print "del mouse fuori dai bordi della finestra grafica."
  else
    cls
    locate 1, 1
    print "Il puntatore del mouse e' fuori dai"
    print "bordi della finestra grafica."
    locate 36, 1
    print "Premi il tasto INVIO per uscire dal programma."
    sleep
  end if
loop until verifica_mouse = 1

Istruzione locate

Come avrete notato per posizionare il testo nei punti voluti è stata utilizzata l’istruzione locate che definisce la posizione del cursore attraverso il numero di riga e di colonna del primo carattere della stringa che si vuole stampare con l’istruzione print.

Bene. Per oggi possiamo dirci soddisfatti.

Nel prossimo articolo vedremo come gestire le informazioni della tastiera. 🙂

FreeBASIC – Grafica [4]

Concludiamo l’esplorazione dell’istruzione screen analizzando il suo quarto attributo che nella documentazione ufficiale in inglese viene definito flags.

Questo attributo serve per impostare diverse proprietà dello schermo, ma per lo scopo didattico della nostra guida ci interesseremo soltanto di quelle relative ad alcune delle proprietà della finestra grafica, ovvero:

  1. la modalità a schermo intero (fullscreen mode);
  2. la presenza o meno dei bordi;
  3. se deve apparire sempre in primo piano o no.

I valori ammissibili per questo attributo sono predefiniti come valori costanti all’interno del file di intestazione fbgfx.bi che deve quindi necessariamente essere incluso nel file sorgente del nostro programma.

Se l’attributo flag viene omesso, verrà aperta una normale finestra (che corrisponde, come vedremo poco più sotto, alla costante GFX_WINDOWED).

Vediamo ora i nomi e il significato di queste costanti:

  • GFX_WINDOWED: apre una normale finestra grafica secondo le caratteristiche specificate dai primi tre attributi dell’istruzione screen (ovvero la modalità grafica, la profondità di colore e il numero di pagine video);
  • GFX_FULLSCREEN: se la modalità è supportata dal sistema operativo del proprio computer forza l’apertura di una finestra grafica a schermo intero, altrimenti verrà impostato di default il valore della costante GFX_WINDOWED;
  • GFX_NO_FRAME: crea una finestra grafica senza bordi;
  • GFX_ALWAYS_ON_TOP: crea una finestra grafica che rimane sempre in primo piano.

Ora non ci resta che provare con un semplice programma dove per testare le diverse proprietà della finestra grafica non dovremo far altro che trasformare in commento l’istruzione attiva, anteponendo il simbolo apice (‘), e poi trasformare in istruzione quella commentata che volete provare cancellando il simbolo apice:

'include il file contenente le costanti per gestire
'le proprietà dello schermo
#include "fbgfx.bi"

'specifica che le costanti rientrano nello spazio
'dei nomi di FreeBASIC (argomento che affronteremo
'più avanti)
#if __fb_lang__ = "fb"
  using fb
#endif

'Imposta una pagina video con la modalità grafica 19 per
'una risoluzione dello schermo di 800x600 pixels e
'la profondità di colore a 32bpp e poi imposta la
'relativa proprietà dello schermo
screen 19, 32, 1, GFX_WINDOWED
'screen 19, 32, 1, GFX_FULLSCREEN
'screen 19, 32, 1, GFX_NO_FRAME
'screen 19, 32, 1, GFX_ALWAYS_ON_TOP

print "Ciao mondo!"

sleep 'rimane in pausa

Bene. Con l’istruzione screen possiamo fermarci qui.

Al prossimo articolo. 🙂

FreeBASIC – Grafica [3]

Dopo aver parlato della risoluzione dello schermo (modalità grafica) e della risoluzione grafica (profondità di colore), in questo articolo continueremo l’esplorazione della istruzione screen giocando con il suo terzo attributo: quello che specifica il numero di pagine video con cui si vuole lavorare.

Pagine video

In FreeBASIC è possibile lavorare con più pagine video.

Quindi, oltre alla normale procedura che prevede di disegnare su una pagina mentre questa è già visibile a schermo, avendo a disposizione più pagine video, si può per esempio disegnare su una pagina mentre se ne sta rendendo visibile un’altra su cui si era disegnato in precedenza.

Qual è il vantaggio?

Lo “spettatore” si gode lo spettacolo sul palcoscenico (pagina visibile), mentre nel retropalco (pagina di lavoro) si prepara la scenografia successiva. 😉

Come definire il numero di pagine video

Per definire il numero delle pagine video che necessitano al nostro programma basta scriverlo come terzo attributo dell’istruzione screen:

'Imposta 3 pagine video con la modalità grafica 19 per
'una risoluzione dello schermo di 800x600 pixels e
'la profondità di colore a 32bpp.
screen 19, 32, 3

Se questo attributo viene omesso, il nostro programma avrà comunque una pagina video di default.

Come specificare la pagina di lavoro e quella visibile

Se il nostro programma ha una sola pagina video, le istruzioni per il disegno agiranno e saranno visibili su questa pagina, ma se possiamo disporre di più pagine video, allora dovremo gestire sia la pagina di lavoro che la pagina visibile.

Per farlo si usa la subroutine screenset che ha due attributi: il primo per definire la pagina di lavoro, il secondo quella visibile. Vediamo alcuni esempi:

screen 19, 32, 2 'per definire due pagine video
screenset 0, 0 'disegna e visualizza la I p.v.
screenset 0, 1 'disegna sulla I p.v. mentre visualizza la II
screenset 1, 0 'disegna sulla II p.v. mentre visualizza la I
screenset 1, 1 'disegna e visualizza la II p.v.

Come è facile notare da questa porzione di codice, l’identificativo delle schede video parte dal valore 0 (zero).

Nel programma dei 3 cerchi colorati riportato più sotto ne vedremo un possibile utilizzo.

Un po’ di grafica 2D

Iniziamo ad avvicinarci alla grafica 2D utilizzando una delle funzioni per il disegno 2D: la funzione circle.

Funzione circle

La funzione circle permette di disegnare cerchi ed ellissi.

Sintassi

Un uso semplificato è questo:

circle (coordinata x, coordinata y), raggio, [colore]

I valori relativi alle coordinate x e y del centro del cerchio e quello del raggio sono obbligatori, mentre l’attributo del colore è opzionale: se omesso sarà quello del primo piano corrente impostabile con la funzione color().

Nell’esempio che vedremo più sotto ci baseremo sul modello di colori RGB utilizzando la funzione rgb() passandole tre attributi che rappresentano rispettivamente la componente rossa, quella verde e quella blu. Il range dei valori ammessi per questi attributi va da 0 a 255.

Programma dei 3 cerchi colorati

'Imposta 3 pagine video con la modalità grafica 19 per
'una risoluzione dello schermo di 800x600 pixels e
'la profondità di colore a 32bpp.
screen 19, 32, 3

'Imposta come pagina di lavoro la prima (valore 0).
screenset 0
'Disegna 255 cerchi al centro dello schermo, di
'raggio e tono di colore rosso crescenti.
for i as integer = 1 to 255
  circle (400,300), i, RGB(i,0,0)
next i

'Imposta come pagina di lavoro la seconda (valore 1).
screenset 1
'Disegna 255 cerchi al centro dello schermo, di
'raggio e tono di colore verde crescenti.
for i as integer = 1 to 255
  circle (400,300), i, RGB(0,i,0)
next i

'Imposta come pagina di lavoro la terza (valore 2).
screenset 2
'Disegna 255 cerchi al centro dello schermo, di
'raggio e tono di colore blu crescenti.
for i as integer = 1 to 255
  circle (400,300), i, rgb(0,0,i)
next i

'Doppio ciclo per rendere alternativamente visibili,
'una volta al secondo, le tre pagine. Il ciclo si
'ripete per 3 volte.
for i as integer = 1 to 3
  for j as integer = 0 to 2
    screenset ,j
    sleep 1000 'pausa di un secondo
  next j
next i

Un po’ ipnotico. No? 🙂

Nel prossimo articolo vedremo come impostare alcune proprietà della finestra grafica.

FreeBASIC – Grafica [2]

Nel precedente articolo abbiamo parlato della risoluzione dello schermo: ovvero di come impostare le dimensioni digitali delle nostre finestre in termini di quanti pixels si possono disegnare in orizzontale (larghezza) e di quanti in verticale (altezza).

Il rapporto tra la larghezza e l’altezza di una finestra grafica rappresenta il cosiddetto rapporto d’aspetto.

In questo nuovo articolo parleremo invece della risoluzione grafica: ovvero della qualità delle immagini che si possono disegnare a video.

Profondità di colore

In FreeBASIC per definire la qualità delle immagini occorre impostare nella istruzione screen il parametro della profondità di colore (color depth): ovvero il numero di bits utilizzati per descrivere il colore di un singolo pixel. L’unità di misura di questo parametro è quindi espressa in bpp (bits per pixel).

Questo parametro ha effetto soltanto per le modalità grafiche dalla 14 alla 21 e può assumere i valori: 8, 16 o 32 bpp.

Più bits vengono utilizzati per un singolo pixel, più la qualità dell’immagine sarà migliore.

Scheda video

Arrivati a questo punto occorre fare una precisazione:

Le caratteristiche tecniche della scheda video del nostro computer limitano le possibilità di scelta della modalità grafica in relazione alla profondità di colore da noi scelta.

Come facciamo quindi a sapere quale modalità grafica (parametro mode) possiamo scegliere con uno specifico valore di profondità di colore (parametro depth)?

L’istruzione screenlist

La risposta alla domanda che ci siamo posti più sopra ce la fornisce l’istruzione screenlist.

Vediamo nel dettaglio i passi da seguire per utilizzare al meglio questa istruzione:

  1. Nella prima chiamata alla funzione screenlist è necessario specificare il valore della profondità di colore desiderata. La funzione restituirà la più bassa risoluzione dello schermo possibile in relazione alla profondità di colore specificata.
  2. Le successive chiamate alla funzione non necessiteranno più di alcun argomento: ciascuna chiamata restituirà le possibili risoluzioni dello schermo in maniera crescente.
  3. La restituzione del valore 0 (zero) starà a significare che non ci sono risoluzioni dello schermo più grandi dell’ultima restituita.

Scriviamo ora un semplice programma per scoprire quali risoluzioni dello schermo sono possibili con la scheda video del nostro computer in base alle tre diverse profondità di colore gestite dal FreeBASIC.

Per realizzare il nostro programma utilizzeremo due strutture di controllo:

  1. un ciclo for-next per selezionare di volta in volta le diverse profondità di colore;
  2. un ciclo do-loop per eseguire le diverse chiamate alla funzione screenlist.
'dimensiona e poi crea un array con i tre valori della
'profondità di colore disponibili in FreeBASIC
dim prof_col (1 to 3) as long
prof_col(1) = 8
prof_col(2) = 16
prof_col(3) = 32

'dimensiona una variabile per ricevere il
'risultato della chiamata alla funzione screenlist
dim risultato as long

'dimensiona una variabile stringa per la
'risoluzione dello schermo
dim risoluzione as string

'doppio ciclo per ottenere tutte le risoluzioni dello schermo
'gestite dalla scheda video del computer in base alle
'diverse profondità di colore
for i as integer = lbound(prof_col) to ubound(prof_col)
  print "Lista risoluzioni dello schermo disponibili"
  print "con la profondita' di colore "; prof_col(i)
  risultato = screenlist(prof_col(i)) 'prima chiamata
    do while risultato <> 0
      print risultato
      risultato = screenlist()
    loop
  print "---"
next i

Ecco il risultato a video:

Che dire? Ciò che abbiamo ottenuto è veramente poco soddisfacente: una serie di numeri che sembrano non dirci nulla. Perché?

La risposta ci permetterà di conoscere una tecnica che potrà tornarci utile in molte occasioni.

Lavorare con le codifiche binarie

Il risultato della funzione screenlist è codificato in un valore a 32 bit: dove i 16 bits più alti (ovvero quelli a sinistra) rappresentano la larghezza della finestra, mentre i 16 bits più bassi (ovvero quelli a destra) rappresentano l’altezza della finestra.

Il compilatore FreeBASIC ci mette a disposizione due utili funzioni per estrarre queste informazioni: l’istruzione hiword e l’istruzione loword.

Modifichiamo quindi il ciclo do-loop del nostro programma in questo modo:

do while risultato <> 0
      risoluzione = hiword(risultato) & "x" & loword(risultato)
      print risoluzione
      risultato = screenlist()
loop

Vediamo ora il nuovo risultato a video:

Molto meglio. No? 🙂

Ora non ci resta che fare un confronto con le modalità grafiche disponibili in FreeBASIC per verificare quali sono disponibili.

Modifichiamo quindi il ciclo do-loop inserendo una istruzione select case:

do while risultato <> 0
  risoluzione = hiword(risultato) & "x" & loword(risultato)
  select case risoluzione
    case "320x240"
      print hiword(risultato); "x"; loword(risultato); " -> "; "14"
    case "400x300"
      print hiword(risultato); "x"; loword(risultato); " -> "; "15"
    case "512x384"
      print hiword(risultato); "x"; loword(risultato); " -> "; "16"
    case "640x400"
      print hiword(risultato); "x"; loword(risultato); " -> "; "17"
    case "640x480"
      print hiword(risultato); "x"; loword(risultato); " -> "; "18"
    case "800x600"
      print hiword(risultato); "x"; loword(risultato); " -> "; "19"
    case "1024x768"
      print hiword(risultato); "x"; loword(risultato); " -> "; "20"
    case "1280x1024"
      print hiword(risultato); "x"; loword(risultato); " -> "; "21"
    case else
      print hiword(risultato); "x"; loword(risultato)
  end select
  risultato = screenlist()
loop

Ecco il risultato:

Ora possiamo dirci soddisfatti! 🙂

Abbiamo finalmente la lista delle risoluzioni dello schermo gestibili dalla scheda video del nostro computer con evidenziate quelle che hanno una corrispondenza con le modalità grafiche gestite dal compilatore FreeBASIC.

Nel prossimo articolo continueremo ad approfondire l’istruzione screen testando un altro dei suoi attributi: quello che gestisce le pagine video.

FreeBASIC – Grafica [1]

E così siamo finalmente arrivati a parlare di grafica.

Disegnare delle semplici figure 2D sullo schermo e interagire con queste sarà l’obiettivo principale di questa nuova serie di articoli.

Come è ormai nostra abitudine, partiamo subito con qualcosa di concreto.

Come creare una finestra grafica

La prima cosa che ci serve è creare una finestra grafica su cui poi andremo a disegnare.

Per farlo si utilizza l’istruzione screen.

screen 16
print "Ecco la mia prima finestra grafica in"
print "modalita' 16: ovvero con risoluzione 512x384 pixels."
sleep 'istruzione per sospendere l'esecuzione del programma

Dare un titolo alla finestra grafica

Per abbellire la nostra finestra grafica diamole un titolo sfruttando la subroutine windowtitle:

windowtitle("La mia prima finestra")
screen 19
sleep

Modalità grafica

Il numero subito dopo l’istruzione screen definisce la modalità grafica (mode) sulla base delle seguenti due tabelle:

Le modalità dalla 1 alla 13 sono compatibili anche con i vecchi programmi scritti con il glorioso QuickBASIC, mentre le nuove modalità dalla 14 alla 21 sono specifiche del FreeBASIC. Sarà proprio su queste ultime che ci concentreremo.

Le due tabelle ci mostrano con chiarezza che più la modalità scelta sarà alta, più grandi saranno le dimensioni digitali della nostra finestra: ovvero la risoluzione dello schermo (resolution).

La dimensione digitale di uno schermo (nel nostro caso della finestra) è espressa come numero di pixels orizzontali e verticali (p.e. 512×384).

Scriviamo ora un semplice programma per visualizzare una finestra in tutte e sedici le diverse modalità. Per farlo sfrutteremo un array e un ciclo for.

'dimensiona un array con tutte le modalità grafiche
 dim mode_array (1 to 16) as integer

 'assegna i valori
 mode_array(1) = 1
 mode_array(2) = 2
 mode_array(3) = 7
 mode_array(4) = 8
 mode_array(5) = 9
 mode_array(6) = 11
 mode_array(7) = 12
 mode_array(8) = 13
 mode_array(9) = 14
 mode_array(10) = 15
 mode_array(11) = 16
 mode_array(12) = 17
 mode_array(13) = 18
 mode_array(14) = 19
 mode_array(15) = 20
 mode_array(16) = 21

 'visualizza con un ciclo le varie finestre
 for i as integer = lbound(mode_array) to ubound(mode_array)
   screen mode_array(i)
   print "Finestra grafica in modalita': "; mode_array(i)
   print "---"
   print "premi un taso per continuare…"
   sleep 'sospende l'esecuzione del programma
 next i

Funzione screenres

Le modalità grafiche che abbiamo visto hanno delle dimensioni digitali preimpostate, ma se volessimo creare una finestra grafica di dimensioni diverse?

Niente panico! FreeBASIC viene in nostro aiuto con la funzione screenres che ci permette proprio di definire le dimensioni digitali che vogliamo.

Questa funzione restituisce il valore 0 (zero) se le dimensioni digitali specificate sono realizzabili dal nostro computer, altrimenti viene restituito un numero che specifica il tipo di errore.

Per la gestione degli errori si rimanda ad un futuro articolo.

Dopo aver provato il codice più sotto, provate a specificare per esempio un numero negativo come larghezza o come altezza:

''crea una finestra grafica larga 800px e alta 50px 
select case screenres(800,50)
  case 0 ''tutto OK
    print "Ecco una strana finestra grafica!"
  case else ''errore
    beep
    print "Non posso creare la finestra grafica che desideri."
end select
sleep ''rimani in pausa

Bene. Per oggi ci fermiamo qui.

Nel prossimo articolo parleremo della risoluzione grafica: ovvero della qualità delle immagini. 🙂