FreeBASIC – Modello MVC

In questo articolo scopriremo uno dei modi per organizzare il codice in maniera efficace ed efficiente.

Per fare questo sfrutteremo il Modello Architetturale MVC (Model-View-Controller).

Modello Architetturale MVC

In pratica ciò che occorre fare per seguire questo schema di progettazione è raccogliere logicamente i moduli del nostro codice nelle 3 componenti del modello MVC che differiscono per scopo e logica di funzionamento. Vediamole in sintesi:

  • Il componente Modello – che rappresenta il cuore del nostro programma – è quella parte del codice che contiene tutte quelle procedure (subroutines e funzioni) per la gestione delle informazioni secondo le regole e la logica decise dal programmatore. In pratica è questo componente che determina il vero e proprio comportamento del programma.
  • Il componente Vista contiene tutta quella parte del codice concepita per la gestione della grafica e del testo. Questo modulo si occupa sia della visualizzazione dei risultati delle elaborazioni avvenute nel componente Modello (output), sia della visualizzazione di quegli elementi grafici e testuali che permettono all’utilizzatore di interagire con il programma (input).
  • Il componente Controllore si occupa invece della fasi di interlavoro con le altre due componenti: una parte del suo codice permette a questo componente di mettersi in ascolto degli input dell’utilizzatore provenienti dal componente Vista, per poi attivare le relative procedure del componente Modulo, da cui raccoglierà i risultati elaborati per attivare le relative procedure del componente Vista che si occuperà infine di trasformare i dati elaborati in oggetti grafici o testuali.

Forse uno schema può aiutarci a capire ancora meglio ciò che abbiamo provato a descrivere più sopra.

Schema del Modello Architetturale MVC

Di Wdror-wsu-ap and Regis Frey – Opera propria, Pubblico dominio, Collegamento

Per non lasciare tutto questo soltanto ad un livello teorico, scriveremo un programma per disegnare dei quadrati rossi, selezionarli o deselezionarli, e spostarli a video.

Programma di esempio

Volendo seguire lo schema di progettazione MVC, scriveremo un modulo per ciascun componente di questo Modello Architetturale. In aggiunta prepareremo anche un file di intestazione per organizzare meglio le dichiarazioni delle procedure e del tipo di dato creato ad hoc per l’occasione, così come si usa fare in FreeBASIC.

Una volta preparati e salvati i 4 files, si dovrà compilare il file sorgente modulo_controllore.bas e quindi eseguire il file compilato.

File di intestazione

''nome file: intestazione.bas
''sito web: https://ciucoinformatico.home.blog/
''ultimo aggiornamento: 04/08/2019

/' DESCRIZIONE
File di intestazione per la dichiarazione del tipo di dato
creato ad hoc e delle procedure contenute negli altri moduli.
'/

''definizione del tipo di dato figura
type figura
  tipo as string
  coord_x as integer
  coord_y as integer
  dimensione as integer
  colore(1 to 3) as integer
  selezione as boolean
  selezione_x as integer
  selezione_y as integer
end type

''dimensiona un array fisso del tipo figura
dim figure(1 to 10) as figura

/'
Componente VISTA
'/

''procedura per stampare a video il menu
declare sub stampa_menu()

''procedura per visualizzare le informazioni del mouse
declare sub info_mouse(x as integer, y as integer, r as integer)

''procedura per visualizzare il numero delle figure create
declare sub stampa_tot_figure(n as integer)

''procedura per disegnare le figure
declare sub disegna_figura(f() as figura)

/'
Componente MODELLO
'/

''procedura per la creazione di una figure geometrica
declare sub crea_figura(x as integer, y as integer, r as integer, n as integer, f() as figura)

''procedura per la selezione di una o più figure
declare sub seleziona(x as integer, y as integer, f() as figura)

''procedura per lo spostamento delle figure
declare function sposta(x as integer, y as integer, f() as figura) as boolean

Modulo Controllore

''nome file: controllore.bas
''architettura MVC (Model-View-Controller): componente CONTROLLORE
''sito web: https://ciucoinformatico.home.blog/
''ultimo aggiornamento: 04/08/2019

/' DESCRIZIONE
Componente CONTROLLO: modulo per l'ascolto degli input
dell'utilizzatore che tramite il mouse interagisce con lo
schermo, e dispaccio degli eventi generati dall'utilizzatore
alle procedure del componente MODELLO e chiamata alle
procedure di visualizzazione del componente VISTA.
'/

