JavascriptProva

martedì 18 marzo 2014

Disunire celle in Excel mettendo in ognuna il testo precedentemente appartenuto all'unione.

Separare una cella "unita" in Excel e mettere in tutte le celle ex facenti parte dell'unione il testo contenuto originariamente nell'unione.

Scrivo nella prima cella della colonna A una parola qualunque, "ciao".
Unisco le celle fino a A15.

...e ci lavoro...

L'unica soluzione che mi è venuta in mente è questa:
Sub azione()
Dim testo As String
Dim numero As Integer
numero = Range("A1").MergeArea.Count
For n = 1 To numero
If Range("A1").MergeArea(n).Formula <> "" Then testo = Range("A1").MergeArea(n).Formula
Next n
Range("A1").UnMerge
For n = 1 To numero
Range("A" & n).Formula = testo
Next n
End Sub
Questa è necessaria per individuare l'unica cella in cui c'è un testo:
For n = 1 To numero
If Range("A1").MergeArea(n).Formula <> "" Then testo = Range("A1").MergeArea(n).Formula
Next n


Memorizzando prima il numero delle celle facenti parte dell'unione:
numero = Range("A1").MergeArea.Count
si usa successivamente quando le celle sono state disunite, per metterci il testo precedentemente rilevato
For n = 1 To numero
Range("A" & n).Formula = testo
Next n


Può essere che esista qualche funzione di VBA che permetta una soluzione più breve, ma al momento non sono riuscito a individuarne nessuna.

martedì 11 marzo 2014

Questi grafici mi stanno facendo dannare...
    Charts.Add
    ActiveChart.ChartType = xlColumnStacked
    ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C1,C3"), PlotBy _
        :=xlColumns
    ActiveChart.SeriesCollection.NewSeries
    ActiveChart.SeriesCollection(2).Values = "=(Foglio7!R1C8,Foglio7!R3C8)"
    ActiveChart.Location Where:=xlLocationAsObject, Name:="Foglio7"
Adesso tolgo il riferimento al Foglio.
    Charts.Add
    ActiveChart.ChartType = xlColumnStacked
    ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C1,C3"), PlotBy _
        :=xlColumns
    ActiveChart.SeriesCollection.NewSeries
    ActiveChart.SeriesCollection(2).Values = "=(R1C8,R3C8)"
    ActiveChart.Location Where:=xlLocationAsObject, Name:="Foglio7"
E vediamo se va...

No, non va.

Ecco, sono arrivato alla conclusione che le celle per impostare SeriesCollection.Values devono essere espresse in questo modo:
"=(Foglio7!R1C8,Foglio7!R3C8)"
Questo quando sono discontinue.
Quando sono continue, invece, la macro registrata le esprime in questo modo:
"=Foglio7!R1C8:R4C8"
Ma credo che anche esprimendole con la notazione usata automaticamente per le selezioni di celle discontinue non cambi niente.
Proviamo.
ActiveChart.SeriesCollection(2).Values = "=(Foglio7!R1C8,Foglio7!R2C8,Foglio7!R3C8,Foglio7!R4C8,Foglio7!R5C8)"
Vediamo se funziona...

Sì... dopo qualche improprietà commessa, devo dire di sì!

domenica 9 marzo 2014

Studio dei grafici in Excel VBA

Analizziamo tutti i passaggi della creazione di un grafico in Excel.

La prima riga è questa:
Charts.Add
Che dovrebbe significare "Aggiungi un elemento all'insieme dei grafici.
E sta bene.

La seconda riga è questa:
ActiveChart.ChartType = xlColumnStacked
E sta a significare il tipo di grafico.

Ed ecco una cosa più succosa:
ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C2:C16"), PlotBy _
        :=xlColumns
Sarebbe la sorgente dei dati e il tipo di organizzazione di questi dati, ossia ciò che si sceglie con questo form:



Ora provo a fare un grafico fino a qua e vediamo cosa viene fuori.
    Charts.Add
    ActiveChart.ChartType = xlColumnStacked
    ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C1:C3"), PlotBy _
        :=xlColumns
    ActiveChart.Location Where:=xlLocationAsObject, Name:="Foglio7"
Ecco:



Ecco, un grafico in cui in ordinate ci sono i valori espressi nel range C1:C3 del foglio di lavoro, mentre in ascisse ci sono semplicemente dei numeri.
Ora rifaccio un grafico usando la scheda "Serie".
Ecco come mi si presenta la scheda all'inizio:



e io proseguo dando i valori:



Ecco il codice:
    Charts.Add
    ActiveChart.ChartType = xlColumnStacked
    ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C1:C3"), PlotBy _
        :=xlColumns
    ActiveChart.SeriesCollection(1).XValues = "=Foglio7!R1C1:R3C1"
    ActiveChart.SeriesCollection(1).Name = "=Foglio7!R1C2"
    ActiveChart.Location Where:=xlLocationAsObject, Name:="Foglio7"
Quindi
ActiveChart.SetSourceData Source:=Sheets("Foglio7").range("C1:C3"), PlotBy _
        :=xlColumns
esprime i valori espressi sull'asse delle ordinate;
 ActiveChart.SeriesCollection(1).XValues = "=Foglio7!R1C1:R3C1"
