JavascriptProva

domenica 16 dicembre 2012

Linee animate in Processing

Proviamo a disegnare una linea animata, adesso.
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(200);
  fill(100);
}
void draw(){
  x++;
  line(0,0,x,500);
}
Ecco, la linea non si muove, ma disegna un triangolo. Per far disegnare un cerchio, dovrei usare le funzioni trigonometriche...
Ma se io voglio che la linea si sposti, posso procedere a quell'artifizio col background... Proviamo.
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(10);
  fill(100);
}
void draw(){
  x++;
  line(0,0,x,500);
  background(100);
}
...che non funziona!
Vediamo con il contatore di frames...

Ecco: un buon artifizio è questo!
int x=0;
void setup(){
  background(100);
  size(1000,800);
  frameRate(100);
  fill(100);
}
void draw(){
  line(0,0,x,500);
  if(frameCount%5==0) {
    background(100);
    x++;
  }
}
Funziona! ...anche se la linea si muove un po' lentamente.
Ho appreso un artifizio per fare i loop. Fare l'operazione frameCount % [numero di frames che compongono il loop]. Ogni volta che il numero di frames eseguiti è divisibile per il numero di frames che compongono il loop, il risultato dell'operazione MODULO è zero, e questa viene posta come condizione per ottenere un effetto.

Primi rudimenti con Processing

Dunque...

Iniziamo con il metodo (o funzione) void setup...

Ecco:
void setup(){
  size(500,500);
}
Così facendo, con il comando size() imposto l'area del mio canvas. Ci provo con l'editor di Processing.
Ottengo una finestra del calibro voluto.

Ora ci disegno una linea:
void setup(){
  size(500,500);
}
void draw(){
  line(10,10,400,400);
}
Benissimo! Ci sono riuscito.

Ora divaghiamo...

Caricare un'immagine. Cerchiamo su Google "load image"...
PImage img;
void setup(){
  size(500,500);
  stroke(0);
  img=loadImage("bella.jpg");
}
void draw(){
  image(img,0,0,img.width/2,img.height/2);
}
Risultato:

Bene...

Quindi il caricamento dell'immagine è indipendente dalla sua visualizzazione.
L'immagine è stata preventivamente messa nella cartella "data" del file .pde.

martedì 11 dicembre 2012

Canvas: per prima cosa rendiamo un canvas trascinabile, potrebbe servire.

Bene... Sono riuscito a creare una libreria dragdrop.js che contiene l'essenziale per trascinare elementi sulla pagina web.
Essa viene chiamata semplicemente dando all'evento window.onload istruzione di eguagliare l'evento document.onmousedown alla funzione OnMouseDown e l'evento document.onmouseup alla funzione OnMouseUp, e di impostare la proprietà di stile position a "absolute" per gli elementi che si vuole trascinabili.

Ora occupiamoci del canvas.
Dato che sto lavorando con Internet Explorer a causa del fatto che è l'unico browser che mi consente di salvare files su disco fisso, e quindi di mantenere e modificare archivi xml, devo imparare la sintassi del canvas per IE.

Anche il canvas può essere soggetto a DragDrop, impostando le giuste proprietà:
<!DOCTYPE HTML>
<html>
<head>
<style>
#mycanvas{
   border:1px solid red;
   position:absolute;
}
</style>
<script src="funzioni.js"></script>
<script src="dragdrop.js"></script>
<script>
function main(){
 document.onmousedown=OnMouseDown;
 document.onmouseup=OnMouseUp;
}
window.onload=main;
</script>
</head>
<body>
   <canvas id="mycanvas" width="100" height="100">
</body>
</html>
Ecco: con il richiamo delle librerie "dragdrop.js" e "funzioni.js", e impostando quei semplici comandi, il canvas si muove se trascinato.

lunedì 5 novembre 2012

Incapsulamento

Ecco uno schema per creare delle interfacce istanziando oggetti e incapsulando, anzichè creando noiosi innerHTML nei quali mi perdo:

Questo è il costruttore dell'oggetto interfaccia:
function interfaccia(){
 var Me;
 var Notizie;
 var creaMe=function(){
  Me=document.createElement("div");
  Me.setAttribute("className","interfaccia");
  document.body.appendChild(Me); 
  
  var Notizie=new notizie();
  Me.appendChild(Notizie.Me);
 
 }
 creaMe();
 
 this.Me=Me; 
}
Nel contesto di questo costruttore viene istanziato l'oggetto notizie da un altro costruttore, in cui è prevista anche la presenza di una textarea:
function notizie(){
 var Me;
 var Testo
 
 var creaMe=function(){
  //Crea l'oggetto
  Me=document.createElement("div");
  Me.setAttribute("className","bordatoblu");
  
  //Crea la Textarea
  var testo=document.createElement("textarea");
  Testo=testo
  Me.appendChild(testo);
  
 }
 creaMe();
 this.Me=Me;
 
}
Di questo secondo oggetto viene resa pubblica soltanto l'interfaccia Me, ma aggiungendo un this.Testo=Testo potrei rendere pubblica anche la textarea, facendo sì che possa essere gestita anche da altre aree del programma.

domenica 28 ottobre 2012

Oggetto con proprietà dai nomi uguali a quelli dei nodi dell'XML

Procediamo per ordine.
Bisogna innanzitutto vedere quali sono i primi nodi di un documento.
Prendiamo il mio documento xml piuttosto semplice e vediamo quali sono i primi nodi.
La prima proprietà di un oggetto che rappresenta un record del mio database dovrebbe essere il tag che rappresenta.
Cerco di creare una proprietà dell'oggetto che abbia lo stesso nome del tag che rappresenta.
Come fare?

La proprietà la chiamo tipo in quanto il suo nome è rappresentativo del tipo di informazione contenuto nel record. Dato che la mia tabella è fatta di persone, il tag si chiama <persona>.
Ecco il codice:
function record(){
 this.tipo=root.childNodes[0] 
}
In pratica assegno alla proprietà tipo il primo elemento figlio del documento.
Questo approccio non è corretto. Infatti se poi vado a usare istanze dell'oggetto che rappresentano records diversi dal primo, le loro proprietà tipo non dovranno rappresentare il primo nodo figlio del documento, ma quelli successivi.

Il ragionamento che posso fare è questo:
  • individuare il nome dei primi nodi figli del documento.
  • assegnare alla proprietà tipo del record il nodo figlio con quel nome identificato da un numero.
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this.tipo=root.getElementsByTagName(nomeNodo)[num];
}
La prima riga prende il nome del primo nodo figlio del documento.
La seconda riga assegna alla proprietà tipo dell'oggetto il nodo figlio identificato dal numero num, presente come parametro.
Ma ora voglio di più.
Voglio che il nome della proprietà sia uguale al nome del primo nodo figlio che viene trovato.
Ci provo:
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this[nomeNodo]=root.getElementsByTagName(nomeNodo)[num];
}
e poi istanzio l'oggetto chiedendo di mostrarmi il nome del nodo della proprietà persona dell'oggetto.
function init(){
 Record=new record(0);
 alert(Record.persona.nodeName);
}
Dunque la proprietà persona dell'oggetto richiama immediatamente l'omonimo tag di ogni record della tabella.
Sembra che stia procedendo bene, almeno questo è quanto sono riuscito a fare finora.

Ora andiamo avanti con altre proprietà...
Ecco, sembra che sia riuscito a ottenere un codice con un minimo di funzionalità:
function record(num){
 var nomeNodo=root.childNodes[0].nodeName;
 this[nomeNodo]=root.getElementsByTagName(nomeNodo)[num];
 
 var nodo=this[nomeNodo];
 
 for(var i=0;i<nodo.childNodes.length;i++){
  nomeNodo=nodo.childNodes[i].nodeName;
  this[nomeNodo]=nodo.getElementsByTagName(nomeNodo);
 }
}
La prima parte desume il nome dei primi nodi figli nella variabile nomeNodo, quindi la usa per creare una proprietà con lo stesso nome dei nodi, alla quale assegna il nodo figlio indicato dal numero fornito come parametro nel costruttore dell'oggetto.

Ora, questa proprietà, che ha il valore di un oggetto, viene immagazzinata nella variabile privata nodo.

Quindi questa proprietà viene usata ripetutamente, per quanti sono i nodi figli, per desumere il nome dei nodi figli e creare le relative proprietà con gli stessi nomi dei nodi figli.

Così, quando istanzio l'oggetto, posso usare direttamente il nome dei nodi come fossero delle semplici proprietà dell'oggetto:
function init(){
 Record=new record(0);
 alert(Record.nome[0].text);
 alert(Record.cognome[0].text);
 alert(Record.professione[0].text);
 alert(Record.figlio[0].text)
 alert(Record.figlio[1].text);
}
Devo mettere lo zero quando le proprietà non sono array, mentre quando lo sono, come nel caso della proprietà "figlio", devo specificare l'indice dell'array.
Provo a usare un risultato più "grafico" in modo da copiarlo e incollarlo qui.
function init(){
 Record=new record(0);
 document.write(Record.nome[0].text+" "+
 Record.cognome[0].text+" "+
 Record.professione[0].text+" "+
 Record.figlio[0].text+" "+
 Record.figlio[1].text);
 
 document.write("<br>");
 
 Record=new record(1);
 document.write(Record.nome[0].text+" "+
 Record.cognome[0].text+" "+
 Record.professione[0].text);
}
Ed ecco il risultato:
Ciccio Rossi rapinatore Giovanni Luigi
Giuseppe Verdi Musicista


Il fatto che il secondo record non abbia i campi "figlio" fa sorgere tutta una serie di interrogativi che vedrò di affrontare successivamente...

Metodo per cambiare il valore di un campo nel file XML

Bene. Ho messo a punto anche un metodo "cambia()" per il mio schema di oggetto atto alla manipolazione dei files XML.
function persona(num){
 var record=root.getElementsByTagName("persona")[num];
 
  this.nome=record.getElementsByTagName("nome")[0];
  this.cognome=record.getElementsByTagName("cognome")[0];
  this.professione=record.getElementsByTagName("professione")[0];
  this.figli=record.getElementsByTagName("figlio");
  this.cambia=function(campo,valore){
   record.getElementsByTagName(campo)[0].childNodes[0].nodeValue=valore;
   var fso=new ActiveXObject("Scripting.FileSystemObject");
   var path=document.location.pathname;
   path=path.substr(1,path.lastIndexOf("/"));
   path=path.replace(/%20/g," ");
   var f=fso.CreateTextFile(path+"data.xml",true);
   f.write(xmlDoc.xml);
   f.Close();
   fso=null;
  }
}
Funziona.