#include once "file_intestazione.bi"
#include once "modulo_vista.bas"
#include once "modulo_modello.bas"

''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 mouse_x, mouse_y, mouse_ruota, mouse_pulsante

''variabile per il conteggio delle figure
dim num_figura as integer
num_figura = 0

''Visualizza il menu
stampa_menu()

''ciclo per l'ascolto degli input (informazioni dal mouse)
do
  verifica_mouse = getmouse(mouse_x, mouse_y, mouse_ruota, mouse_pulsante)
  if verifica_mouse = 0 then
    ''visualizza a video le informazioni del mouse
    info_mouse(mouse_x, mouse_y, mouse_ruota)
  else
    ''non fare nulla
  end if
  if mouse_pulsante = 1 then
    ''tasto sinistro del mouse
    seleziona(mouse_x, mouse_y, figure())
    disegna_figura(figure())
    stampa_menu()
    stampa_tot_figure(num_figura)
  elseif mouse_pulsante = 4 then
    ''tasto centrale del mouse
    if sposta(mouse_x, mouse_y, figure()) then
      disegna_figura(figure())
      stampa_menu()
      stampa_tot_figure(num_figura)
      sleep 200
    else
    end if
  elseif mouse_pulsante = 2 then
    ''tasto destro del mouse
    if num_figura < 10 then
      num_figura = num_figura + 1
      crea_figura(mouse_x, mouse_y, mouse_ruota, num_figura, figure())
      disegna_figura(figure())
      stampa_menu()
      stampa_tot_figure(num_figura)
      sleep 200
    else
      beep
    end if
  else
    ''non fare nulla
  end if
loop until verifica_mouse = 1

Modulo Vista

''nome file: vista.bas
''architettura MVC (Model-View-Controller): componente VISTA
''sito web: https://ciucoinformatico.home.blog/
''ultimo aggiornamento: 03/08/2019

/' DESCRIZIONE
Componente VISTA: modulo per la rappresentazione a video
del testo e delle figure.
'/

''Imposta una pagina video con la modalità grafica 19 per
''una risoluzione dello schermo di 800x600 pixels, una
''dimenzione testuale di 100 colonne x 37 righe e
''una profondità di colore a 32bpp.
screen 19, 32, 1

''posiziona il mouse al centro
setmouse 400, 300

''procedura per stampare a video il menu
sub stampa_menu()
  locate 1,1: print "Mouse:"
  locate 2, 1: print "tasto sinistro = seleziona le figure"
  locate 3, 1: print "tasto centrale = sposta le figure selezionate"
  locate 4, 1: print "tasto destro = crea una figura"
  locate 5, 1: print "Nota:"
  locate 6, 1: print "Per ingrandire o rimpicciolire la figura, prima"
  locate 7, 1: print "di crearla, usa la ruota."
  locate 36, 1: print "Per uscire dal programma porta il puntatore del";
  print " mouse fuori dalla finestra grafica."
end sub

''procedura per visualizzare il numero delle figure create
sub stampa_tot_figure(n as integer)
  locate 8, 1: print "Totale figure create:"; n; _
                     " (al massimo ne puoi creare 10)"
end sub

''procedura per visualizzare le informazioni del mouse
sub info_mouse(x as integer, y as integer, r as integer)
  locate 9, 1
  print "x:"; x; " y:"; y; " ruota:"; r
end sub

''procedura per disegnare le figure
sub disegna_figura(f() as figura)
  cls 1
  ''itera gli elementi del contenitore delle figure
  for i as integer = lbound(f) to ubound(f)
    if f(i).tipo = "quadrato" then
      line(f(i).coord_x, f(i).coord_y)-(f(i).coord_x + f(i).dimensione, f(i).coord_y), rgb(f(i).colore(1),f(i).colore(2),f(1).colore(3))
      line(f(i).coord_x + f(i).dimensione, f(i).coord_y)-(f(i).coord_x + f(i).dimensione, f(i).coord_y + f(i).dimensione), rgb(f(i).colore(1),f(i).colore(2),f(i).colore(3))
      line(f(i).coord_x + f(i).dimensione, f(i).coord_y + f(i).dimensione)-(f(i).coord_x, f(i).coord_y + f(i).dimensione), rgb(f(i).colore(1),f(i).colore(2),f(i).colore(3))
      line(f(i).coord_x, f(i).coord_y + f(i).dimensione)-(f(i).coord_x, f(i).coord_y), rgb(f(i).colore(1),f(i).colore(2),f(1).colore(3))
    end if
  next i