esprime i nomi espressi sull'asse delle ascisse;
 ActiveChart.SeriesCollection(1).Name = "=Foglio7!R1C2"
esprime il nome della serie.

Così, se io voglio sapere quanti ROSSI sono stati fatti dal 118 di Roccasecca, Pizzobello e Casaminchiola, ho come SetSourceData i numeri dei rossi fatti dalle tre sedi, come XValues i nomi dei tre paesi e come Name il nome ROSSI, appunto.
Isoliamo le prestazioni svolte dalle postazioni medicalizzate, sempre partendo dal foglio bianco.

Ah, dobbiamo fare un pulsante che cancelli tutto.

Fatto.
Sub DeleteAll()
    Cells.Select
    Selection.Delete Shift:=xlUp
    Sheets("Foglio5").Select
End Sub
Facilissimo.
Ora studiamo un pulsante per eliminare i grafici.
Sub deleteCharts()
For Each elemento In Charts
    Sheets(elemento.Name).Select
    ActiveWindow.SelectedSheets.Delete
Next
End Sub

sabato 1 marzo 2014

Grafici in Excel

La prima finestra della costruzione del grafico mi dice di selezionare un intervallo dati, e poi di selezionare Righe e Colonne.
Seleziono un intervallo dati 3, 1 e 2. L'opzione "Righe-Colonne" è selezionata su "Colonne".



Adesso la seleziono su "Righe".



Ecco.
Adesso voglio dare un colore alle righe... Come fare?

domenica 23 febbraio 2014

Lo scheletro del blog (ad eccezione dei commenti)

Ecco lo scheletro di tutto, tranne i commenti:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">



<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<$BlogLanguageDirection$>">

<head>
  <title><$BlogPageTitle$></title>

  <$BlogMetaData$>

 <style>
</style>
</head>
<body>

<Blogger>
<BlogItemTitle>
   <$BlogItemTitle$>
</BlogItemTitle>

<$BlogItemBody$>


<$I18NPostedByAuthorNickname$> alle <a href="<$BlogItemPermalinkUrl$>"><$BlogItemDateTime$></a>

<BlogItemCommentsEnabled>
<a href="<$BlogItemCommentCreate$>"<$BlogItemCommentFormOnClick$>><$I18NNumComments$></a>


</Blogger>
</body>
</html>

Sintesi dei tags sulla pagina principale

Mi ricostruisco tutto...
Prendiamo nota dei tags...
  1. Titolo del post
    BlogItemTitle
       $BlogItemTitle$
    /BlogItemTitle
    
  2. Corpo del post
    $BlogItemBody$
    
  3. Footer
    • Postato da... il...
      $I18NPostedByAuthorNickname$ $BlogItemPermalinkUrl$ $BlogItemDateTime$
      
    • Link ai commenti col numero commenti
      BlogItemCommentEnabled
          $BlogItemCommentCreate$ $BlogItemCommentFormOnClick$ $I18NNumComments$
      /BlogItemCommentEnabled
      

sabato 22 febbraio 2014

Il corpo dei commenti

Bene.
Ecco tutta la raccolta dei commenti scorporata dai tag HTML:
<BlogItemComments>
     <$I18NAtCommentTimeWithPermalink$>
     <$I18NCommentAuthorSaid$>
     <$BlogCommentBody$>
     <$BlogCommentDeleteIcon$>
</BlogItemComments> 
Che danno una sistemazione grezza, la quale andrà rimaneggiata coi tag HTML.

La sezione commenti

Per quanto riguarda i commenti, c'è un'indicazione del numero dei commenti.



L'indicazione del numero dei commenti è quella che io ho colorato in rosso mediante un aggiustamento dello stile, per poterla meglio identificare.
E' specificata con questo codice:
<ItemPage>

  <div id="comments">
 <BlogItemCommentsEnabled><a name="comments"></a>

        <h4 style="background-color:red"><$I18NNumComments$>:</h4>
Lasciamo soltanto i tag di Blogger:
<ItemPage>


 <BlogItemCommentsEnabled>

        <$I18NNumComments$>
A parte il tag condizionale <ItemPage c'è di nuovo l'apertura del tag <BlogItemCommentsEnabled>, e di nuovo il tag che specifica il numero dei commenti, <I18NNumComments>, questa volta senza link.


Bene, per il momento mi fermo qua...

Footer: autore del post e commenti.

Adesso veniamo ai commenti.
Che sarebbe quell'altra scritta col numero dei commenti presente in basso a destra sul footer, insieme al "Posted by... @...".



Ripasso il codice necessario per il "postato da..."
Come prova, lo tolgo dal footer e lo metto nel BlogItemBody
<div class="post-body">

          <p>

      <$BlogItemBody$>

    </p>
<$I18NPostedByAuthorNickname$> alle <a href="<$BlogItemPermalinkUrl$>"><$BlogItemDateTime$></a>
        </div>
E vediamo se funziona (ho fatto tutto a memoria).



Perfetto! Postato da... eccetera, è andato fuori dal footer.
Adesso lo rimetto nel footer, sempre a memoria:
        <p class="post-footer">
