simply4you.it simply4you.it

   Home
     Articoli, Tutorial...
       Visual Basic
         Lezione 33
Indice
Lez. 01
Lez. 02
Lez. 03
Lez. 04
Lez. 05
Lez. 06
Lez. 07
Lez. 08
Lez. 09
Lez. 10
Lez. 11
Lez. 12
Lez. 13
Lez. 14
Lez. 15
Lez. 16
Lez. 17
Lez. 18
Lez. 19
Lez. 20
Lez. 21
Lez. 22
Lez. 23
Lez. 24
Lez. 25
Lez. 26
Lez. 27
Lez. 28
Lez. 29
Lez. 30
Lez. 31
Lez. 32
Lez. 33


Autore
Giorgio Abraini

E-Mail
giorgio102@libero.it

VBItalia.it



Commenta anche tu !  


LINK Visual Basic













   Invia il link di questo articolo ad un amico  Invia ad un amico Visualizza la versione stampabile di questo articolo  Stampa Commenta questo Articolo  Commenta Parlane in Chat  Chat   Parlane sul Forum  Forum

Corsi Programmazione in aula:
ASP, Dreamweaver MX, Flash MX, HTML, Introduzione alla programmazione strutturata, JSP/Servlet, JavaScript, Linguaggio C, Linux programmazione shell, Oracle PL/SQL, Oracle Portal 9.0.2, PHP, Perl, Programmazione Java, Programmazione Java avanzata, Programmazione web Corso avanzato, Programmazione web Corso base, Programmazione web Corso intermedio, XML


Trentreesima lezione - Uso avanzo di controlli Active X (2)

Il problema prospetto alla fine dell'ultima lezione è il seguente: quando un pulsante Mina è disabilito la bandiera appare "grigia": non che sia un grosso problema, ma non sembra esteticamente gradevole. Per superare l'ostacolo conviene in realtà aggirarlo: anziché affibbiare la bandiera al pulsante stesso tramite la proprietà Picture, la affibbiamo a un controllo Picture (tenzione a non confondersi) dedico all'uopo; dovremo quindi fare in modo che quando vogliamo il pulsante disabilito sopra di esso compaia una PictureBox (questo il nome del controllo che trove nella casella degli strumenti) con la bandiera. Si potrebbe anche usare un controllo Image, che ha il vantaggio di fornire la proprietà Stretch: impostando a true questa proprietà, l'immagine riprodotta viene ridimensiona automicamente in modo da farla coincidere con le dimensioni del controllo; invece il controllo PictureBox non dispone di questa proprietà e l'immagine resta con le sue dimensioni originali: ciò significa che se l'immagine è troppo grande per essere contenuta interamente nel controllo essa sarà taglia, mentre se è troppo piccola rimarrà spazio vuoto. Il controllo PictureBox ha una proprietà simile ma che funziona nel modo opposto: la proprietà AutoSize, se imposta a true, ridimensiona automicamente il controllo adtandolo all'immagine contenuta, ma questo non sempre è opportuno. Allora perché non usare il controllo Image? Purtroppo questo ha il grave difetto di non poter apparire in primo piano rispetto a un commandbutton, perché è un controllo grafico, e quindi la nostra bandiera rimarrebbe perennemente nascosta dietro il relivo pulsante.
Infti nei form, come in altri controlli "contenitori" (cioè che possono contenere altri controlli) esistono tre livelli grafici: il primo riservo a controlli non grafici (commandbutton, listbox, ecc.), il secondo contiene controlli grafici ed etichette, il terzo sta sullo sfondo del form e contiene il prodotto dei metodi grafici come ad es. il metodo Line. Sfruttare il metodo Zorder non serve a nulla, perché esso consente di impostare la disposizione degli oggetti solo all'interno del proprio livello grafico; ad es. è possibile usare il metodo Zorder per far apparire un Image in primo piano rispetto a un altro Image, ma non rispetto a un commandbutton, perché quest'ultimo appartiene a un livello grafico superiore. Il controllo PictureBox, invece, pur potendo anch'esso contenere immagini come il controllo Image, può fungere da contenitore e fa quindi parte dei controlli di "primo livello": perciò esso può essere effettivamente sovrapposto a un commandbutton. Ora, il problema nuralmente si può risolvere, e senza neanche troppe complicazioni: basterebbe infti inserire un controllo Image all'interno di un PictureBox, o magari creare un ulteriore controllo personalizzo ad hoc da usare quando ce n'è bisogno, del tutto simile a un PictureBox ma con in più la proprietà Stretch come un controllo Image. È un utile esercizio che lascio fare a voi, io per semplicità proseguo utilizzando un semplice PictureBox.
Torniamo dunque al nostro problema: far apparire la bandiera su un PictureBox in primo piano rispetto al pulsante Mina. Andiamo nella finestra di progettazione del nostro controllo personalizzo Mina e aggiungiamo un controllo PictureBox: chiamiamolo ad es. picFlag (ovviamente "pic" è il prefisso standard per indicare che si trta di un PictureBox). Occorre prima di tutto aggiornare la procedura dell'evento Resize dello UserControl per tener conto del nuovo controllo inserito:

Prive Sub UserControl_Resize()
With cmdMina
    .Left = 0
    .Top = 0
    .Height = UserControl.Height
    .Width = UserControl.Width
End With
With picFlag
    .Left = 10
    .Top = 10
    .Height = UserControl.Height - 40
    .Width = UserControl.Width - 40
End With

RaiseEvent Resize
End Sub

Bisogna poi delegare l'evento ClickRight anche per il controllo PictureBox: infti abbiamo scelto di far apparire questo controllo "sopra" il CommandButton che rappresenta la mina quando questa viene distiva; di conseguenza, un ulteriore click col tasto destro (come anche col tasto sinistro o qualunque altro input del mouse) non sarà più intercetto dal CommandButton bensì dal PictureBox. Perciò occorre sfruttare nuovamente l'evento MouseDown:

Prive Sub picFlag_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
If Button = vbRightButton Then
    RaiseEvent ClickRight
End If
End Sub

Infine, bisogna modificare opportunamente le proprietà che abbiamo assegno allo UserControl per tener conto della nuova stregia da implementare. Infti ora non è più strettamente necessario disabilitare il pulsante cmdMina all'interno dello UserControl, perché quando l'utente cliccherà col tasto destro sul pulsante vedrà in primo piano la bandiera contenuta nel PictureBox e quindi come si è detto tutti gli input del mouse saranno diretti al PictureBox, anche se il CommandButton sottostante è ancora abilito. Le proprietà EnableCmd, ad es., diventeranno così:

Public Property Get EnabledCmd() As Boolean
  EnabledCmd = Not picFlag.Visible 
End Property

Public Property Let EnabledCmd(ByVal vNewValue As Boolean)
  picFlag.Visible = Not vNewValue
  PropertyChanged "EnabledCmd"
End Property

Se il pulsante è "abilito" (nel senso che l'input del mouse giunge direttamente al pulsante cmdMina all'interno dello UserControl), significa che il PictureBox con la bandiera non è visibile, da qui l'uso dell'operore Not per controllare e/o impostare lo stus del pulsante. Un'istruzione come questa, ad es.:

Mina1.EnableCmd = Not Mina1.EnableCmd

funzionerebbe in questo modo: supponiamo che Mina1 sia abilito; allora picFlag non è visibile, quindi la proprietà EnableCmd restituirà, in lettura, il valore True. Questo valore viene convertito in False nell'istruzione esemplifica qui sopra, e di conseguenza assegno nuovamente alla proprietà EnableCmd: pertanto il parametro vNewValue sarà False, e la proprietà Visible di picFlag diventerà True; l'utente vedrà quindi la sua bandierina sulla mina, senza però che il pulsante cmdMina sia sto effettivamente disabilito.
Un'altra proprietà da modificare è Picture:

Public Property Get Picture() As IPictureDisp
  Set Picture = picFlag.Picture
End Property

Public Property Set Picture(ByVal _
	vNewValue As IPictureDisp)
  picFlag.Picture = vNewValue
  If picFlag.Picture.Handle = 0 Then
    picFlag.Visible = False
  Else
    picFlag.Visible = True
    picFlag.SetFocus
  End If
End Property