end sub

Modulo Modello

''nome file: modello.bas
''architettura MVC (Model-View-Controller): componente MODELLO
''sito web: https://ciucoinformatico.home.blog/
''ultimo aggiornamento: 03/08/2019

/' DESCRIZIONE
Modulo contenente le procedure per la gestione dei dati
e la logica di funzionamento del programma.
'/

''procedura per la creazione di una figure geometrica
sub crea_figura(x as integer, y as integer, r as integer, n as integer, f() as figura)
  f(n).tipo = "quadrato"
  f(n).coord_x = x
  f(n).coord_y = y
  f(n).dimensione = 80 + r
  f(n).colore(1) = 255
  f(n).colore(2) = 0
  f(n).colore(3) = 0
  f(n).selezione = false
end sub

''procedura per la selezione di una o più figure
sub seleziona(x as integer, y as integer, f() as figura)
  ''itera gli elementi del contenitore delle figure
  for i as integer = lbound(f) to ubound(f)
    if x >= f(i).coord_x and x <= (f(i).coord_x + f(i).dimensione) and y >= f(i).coord_y and y <= (f(i).coord_y + f(i).dimensione) then
       f(i).colore(2) = 255
       f(i).selezione = true
       f(i).selezione_x = x - f(i).coord_x
       f(i).selezione_y = y - f(i).coord_y
    else
      f(i).colore(2) = 0
      f(i).selezione = false
      f(i).selezione_x = 0
      f(i).selezione_y = 0       
    end if
  next i
end sub

''procedura per lo spostamento delle figure
function sposta(x as integer, y as integer, f() as figura) as boolean
  dim controllo as boolean
  controllo = false
  ''itera gli elementi del contenitore delle figure
  for i as integer = lbound(f) to ubound(f)
    if f(i).selezione = true then
      f(i).coord_x = x - f(i).selezione_x
      f(i).coord_y = y - f(i).selezione_y
      ''deselezione
      f(i).colore(2) = 0
      f(i).selezione = false
      f(i).selezione_x = 0
      f(i).selezione_y = 0       
      controllo = true     
    else
      ''non fare nulla
    end if
  next i
  return controllo 
end function

Bene. Per oggi ci fermiamo qui.

A rileggerci tra circa una settimana. 🙂

FreeBASIC – lavorare con i files [2]

Nel precedente articolo abbiamo visto come creare un file di testo e come leggerlo riga per riga.

Oggi scopriremo come aggiungere del contenuto testuale.

Per farlo dobbiamo aprire un file di testo esistente in modalità append. Se il file non dovesse esistere ne verrebbe comunque creato uno nuovo:

'Crea un file di testo e scrive la prima riga.
open "prova.txt" for output as #1
 print #1, "riga 1"
close #1

'Apre il file di testo esistente e aggiunge una nuova riga di testo.
open "prova.txt" for append as #1
  print #1, "riga 2"
close #1

Scrivere e leggere valori in formato tabellare

Oltre a poter leggere una riga di testo per volta con l’istruzione line input # e a scriverne una per volta con l’istruzione print #, è possibile memorizzare in un file di testo delle informazioni in formato tabellare (dati separati da virgole) attraverso l’istruzione write # e quindi leggerli con l’istruzione input #:

dim as string a, c
dim as integer b

'Crea un file di testo con tre informazioni separate da virgola.
open "prova.txt" for output as #1
  write #1, "la gatta ha partorito", 4, "gattini"
close #1

'Apre in lettura il file di testo ed assegna a tre variabili le rispettive informazioni.
open "prova.txt" for input as #1
  input #1, a, b, c
close #1

'Stampa il valore delle variabili.
print "la prima informazione e': "; a
print "la seconda informazione e': "; b
print "la terza informazione e': "; c

Bene. Per oggi ci fermiamo qui.

Nel prossimo articolo affronteremo la modalità di apertura binary.

FreeBASIC – lavorare con i files [1]