sabato 27 ottobre 2012

Creazione di oggetti per muoversi in un file XML

Un piccolo artifizio per facilitarsi la vita con le tabelle costruite intorno ai files XML.
C'è un oggetto che rappresenta il record, le cui proprietà sono rappresentate dai suoi childNodes, come se fossero tanti elementi di una tabella.
L'oggetto viene poi istanziato in base al numero ordinale.
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("data.xml");
var root=xmlDoc.documentElement;

function persona(num){
 var record=root.getElementsByTagName("persona")[num];
 
  this.nome=record.getElementsByTagName("nome")[0];
  this.cognome=record.getElementsByTagName("cognome")[0];
  this.professione=record.getElementsByTagName("professione")[0];
  this.figli=record.getElementsByTagName("figlio");
}
function init(){
Mario=new persona(0);
Giuseppe=new persona(1);
alert(Mario.nome.text);
alert(Mario.cognome.text);
 for(var n=0;n<Mario.figli.length;n++)
  alert(Mario.figli[n].text);
}
window.onload=init;
costruito per questo XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tabella [
<!ELEMENT tabella (persona*)>
<!ELEMENT persona (nome, cognome, professione,figlio*)>
<!ELEMENT nome (#PCDATA)>
<!ELEMENT cognome (#PCDATA)>
<!ELEMENT professione (#PCDATA)>
<!ELEMENT figlio (#PCDATA)>
]>
<tabella>
 <persona>
  <nome>Mario</nome>
  <cognome>Rossi</cognome>
  <professione>Ladro</professione>
  <figlio>Giovanni</figlio>
  <figlio>Luigi</figlio>
 </persona>
 <persona>
  <nome>Giuseppe</nome>
  <cognome>Verdi</cognome>
  <professione>Musicista</professione>
 </persona>
</tabella>


Mi sembra molto funzionale, perchè istanziando volta per volta l'oggetto si può accedere a tutti i record della "tabella" e prenderne i campi desiderati come proprietà dell'oggetto.

lunedì 22 ottobre 2012

Elementi XML: dichiarazione del numero dei figli

La logica dell'XML è ferrea, a quanto pare!
Ho un file XML di questo genere:
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
</documento> 
E con il codice javaScript:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[0].text);
...riesco a caricarlo e a ottenere, come fatto prima, il messaggio "ciao merdaccia".
Adesso provo ad aumentare il numero degli elementi %lt;controllo> nel file XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
...e con quel codice javaScript non ottengo nulla, ma il debugger mi dà il messaggio di errore:
Impossibile ottenere il valore della proprietà 'getElementsByTagName': 
oggetto nullo o non definito


Perchè?

L'ho scoperto subito: perchè quando io specifico i figli dell'elemento <documento> uso la seguente sintassi:
<!ELEMENT documento (capitolo)>
che significa che l'elemento documento ha un solo figlio, mentre poi, di fatto, ne ha due.

Allora metto il simbolo +, che significa "uno o più figli":
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo+)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
e ottengo di nuovo l'insulto di prima, regolarmente, perchè adesso si specifica che i figli dell'elemento documento possono essere uno o più.
Adesso uso il simboletto ? che significa "zero o uno figli".
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo?)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
e non ottengo niente, perchè qui i figli sono due!
Provo infine a usare il simboletto *, che significa "zero o più":
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo*)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
 <capitolo>
 "ciao deficiente"
 </capitolo>
</documento> 
E ottengo il mio caro "ciao merdaccia", oppure, se chiedo il contenuto del secondo elemento:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[1].text);
ottengo un meraviglioso "ciao deficiente"!
Nonostante gli insulti, sono contento!!!

Il mio primo caricamento di un file XML