<$I18NPostedByAuthorNickname$> alle <a href="<$BlogItemPermalinkUrl$>"><$BlogItemDateTime$></a>
      
      <BlogItemCommentsEnabled>
         <a class="comment-link" href="<$BlogItemCommentCreate$>"<$BlogItemCommentFormOnclick$>><span style="text-transform:lowercase"><$I18NNumComments$></span></a>
      </BlogItemCommentsEnabled>
Ah, ecco, viene così:



perchè ho dimenticato il tag <em>
        <p class="post-footer">
<em><$I18NPostedByAuthorNickname$> alle <a href="<$BlogItemPermalinkUrl$>"><$BlogItemDateTime$></a></em>
      
      <BlogItemCommentsEnabled>
         <a class="comment-link" href="<$BlogItemCommentCreate$>"<$BlogItemCommentFormOnclick$>><span style="text-transform:lowercase"><$I18NNumComments$></span></a>
      </BlogItemCommentsEnabled>
 
ed è tornato a posto!

Adesso veniamo ai commenti.

I tags che comprendono quella voce che dice il numero dei commenti, vicino alla matitina, sono
      <BlogItemCommentsEnabled>

      </BlogItemCommentsEnabled> 
Se ce li metto da soli, non danno nessun effetto, il numero di commenti non compare.
Per quanto ho capito, per fare apparire il numero dei commenti bisogna mettere il tag $lt;$I18NNumComments$>
Proviamoci:
      <BlogItemCommentsEnabled>
         <$I18NNumComments$>
      </BlogItemCommentsEnabled> 
E infatti appare il numero di commenti, ma NON come collegamento ipertestuale.

Per fare questo bisogna creare il link all'indirizzo specificato dal tag che, appunto, permette la creazione dei commenti, linkando o alla pagina del post o a una finestra popup a seconda delle opzioni.

Aggiungiamo <BlogItemCommentCreate$>
<BlogItemCommentsEnabled>
<a href="<$BlogItemCommentCreate$>"><$I18NNumComments$></a>
</BlogItemCommentsEnabled> 
...e funziona!

Se però io nelle impostazioni seleziono i commenti in un form a parte (finestra popup), non funziona ancora.
E' necessario che io aggiunga, dopo il collegamento ipertestuale, <$BlogItemCommentFormOnClick$>.
<BlogItemCommentsEnabled>
<a href="<$BlogItemCommentCreate$>"<$BlogItemCommentFormOnClick$>><$I18NNumComments$></a>
</BlogItemCommentsEnabled> 
Che faticaccia!

venerdì 21 febbraio 2014

Postato da... alle ... con link al Permalink del post

Adesso dobbiamo curare la parte che dice "Postato da Trigon @ 16:08



Il codice sarebbe questo:
<em><$I18NPostedByAuthorNickname$> @ 
<a href="<$BlogItemPermalinkUrl$>" title="permanent link">
<$BlogItemDateTime$></a></em>  
Quell'I18N mi risulta strano. Prendiamolo per buono mnemonicamente.
Invece quel PostedByAuthorNickname è chiaro: traduciamocelo in italiano per memorizzarlo meglio:
Postato da Nickname dell'Autore.

La chiocciolina resta invariata perchè è un semplice carattere grafico.

Invece $BlogItemPermalinkUrl$ è l'url del Permalink del solito elemento blog, ed è l'indirizzo cui si va a finire cliccando sul link specificato da BlogItemDateTime, che sarebbe l'ora dell'elemento blog.

Provo a rimaneggiarmelo un po'...

Ripassiamo i tag di Blogger che abbiamo già imparato.

Vediamo...

Quelli che ho visto finora iniziano sempre per Blog.
E sono:
<BlogDateHeader>
 <$BlogDateHeaderDate$>
</BlogDateHeader>
Come ricordarli?
  • La parola iniziale è sempre Blog
  • Trattandosi di data, la parola successiva è Date, e siccome è un'intestazione, ricordiamo anche Header.
  • Il tag che specifica la data sarebbe la data dell'header di data del blog, e quindi va aggiunto Date componendo $BlogDateHeaderDate$


<BlogItemTitle>
 <$BlogItemTitle$>