Ora la proprietà Picture non fa più riferimento a cmdMina.Picture, bensì a picFlag.Picture, poiché non c'è più bisogno di manipolare direttamente il CommandButton.
Vediamo ora come modificare il programma client che usa il controllo Mina (ovvero il progetto del Campo Mino): l'unica procedura da rivedere è quella dell'evento Mina_ClickRight:

Prive Sub Mina_ClickRight(Index As Integer)

With Mina(Index)
	'nessuna bandiera sul pulsante
    If .Picture.Handle = 0 Then  
        Set .Picture = LoadPicture("BandieraCampoMino.ico")
        ContaBandiere = ContaBandiere + 1
        '.EnabledCmd = False
    Else 'il pulsante ha già la bandiera
        Set .Picture = LoadPicture()
        ContaBandiere = ContaBandiere - 1
        '.EnabledCmd = True
    End If
End With

lblMine.Caption = CStr(3 - ContaBandiere)

End Sub

La sola differenza rispetto alla routine precedente è la mancanza delle istruzioni di disabilitazione/riabilitazione del pulsante (ovvero, le istruzioni di impostazione della proprietà EnableCmd sono commente): questo appunto perché non è più strettamente necessario disabilitare direttamente il pulsante. Sarebbe comunque una cosa utile, perché in questo modo lo UserControl sarebbe davvero pienamente riutilizzabile in altri progetti: invece allo sto tuale è progetto specificamente per il progetto Campo Mino; basta che uno imposti la proprietà Picture dello UserControl e automicamente il pulsante non sarà più utilizzabile. Tuttavia, la rimozione di questi vincoli dovrebbe essere abbastanza semplice: anche questo è un utile esercizio.
Ora il programma dovrebbe funzionare correttamente: tuttavia c'è ancora qualche piccolo dettaglio da mettere a posto: se, dalla finestra di progettazione del form del Campo Mino, selezione il pulsante Mina(0), vedrete nella finestra delle proprietà anche le proprietà che abbiamo aggiunto noi nello UserControl (ad es. EnableCmd, NumeroMine, ecc.). Selezionando queste proprietà noterete prima di tutto che non compare alcuna descrizione nella parte inferiore della finestra, e poi al programmore potrebbe dare fastidio che l'utente possa modificare direttamente in fase di progettazione queste proprietà, che sono invece controlle automicamente o dal controllo stesso o via codice nel progetto client. Per cambiare le cose dobbiamo andare nel menù Strumenti di Visual Basic e selezionare la voce tributi Routine (se non è abilita è perché la finestra tiva non è quella del codice dello UserControl). Da qui possiamo manipolare le proprietà e gli eventi che abbiamo aggiunto, inserendo una descrizione nell'apposito campo; aprendo il pannello "Opzioni" possiamo anche fare in modo che le suddette proprietà non compaiano nella finestra delle proprietà impostando il check nella casella "Non visualizzare nella finestra Proprietà". Dando l'ok e ritornando alla finestra delle proprietà possiamo constare che le nostre proprietà aggiuntive non sono più modificabili in fase di progettazione.
Da ultimo, cerchiamo di fare in modo che il programma sia facilmente utilizzabile anche tramite l'uso della sola tastiera: "a che scopo?", direte voi. Lo scopo è quello di migliorare l'accessibilità dell'applicazione, rendendola fruibile anche a coloro che vogliono o possono fare a meno del mouse: ad es. i non vedenti. Rendere un'applicazione, anche la più modesta, accessibile a tutti è un po' come rimuovere le barriere architettoniche che costellano le nostre città e i nostri paesi: aumenta il numero di persone che possono utilizzare il programma, cosa che oltre ad essere un doveroso servizio verso gli utenti, risulta anche di indubbia soddisfazione per il programmore. Oltretutto non è una cosa complica, basta solo usare qualche accorgimento: ad es. è opportuno impostare delle combinazioni di tasti per le voci di menù: il nostro menù "partita" dispone di due sole voci: "Nuova" e "Esci". Solitamente le combinazioni standard per queste voci sono del tipo "CTRL+N" per una nuova partita e "CTRL+E" per uscire dal programma; un altro tipo di combinazioni è l'uso del tasto ALT unito a una lettera (solitamente la prima) delle voci di menù: ad es. la combinazione "ALT+P, N" aprirà il menù "Partita" e selezionerà la voce "Nuova", mentre la combinazione "ALT+P, E" aprirà il menù "Partita" e selezionerà la voce "Esci". Per impostare queste combinazioni occorre selezionare la finestra di progettazione del form e poi andare nell'editor dei menù, lo stesso utilizzo per creare il menù. Per ogni voce di menù (tranne il separore, ovviamente, che non ha alcuna reale funzione) aggiungiamo il cartere "&" nella Caption prima della prima lettera (o comunque prima della lettera che vogliamo utilizzare nella combinazione di tasti): ad es. per il menù "partita" la caption diventerà "&Partita". Aggiungiamo anche una combinazione dalla casella "shortcut": ctrl+n per la voce "Nuova", ctrl+e per la voce "Esci"; solitamente per il menù vero e proprio ("Partita") non si usa alcuna combinazione di questo tipo ma ci si limita ad abiltare l'uso del tasto ALT con il cartere "&" come abbiamo visto. Un'altra cosa utile può essere l'impostazione del focus al primo pulsante quando si comincia una nuova partita, in modo che tutte le volte si parta sempre dallo stesso punto: basta aggiungere nella routine mnuNew_Click questa istruzione:

Mina(0).SetFocus
preferibilmente alla fine della routine. Un altro accorgimento può essere quello di assegnare una combinazione di tasti anche per il click col tasto destro (per il click sinistro non ce n'è bisogno, basta premere la barra spazirice quando il focus è sul pulsante: questo vale per tutti i pulsanti, è direttamente il sistema operivo che se ne occupa): un modo semplice per fare ciò è sfruttare l'evento KeyDown, presente sia per i CommandButton che per le PictureBox che per gli UserControl. Nuralmente occorre delegarlo a tutti i livelli, dopo aver dichiaro l'evento nello UserControl:
Prive Sub UserControl_KeyDown(KeyCode As Integer, _
	Shift As Integer)
  RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Prive Sub cmdMina_KeyDown(KeyCode As Integer, _
	Shift As Integer)
  RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Prive Sub picFlag_KeyDown(KeyCode As Integer, _
	Shift As Integer)
  RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Non dimentice i parametri, soprtutto nella dichiarazione dell'evento. Ora possiamo scrivere nel progetto del Campo Mino:

Prive Sub Mina_KeyDown(Index As Integer, KeyCode As Integer, _
	Shift As Integer)
If Shift = vbCtrlMask And KeyCode = vbKeyR Then
    Mina_ClickRight (Index)
End If
End Sub

Note che i parametri dell'evento includono sia quelli specifici dell'evento (KeyCode e Shift), sia l'indice della mina. Se il tasto premuto (KeyCode) è la "r" ed è premuto anche il tasto Control (Shift=vbCtrlMask), allora viene richiamo l'evento del click destro. Il parametro Shift controlla lo sto dei tasti Alt, Control e Shift (maiuscolo): per controllare quali di essi sono premuti occorre verificare quali bit del parametro sono imposti. Infti il valore di Shift può andare da 0 a 7 a seconda delle varie combinazioni possibili: i tasti sono tre, ciascuno ha due sti possibili (premuto o non premuto), perciò le combinazioni sono 2^3=8. Le costanti di Visual Basic vbShiftMask, vbCtrlMask e vbAltMask corrispondono ai primi tre bit, ovvero ai valori 1, 2, 4: la loro combinazione (cioè la somma) dà i possibili valori da 0 (nessun tasto premuto) a 7 (tutti i tasti premuti); funziona insomma come il parametro Button nell'evento MouseDown.

   Scarica l'esempio.



<< Lezione Precedente (32 Lezione) Lezione Successiva (Indice) >>




Note sul corso:
I diritti di ognuna delle lezioni presente in queste pagine appartengono all'autore Giorgio Abraini. La riproduzione e la divulgazione delle stesse sono consentite solamente dietro citazione di fonte ed autore.
Per suggerimenti, consigli o richieste conttare giorgio102@libero.it.
Fonte : VBItalia.it



   Invia il link di questo articolo ad un amico  Invia ad un amico Visualizza la versione stampabile di questo articolo  Stampa Commenta questo Articolo  Commenta Parlane in Chat  Chat   Parlane sul Forum  Forum