VB.NET - Criando menus em tempo de execução II


Estou voltando a este assunto abordado no artigo - VB.NET - Criando menus em tempo de execução - para atualizar e expandir o conceito de criar menus em tempo de execução no VB.

Neste artigo não vou usar o VS.NET vou usar o SharpDevelop e mostrar também como você pode obter o mesmo resultado usando a linha de comando.

Requisitos para testar o código deste artigo:

Podemos criar menus e menus contexto diretamente via código e é isto que vou mostrar como fazer neste artigo. Os passos essenciais para atingir este objetivo são:

  1. Declarar um objeto MainMenu para representar o Menu
  2. Declarar um objeto MenuItem para cada item do Menu
  3. Instanciar o objeto MainMenu e todos os objetos MenuItem
  4. Definir as propriedades dos objetos MenuItem (text , color , etc..) como desejado
  5. Incluir os objetos MenuItem na coleção MenuItems do objeto MainMenu

Abaixo temos o código que cria um Menu com um item principal com alguns subitens:

Imports System
Imports System.Drawing
Imports System.Windows.Forms

Namespace menuVB2

module modMain
<STAThreadAttribute( )> Public Sub Main( )
  System.Threading.Thread.CurrentThread.ApartmentState = System.Threading.ApartmentState.STA
     Application.Run(New Form1( ))
  End Sub
End Module

Public Class Form1
            Inherits Form


' faz referência a label1 para exibir o texto
Private WithEvents Label1 As New Label( )
 
' Estes membros armazenam as propriedades originais de cor e fonte do controle label1
  Private origFont As Font
  Private origForeColor As Color
  Private origBackColor As Color
 
  ' Estes membros manipulam os objetos MainMenu e ContextMenu.
  Private WithEvents MainMenu1 As New MainMenu( )
  Private WithEvents ContextMenu1 As New ContextMenu( )
 
  ' Estes membros tratam os objetos MenuItem
  Private WithEvents mnuFormat As New MenuItem( )
  Private WithEvents mnuFormatFont As New MenuItem( )
  Private WithEvents mnuFormatForeColor As New MenuItem( )
  Private WithEvents mnuFormatBackColor As New MenuItem( )
  Private mnuSeparator As New MenuItem( )
  Private WithEvents mnuFormatReset As New MenuItem( )

Public Sub New( )
   'chama o construtor da classe pai (Forms)
   MyBase.New( )
   ' Define o menu Formatar
   mnuFormat.Text = "F&ormatar"
   mnuFormatFont.Text = "&Fonte..."
   mnuFormatForeColor.Text = "F&oreColor..."
   mnuFormatBackColor.Text = "&BackColor..."
   mnuSeparator.Text = "-"
   mnuFormatReset.Text = "&Limpar"
   mnuFormat.MenuItems.AddRange(New MenuItem( ) {mnuFormatFont, _
   mnuFormatForeColor, mnuFormatBackColor, mnuSeparator,mnuFormatReset})
 
   ' Vincula o menu Formatar ao menu principal e vincula o menu principal ao formulário
   MainMenu1.MenuItems.Add(mnuFormat)
   Menu = MainMenu1

   ' Faz um Clone do menu Formatar, vincula o clone ao menu de contexto e vincula o menu de contexto ao controle label
   ContextMenu1.MenuItems.Add(mnuFormat.CloneMenu( ))
   Label1.ContextMenu = ContextMenu1

   ' Define as propriedades relacionadas do formulário e da label
   AutoScaleBaseSize = New Size(5, 13)
   ClientSize = New Size(312, 81)
   Controls.Add(Label1)
   Menu = MainMenu1
   Name = "Form1"
   Text = "Criando Menus em tempo de execução"
   Label1.Text = "Testando Menu"
   Label1.AutoSize = True

   ' Salva as propriedades fonte e cor original do controle label
   origFont = Label1.Font
   origForeColor = Label1.ForeColor
   origBackColor = Label1.BackColor
End Sub

' Tratamento do evento Click para Font
Private Sub mnuFormatFont_Click( ByVal sender As Object, ByVal e As EventArgs ) Handles mnuFormatFont.Click
  Dim dlg As New FontDialog( )
  dlg.Font = Label1.Font
  If dlg.ShowDialog = DialogResult.OK Then
     Label1.Font = dlg.Font
  End If
  dlg.Dispose( )