</BlogItemTitle>
Il successivo è quello del Titolo
  • Inizia sempre con Blog.
  • Questa volta entriamo nell'elemento del post, quindi ci aggiungiamo Item
  • Essendo il titolo, andiamo con Title. Il tag che specifica il titolo resta invariato $BlogItemTitle$.

    Andiamo al corpo.
    • La parola iniziale è sempre Blog
    • Si tratta sempre dell'elemento post, quindi aggiungiamo Item
    • Essendo il corpo, si aggiunge Body
    Non ci vogliono i tag iniziali e finali e si scrive solo $BlogItemBody$.
  • mercoledì 19 febbraio 2014

    Smontaggio e rimontaggio da zero di un blog

    Ho distrutto completamente il blog JacTest di questa piattaforma, in modo da esercitarmi a ricostruirlo pezzo-pezzo.
    Ecco lo scheletro essenziale cui mi sono ridotto:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    
    
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<$BlogLanguageDirection$>">
    
    <head>
      
      <style type="text/css">
    body {
    background:#afc;
      </style>
    </head>
    <body>
    </body>
    </html> 
    
    Ed ecco cosa ne viene fuori:



    Praticamente l'unica informazione che ho passato è quell' #afc del colore di background, che riproduce una delle tonalità azzurrine che a me piacciono tanto.

    Ora cerchiamo di stabilire la struttura del blog.
    Vediamo dal codice che ho salvato come vengono strutturate le varie sezioni...

    Ecco!
    Incontro il tag %lt;Blogger>.
    Pongo l'inizio e la fine, e intanto ci metto dentro il tag <BlogDateHeader> e pongo l'inizio e la fine.
    In mezzo ci metto <BlogDateHeaderDate>, ed ecco che mi compaiono le date dei posts:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    
    
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<$BlogLanguageDirection$>">
    
    <head>
      
      <style type="text/css">
    body {
    background:#afc;
      </style>
    </head>
    <body>
    <Blogger>
    <BlogDateHeader>
    <$BlogDateHeaderDate$>
    </BlogDateHeader>
    
    </Blogger>
    </body>
    </html> 
    


    sabato 15 febbraio 2014

    Sfasciando e rimontando il date header dei post di blogger...

    Vediamo di modificare le varie sezioni di un post...
    Non è facile capire l'HTML di questi blog perchè ci sono dei tags particolari...


    /* Posts
    ----------------------------------------------- */
    .date-header span {
      background-color: red;
      color: $(date.header.color);
      padding: $(date.header.padding);
      letter-spacing: $(date.header.letterspacing);
      margin: $(date.header.margin);
    }
    
    Ecco, adesso dovrebbe essere modificato il colore di sfondo della data:



    Ho sostituito il colore predefinito con quello rosso.
    Dunque so che la classe .date-header span sta a significare la data del post.

    Provo a modificare altri dettagli...
    .date-header span {
      background-color: cyan;
      color:blue;
      padding: $(date.header.padding);
      letter-spacing: $(date.header.letterspacing);
      margin: $(date.header.margin);
    }
    
    Ed ecco:



    Cominciamo a capirci qualcosa...

    Ancora:
    .date-header span {
      background-color: cyan;
      color:blue;
      padding: 20px;
      letter-spacing:15px;
      font-style:italic;
      margin:0px);
    }
    
    Ho alterato a man bassa il padding, il letter spacing e ci ho aggiunto anche il font-style italic.
    Per quanto riguarda il margin, non sono riuscito a verificare gli effetti.

    E abbiamo iniziato a dominare una parte del blog: il date header

    giovedì 13 febbraio 2014

    Riprovo il mio programmino per convertire i tag nei caratteri di escape...

    Ho ripescato il mio programmino converti.exe
    Lo metto in una cartella del desktop chiamata "Conversione".

    Ecco:
    C:\Users\Antonello>cd desktop
    
    C:\Users\Antonello\Desktop>dir /p /o
     Il volume nell'unità C è Acer
     Numero di serie del volume: 9AE5-9692
    
     Directory di C:\Users\Antonello\Desktop
    
    13/02/2014  22.39    <DIR>          .
    13/02/2014  22.39    <DIR>          ..
    20/01/2014  21.36    <DIR>          Camera Roll
    04/12/2013  20.36    <DIR>          Computer di Daniele
    13/02/2014  22.39    <DIR>          Conversione
    11/02/2014  00.01    <DIR>          immagini dal cellulare
    08/01/2014  01.05    <DIR>          Kyodai
    20/01/2014  13.21    <DIR>          Nuova cartella
    12/12/2013  15.32    <DIR>          Nuova filmati
    29/12/2013  15.25    <DIR>          Tomb Raider 2
    18/01/2014  19.30    <DIR>          wolf
    19/01/2014  18.27    <DIR>          Wolf modificato
    03/01/2014  20.48    <DIR>          wolfpic
    07/12/2013  11.16           155.777 2013-12-07-320.jpg
    03/02/2014  12.26         1.580.988 2014-02-03 12.26.41.jpg
    03/02/2014  12.29         1.345.872 2014-02-03 12.29.32.jpg
    13/12/2013  18.32            19.826 Applicazioni rimosse.html
    12/01/2014  17.25                16 batch.bat
    04/12/2013  15.41             1.468 BOOTEX.LOG
    Premere un tasto per continuare . . . 
    
    E la apro:
    C:\Users\Antonello\Desktop>cd conversione
    
    C:\Users\Antonello\Desktop\Conversione>dir
     Il volume nell'unità C è Acer
     Numero di serie del volume: 9AE5-9692
    
     Directory di C:\Users\Antonello\Desktop\Conversione
    
    13/02/2014  22.39    <DIR>          .
    13/02/2014  22.39    <DIR>          ..
    03/06/2009  15.55            20.480 converti.exe
                   1 File         20.480 byte
                   2 Directory  399.748.722.688 byte disponibili 
    

    Adesso, dato che il prompt del DOS mi si apre sulla cartella Antonello, mi creo su un file di testo un pipistrello.
    @ECHO OFF
    cd desktop/conversione
    
    e lo salvo sulla cartella Antonello:
    C:\Users\Antonello>dir /p /o
     Il volume nell'unità C è Acer
     Numero di serie del volume: 9AE5-9692
    
     Directory di C:\Users\Antonello
    
    13/02/2014  22.45    <DIR>          .
    13/02/2014  22.45    <DIR>          ..
    04/12/2013  18.00    <DIR>          Application Data
    19/12/2013  22.01    <DIR>          Contacts
    13/02/2014  22.39    <DIR>          Desktop
    12/02/2014  12.35    <DIR>          Documents
    13/02/2014  02.28    <DIR>          Downloads
    13/02/2014  17.36    <DIR>          Dropbox
    11/02/2014  18.26    <DIR>          dwhelper
    19/12/2013  22.01    <DIR>          Favorites
    30/12/2013  19.35    <DIR>          Links
    22/12/2013  10.57    <DIR>          Music
    04/12/2013  16.09    <DIR>          PicStream
    01/02/2014  21.45    <DIR>          Pictures
    19/12/2013  22.01    <DIR>          Saved Games
    19/12/2013  22.01    <DIR>          Searches
    24/01/2014  13.42    <DIR>          Videos
    13/02/2014  22.45                35 converti.bat
    14/12/2013  18.04               621 Last session Antonello.prj
    Premere un tasto per continuare . . . 
    


    Ed ecco che all'apertura del prompt del DOS mi basta digitare converti per trovarmi subito nella mia cartella per la conversione.
    C:\Users\Antonello>converti
    
    C:\Users\Antonello\Desktop\Conversione>
    


    Roba da poco, ma dà soddisfazione

    Per mettere qui il codice del prompt del DOS ho usato proprio il mio programmino!

    mercoledì 12 febbraio 2014

    Ancora sui menu...

    Ora devo aggiungere alla Casella che ho messo nel contenitore un nuovo menu.
    Intanto, se clicco su questa, si attiva il menu che viene in qualche modo "ereditato" dal controllo contenitore, e questo mi sballa tutta la logica...

    Ci metto alcuni comandi "test"...
        Sub aggiungi(sender As Object, e As EventArgs)
            Debug.Print(mioMenu.SourceControl.GetType.ToString)
            Dim c As New Casella
            c.ContextMenuStrip = mioMenu
            elementoSelezionato.controls.add(c)
        End Sub
    
    Ecco: ho aggiunto questa riga:
    Debug.Print(mioMenu.SourceControl.GetType.ToString)
    
    per desumere l'elemento che ha "innescato" il menu contestuale.
    Poi ho impostato l'innesco del menu contestuale anche da parte della casella, per vedere se il sourceElement, ossia l'elemento che ha innescato il menu, sia sempre lo stesso.
            Dim c As New Casella
            c.ContextMenuStrip = mioMenu
            elementoSelezionato.controls.add(c)
    
    Se evito di inserire la riga:
    c.ContextMenuStrip = mioMenu
    
    che attribuisce il menu contestuale alla casella, ottengo come sourceControl:
    gridProject.Pannello
    gridProject.Pannello
    
    avendo cliccato la prima volta sul Pannello per aggiungere la Casella, e la seconda volta sulla Casella:

    Invece se metto la riga che attribuisce alla Casella il menu contestuale:
        Sub aggiungi(sender As Object, e As EventArgs)
            Debug.Print(mioMenu.SourceControl.GetType.ToString)
            Dim c As New Casella
            c.ContextMenuStrip = mioMenu
            elementoSelezionato.controls.add(c)
        End Sub
    
    Ottengo, sempre cliccando prima sul Pannello e poi sulla Casella:
    gridProject.Pannello
    gridProject.Casella
    
    ottenendo quello che voglio, ossia che al click sul menu sia riconosciuto il controllo sul quale ho cliccato per aprire il menu contestuale.

    Menu di contenitori e controlli...

    Cerchiamo di risolvere 'sta cosa che non ne ho mai voglia e la sto tirando per le lunghe...

            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                elemento.ContextMenuStrip = mioMenu
            Next
    
    Mediante la classe da me creata Griglia ho creato una griglia di controlli di tipo Pannello, erede di Panel.

    Ad ognuno di questi attribuisco il menu contestuale mioMenu che ho creato in fase di progettazione, vuoto.
    Ovviamente, quando clicco col destro, dato che il menu contestuale è vuoto, non succede, apparentemente, assolutamente niente.
    Ecco, ho fatto delle aggiunte, che marco in rosso:
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf SetMenu
                elemento.ContextMenuStrip = mioMenu
            Next
    
       
        End Sub
    
        Sub setMenu()
            mioMenu.Items.Clear()
            Dim m As New ToolStripMenuItem
            m.Text = VociDelMenu(0)
            mioMenu.Items.Add(m)
        End Sub
    
    Così, prima che il menu si mostri, lo posso modificare in quanto al click del mouse sull'elemento chiamo la routine setMenu che mi aggiunge un menu con una voce, che nella fattispecie prendo da una matrice di voci del menu, e che ha come testo "aggiungi".
    Adesso attribuisco al menu "aggiungi" l'esecuzione di una routine.
    Per far questo, però, devo identificare e memorizzare in una variabile l'elemento da cui ho evocato il menu.
    Dichiaro una variabile oggetto:
        Dim elementoSelezionato As Object
    
    E poi, nella routine setMenu, prima di settare il menu, memorizzo l'elemento nella variabile oggetto.
        Sub setMenu(sender As Object, e As MouseEventArgs)
            elementoSelezionato = sender
            mioMenu.Items.Clear()
            Dim m As New ToolStripMenuItem
            m.Text = VociDelMenu(0)
            mioMenu.Items.Add(m)
        End Sub
    
    E ora studio come aggiungere un controllo nell'insieme control dell'elemento (che è una classe derivata di Panel):
        Sub aggiungi()
            elementoSelezionato.controls.add(New Button)
        End Sub
    
    quindi attribuisco all'evento click del menu aggiunto l'handler alla routine aggiungi.
        Sub setMenu(sender As Object, e As EventArgs)
            elementoSelezionato = sender
            mioMenu.Items.Clear()
            Dim m As New ToolStripMenuItem
            m.Text = VociDelMenu(0)
            AddHandler m.Click, AddressOf aggiungi
            mioMenu.Items.Add(m)
        End Sub
    
    E pare che funzioni...

    Ho sostituito al Button una classe Casella da me creata in pochi secondi (azz, che bravo!) provvisoriamente con un'ampiezza limitata in previsione di studi futuri.
    Class Casella
        Inherits Label
        Sub New()
            BackColor = Color.LightGreen
            Width = 50
        End Sub
    End Class
    
    E adesso dobbiamo studiarci un po' la gestione dei menu per quanto riguarda i controlli aggiunti...

    sabato 1 febbraio 2014

    Smontare le costruzioni cervellotiche per i menu contestuali...

    Personalizziamo il menu per i pannelli.
            'costruzione della griglia
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf AggiustaMenuPannello
                elemento.ContextMenuStrip = mioMenu
            Next
        End Sub
    
        Sub AggiustaMenuPannello()
    
            aggiungiVociAlMenu(voci.aggiungi, voci.aggiungi)
    
        End Sub
    
        Sub aggiungiVociAlMenu(inizio As Integer, fine As Integer)
            mioMenu.Items.Clear()
            For n = inizio To fine
                Dim m As New ToolStripMenuItem With {.Text = VociDelMenu(n)}
                mioMenu.Items.Add(m)
            Next
        End Sub
    

    Con il codice
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf AggiustaMenuPannello
                elemento.ContextMenuStrip = mioMenu
            Next
    
    Si attribuisce il gestore d'evento AggiustaMenuPannello al click su ciascuno dei pannelli della griglia, ossia si personalizza il menu mioMenu per il Pannello.
    Nello stesso tempo si attribuisce come menu contestuale il menu mioMenu
    L'aggiustamento del mioMenu per il pannello si vale delle due routines
        Sub AggiustaMenuPannello()
    
            aggiungiVociAlMenu(voci.aggiungi, voci.aggiungi)
    
        End Sub
    
        Sub aggiungiVociAlMenu(inizio As Integer, fine As Integer)
            mioMenu.Items.Clear()
            For n = inizio To fine
                Dim m As New ToolStripMenuItem With {.Text = VociDelMenu(n)}
                mioMenu.Items.Add(m)
            Next
        End Sub
    
    ...anche se forse si potrebbe fare prima con:
    
        Sub AggiustaMenuPannello()
            mioMenu.Items.Clear()
            mioMenu.Items.Add(New ToolStripMenuItem With {.Text = VociDelMenu(0)})
        End Sub
    
    ...che funziona lo stesso e non è così cervellotico.
    Quindi il codice, a questo punto diventa, semplificando ed evitando di intricarsi in jungle di pensiero contorto:
            'costruzione della griglia
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf AggiustaMenuPannello
                elemento.ContextMenuStrip = mioMenu
            Next
        End Sub
    
        Sub AggiustaMenuPannello()
            mioMenu.Items.Clear()
            mioMenu.Items.Add(New ToolStripMenuItem With {.Text = VociDelMenu(0)})
        End Sub
    
    laddove a ogni pannello della griglia viene semplicemente attribuita la funzione che formatta il menu su misura per il pannello e il menu stesso come menu contestuale.
    Punto!

    sabato 18 gennaio 2014

    Aggiunta di diversi sottomenu a runtime.

    Ecco costruito un altro pezzetto: l'aggiunta di menu e sottomenu a runtime.
        Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            matrice(0) = "Tizio"
            matrice(1) = "Caio"
            matrice(2) = "Sempronio"
            aggiungiElementiAlMenu()
            AggiungiSottomenu()
        End Sub
        Sub aggiungiElementiAlMenu()
            For n = 0 To matrice.Length - 1
                Dim mn As New ToolStripMenuItem With {.Text = matrice(n)}
    
                Menu.Items.Add(mn)
            Next
    
        End Sub
        Sub AggiungiSottomenu()
            For Each elemento In Menu.Items
                If elemento.Text = "Sempronio" Then
                    For n = 0 To matrice.Length - 1
                        Dim submenu As New ToolStripMenuItem With {.Text = matrice(n)}
                        elemento.DropDownItems.Add(submenu)
                    Next
                End If
            Next
        End Sub
    
    Ho isolato le varie funzioni per avere un programma più maneggevole. E' meglio fare sempre così.

    venerdì 17 gennaio 2014

    Un sottomenu a runtime...

    Come si aggiunge un sottomenu a runtime a un contextmenu?
     Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            matrice(0) = "Tizio"
            matrice(1) = "Caio"
            matrice(2) = "Sempronio"
            For n = 0 To matrice.Length - 1
                Dim mn As New ToolStripMenuItem
                mn.Text = matrice(n)
    
                Menu.Items.Add(mn)
            Next
            For Each elemento In Menu.Items
                If elemento.Text = "Sempronio" Then
                    Dim submenu As New ToolStripMenuItem With {.Text = "ciccio"}
                    elemento.DropDownItems.Add(submenu)
    
                End If
            Next
        End Sub
    

    domenica 12 gennaio 2014

    Appunti personali: il codice finora costruito

    Riassumo qui l'ultimo codice:
    Public Class Form1
        Dim WithEvents mGrid As Griglia(Of Pannello)
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf Aggiungi
            Next
        End Sub
        Sub Aggiungi(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Dim child As New miaLabel
                AddHandler child.MouseDown, AddressOf ClickContenuto
                sender.controls.add(child)
                Ridistribuisci(sender)
            End If
        End Sub
        Sub ClickContenuto(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Aggiungi(sender.parent, e)
            Else
                Rimuovimi(sender)
            End If
        End Sub
        Private Sub Ridistribuisci(contenitore As Object)
            Dim base = 0
            For Each C In contenitore.Controls
                C.width = contenitore.Width / contenitore.Controls.Count
                C.location = New Point(base * contenitore.Width / contenitore.Controls.Count, 0)
                base += 1
                C.bringtofront()
            Next
        End Sub
        Sub Rimuovimi(contenuto As Object)
            Dim temp As Object = contenuto.parent
            contenuto.parent.controls.remove(contenuto)
            Ridistribuisci(temp)
            temp = Nothing
        End Sub
    End Class
    Class Pannello
        Inherits Panel
        Sub New()
            Width = 100
            Height = 20
            BorderStyle = Windows.Forms.BorderStyle.FixedSingle
        End Sub
    End Class
    
    ...casomai dovessi dimenticarlo così lo prendo e lo riattacco pari pari...

    Aggiunta ed eliminazione di contenuti in un contenitore Panel.

    Questo è il codice, con qualche modifica dovuta al fatto che sto studiando la rimozione degli elementi:
    Public Class Form1
        Dim WithEvents mGrid As Griglia(Of Pannello)
     
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf aggiungi
    
            Next
        End Sub
        Sub aggiungi(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Dim child As New miaLabel
                AddHandler child.MouseDown, AddressOf genitore
                sender.controls.add(child)
                Dim base = 0
                For Each C In sender.controls
                    C.width = sender.width / sender.controls.count
                    C.location = New Point(base * sender.width / sender.controls.count, 0)
                    base += 1
                    C.bringtofront()
                Next
            Else
    
                
    
            End If
    
        End Sub
        Sub genitore(sender As Object, e As MouseEventArgs)
    
            aggiungi(sender.parent, e)
        End Sub
    End Class
    Class Pannello
        Inherits Panel
        Sub New()
            Width = 100
            Height = 20
            BorderStyle = Windows.Forms.BorderStyle.FixedSingle
        End Sub
    End Class
    
    Il problema è che quando clicco sul contenitore o su uno dei contenuti con il sinistro il risultato deve essere l'aggiunta di un contenuto al contenitore, mentre quando clicco sul contenitore con il destro non deve succedere niente, mentre se clicco su un contenuto con il destro, questo deve essere rimosso.
    Cominciamo a isolare una parte del codice che è quella che ridistribuisce lo spazio del contenitore fra i contenuti.
        Sub aggiungi(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Dim child As New miaLabel
                AddHandler child.MouseDown, AddressOf genitore
                sender.controls.add(child)
    
                Ridistribuisci(sender)
            Else
    
                
    
            End If
    
        End Sub
    
    
    .........
    
    
        Private Sub Ridistribuisci(contenitore As Object)
            Dim base = 0
            For Each C In contenitore.controls
                C.width = contenitore.width / contenitore.controls.count
                C.location = New Point(base * contenitore.width / contenitore.controls.count, 0)
                base += 1
                C.bringtofront()
            Next
        End Sub
    
    ...

    Ho trovato la soluzione:
    Public Class Form1
        Dim WithEvents mGrid As Griglia(Of Pannello)
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            mGrid = New Griglia(Of Pannello)(Me, True, 30, 5, 10, 10)
            For Each elemento As Pannello In mGrid
                AddHandler elemento.MouseDown, AddressOf aggiungi
            Next
        End Sub
        Sub aggiungi(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                Dim child As New miaLabel
                AddHandler child.MouseDown, AddressOf ClickContenuto
                sender.controls.add(child)
                Ridistribuisci(sender)
            End If
        End Sub
        Sub ClickContenuto(sender As Object, e As MouseEventArgs)
            If e.Button = Windows.Forms.MouseButtons.Left Then
                aggiungi(sender.parent, e)
            Else
                Dim temp As Object = sender.parent
                sender.parent.controls.remove(sender)
                Ridistribuisci(temp)
                temp = Nothing
            End If
        End Sub
        Private Sub Ridistribuisci(contenitore As Object)
            Dim base = 0
            For Each C In contenitore.Controls
                C.width = contenitore.Width / contenitore.Controls.Count
                C.location = New Point(base * contenitore.Width / contenitore.Controls.Count, 0)
                base += 1
                C.bringtofront()
            Next
        End Sub
    End Class
    Class Pannello
        Inherits Panel
        Sub New()
            Width = 100
            Height = 20
            BorderStyle = Windows.Forms.BorderStyle.FixedSingle
        End Sub
    End Class
    
    Ecco il risultato (bella idea, nei filmati che non commento a voce, quella di inserire brani musicali):

    giovedì 9 gennaio 2014

    Devo capire bene i criteri con i quali vengono fatti i turni...

    Purtroppo non posso annotare qui i nomi reali delle persone di cui ho il prospetto dei turni, per cui devo sostituirli con degli pseudonimi, e per lo stesso motivo non posso mettere qui il prospetto che ho realizzato con la mia applicazione.

    Partiamo dalla dottoressa Mannoni...
    Presenta un totale di 138 ore di turni effettivi.
    Più tre turni di legge 104.
    138+ 6 x 3 = 138 + 18 = 156.
    Adesso il dottor Lungoni:
    90 ore di turni effettivi.
    10 turni di ferie
    2 turni di aggiornamento.
    90 + 60 + 12= 162
    Adesso il dottor Fregnetti:
    126 ore di turni effettivi.
    3 turni di ferie.
    126 + 6 x 3 = 126 + 18 = 144
    Il dottor Morselli:
    126 ore di turni effettivi.
    6 turni di ferie.
    126 + 36 = 162.
    La dottoressa Cagnacci:
    138 ore di turni effettivi.
    Nessun turno di ferie o aggiornamento.
    La dottoressa Arboretti:
    156 ore di turni effettivi.
    Nessun turno di ferie o aggiornamento.
    Il dottor Dolcetti:
    156 ore di turni effettivi.
    Nessun turno di ferie o aggiornamento.
    Il dottor Grandi:
    132 ore di turni effettivi.
    1 turno di aggiornamento.
    132 + 6 = 138.
    Dunque il totale viene così:

    Mannoni156
    Lungoni162
    Fregnetti144
    Morselli162
    Cagnacci138
    Arboretti156
    Dolcetti156
    Grandi138

    Perchè questa disparità?

    sabato 4 gennaio 2014

    Esame del programma di attribuzione dei turni.

    Dunque le variabili di cui devo tener conto sono:
    • totPref, che parte da zero e viene calcolato con un ciclo for-next
    • numTurni, che è il numero totale dei turni a disposizione, il quale parte con un preciso valore
    • attribuiti, che è il numero dei turni attribuiti, calcolato nel ciclo for-next che calcola i turni
    • resto, che viene calcolato alla fine di ogni ciclo Loop, ottenuto sottraendo attribuiti da numTurni.
    Creazione della matrice principale:
            mario.nome = "Mario"
            giuseppe.nome = "Giuseppe"
            luigi.nome = "Luigi"
            mario.preferenza = 0
            giuseppe.preferenza = 20
            luigi.preferenza = 20
    
            matrice = New ArrayList
            matrice.Add(mario)
            matrice.Add(giuseppe)
            matrice.Add(luigi)
    


    Creazione della matrice "di lavoro":
            Dim matrice2 As New ArrayList
    
    


    Rimescolamento e ordinamento della matrice principale:
            'Rimescolamento casuale della matrice di partenza
            Dim r As New Random
            Dim x As Integer
            Dim temp As persona
            For n = 0 To matrice.Count - 1
                x = r.Next(matrice.Count - n) + n
                temp = matrice(n)
                matrice(n) = matrice(x)
                matrice(x) = temp
            Next
    
    
            'ordinamento della matrice
            matrice.Sort()
    


    Caricamento degli elementi nella matrice di lavoro (inizia il ciclo):
            Do
                For n = startnum To matrice.Count - 1
                    matrice2.Add(matrice(n))
                Next
    


    Calcolo del totale delle preferenze totPref:
                'si calcola il totale delle preferenze
                totPref = 0
                For n = 0 To matrice2.Count - 1
                    totPref += matrice2(n).preferenza
                Next
    


    Esecuzione del calcolo con calcolo dei turni attribuiti e del resto, da numTurni e attribuiti:
              
                'quindi si fa il calcolo
                For n = 0 To matrice2.Count - 1
                    matrice2(n).turni += Math.Floor(numTurni / totPref * matrice2(n).preferenza)
                    attribuiti += Math.Floor(numTurni / totPref * matrice2(n).preferenza)
                    resto = numTurni - attribuiti
                Next
    


    Mostra la matrice di partenza con i turni attribuiti
                'mette a video la matrice di partenza
                mostra(matrice)
                Debug.Print("resto " & resto)
                Debug.Print("-----")
    


    Azzera totPref e attribuiti, che vanno ricalcolati al ciclo successivo; cancella la matrice di lavoro; attribuisce a numTurni il valore di resto e avanza startNum per caricare nuovamente nella matrice di lavoro con esclusione dei valori di preferenza più bassi; ricomincia il ciclo:
                totPref = 0
                attribuiti = 0
                matrice2.Clear()
                numTurni = resto
                startnum += 1
            Loop While resto <> 0