BENE! Sono riuscito a caricare un file xml elementare in un documento HTML.
La sintassi in IE è questa:
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("prova.xml");
var root = xmlDoc.documentElement;
alert(root.getElementsByTagName("capitolo")[0].text);
Ho caricato questo file xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE documento [
<!ELEMENT documento (capitolo)>
<!ELEMENT capitolo (#PCDATA)>
]>
<documento>
 <capitolo>
 "ciao merdaccia"
 </capitolo>
</documento> 
E ho ottenuto una finestra di messaggio con scritto "ciao merdaccia".
Ottimo!!!

DTD

Saltiamo subito al sodo.
Analizziamo quella diavoleria che si trova all'inizio di un DTD.
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>  
Che cosa sono quegli ELEMENT preceduti dai punti esclamativi?
Significano rispettivamente che:
  • l'elemento note contiene altri elementi to, from, heading, body;
  • l'elemento to è un #PCDATA, come tutti gli altri elementi.
Che accidenti significa #PCDATA?

Meglio che mi eserciti perchè le cose si imparano meglio con la pratica...

XML

Prendo questo tutorial e me lo studio...

"If you need to display dynamic data in your HTML document, it will 
take a lot of work to edit the HTML each time the data changes.

With XML, data can be stored in separate XML files. This way you 
can concentrate on using HTML/CSS for display and layout, and be 
sure that changes in the underlying data will not require any 
changes to the HTML.

With a few lines of JavaScript code, you can read an external 
XML file and update the data content of your web page."

E' proprio quello che mi serve.


Bene, posso creare i miei tags come e quando voglio.
Ma come li uso?


Questa "intestazione", cosa è?
<?xml version="1.0" encoding="ISO-8859-1"?>
The first line is the XML declaration. It defines the 
XML version (1.0) and the encoding used (ISO-8859-1 = 
Latin-1/West European character set).
La dichiarazione XML inizia con un punto interrogativo, chissà perchè...
Poi c'è la versione. E quindi un encoding.

Cosa significa questo?

version è la versione xml, mentre encoding è il set di caratteri in cui è scritto l'xml...
Ah, ecco, spicchiamo il volo!
Ci sono slcuni tipi di files: il documento xml, che deve essere ben formato, e questo lo sapevamo, e valido.
Che significa valido?

A "Valid" XML document is a "Well Formed" XML document, which 
also conforms to the rules of a Document Type Definition (DTD)
Ecco: valido significa che si conforma alle regole di un DTD (definizione del tipo di documento).
Quindi ci deve essere un DTD, che dobbiamo creare a parte.
Ecco, sto ricominciando a "quagliare" le nozioni che avevo appreso un tempo e poi abbandonato per noia in quanto, siccome questo XML apparentemente non "fa" niente, era più bello trafficare con le pagine HTML e con il javaScript che permettono di ottenere risultati di "effetto"!
Un po' come il solfeggio per gli studenti di musica, che non vedono l'ora di "suonare" e sbuffano non poco su quel noioso esercizio, il quale, però, fornisce uno dei fondamenti di base per imparare a leggere la musica, tanto che se non avessi fatto solfeggio non sarei in grado di leggere una musica scritta su uno spartito come riesco a farlo abitualmente!

lunedì 8 ottobre 2012

Razionalizzazione degli antenati

Il programma va ulteriormente razionalizzato.

Risaliamo al capostipite.
Ogni parte della sezione deve avere un suo preciso attributo name. La mia sezione sarà formata da:
  • Container (il capostipite);
  • Notizie;
  • Lista;
  • Risultati
Dal capostipite si va a ogni elemento mediante il querySelector Ho implementato la funzione che individua il capostipite rispetto a ciascun oggetto della sezione:
function Container(e){
 var oggetto=e;
 while(oggetto.getAttribute("name") !="Container") {  
  oggetto=oggetto.parentNode;
 }
 return oggetto;
}


Ed ecco implementata la prima delle funzioni che dal capostipite discendono ai singoli discendenti individuandoli per nome:
function Notizie(e){
 var oggetto=Container(e).querySelector("[name='Notizie']");
 return oggetto;
}
E' fatta! Il programmino può essere ben razionalizzato!!!

Struttura generale della sezione del mio programma

Composizione di una sezione: Ho un contenitore.
Dentro questo contenitore ci sono quattro elementi, chiamati:
  • notizie
  • lista
  • risultati
  • pulsanti
Dunque l'innerHTML di contenitore è questo:
"<div class=giallochrosso>"+risposta+"</div>  
<div name='notizie' class=bordatoblu><textarea style='width:290px'></textarea>
</div>
<div name='lista' class=bordatoblu><input type='button' value='Aggiungi Blocco' onClick='aggiungiBlocco(this)'>
</div>  
<div name='risultati' class=bordatoblu>
</div>  
<div name="pulsanti" style='clear:left'><center><input type='button' value='NUOVO'onClick='aggiungiSezione()'>  <input type='button' value='DIMESSO' onClick='eliminaSezione(this)'></center>
</div>" 
I pulsanti sono:
  • Il pulsante "NUOVO", che aggiunge una nuova sezione
  • il pulsante "DIMESSO" che elimina la sua stessa sezione
  • il pulsante "AGGIUNGI BLOCCO" che aggiunge un blocco all'elemento "lista"
Dunque devo creare le funzioni chiamate da ognuno di questi pulsanti.

venerdì 5 ottobre 2012

Il figlio fantasma di HTML...

Ah! Ecco! Ma tu guarda...
Se faccio così
<html>
<head>
<script>
function mostra(){
 for(n=0;n<document.childNodes[0].childNodes.length;n++)
 {
  alert(document.childNodes[0].childNodes[n].nodeName);
 }
}
window.onload=mostra;
</script>
</head><body>
</body>
</html> 
mi sparisce quel #text e ottengo:
  • HEAD
  • BODY
Forse nel documento di testo che ho usato, sono andato a capo, o ho lasciato uno spazio che poi ho tolto, e così facendo ho creato un figlio "testo" per HTML.

i figli di HTML, figlio di document.

Ecco, ora vado avanti a vedere chi sono i figli di HTML.
<html>
<head>
<script>
function mostra(){
 for(n=0;n<document.childNodes[0].childNodes.length;n++)
 {
  alert(document.childNodes[0].childNodes[n].nodeName);
 }
}
window.onload=mostra;
</script>
</head>
<body>
</body>
</html> 
E qui c'è un'incognita! Mi restituisce HEAD, #text e BODY
Che accidenti è quel #text?

Iniziamo a vederci chiaro tra padri e figli nel DOM

Procediamo per ordine.
<html>
<head>
<script>
function mostra(){

 alert(document.childNodes[0].nodeName);
}
window.onload=mostra;
</script>
</head>
<body>


</body>
</html> 
...mi restituisce HTML.
Questo significa che il figlio di document è HTML.
document ha un figlio solo, come dimostrato da questo codice:
<html>
<head>
<script>
function mostra(){

 alert(document.childNodes.length);
}
window.onload=mostra;
</script>
</head>
<body>


</body>
</html> 
...che restituisce 1.

Quindi: document ha un solo figlio che è HTML.

domenica 30 settembre 2012

Aggiunta di elementi in un DIV figlio

Ecco un codice in cui ogni DIV figlio può essere gestito aggiungendovi degli elementi.
Per ora iniziamo solo con uno.
Ho tolto gli "id" in quanto quell'attributo deve essere univoco, e non è corretto attribuire lo stesso "id" a più elementi.
<html>
<head>
<style>
.bordato {
 border: 5px solid black;
 float:left;
}
.bordatorosso {
 border: 5px solid blue;
 
 width:200px;
 
 float:left;
 margin-left:5px;
 padding:5px;
 
}
</style>

<script>
function $(a){
 return (document.getElementById(a));
}

function aggiungiFiglio(elemento){
 var nuovo=document.createElement("div");
 nuovo.innerHTML="<input type='text'>";
 elemento.appendChild(nuovo);
}

</script>
</head>




<body>
<div id="padre" class=bordato>

 <div class=bordatorosso>
 Uno due tre

 </div>
 <div class=bordatorosso>
 <input type='button' value='Aggiungi' onClick=aggiungiFiglio(this.parentNode)>
 

 </div>
 <div class=bordatorosso>
 sette otto nove

 </div>


</div>
</body>
</html>

Ho trovato il modo di affiancare e includere in un contenitore con il solo uso dei fogli di stile.

Dopo un po' di confusione, ritorniamo a vedere come si affiancano gli elementi all'interno di un contenitore.
Ecco:
<html>
<head>
<style>
.bordato {
 border: 10px solid black;
 float:left;
}
.bordatorosso {
 border: 5px solid red;
 
 width:200px;
 
 float:left;
 margin:10px;
 
 
}
</style>

<script>
function $(a){
 return (document.getElementById(a));
}


</script>
</head>




<body>
<div id="padre" class=bordato>

 <div id="figlio1" class=bordatorosso>
 Uno due tre

 </div>
 <div id="figlio1" class=bordatorosso>
 quattro cinque sei

 </div>
</div>
</body>
</html>

GetComputedStyle

Ecco, era GetComputedStyle.
Ripassiamolo...

Ecco un autolink in proposito.


Ho trovato un codice...
<html>
<head>
<style>
.bordato {
 border: 2px solid black;
}
.bordatorosso {
 border: 50px solid red;
 width:"200px";
}
</style>

<script>
function $(a){
 return (document.getElementById(a));
}

function dimensiona(){
 alert(getComputedStyle(document.getElementById("figlio1"), null).getPropertyValue("border-width"));
 
 
}
window.onload=dimensiona;
</script>
</head>




<body>
<div id="padre" class=bordato style="height:200px;width:800px">

 <div id="figlio1" class=bordatorosso>
 </div>


</div>
</body>
</html>

sabato 29 settembre 2012

Creazione di DIV padri e figli in un documento

Architettare un sistema in cui si aggiungono figli a un elemento, i quali passano, all'occorrenza, a un altro elemento...
Come ho già fatto, è necessario predisporre delle funzioni che permettano di fare rapidamente riferimento al genitore e a degli specifici fratelli.

Costruire un div con due div figli posti in esso, affiancati.
<html>
<head>
<style>
.bordato {
 border: 2px solid black;
}
.bordatorosso {
 border: 2px solid red;
}
</style>

<script>

</script>
</head>




<body>
<div id="padre" class=bordato style="height:200px;width:800px">
 <div id="figlio1" class=bordatorosso style="height:200px;width:400px">
 </div>


</div>
</body>
</html>
Ecco un primo rudimentale tentativo di costruire un genitore con un figlio, fatto dando volta per volta le misure, cosa che dovrà essere eliminata concentrando le istruzioni relative alla formattazione in poche istruzioni buone per tutta la pagina.


C'è un primo limite: il bordo del figlio si estende oltre il bordo del padre.
Ricordo che c'erano delle definizioni di attributi di stile che tenevano conto del bordo degli elementi, ma non ricordo precisamente quali...

domenica 23 settembre 2012

Due funzioni utili per i blocchi che voglio creare nel mio programma

Ho elaborato due funzioni, una già presente in qualche libreria di JavaScript, che risparmia di scrivere il document.getElementById, e un'altra che permette di isolare gli elementi all'interno dell'innerHTML di un elemento.
Questo è il codice completo di prova che ho usato.
Le funzioni andranno poi messe in una libreria a parte.
<html>
<head>
<script>
function $(a){
 return (document.getElementById(a));
}
function Sottoelemento(elemento,nome){
 return ($(elemento).querySelector("div[id="+nome+"]"));
}


function funzione(){
  $("mioDiv").innerHTML="<div id='ciccio'>uno</div><div id='pippo'>due</div>";
  alert(Sottoelemento("mioDiv","ciccio").innerHTML);
  alert(Sottoelemento("mioDiv","pippo").innerHTML);
}
window.onload=funzione;
</script>
</head>
<body>
<div id="mioDiv"></div>
</body>
</html>

Aggiunta di elementi che possono essere selettivamente eliminati.

Ecco un codice che aggiunge elementi ognuno dei quali possiede un pulsante che lo elimina dalla serie.
<html>
<head>
<style>
.tipo {
 border:2px solid black;
 width: 300px;
}
</style>
<script>
var contatore=0;
function crea(){
 
 var nuovo=document.createElement("div");
 nuovo.setAttribute("class","tipo")
 nuovo.setAttribute("id",contatore)
 nuovo.innerHTML="<input type='text'><input type='button' id="+contatore+" onClick='elimina(this.id)'>"
 document.getElementById("primo").appendChild(nuovo);
 contatore++;
 
}
function elimina(n){
 var eliminato=document.getElementById(n);

 primo.removeChild(eliminato);
}

</script>
</head>
<body>
<div id ="primo">Elemento</div>

<input type="button" value="aggiungi" onClick="crea()">
</body>
</html>

Eliminazione di elementi precedentemente aggiunti.

Ecco un codice per eliminare un elemento di quelli precedentemente aggiunti:
<html>
<head>
<style>
.tipo {
 border:2px solid black;
 width: 300px;
}
</style>
<script>
var contatore=0;
function crea(){
 for (n=0; n<10;n++) {
  var nuovo=document.createElement("div");
  nuovo.setAttribute("class","tipo")
  nuovo.setAttribute("id",contatore)
  nuovo.innerHTML="ciccio"+contatore;
  document.getElementById("primo").appendChild(nuovo);
  contatore++;
 }
}
function elimina(){
 var eliminato=document.getElementById(3);
 primo.removeChild(eliminato);
}
window.onload=crea;
</script>
</head>
<body>
<div id ="primo">Elemento</div>
<input type="button" value="elimina" onClick="elimina()">

</body>
</html>

Creazione e aggiunta di nuovi elementi HTML

Ecco, ho trovato il modo di creare dinamicamente diversi elementi nuovi in una pagina HTML:
<html>
<head>
<style>
.tipo {
 border:2px solid black;
 width: 300px;
}
</style>
<script>
var contatore=0;
function crea(){
 for (n=0; n<10;n++) {
  var nuovo=document.createElement("div");
  nuovo.setAttribute("class","tipo")
  nuovo.innerHTML="ciccio"+contatore;
  document.getElementById("primo").appendChild(nuovo);
  contatore++;
 }
}
window.onload=crea;
</script>
</head>
<body>
<div id ="primo">Elemento</div>


</body>
</html>
 
E funziona.

venerdì 21 settembre 2012

Un nuovo programmino in JavaScript?

Iniziamo dal meno... E' difficile avere chiare le caratteristiche di funzionamento di un nuovo programma dall'inizio, almeno per me.

Sarebbe meglio farlo in Javascript, anche a rischio di farsi fregare il codice... anche se nell'ambiente non c'è sicuramente nessuna persona che non solo non ha alcuna cognizione di JavaScript o finanche della sua esistenza, ma non sa nemmeno che il codice può semplicemente essere letto con "visualizza sorgente" o aprendo la pagina web con il blocco note...

Dunque, per iniziare ho un foglio in cui si debbono aggiungere dei nomi.
Un tasto "Aggiungi", premendo il quale si apre una textbox nella quale digitare un nome, che si auspica possa diventare immodificabile una volta che il nome sia stato aggiunto a meno di non volerla modificare espressamente con la pressione di un altro tasto.

Inizio con lo scheletro iniziale:
<html>
<head>
<script>


</script>
</head>
<body>


</body>
</html>
Ora devo ricordarmi come si inserisce una textbox.
Ecco:
<html>
<head>
<script>


</script>
</head>
<body>
<input type="text">

</body>
</html>
Come la manovro, adesso?

venerdì 14 settembre 2012

Ho apportato qualche correzione al codice.
Quello che adesso mi serve è regolare la spaziatura fra le caselle.
Cerchiamo di sistemare questi problemi di formattazione delle tabelle prima di affrontare la sezione menu e la nutrita parte relativa ai calcoli...

mercoledì 12 settembre 2012

Estrapolare una parte di una stringa in VB.NET (diverso da VB6)

Un'idea.
Fra il nome e il numero mettere un carattere come un punto.
Così:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim parola As String = "parola.12"

    End Sub
Ora individuare la posizione del punto all'interno della stringa.
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim parola As String = "parola.12"
        MsgBox(parola.IndexOf("."))

    End Sub
Ottengo 6, ossia, considerato che la prima lettera è in posizione 0, significa che il punto è al settimo posto.

Ora voglio isolare la parte della stringa che sta dopo il punto.
Ecco, con un po' di tribolazione, dopo aver capito che in VB.NET non esistono più le operazioni Left, Right e Mid:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim parola As String = "parola.12"
        MsgBox(parola.Substring(parola.Length - (parola.Length - parola.IndexOf(".") - 1)))


    End Sub
Così ottengo ciò che è dopo il punto.
Potrei immettere anche questo codice sotto forma di una funzione nel modulo Funzioni.vb... ma lo vedrò dopo.
...e invece l'ho visto subito perchè è veramente facilissimo:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim parola As String = "parola.12324"
        MsgBox(Numero(parola))


    End Sub
    
    Function Numero(ByVal stringa) As Integer
        Dim s As String = stringa.Substring(stringa.Length - (stringa.Length - stringa.IndexOf(".") - 1))
        Dim n As Integer = CInt(s)
        Return n
    End Function

Simulazione di matrici di controlli: un'idea

Una delle cose che più mi ha sconvolto del nuovo ambiente di programmazione è che non è più possibile creare matrici di controlli!
Pare che non solo io, ma anche fior di programmatori professionisti si siano trovati in difficoltà per questo.
Uno degli artifizi che ho trovato spulciando alla ricerca di soluzioni al problema è quello di apporre alla proprietà Name del controllo un numero, in modo da usarlo come indice di una matrice di controlli.
Posso sperimentare sullo scheletro del mio programma qualcosa del genere...

Per intanto, diamo un Nome ai controlli che ho creato.
    Sub disponiCaselle(Of T As New)(ByVal nome As String, ByVal larghezza As Integer, ByVal sinistra As Integer)
        Dim numero As Integer
        numero = DateTime.DaysInMonth(anno, mese)
        Dim cas As Object
        For n = 0 To numero - 1
            cas = New T
            With cas
                .Name = nome & n + 1
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = larghezza
                .Left = sinistra
                .Top = .Height * (n Mod numero)
                .testo = .Name 'GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
                .Scrivi()
            End With
            Me.Controls.Add(cas)
        Next
    End Sub
Sì, ecco. Per fare la prova ho fatto in modo che la proprietà testo di ogni elemento fosse la sua proprietà Name, "commentizzando" il codice che c'era prima per non perderlo.



Ora sto pensando di creare per ciascuna classe una proprietà Index nella quale porre il numero ricavato dalla proprietà Name con un artifizio di manipolazione delle stringhe.
In questo modo, posso far riferimento a ogni elemento con il suo indice, un po' come nel buon (neanche tanto!) vecchio VB6...

Creazione immediata di altre colonne

A questo punto mi bastano pochissimi secondi per creare una nuova colonna giocando liberamente sulle larghezze delle varie colonne. Basta aggiungere un altro elemento alla matrice larghezze, della larghezza voluta, e chiamare un'altra volta il metodo disponiCaselle con il numero del successivo elemento della matrice:
....
    Dim larghezze As Integer() = {150, 100, 100}
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        disponiCaselle(Of Calendario)(larghezze(0), SommaElementiDiArray(larghezze, 0))
        disponiCaselle(Of Casella)(larghezze(1), SommaElementiDiArray(larghezze, 1))
        disponiCaselle(Of Casella)(larghezze(2), SommaElementiDiArray(larghezze, 2))
....
Ed ecco:



Facilissimo!

Creazione di classi derivate, funzioni template e prima realizzazione del calendario.

Ora mi devo cimentare a creare dei derivati di Label, funzione specifica di VB.NET che VB6 si sognava beatamente.
Ereditarietà!!!

Class Casella
    Inherits Label

End Class
Bene.
Praticamente a questo punto si chiama casella ma è praticamente ancora una Label.
Sostituisco Casella a Label nel codice.
    Sub disponiCaselle(ByVal larghezza As Integer, ByVal sinistra As Integer)
        Dim numero As Integer
        numero = DateTime.DaysInMonth(anno, mese)
        Dim cas As Casella
        For n = 0 To numero - 1
            cas = New Casella
            With cas
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = larghezza
                .Left = sinistra
                .Top = .Height * (n Mod numero)
                .Text = GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
            End With
            Me.Controls.Add(cas)
        Next
    End Sub
E ovviamente funziona ancora.

E' possibile aggiungervi delle proprietà?

Provo...

Ecco la mia caselluccia: forte di esperienze già fatte, ho fatto in modo che il codice dapprima imposti la sua proprietà pubblica testo, quindi inneschi il suo metodo Scrivi per fare apparire sulla casella il testo.
Class Casella
    Inherits Label
    Public testo As String
    Sub Scrivi()
        Text = testo
    End Sub
End Class
Ed ecco il codice che la usa:
    Sub disponiCaselle(ByVal larghezza As Integer, ByVal sinistra As Integer)
        Dim numero As Integer
        numero = DateTime.DaysInMonth(anno, mese)
        Dim cas As Casella
        For n = 0 To numero - 1
            cas = New Casella
            With cas
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = larghezza
                .Left = sinistra
                .Top = .Height * (n Mod numero)
                .testo = GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
                .Scrivi()
            End With
            Me.Controls.Add(cas)
        Next
    End Sub


Bene. Adesso voglio fare in modo che sia in qualche modo "passato come parametro" anche il tipo di controllo sul quale deve agire la subroutine disponicaselle.
Ricordo che si deve usare una funzione template o generica, con la parola chiave Of.
Ricordiamo...

In pratica, mi serve una subroutine che agisca con diverse classi di oggetti, in quanto devo poterla usare con una classe o con una classe derivata della prima...

Ecco rinfrescata la memoria.
Si deve mettere As New dopo la Of seguita dalla variabile, e bisogna dichiarare la variabile oggetto As Object.
Ecco:
    Sub disponiCaselle(Of T As New)(ByVal larghezza As Integer, ByVal sinistra As Integer)
        Dim numero As Integer
        numero = DateTime.DaysInMonth(anno, mese)
        Dim cas As Object
        For n = 0 To numero - 1
            cas = New T
Ora posso creare una sottoclasse di Label per la seconda colonna...
Ecco i due oggetti.
Ho creato prima Casella, destinato ad apparire sulla seconda e su eventuali altre colonne con sfondo bianco, successivamente Calendario, destinato ad apparire sulla prima colonna con le date scritte sopra.
Nella prima ho una proprietà testo e un metodo Scrivi che non fa assolutamente nulla (in modo che quando il codice li chiami non generi un errore in quanto inesistenti); il metodo Scrivi viene overridato nella classe derivata Calendario con un metodo Scrivi che invece scrive il valore della proprietà testo.
Class Casella
    Inherits Label
    Public testo As String
    Overridable Sub Scrivi()
    End Sub
End Class

Class Calendario
    Inherits Casella
    Overrides Sub Scrivi()
        Text = testo
    End Sub
End Class
la proprietà testo non viene specificata nella classe derivata Calendario in quanto già presente nella classe genitrice e quindi ereditata.

Ed ecco il codice che chiama per due volte la funzione disponiCaselle, l'una per la classe Calendario, prima colonna, e l'altra per la classe Casella, seconda colonna.
        disponiCaselle(Of Calendario)(larghezze(0), SommaElementiDiArray(larghezze, 0))
        disponiCaselle(Of Casella)(larghezze(1), SommaElementiDiArray(larghezze, 1))
Il risultato è perfetto:

Uso della funzione che somma gli elementi di una matrice

Ed ecco come ho impiegato la mia funzione che somma gli elementi di un array:
Public Class Form1
    Dim mese As Integer = 9
    Dim anno As Integer = 2012
    Dim larghezze As Integer() = {300, 100}
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        disponiCaselle(larghezze(0), SommaElementiDiArray(larghezze, 0))
        disponiCaselle(larghezze(1), SommaElementiDiArray(larghezze, 1))
    End Sub
    Sub disponiCaselle(ByVal larghezza As Integer, ByVal sinistra As Integer)
        Dim numero As Integer
        numero = DateTime.DaysInMonth(anno, mese)
        Dim casella As Label
        For n = 0 To numero - 1
            casella = New Label
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = larghezza
                .Left = sinistra
                .Top = .Height * (n Mod numero)
                .Text = GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
            End With
            Me.Controls.Add(casella)
        Next
    End Sub
End Class
Ho isolato il codice che dispone le caselle in colonna nella subroutine disponicaselle, in modo da poterla richiamare più volte.
Quindi do alla routine due parametri, uno per la larghezza della colonna e uno per la posizione sinistra della colonna.
Ponendo in una matrice le larghezze predeterminate per ciascuna colonna, dalla prima all'ultima, faccio in modo che il primo parametro della subroutine sia il numero dell'elemento della matrice che contiene la larghezza della colonna, e il secondo parametro sia la somma delle larghezze delle colonne precedenti.
Funziona.
In questo modo posso predeterminare le larghezze delle varie colonne semplicemente modificando i valori della matrice larghezze, senza impazzire più di tanto.

Una funzione per sommare elementi di una matrice

Una funzioncina per sommare gli elementi di una matrice.
Mi serve per un'ulteriore evoluzione del mio progetto:

    Function SommaElementiDiArray(ByVal matrice As Integer(), ByVal num As Integer) As Integer
        Dim numero As Integer
        For n = 0 To num - 1
            numero += matrice(n)
        Next
        Return numero
    End Function
L'ho inserita nel modulo Funzioni.vb, e viene richiamata dal codice del Form1 in questo modo, usando un array larghezze:
        Debug.Print(SommaElementiDiArray(larghezze, 1))
si tratta di una prova con la quale faccio stampare il risultato nella finestra immediata. Il primo parametro esprime il nome della matrice, mentre il secondo è l'elemento della matrice prima del quale gli elementi vengono sommati.
La matrice con cui ho fatto la prova è questa:
    Dim larghezze As Integer() = {150, 100, 100}
e con il numero 1 come secondo parametro, ottengo la somma del solo elemento 0 della matrice, ossia 150:
150


Se come parametro metto il 2, invece, ottengo come risultato la somma dell'elemento 0 e dell'elemento 1 della matrice:
        Debug.Print(SommaElementiDiArray(larghezze, 2))
250
Mi servirà per un certo progetto che ho in mente...

Aggiunta del giorno della settimana

Aggiunngo il giorno della settimana.
Per fare questo ho dovuto aumentare la larghezza delle mie caselle rispetto a quella standard predeterminata.
Dim mese As Integer = 9
    Dim anno As Integer = 2012
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Calcolo del numero dei giorni del mese
        Dim numero As Integer

        numero = DateTime.DaysInMonth(anno, mese)



        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = 200
                .Left = 0
                .Top = .Height * (n Mod numero)
                .Text = WeekdayName(Weekday(CDate(n + 1 & "/" & mese & "/" & anno)), , 1) & " " & CDate(n + 1 & "/" & mese & "/" & anno)
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
Ma forse potrei inserire tutto quel po' po' di codice in una funzione usando come parametro la data.
Vediamo di ingegnarci.
Dim mese As Integer = 9
    Dim anno As Integer = 2012
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Calcolo del numero dei giorni del mese
        Dim numero As Integer

        numero = DateTime.DaysInMonth(anno, mese)

        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = 200
                .Left = 0
                .Top = .Height * (n Mod numero)
                .Text = GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
    Function GiornoDellaSettimana(ByVal d As Date) As String
        Dim testo As String = WeekdayName(Weekday(d), , 1) & " " & d
        Return testo
    End Function


Questa funzione posso toglierla di qua per non appesantire il codice del form e metterla in un modulo a parte, magari da dedicare ad altre eventuali funzioni.
(Tolgo i commenti per evitare la scocciatura di rimarcarli in verde ogni volta)

Codice del Form (ci aggiungo anche la definizione della classe Form1):
Public Class Form1
    Dim mese As Integer = 9
    Dim anno As Integer = 2012
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim numero As Integer

        numero = DateTime.DaysInMonth(anno, mese)


        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label

            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Width = 200
                .Left = 0
                .Top = .Height * (n Mod numero)
                .Text = GiornoDellaSettimana(CDate(n + 1 & "/" & mese & "/" & anno))
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
End Class


Codice del modulo Funzioni.vb:
Module Funzioni
    Function GiornoDellaSettimana(ByVal d As Date) As String
        Dim testo As String = WeekdayName(Weekday(d), , 1) & " " & d
        Return testo
    End Function
End Module
E funziona ugualmente, perchè la funzione del modulo è pubblica e quindi viene "vista" dal codice del Form1.

Date come testi delle caselle del calendario

Ora riempiamo le caselle con tutte le date. Prendo il numero n di ordine delle caselle e ci aggiungo 1 dato che inizia con 0 e termina con numero-1, e lo uso come numero del giorno del mese nel contesto della data.
Dichiaro una variabile mese e una anno di tipo integer in modo da poter poi cambiare la definizione del mese e dell'anno in rapporto alle esigenze del programma.
    Dim mese As Integer = 9
    Dim anno As Integer = 2012
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Calcolo del numero dei giorni del mese
        Dim numero As Integer

        numero = DateTime.DaysInMonth(anno, mese)



        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .BackColor = Color.White
                .Left = 0
                .Top = .Height * (n Mod numero)
                .Text = CDate(n + 1 & "/" & mese & "/" & anno)
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
ed ottengo il risultato voluto.

martedì 11 settembre 2012

Calcolo del numero dei giorni del mese

Ecco riscritto il codice che calcola il numero dei giorni del mese.
Mi chiedo se esista un modo più breve per ottenere il numero dei giorni di un mese.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Calcolo del numero dei giorni del mese
        Dim dat, base As Date
        Dim numero As Integer = 1
        Dim mese As Integer = Now.Month
        dat = CDate("1/" & Now.Month & "/" & Now.Year)
        base = dat
        Do
            dat = dat.AddDays(1)
            If dat.Month <> base.Month Then Exit Do
            numero += 1
        Loop



        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = .Height * (n Mod numero)
            End With
            Me.Controls.Add(casella)

        Next
    End Sub


Funziona, ma mi chiedo se esista un metodo in VB.NET che mi possa evitare di fare tutto questo casino...

Ho trovato qualcosina. Ora provo...

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Calcolo del numero dei giorni del mese
        Dim numero As Integer
        numero = DateTime.DaysInMonth(2012, 2)



        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = .Height * (n Mod numero)
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
Funziona! Ed è molto più breve!!!
(ho provato con febbraio perchè si distingue dagli altri, e quest'anno è pure bisestile!)

Disposizione di elementi in colonna

Riparto da zero.
Ho bisogno di tante labels che vengano messe in colonna, ognuna delle quali rechi la data di un giorno del mese, dal primo all'ultimo giorno.
Inizio con un numero arbitrario 10
 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'numero delle caselle
        Dim numero As Integer = 10
        'definizione della variabile oggetto
        Dim casella As Label

        For n = 0 To numero - 1
            casella = New Label
            'attribuzione delle proprietà alla label appena istanziata
            With casella
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = .Height * (n Mod numero)
            End With
            Me.Controls.Add(casella)

        Next
    End Sub
Usare il Modulo è ingegnoso.
0/numero dà come resto 0, 1/numero dà come resto 1, 2/numero dè come resto 2, fino a (numero-1)/numero chè dà come resto numero-1.
Per ogni dividendo minore del divisore, l'operazione dà come resto il dividendo stesso. Quindi moltiplicando l'altezza dell'elemento per il resto della divisione fra il numero d'ordine dell'elemento e il numero degli elementi meno uno, e impostando la posizione verticale dell'elemento a questo numero, si ha che il primo elemento è alla posizione altezza x 0, ossia zero, il secondo a altezza x 1, il secondo a altezza x 2 fino all'ultimo, in cui la posizione è altezza x (numero-1).

giovedì 30 agosto 2012

Soluzione per il fatto che la procedura template accetta solo il costruttore di default

Bene... per i miei scopi, non devo fare in modo che il testo della mia casella venga definito nel costruttore, perchè la creazione della nuova istanza, e quindi la chiamata del costruttore, è immediata, e definendo nell'ambito del costruttore che il testo debba essere uguale alla proprietà Dati, questa proprietà è ancora pari a una stringa vuota, in quanto la procedura template la "riempie" dopo che l'istanza è stata creata, e quindi solo dopo che il costruttore è entrato in azione.

Lascio quindi il costruttore di default sottinteso (ossia non specifico costruttori nella classe), e creo un metodo che viene chiamato dopo.
Ci provo...Creo due classi, la prima "casella" che eredita da Label, la seconda "calendario", in cui voglio che il testo rispecchi il valore della proprietà Dati, che eredita da "casella".
Class casella
    Inherits Label
    Protected Dati As Date
    Sub New()
        BorderStyle = BorderStyle.FixedSingle
    End Sub
    Overridable Sub scriviDati(ByVal dato As String)
        Dati = dato
    End Sub
End Class

Class calendario
    Inherits casella
    Overrides Sub scrividati(ByVal dato As String)
        Dati = dato
        Text = Dati
    End Sub
End Class
Il metodo scriviDati è overridable, in modo che nella classe genitrice compila solo il valore della proprietà, mentre nella classe derivata compila anche il testo con il valore della proprietà.

Ecco la procedura template:
    Sub popola(Of oggetto As New)(ByVal frm As Form, ByVal dt As Object)
        Dim obj As Object
        For n = 0 To dt.Length - 1
            obj = New oggetto
            With obj
                .left = 0
                .top = obj.height * (n Mod dt.Length)
                .scriviDati(dt(n))

            End With
            frm.Controls.Add(obj)
        Next
    End Sub
...che esegue sempre la funzione scriviDati, la quale, se il tipo di oggetto fornito alla procedura template è "casella" compila soltanto il valore della proprietà Dati, mentre se il tipo di oggetto fornito alla procedura template è "calendario", fa apparire anche questo valore come testo.

Funziona!

Mi sbizzarrisco un po', traendo le conclusioni logiche più tardi...
Class casella
    Inherits Label
    Protected Dati As Date
    Sub New()
        BorderStyle = BorderStyle.FixedSingle
    End Sub
    Overridable Sub scriviDati(ByVal dato As String)
        Dati = dato
    End Sub
End Class

Class calendario
    Inherits casella
    Sub New()
        BorderStyle = BorderStyle.Fixed3D
        BackColor = Color.Green
    End Sub
    Overrides Sub scrividati(ByVal dato As String)
        Dati = dato
        Text = Dati
    End Sub
End Class
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        popola(Of calendario)(0, Me, giorniDelMese(8, 2012))
        popola(Of casella)(100, Me, giorniDelMese(8, 2012))
    End Sub
    Sub popola(Of oggetto As New)(ByVal sinistra As Integer, ByVal frm As Form, ByVal dt As Object)
        Dim obj As Object
        For n = 0 To dt.Length - 1

            obj = New oggetto
            With obj
                .left = sinistra
                .top = obj.height * (n Mod dt.Length)
                .scriviDati(dt(n))

            End With
            frm.Controls.Add(obj)
        Next
    End Sub
Ed ecco cosa ottengo:

Procedure template che usano costruttori non di default?... Boh?

Adesso utilizzo una procedura template per istanziare un oggetto di classe classe derivata da Label
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        procedura(Of classe)()
    End Sub
    Sub procedura(Of T As New)()
        Dim a As Object
        a = New T
        Me.Controls.Add(a)
        a.Left = 0
    End Sub
All'evento Load del form viene chiamata la procedura template (chiamata, con molta fantasia, procedura), che usa il costruttore di default, e la cosa funziona: ottengo un'etichetta rossa a left=0.
Ora vediamo se è possibile usare il secondo costruttore...

Credo che sia impossibile! Ho googlato come un matto ma sembra che le procedure generiche, o template, non possano chiamare se non il costruttore di default...

Preparazione alla creazione di una procedura template che istanzi una classe con più costruttori

Voglio costruire una procedura template fatta bene, che utilizzi più costruttori di una classe.
Creo un nuovo programmino di sana pianta per esercitarmi...

Costruisco una classe che eredita da Label:
Class classe
    Inherits Label
    Sub New()
        BackColor = Color.Red
    End Sub
    Sub New(ByVal stringa As String)
        BackColor = Color.Cyan
    End Sub
End Class
Questa classe possiede due costruttori (overloading dei costruttori, ricordiamo dal C++): uno senza parametri, che dà alla casella un colore rosso, e uno con un parametro stringa che dà alla casella un colore celeste.
Istanzio la classe con i due costruttori e aggiungo i controlli al Form, con una diversa proprietà left perchè non si sovrappongano:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim cl As Object

        cl = New classe()
        Me.Controls.Add(cl)
        cl.left = 0

        cl = New classe("uh")
        Me.Controls.Add(cl)
        cl.left = 300
    End Sub
Funziona perfettamente: ottengo due etichette una di colore rosso a left=0 e una di color celeste a left=300. E finora, bene. Non ho usato alcuna funzione template...

mercoledì 29 agosto 2012

Uso della procedura template per creare un calendario

Ora posso creare un calendario, con una serie di labels in colonna, che mostrino la data.
Torno a usare la procedura template (speriamo di ricordare come si fa)...
La metto nel modulo Funzioni:
    Sub popola(Of oggetto)(ByVal frm As Form)
        Dim obj As Object
        For n = 0 To giorniDelMese(8, 2012).Length - 1
            obj = New Label
            With obj
                .left = 0
                .top = obj.height * (n Mod giorniDelMese(8, 2012).Length)
                .borderstyle = BorderStyle.FixedSingle
                .text = giorniDelMese(8, 2012)(n)
            End With
            frm.Controls.Add(obj)
        Next
    End Sub
Sì! Sono riuscito a creare a memoria una procedura template, che popola il form di labels in quanto specificato nella chiamata della procedura:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        popola(Of Label)(Me)
    End Sub
Ecco un pezzetto di calendario

...Che non è vero niente!
Mi rendo conto a posteriori che la procedura template non è stata costruita bene e il fatto che funzioni è illusorio!

Una miglioria del codice precedente, con una funzione che restituisce una matrice come risultato.

Che idiota! Ma era proprio necessario creare una matrice e poi una procedura che la compili?
Molto più intelligente creare una funzione che dia come risultato una matrice di date prendendo sempre come parametri il mese e l'anno.
Eccola:
Module Funzioni
    Function giorniDelMese(ByVal mese As Integer, ByVal anno As Integer) As Date()
        Dim data As Date = CDate("01/" & mese & "/" & anno)
        Dim dataStart As Date = data
        Dim contatore As Integer = 0
        Dim matrice As Date()
        Do
            ReDim Preserve matrice(contatore)
            matrice(contatore) = data
            data = data.AddDays(1)
            If data.Month <> dataStart.Month Then Exit Do
            contatore += 1
        Loop
        Return matrice
    End Function
End Module
...e chiamarla dal form iniziale in questo modo:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To giorniDelMese(8, 2012).Length - 1
            Debug.Print(giorniDelMese(8, 2012)(n))
        Next
    End Sub
...ottenendo il medesimo risultato:
01/08/2012
02/08/2012
03/08/2012
04/08/2012
05/08/2012
06/08/2012
07/08/2012
08/08/2012
09/08/2012
10/08/2012
11/08/2012
12/08/2012
13/08/2012
14/08/2012
15/08/2012
16/08/2012
17/08/2012
18/08/2012
19/08/2012
20/08/2012
21/08/2012
22/08/2012
23/08/2012
24/08/2012
25/08/2012
26/08/2012
27/08/2012
28/08/2012
29/08/2012
30/08/2012
31/08/2012
Perfetto!

Una matrice con i giorni del mese e la procedura per compilarla

Ora mi serve una procedura (ossia un metodo) che mi compili un array di date con tutti i giorni di un mese.
La metto in un modulo. Potrei provare ad "esporre" l'array come proprietà del modulo stesso...
Rimetto in pratica i concetti che ho elaborato recentemente...
Module Funzioni
    Public giorniDelMese As Date()
    Sub compilaMese(ByVal mese As Integer, ByVal anno As Integer)
        Dim data As Date = CDate("01/" & mese & "/" & anno)
        Dim dataStart As Date = data
        Dim contatore As Integer = 0
        Do
            ReDim Preserve giorniDelMese(contatore)
            giorniDelMese(contatore) = data
            data = data.AddDays(1)
            If data.Month <> dataStart.Month Then Exit Do
            contatore += 1
        Loop
    End Sub
End Module
Questa procedura compila la matrice giorniDelMese che è una proprietà del modulo Funzioni
Ora uso questa procedura dal form di inizio, dall'evento Load del form:
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        compilaMese(8, 2012)
        For n = 0 To giorniDelMese.Length - 1
            Debug.Print(giorniDelMese(n))
        Next
    End Sub
Questo codice dovrebbe scrivermi sulla finestra immediata tutte le date del mese di agosto del 2012 (che la procedura compilaMese del modulo Funzioni accetta come parametri).
Ecco copiato e incollato il contenuto della finestra di debug dopo l'esecuzione del programma:
01/08/2012
02/08/2012
03/08/2012
04/08/2012
05/08/2012
06/08/2012
07/08/2012
08/08/2012
09/08/2012
10/08/2012
11/08/2012
12/08/2012
13/08/2012
14/08/2012
15/08/2012
16/08/2012
17/08/2012
18/08/2012
19/08/2012
20/08/2012
21/08/2012
22/08/2012
23/08/2012
24/08/2012
25/08/2012
26/08/2012
27/08/2012
28/08/2012
29/08/2012
30/08/2012
31/08/2012


Riuscito!

Definizione di una variabile del tipo base e sua istanziazione del tipo derivato

Mi annoto qui il metodo template che ho imparato a creare in VB.NET
Module Funzioni
    Sub popola(Of T As New)(ByVal frm As Form, ByVal sinistra As Integer, ByVal alto As Integer, ByVal numero As Integer)
        Dim ogg As Object
        For n = 1 To numero
            ogg = New T
            With ogg
                .left = sinistra
                .top = alto + .height * (n Mod numero)
                If ogg.GetType().Name = "casella" Then .backcolor = Color.Cyan
            End With
            frm.Controls.Add(ogg)
        Next
    End Sub
End Module
Bene. Ricordo una regola del C++, secondo la quale un puntatore si può definire di un tipo e si può istanziare di un tipo derivato... o qualcosa del genere.
Proviamo qualcosa del genere in VB.

Creo una classe casella che eredita da Label
Class casella
    Inherits Label
    Sub New()
        Text = "Ciao, ciccio"
        BorderStyle = Windows.Forms.BorderStyle.FixedSingle
    End Sub
End Class
Nel suo costruttore, questa classe inizializza il testo della casella e lo stile del bordo.
Quindi definisco la variabile come Label e la istanzio come casella
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim a As Label
        a = New casella
        Me.Controls.Add(a)

End Sub
E funziona. Ecco il risultato, in cui al form viene aggiunta una casella con le proprietà Text e BorderStyle inizializzate secondo le direttive del costruttore:



Dunque questa regola vale anche in vb.
Devo rivederla compiutamente in C++ perchè ne ho una reminiscenza un po' vaga...

domenica 19 agosto 2012

Primo tentativo riuscito di accesso al filesystem con VB.NET

Ecco anche i primi rudimenti di esplorazione del filesystem mediante VB.NET: Cerco tutti i files che stanno in una determinata directory e li stampo nella finestra di debug.
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For Each fl In My.Computer.FileSystem.GetFiles("c:\users\antonello\desktop")
            Debug.Print(CType(fl, String))
        Next
    End Sub

End Class
Risultato:
c:\users\antonello\Desktop\BUDINO (2).jpg
c:\users\antonello\Desktop\BUDINO.jpg
c:\users\antonello\Desktop\budino.wav
c:\users\antonello\Desktop\codice di registrazione di vb express.txt
c:\users\antonello\Desktop\converti.exe
c:\users\antonello\Desktop\desktop.ini
c:\users\antonello\Desktop\dest.txt
c:\users\antonello\Desktop\div.js
c:\users\antonello\Desktop\FLV Player.lnk
c:\users\antonello\Desktop\img012.jpg
c:\users\antonello\Desktop\lab.html
c:\users\antonello\Desktop\lecca lecca.jpg
c:\users\antonello\Desktop\lecca lecca.wav
c:\users\antonello\Desktop\Microsoft Office Word 2003.lnk
c:\users\antonello\Desktop\Microsoft Visual Basic 2010 Express.lnk
c:\users\antonello\Desktop\NomeDelFile.jac
c:\users\antonello\Desktop\pagina.html
c:\users\antonello\Desktop\succo con la cannuccia.jpg
c:\users\antonello\Desktop\succo con la cannuccia.wav
c:\users\antonello\Desktop\succo di frutta.bmp
c:\users\antonello\Desktop\succo di frutta.wav
c:\users\antonello\Desktop\testo.czz
Che sono tutti i files che stanno in desktop (i nomi strani sono files fatti per i bambini)

Creare un file con VB.NET

Creare un file con un'estensione qualunque, e salvarlo in desktop

Si dichiara una variabile come FileStream.
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream

    End Sub

End Class
Si dichiara una matrice di Bytes:
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte

    End Sub

End Class
In questa matrice si raccolgono i bytes corrispondenti a una stringa, o a qualunque altra cosa:
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")

    End Sub

End Class
Si inizializza la variabile di tipo FileStream, con il nome del file e la parola FileMode, che dovrebbe essere la modalità di scrittura, che vedrò in seguito
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")
        fs = New FileStream("C:\users\antonello\desktop\NomeDelFile.jac", FileMode.Append)
    End Sub

End Class
Si scrive sul file. con il metodo Write dell'oggetto FileStream, specificando la matrice da cui attingere i dati, l'offset e la quantità di bytes da scrivere.
Quindi si chiude il FileStream
Imports System.IO
Imports System.Text
Public Class Form1
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As FileStream
        Dim dati() As Byte
        dati = Encoding.ASCII.GetBytes("Questa è una stringa")
        fs = New FileStream("C:\users\antonello\desktop\NomeDelFile.jac", FileMode.Append)
        fs.Write(dati, 0, dati.Length)
        fs.Close()
    End Sub

End Class


Facciamo partire il codice e vediamo se funziona.

Funziona! Ho in desktop un nuovo file chiamato NomeDelFile.jac.
L'unica cosa strana è che nel testo non mi ha riconosciuto la "è" e me l'ha sostituita con un punto interrogativo. Credo che sia un problema relativo a Encoding, da affrontare successivamente.

sabato 18 agosto 2012

Maneggiare files con VB.NET, primi approcci

E adesso, vogliamo vedere come si può fare a salvare e aprire files di testo in VB.NET?

Ho trovato un codice e l'ho riprodotto a modo mio
Public Class Form2

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim fs As System.IO.FileStream
        Dim byteData As Byte()
        byteData = System.Text.Encoding.ASCII.GetBytes("Antonello")
        fs = New System.IO.FileStream("C:\users\antonello\desktop\testo.czz", IO.FileMode.Append)
        fs.Write(byteData, 0, byteData.Length)
        fs.Close()


    End Sub
End Class
Questo può servire per salvare i files della mia applicazione.

mercoledì 15 agosto 2012

Passare come parametro una istanza di una struttura

Una routine da usare innumerevoli volte per definire diverse proprietà di diverse labels. Bene, ma dato che le proprietà sono tante, è scomodo passarle una per una come parametri: ci troviamo poi con una routine avente innumerevoli parametri.
Ecco invece come l'uso delle strutture può risolvere egregiamente il problema, anzi è l'unica soluzione possibile.
Si istanzia diverse volte, con diversi valori, la struttura avente per membri le varie proprietà delle labels, e quindi si passa alla routine come parametro una diversa istanza della struttura a seconda della "combinazione" di proprietà da dare alla label.
Public Class Form1
    Structure Struttura
        Dim colore As Color
        Dim altezza As Integer
    End Structure
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim lblStruc As Struttura
        lblStruc.altezza = 500
        lblStruc.colore = Color.Cyan

        Dim lblstruc2 As Struttura
        With lblstruc2
            .altezza = 300
            .colore = Color.Red
        End With

        routine(Label1, lblStruc)
        routine(Label2, lblstruc2)
    End Sub
    Sub routine(ByRef casella As Label, ByVal strut As Struttura)
        With casella
            .BackColor = strut.colore
            .Height = strut.altezza
        End With
    End Sub
End Class
E funziona egregiamente!!!

Drag drop con più controlli

Ecco come un singolo evento può essere usato per più controlli grazie alla flessibilità degli eventi in VB.NET.
Ho aggiunto un'altra label destinazione, e mi è bastato rimaneggiare un paio di eventi per ottenere lo stesso comportamento della label già presente.

Public Class Form1
    Private Sub evento(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles lblMario.MouseDown, lblPippo.MouseDown, lblCiccio.MouseDown
        sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
    End Sub

    Private Sub Label1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragDrop
        Label1.Text = e.Data.GetData(DataFormats.Text)
    End Sub

    Private Sub Label1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragEnter
        e.Effect = DragDropEffects.Copy
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub
End Class

Primo tentativo riuscito di drag drop in VB.NET

Facciamo dei passi graduali per riuscire a creare un codice decente per il drag-drop.
Ho bisogno di diverse labels che trascinate su un'altra label ne modifichino il testo con il loro proprio testo.

Ecco il form. Trascinando ognuna delle labels con scritti i nomi sulla label bianca, in questa deve apparire il nome della label trascinata.



Ecco il codice:
Public Class Form1

    
    Private Sub evento(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles lblMario.MouseDown, lblPippo.MouseDown, lblCiccio.MouseDown
        sender.DoDragDrop(sender.Text, DragDropEffects.Copy)
    End Sub

    Private Sub Label1_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragDrop
        Label1.Text = e.Data.GetData(DataFormats.Text)
    End Sub

    Private Sub Label1_DragEnter(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Label1.DragEnter
        e.Effect = DragDropEffects.Copy
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    End Sub
End Class
E funziona.

domenica 12 agosto 2012

Adattamento delle labels alle dimensioni del form

Ora ho alcuni problemi...
Devo adattare l'altezza delle labels alle dimensioni del form.
Questo è il codice che ho trovato.
Non mi piace molto, perchè ho dovuto togliere una fetta arbitraria all'altezza del form per evitare che l'ultima label fosse "spezzata"... ci deve essere qualcosa che non torna... forse è perchè il risultato del rapporto fra l'altezza dell'area client del form e il numero di labels restituisce cifre decimali.
Public Class Form1
    Dim lblMorning, lblAfternoon, lblNight As ArrayList

    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        lblNight(13).backcolor = Color.Red
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lblMorning = New ArrayList
        lblAfternoon = New ArrayList
        lblNight = New ArrayList
        Dim numero, vertSpace, horSpace As Integer
        numero = 31
        vertSpace = 0
        horSpace = 2
        popola(0, numero, vertSpace, horSpace, lblMorning)
        popola(1, numero, vertSpace, horSpace, lblAfternoon)
        popola(2, numero, vertSpace, horSpace, lblNight)

    End Sub
    Sub popola(ByVal ordine, ByVal numero, ByVal vertSpace, ByVal horSpace, ByVal lblArray)
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .Text = n + 1
                .Height = (Me.ClientSize.Height - 50) / (numero - 1)
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = (.Width + horSpace) * ordine
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            lblArray.add(etichetta)
        Next
    End Sub
End Class
C'è sempre l'evento sentinella, che a questo punto potrei anche togliere perchè è assodato che la creazione di matrici mediante gli oggetti ArrayList funziona egregiamente.

Popolando un form di Labels per i turni di mattina, pomeriggio e notte.

Ecco il codice, compreso l'"evento test" che cambia colore a una label a scelta, per verificare che funzionino i riferimenti a una specifica label dell'array
Public Class Form1
    Dim lblMorning, lblAfternoon, lblNight As ArrayList

    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        lblNight(13).backcolor = Color.Red
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lblMorning = New ArrayList
        lblAfternoon = New ArrayList
        lblNight = New ArrayList
        Dim numero, vertSpace, horSpace As Integer
        numero = 20
        vertSpace = 2
        horSpace = 2
        popola(0, numero, vertSpace, horSpace, lblMorning)
        popola(1, numero, vertSpace, horSpace, lblAfternoon)
        popola(2, numero, vertSpace, horSpace, lblNight)
    End Sub
    Sub popola(ByVal ordine, ByVal numero, ByVal vertSpace, ByVal horSpace, ByVal lblArray)
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = (.Width + horSpace) * ordine
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            lblArray.add(etichetta)
        Next

    End Sub
End Class
Il codice funziona bene, come previsto.
Ci ho aggiunto anche lo spazio orizzontale fra le diverse colonne.
Ogni colonna viene memorizzata in una matrice ArrayList, in modo da mantenerne i riferimenti.

Popolando il form di un array di labels

Ecco il codice per aggiungere a un form, in runtime, una serie di labels, di numero variabile e con una spaziatura regolabile impostando una semplice variabile.
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim numero, vertSpace As Integer
        numero = 10
        vertSpace = 5
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
        Next
    End Sub
End Class
E funziona alla grande!
Non ho ancora raccolto le etichette in una ArrayList, che permetterà di fare riferimento a ogni singolo elemento della matrice.

Ho anche creato l'arraylist, insieme con l'evento che mi permette di vedere se il riferimento all'elemento funziona.
Public Class Form1
    Dim Etichette As ArrayList
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Etichette(2).backcolor = Color.Yellow
    End Sub
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Etichette = New ArrayList
        Dim numero, vertSpace As Integer
        numero = 10
        vertSpace = 2
        Dim etichetta As Label
        For n = 0 To numero
            etichetta = New Label
            With etichetta
                .BackColor = Color.White
                .BorderStyle = BorderStyle.FixedSingle
                .Left = 0
                .Top = (etichetta.Height + vertSpace) * (n Mod numero)
            End With
            Me.Controls.Add(etichetta)
            Etichette.Add(etichetta)
        Next
    End Sub
End Class
E funziona!

Problemi e nuove tecniche per creare matrici di controlli in VB.NET, ragionamenti...

Non comprendo la natura dell'errore la cui segnalazione ottengo dal codice che ho ideato prima. Non ricordo la dizione esatta della segnalazione di errore, ma è senz'altro un errore relativo al modo poco ortodosso di creare matrici di controlli che ho usato, in quanto richiama il riferimento a un oggetto assente.

Ho trovato un altro modo di aggiungere controlli a un form.
Ho ricopiato il codice sfrondandolo di alcune righe che devo ancora comprendere, e non ottengo alcuna segnalazione di errori. Il problema, però, è che una volta aggiunti i controlli non ho più alcun riferimento ai singoli elementi. Non ho creato un vero e proprio array, o matrice che dir si voglia, perchè una volta che l'identificatore è stato attribuito a un nuovo controllo, si perde il riferimento a quello precedente.
Il codice è questo:
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim LV As Integer
        Dim Btn As Button
        For LV = 0 To 49
            Btn = New Button
            Btn.Left = Btn.Width * (LV Mod 10)
            Btn.Top = Btn.Height * (LV \ 10)
            Btn.Text = "???"
            Me.Controls.Add(Btn)
        Next
    End Sub
End Class
e funziona egregiamente.

L'unico problema è che ho perso i riferimenti.

Ossia, se voglio richiamare un bottone dell'insieme di quelli aggiunti al form non ho nessun "appiglio" con il quale chiemarlo. Sono tutti bottoni"senza nome".
Vediamo come si risolve la cosa...

In realtà, una delle righe che ho cancellato è questa marcata in rosso:
Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim LV As Integer
        Dim Btn As Button
        For LV = 0 To 49
            Btn = New Button
            Btn.Left = Btn.Width * (LV Mod 10)
            Btn.Top = Btn.Height * (LV \ 10)
            Btn.Text = "???"
            Me.Controls.Add(Btn)
            Buttons.Add(Btn)            
        Next
    End Sub
End Class
Se lascio questa riga nel mio IDE, ottengo una segnalazione di errore:
Errore 1 'Buttons' non dichiarato. Non è accessibile a causa del livello di protezione. 
...perchè nell'esempio in rete questo Buttons è un array.
Vediamo il codice usato per crearlo...
Friend Buttons As ArrayList
Buttons = New ArrayList
L'oggetto ArrayLiet viene dichiarato e poi istanziato.
Non mi è chiaro ancora perchè Friend...

Comunque, poi, mentre vengono aggiunti gli elementi al Form, ogni elemento viene aggiunto all'ArrayList chiamata Buttons.
In tal modo si può fare probabilmente riferimento al singolo elemento della matrice.
E infatti ho scritto un piccolo evento Click del Form, che cambia il testo dell'elemento 3 dell'array di bottoni, e funziona:
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Buttons(3).text = "Fanculo"
    End Sub


Conclusioni: usare un unico identificatore per caricare tutti i controlli che si vogliono, avendo l'accortezza di inserire ogni controllo in un oggetto di classe ArrayList, in modo da poter identificare ogni controllo della matrice per mezzo di un indice.

sabato 11 agosto 2012

Eventi di una matrice di controlli in VB.NET

Ho trovato come far rispondere a uno stesso evento una matrice di controlli!
Tramite l'istruzione AddHandler aggiungo a un evento da me creato con un nome arbitrario l'handler dell'evento di ciascun elemento della matrice che voglio evocare con l'evento da me creato.
Public Class Form1
    Dim btn(3) As Button
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To 2
            btn(n) = New Button
            Me.Controls.Add(btn(n))
            On Error Resume Next
            btn(n).Top = btn(n - 1).Top + btn(n).Height
            AddHandler btn(n).Click, AddressOf evento
        Next
    End Sub
    Private Sub evento(ByVal sender As System.Object, ByVal e As System.EventArgs)
        MsgBox("ciao")
    End Sub
End Class
Semplice!!!
La gestione degli eventi in VB.NET è nettamente superiore a quella del VB6.

Matrice di controlli in VB.NET

Ho trovato il modo di creare una matrice di controlli in VB.NRT.
Non differisce molto da come la creavo in VB6.
Mi pare di ricordare che anche in VB6 si poteva creare con Me.Controls.Add.
Io la creavo con Load. Comunque il risultato è ottimo anche qui.
Posso fare riferimento a uno degli elementi della matrice, come evidenziato dal codice dell'evento Form_Click che mi sposta il secondo elemento della matrice a destra, e che ho appunto creato come prova della possibilità di accedere a un preciso elemento a scelta della matrice.
Public Class Form1
    Dim btn(3) As Button
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        For n = 0 To 2
            btn(n) = New Button
            Me.Controls.Add(btn(n))
            On Error Resume Next
            btn(n).Top = btn(n - 1).Top + btn(n).Height
        Next
    End Sub
    Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        btn(1).Left = btn(1).Left + 200
    End Sub
End Class

giovedì 9 agosto 2012

Eventualità di misure del DIV inferiori allo spazio occupato dal border e padding

Ho risolto il problema dell'eventualità in cui la larghezza del DIV dovesse essere inferiore alla larghezza complessiva del padding e del bordo.
function div(colore,bord,largh,alt,sn,top,pad){
  var bordo=bord;
  var sinistra=sn;
  var alto=top;
  var padding=pad;
  var spazioMorto=((2*pad)+(2*(parseInt(bord))));
  var larghezza=function(){
   if(largh>=spazioMorto)
    return(largh-spazioMorto);
   else{
    padding=0;
    return(0);
   }
    
  }
  var altezza=function(){
   if(alt>=spazioMorto)
    return(alt-spazioMorto);
   else{
    padding=0;
    return(0);
   }
  }
 
 var inizia=function(){

  var elemento=document.createElement("div");
  elemento.style.position="absolute";
  elemento.style.backgroundColor=colore;
  elemento.style.border=bordo;
  elemento.style.width=larghezza();
  elemento.style.height=altezza();
  elemento.style.left=sinistra;
  elemento.style.top=alto;
  elemento.style.padding=padding;
  document.body.appendChild(elemento);
 }
 inizia();
} 

Creazione e aggiunta di un TextNode.

Ora proviamo ad "appendere" un textnode a un div.

Ecco il codice:
<html>
<head>
<script>
function addNode(){
 var testo=document.createTextNode("Ciao scemo!");
 document.getElementById("mioDiv").appendChild(testo);
 
}
</script>
</head>
<body onClick="addNode()">
<div id="mioDiv" style="background-color:#AAFFCC;height:100px"></div>
</body>
</html>
E funziona. A ogni click sul DIV viene aggiunta una nuova frase "Ciao scemo" al DIV stesso.

Padding e Border cambiano le dimensioni di un elemento.

Che relazione c'è fra la proprietà "padding" e le proprietà "height" e "width"?

Ecco, mediante una serie di ragionamenti e di correzioni, ho capito che il valore di padding e quello di border cambiano la larghezza e l'altezza dell'elemento, e ho apportato le necessarie correzioni nella funzione mediante la quale creo un elemento DIV:
function div(colore,bordo,larghezza,altezza,sinistra,alto,padding){
 var colore=colore;
 var bordo=bordo;
 var larghezza=larghezza-(2*padding)-(2*(parseInt(bordo)));
 var altezza=altezza-(2*padding)-(2*(parseInt(bordo)));
 var sinistra=sinistra;
 var alto=alto;
  
 var inner="
Fesso
" var inizia=function(){ var elemento=document.createElement("div"); elemento.innerHTML=inner; document.body.appendChild(elemento); } inizia(); }

giovedì 2 agosto 2012

Variabili private e scope, ancora esercizi

Vogliamo vedere come in un oggetto si mettono le variabili private?
Vediamo qual è lo scope per una variabile dichiarata dentro e fuori da una funzione...
<html>
<head>
<script>
var cerchio=function(){
 variabile =123;
}

cerchio();
alert (variabile); 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
così facendo ottengo
123

Se dichiaro la variabile con this che succede?
<html>
<head>
<script>
var cerchio=function(){
 this.variabile =123;
}

cerchio();
alert (variabile); 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
ottengo
123
quindi è esattamente la stessa cosa...

mercoledì 1 agosto 2012

La funzione usata come funzione o come costruttore

Bene, dopo aver fatto questa clamorosa scoperta dell'acqua calda, uso una funzione dell'oggetto finestra, quello di base, come costruttore per un nuovo oggetto.
 
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI;
 
 
}
var Cerchio = new cerchio(3);

alert(Cerchio.area);
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
Ecco:
28.274333882308138

Se viceversa, uso this.area al di fuori dell'oggetto Cerchio, che succede?
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

cerchio(3);
alert(window.area);

 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
28.274333882308138
in questo caso non istanzio alcun oggetto Cerchio di tipo cerchio, ma eseguo semplicemente la funzione appartenente all'oggetto window.
In questo caso la proprietà area appartiene all'oggetto window, tant'è vero che viene mostrata chiedendo al programma di mostrare nella finestra di dialogo la proprietà window.area.
Ora invece di eseguire la funzione cerchio, la uso come costruttore per istanziare un oggetto Cerchio, e poi vedo se dicendo al programma di mostrare la proprietà window.area avviene qualcosa di diverso.
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

var Cerchio=new cerchio(3);
alert(window.area);

 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
undefined
Ecco: in questo caso, usando la funzione cerchio(raggio) come costruttore non l'ho eseguita nell'ambito dell'oggetto window, ma per costruire un oggetto Cerchio, cosa che crea una proprietà area dell'oggetto Cerchio, non dell'oggetto window.
Provo a chiedere al programma di mostrare sia la proprietà window.area sia la proprietà Cerchio.area
<html>
<head>
<script>
function cerchio(raggio){
 this.area=raggio*raggio*Math.PI
}

var Cerchio=new cerchio(3);
alert(window.area);
alert(Cerchio.area);
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
undefined
28.274333882308138
Come volevasi dimostrare.

Vorrei cogliere l'essenza della differenza fra il Javascript, il Java, il C++ per quanto riguarda l'uso dei costruttori...

Riprendendo un po' di Javascript

Vediamo di ricreare un oggetto javascript.
Parto dall'oggetto window, che è l'oggetto dal quale partiamo sempre.
Per dimostrare che è l'oggetto dal quale parto sempre, faccio alcune piccole prove.
<html>
<head>
<script>
function main(){
 alert(this);
}
main();
 
</script>
</head>
<body bgcolor = cyan>


</body>
</html>
Ottengo:
[object Window]
Il this, che fa riferimento all'oggetto corrente, in questo caso fa riferimento alla finestra, che è sempre l'oggetto corrente.

martedì 5 giugno 2012

Rudimenti di terminale Linux: spostare e copiare cartelle

Adesso che ho imparato a creare e distruggere cartelle vuote e piene, mi rimane spostare e copiare cartelle.

Creo una cartella:
antonello@ubuntu:~$ ls
Documenti         Immagini  Musica    Scaricati  Video
examples.desktop  Modelli   Pubblici  Scrivania
antonello@ubuntu:~$ mkdir MiaCartella
antonello@ubuntu:~$ ls
Documenti         Immagini     Modelli  Pubblici   Scrivania
examples.desktop  MiaCartella  Musica   Scaricati  Video
antonello@ubuntu:~$ cd MiaCartella
antonello@ubuntu:~/MiaCartella$ mkdir Uno
antonello@ubuntu:~/MiaCartella$ mkdir Due
antonello@ubuntu:~/MiaCartella$ ls
Due  Uno
antonello@ubuntu:~/MiaCartella$ cd Uno
antonello@ubuntu:~/MiaCartella/Uno$ mkdir CartellaDelCavolo
antonello@ubuntu:~/MiaCartella/Uno$ ls
CartellaDelCavolo
antonello@ubuntu:~/MiaCartella/Uno$ cd ..
antonello@ubuntu:~/MiaCartella$ cd ..
antonello@ubuntu:~$ 
Ecco: ho creato una cartella CartellaDelCavolo posta nella cartella Uno.
La voglio spostare nella cartella Due.
antonello@ubuntu:~$ mv MiaCartella/Uno/CartellaDelCavolo MiaCartella/Due/CartellaDelCavolo
antonello@ubuntu:~$ cd MiaCartella/Uno
antonello@ubuntu:~/MiaCartella/Uno$ cd ../Due
antonello@ubuntu:~/MiaCartella/Due$ ls
CartellaDelCavolo
antonello@ubuntu:~/MiaCartella/Due$ 
Fatto.
Adesso copio la cartella anche nella cartella Uno: Dopo vari impazzimenti ho capito che cp funzionerà per i files, ma non per le cartelle per le quali ci vuole il parametro -r.

Ecco l'errore:
antonello@ubuntu:~$ cp MiaCartella/Due/CartellaDelCavolo MiaCartella/Uno/CartellaDelCavolo
cp: omitting directory `MiaCartella/Due/CartellaDelCavolo'
antonello@ubuntu:~$ 


Ed ecco la correzione:
antonello@ubuntu:~$ cp -r MiaCartella/Due/CartellaDelCavolo MiaCartella/Uno/CartellaDelCavolo
antonello@ubuntu:~$ cd MiaCartella/Uno
antonello@ubuntu:~/MiaCartella/Uno$ ls
CartellaDelCavolo
antonello@ubuntu:~/MiaCartella/Uno$ cd ..
antonello@ubuntu:~/MiaCartella$ cd Due
antonello@ubuntu:~/MiaCartella/Due$ ls
CartellaDelCavolo
antonello@ubuntu:~/MiaCartella/Due$ 
Ecco che funziona: la cartella si trova in tutte e due le cartelle!