End Sub

' Tratamento do evento Click para ForeColor
Private Sub mnuFormatForeColor_Click( ByVal sender As Object, ByVal e As EventArgs) Handles mnuFormatForeColor.Click
  Dim dlg As New ColorDialog( )
  dlg.Color = Label1.ForeColor
 
   If dlg.ShowDialog = DialogResult.OK Then
      Label1.ForeColor = dlg.Color
   End If
   dlg.Dispose( )
End Sub

' Tratamento do evento Click para BackColor
Private Sub mnuFormatBackColor_Click( ByVal sender As Object, ByVal e As EventArgs ) Handles mnuFormatBackColor.Click
  Dim dlg As New ColorDialog( )
  dlg.Color = Label1.BackColor
 
  If dlg.ShowDialog = DialogResult.OK Then
     Label1.BackColor = dlg.Color
   End If
   dlg.Dispose( )
End Sub

Compilando e Executando o código acima no SharpDevelop temos o resultado exibido nas figuras abaixo:

 
O menu   O menu de contexto

A interação do usuário com os Menus e seus itens disparam eventos. O evento mais comum da classe MenuItem é o evento Click que dispara quando um usuário clica um item do menu. Abaixo temos um trecho de código que faz o tratamento para um suposto item de menu Sair que encerra a aplicação.

Private Sub mnuSair_Click( ByVal sender As Object, ByVal e As EventArgs ) Handles mnuSair.Click
    Me.Close( )
End Sub

Alguns do principais eventos da classe MeuItem são :

Click Disparado quando um item do menu é selecionado via mouse ou via atalho
Dispose Disparado quando o método Dispose do objeto MenuItem é invocado.
DrawItem Disparado quando um item do menu precisa ser desenhado, quando a propriedade OwnerDraw for True
Popup Disparado quando o sub-menu esta prestes a ser exibido quando um item do menu possui sub-itens associados a ele
Select Disparado quando o usuário põe o mouse sobre o item do menu ou quando o navega pelo item usando o teclado.
MeasureItem Disparado antes do evento DrawItem quando a propriedade OwnerDraw do objeto MenuItem for True
Index O índice de um item do menu dentro do menu pai.
State Indica o estado do item do menu. O tipo é DrawItemState.
Graphics A superfície gráfica onde o item vai ser desenhado

Clonando Menus

As vezes os itens de Meus e seus subitens precisam aparecer em mais de um local e não somente no Menu. Um exemplo comum é o caso de uma aplicação que possui menus de contexto contendo algumas das mesmas funcionalidades que o menu da aplicação.

Os objetos MenuItem não funcionam corretamente quando são atribuídos a mais de um menu. Uma solução simples para o problema é usar o método CloneMenu que retorna um novo objeto MenuItem cujas propriedades são definidas da mesma forma que o objeto MenuItem. Se o MenuItem original possuir submenus, ele será clonado também.

Se você quiser compilar o código acima usando a linha de comando fique a vontade , abaixo esta o comando , apenas substitua o nome_do_arquivo  pelo nome que você salvou o arquivo com o código cima.

vbc nome_do_arquivo.vb /r:System.dll,System.Drawing.dll,System.Windows.Forms.dll /t:winexe

Nota: Para saber mais leia o artigo : VB.NET - O DOS morreu . Viva o DOS !

O evento CloneMenu detecta os manipuladores de eventos que estão definidos para MenuItems os clona e automaticamente registra os eventos manipuladores com eventos correspondentes para os novo objetos MenuItem criados.

Para exibir as opções de fonte e de cores dos itens do Menu eu estou usando as Caixas de Diálogo : ColorDialog() e FontDialog(). Além destas caixas temos também as caixas de diálogo Open e Save. O código para abrir e exibir as caixas é padrão , veja abaixo :

Dim dlg As New FontDialog( )
  dlg.Font = Label1.Font
  If dlg.ShowDialog = DialogResult.OK Then
     Label1.Font = dlg.Font
  End If
  dlg.Dispose( )
End Sub
- instanciamos um objeto dlg do tipo FontDialog (ColorDialog, etc)

- atribuímos a Fonte usada a propriedade Font do controle

Até o próximo artigo VB.NET


José Carlos Macoratti