Dopo un po’ di tempo che si è iniziato a programmare, è inevitabile che sorga l’esigenza di lavorare con delle informazioni salvate su files.

È bene quindi sapere come farlo anche con FreeBASIC.

Istruzione open

L’istruzione che si utilizza in FreeBASIC per lavorare con i files è l’istruzione open.

Di per sé l’istruzione open non specifica cosa in realtà vogliamo fare: se, per esempio, leggere un file esistente, oppure scriverci sopra, o magari crearne uno nuovo.

Per dire al nostro computer cosa vogliamo fare occorre specificare una delle seguenti cinque modalità di apertura:

  1. Per scrivere del testo a partire da un file vuoto (parola-chiave output)
  2. Per leggere il contenuto testuale (parola-chiave input)
  3. Per aggiungere del testo ad un file esistente (parola-chiave append)
  4. Modalità binaria (parola-chiave binary)
  5. Modalità casuale (parola-chiave random)

In questo articolo vedremo le prime due.

Creare un file di testo (output)

Proviamo a creare il nostro primo file di testo:

dim nome_file as string
dim numero_file as long

nome_file = "prova.txt"
numero_file = freefile 'restituisce un numero di file libero

open nome_file for output encoding "utf8" lock write as #numero_file
print #numero_file, "FreeBASIC è figo!"
close #numero_file

Vediamo di spiegare nel dettaglio cosa abbiamo fatto.

Numero del file

In FreeBASIC è necessario identificare il file su cui stiamo lavorando con un numero.

Nonostante siamo liberi di specificare direttamente noi un valore che sia compreso tra 1 e 255, è preferibile utilizzare la funzione freefile che evita il rischio di utilizzare un valore già in uso.

Nome del file

Se nella stringa del nome del file non viene specificato alcun percorso, il file verrà aperto nella cartella corrente (vedi anche la funzione curdir).

Codifica dei caratteri

Per quanto riguarda la scelta della codifica dei caratteri, in FreeBASIC possiamo sceglierne una tra le seguenti quattro attraverso l’istruzione encoding:

  1. ASCII: digitando “ascii” (codifica di default se non specificata)
  2. UTF-8: digitando “utf8” (codifica consigliata dal W3C)
  3. UTF-16: digitando “utf16”
  4. UTF-32: digitando “utf32”

Accessibilità al file

Con l’istruzione lock si può specificare se l’accesso al file è esclusivo o se ne è permesso l’accesso in lettura o scrittura anche ad altri programmi presenti sul nostro computer:

  • read: impedita la lettura da parte di altri programmi
  • write: impedita la sola scrittura
  • read write: accesso totalmente negato ad altri programmi (valore di default)

Come leggere un file di testo

Proviamo ora a leggere il contenuto del file appena creato utilizzando la modalità input e aggiungendo al nostro programma le seguenti linee di codice:

dim riga_di_testo as string

numero_file = freefile

open nome_file for input as #numero_file
line input #numero_file, riga_di_testo
close #numero_file

print riga_di_testo

Compilando e mandando in esecuzione il programma ci accorgiamo subito che la lettura del carattere accentato “è” non è andata a buon fine. Questo perché non avendo specificato la codifica dei caratteri, di default FreeBASIC ha interpretato il testo come codificato in ASCII. Basterà quindi modificare il codice aggiungendo la codifica in UTF-8 e la lettura del testo sarà corretta.

Modalità di lettura

Per leggere il contenuto di un file di testo abbiamo due diverse istruzioni:

  • line input #: che permette la lettura di una intera riga di testo sino al carattere di fine riga che viene scartato;
  • input #: che permette la lettura di valori separati da virgola (ne parleremo nel prossimo articolo).

Intercettare la fine di un file

Una volta scelta la modalità di lettura, dovremo inserirla in un ciclo in modo tale da leggere tutto il contenuto del file.

Qui si pone un problema: quando uscire dal ciclo di lettura?

Niente panico! FreeBASIC ci mette a disposizione la funzione eof che restituisce il valore -1 (true) se si è raggiunta la fine del file, altrimenti viene restituito il valore 0 (false).

Bene! Per oggi ci fermiamo qui.

Nel prossimo articolo continueremo comunque ad approfondire l’argomento e vedremo come lavora la modalità di apertura append. 🙂