blob: 153c2adfe5428b67edc3f324e8dfb57c53545187 [file] [log] [blame]
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
= Tutorial do módulo de assistente do NetBeans
:jbake-type: platform_tutorial
:jbake-tags: tutorials
:jbake-status: published
:syntax: true
:source-highlighter: pygments
:toc: left
:toc-title:
:icons: font
:experimental:
:description: Tutorial do módulo de assistente do NetBeans - Apache NetBeans
:keywords: Apache NetBeans Platform, Platform Tutorials, Tutorial do módulo de assistente do NetBeans
Neste tutorial, você aprenderá como utilizar os recursos principais fornecidos pelas classes de assistente da link:http://bits.netbeans.org/dev/javadoc/org-openide-dialogs/org/openide/package-summary.html[API de diálogos do NetBeans].
Nos aplicativos da plataforma NetBeans, é possível criar diferentes tipos de assistentes. Se deseja criar um assistente que apareça na caixa de diálogo Novo projeto, consulte o link:https://netbeans.apache.org/tutorials/nbm-projectsamples.html[Tutorial do módulo de amostra do projeto]. Se deseja criar um assistente que apareça na caixa de diálogo Novo arquivo, consulte o link:https://netbeans.apache.org/tutorials/nbm-filetemplates.html[Tutorial do módulo de arquivo de modelo]. Neste tutorial, é criado um assistente geral que aparece ao clicar em um botão na barra de ferramentas.
== Criando o projeto do módulo
Começamos a trabalhar através do assistente para novo projeto de módulo. No final, teremos uma estrutura de código-fonte básica com alguns arquivos padrão, que todos os módulos NetBeans exigem.
[start=1]
1. Escolha Arquivo > Novo projeto (Ctrl-Shift-N). Em Categorias, selecione Módulos do NetBeans. Em Projetos, selecione Módulo. Clique em Próximo.
[start=2]
1. No painel Nome e localização, digite ``DemoWizard`` no campo Nome do projeto. Altere Local do projeto para qualquer diretório no computador. Deixe marcadas a opção Módulo independente e a caixa de verificação Definir como projeto principal. Clique em Próximo.
[start=3]
1. No painel Configuração básica de módulos, digite ``org.demo.wizard`` no Nome de base de código.
[start=4]
1. Selecione "Gerar camada XML". Deixe as localizações do pacote de localizações e da camada XML de modo que sejam armazenados em um pacote com o nome ``org/demo/wizard`` . Clique em Terminar.
O IDE cria o projeto ``DemoWizard`` . O projeto contém todos os metadados de projeto e códigos-fonte, como o script de construção Ant do projeto. O projeto se abre no IDE. É possível ver a estrutura lógica na janela Projetos (Ctrl-1) e a estrutura de arquivos na janela Arquivos (Ctrl+2).
== Criando a infraestrutura do assistente
Nesta seção, utilizamos o assistente Wizard para adicionar stubs de um assistente ao nosso módulo.
[start=1]
1. Na janela Projetos, clique com o botão direito do mouse no nó do projeto DemoWizard e selecione Desenvolvimento do módulo | Assistente:
image::images/wizard_wizard-wizard.png[]
Clique em Avançar.
[start=2]
1. No painel Tipo de assistente, digite 2 no campo "Número de painéis do assistente" e deixe os outros valores inalterados:
image::images/wizard_wizard-wizard-3.png[]
Os campos no painel acima são os seguintes:
* *Tipo de registro.* Determina onde o usuário acessará o assistente. Se selecionar "Personalizado", o assistente Wizard criará uma nova classe de ação que você pode utilizar para abrir e inicializar seu assistente. Se selecionar "Novo arquivo", o assistente Wizard registrará seu assistente no arquivo ``layer.xml`` do módulo.
* *Sequência de etapas do assistente.* Determina se o assistente será linear ou se o usuário do assistente poderá saltar etapas dependendo das escolhas feitas anteriormente. Os assistentes lineares são 'estáticos', que é o padrão, enquanto que os assistentes com etapas que podem ser saltadas requerem uma classe de repetidor personalizada, que é criada se você seleciona 'dinâmico'.
* *Número de painéis do assistente.* Determina o número de painéis que serão criados. Para cada etapa do assistente, serão criados dois arquivos Java: uma visualização e um controlador.
Clique em Avançar.
[start=3]
1. No painel Nome e localização, digite ``Demo`` no Prefixo do nome da classe e selecione o pacote principal na lista suspensa Pacote:
image::images/wizard_wizard-wizard-4.png[]
Clique em Terminar.
Na janela Projetos, agora deveria aparecer o seguinte:
image::images/wizard_projects-window.png[]
== Registrando a classe de ação do assistente
Nesta seção, modificamos a classe Action e a registramos no arquivo ``layer.xml`` .
[start=1]
1. Abra o arquivo ``DemoWizardAction.java`` e substitua todos os códigos pelo seguinte:
[source,java]
----
package org.demo.wizard;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.MessageFormat;
import javax.swing.JComponent;
import org.openide.DialogDisplayer;
import org.openide.WizardDescriptor;
public final class DemoWizardAction implements ActionListener {
private WizardDescriptor.Panel[] panels;
public void actionPerformed(ActionEvent e) {
WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
wizardDescriptor.setTitle("Your wizard dialog title here");
Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
dialog.setVisible(true);
dialog.toFront();
boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
if (!cancelled) {
// do something
}
}
/**
* Initialize panels representing individual wizard's steps and sets
* various properties for them influencing wizard appearance.
*/
private WizardDescriptor.Panel[] getPanels() {
if (panels == null) {
panels = new WizardDescriptor.Panel[]{
new DemoWizardPanel1(),
new DemoWizardPanel2()
};
String[] steps = new String[panels.length];
for (int i = 0; i < panels.length; i++) {
Component c = panels[i].getComponent();
// Default step name to component name of panel. Mainly useful
// for getting the name of the target chooser to appear in the
// list of steps.
steps[i] = c.getName();
if (c instanceof JComponent) { // assume Swing components
JComponent jc = (JComponent) c;
// Sets step number of a component
// TODO if using org.openide.dialogs >= 7.8, can use WizardDescriptor.PROP_*:
jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i));
// Sets steps names for a panel
jc.putClientProperty("WizardPanel_contentData", steps);
// Turn on subtitle creation on each step
jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE);
// Show steps on the left side with the image on the background
jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE);
// Turn on numbering of all steps
jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE);
}
}
}
return panels;
}
public String getName() {
return "Start Sample Wizard";
}
}
----
Estamos utilizando o mesmo código que foi gerado, exceto que implementamos o ``ActionListener`` em vez do ``CallableSystemAction`` . Fazemos isso porque ``ActionListener`` é uma classe JDK padrão, enquanto que ``CallableSystemAction`` não. A partir da plataforma NetBeans 6.5, é possível utilizar a classe JDK padrão, que é mais apropriada e exige menos código.
[start=2]
1. Registre a classe de ação no arquivo ``layer.xml`` da seguinte forma:
[source,xml]
----
<filesystem>
<folder name="Actions">
<folder name="File">
<file name="org-demo-wizard-DemoWizardAction.instance">
<attr name="delegate" newvalue="org.demo.wizard.DemoWizardAction"/>
<attr name="iconBase" stringvalue="org/demo/wizard/icon.png"/>
<attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/>
<attr name="noIconInMenu" stringvalue="false"/>
</file>
</folder>
</folder>
<folder name="Toolbars">
<folder name="File">
<file name="org-demo-wizard-DemoWizardAction.shadow">
<attr name="originalFile" stringvalue="Actions/File/org-demo-wizard-DemoWizardAction.instance"/>
<attr name="position" intvalue="0"/>
</file>
</folder>
</folder>
</filesystem>
----
O elemento "iconBase" aponta para uma imagem denominada "icon.png" do pacote principal. Utilize sua própria imagem com tal nome, certificando-se de que o tamanho seja de 16x16 pixels ou utilize a imagem seguinte:
image::images/wizard_icon.png[]
[start=3]
1. Execute o módulo. O aplicativo se inicia e o botão deveria ser visto na barra de ferramentas que foi especificada no arquivo ``layer.xml`` :
image::images/wizard_result-1.png[]
Clique no botão e o assistente é exibido:
image::images/wizard_result-2.png[]
Clique em Próximo e observe que no painel final o botão Terminar está habilitado:
image::images/wizard_result-3.png[]
Agora que a infraestrutura do assistente está funcionando, vamos adicionar algum tipo de conteúdo.
== Criando o conteúdo do assistente
Nesta seção, adicionamos o conteúdo ao assistente e personalizamos os recursos básicos.
[start=1]
1. Abra o arquivo ``DemoWizardAction.java`` e observe que é possível definir várias propriedades de personalização para o assistente:
image::images/wizard_wizard-tweaking.png[]
Leia mais sobre estas propriedades link:http://ui.netbeans.org/docs/ui_apis/wide/index.html[aqui].
[start=2]
1. Em ``DemoWizardAction.java`` , altere ``wizardDescriptor.setTitle`` pelo seguinte:
[source,java]
----
wizardDescriptor.setTitle("Music Selection");
----
[start=3]
1. Abra os arquivos ``DemoVisualPanel1.java`` e ``DemoVisualPanel2.java`` e utilize o construtor de GUI "Matisse" para adicionar alguns componentes Swing, como os seguintes:
image::images/wizard_panel-1-design.png[]
image::images/wizard_panel-2-design.png[]
Acima, você vê os arquivos ``DemoVisualPanel1.java`` e ``DemoVisualPanel2.java`` com alguns componentes Swing.
[start=4]
1. Abra os dois painéis na visualização Código-fonte e altere seus métodos ``getName()`` por "Name and Address" e "Musician Details", respectivamente.
[start=5]
1.
Execute o módulo novamente. Quando o assistente for aberto, você deveria ver algo semelhante ao exibido abaixo, dependendo dos componentes Swing adicionados e das personalizações feitas:
image::images/wizard_result-4.png[]
A imagem na barra lateral esquerda do assistente acima é definida no arquivo ``DemoWizardAction.java`` , da seguinte forma:
[source,java]
----
wizardDescriptor.putProperty("WizardPanel_image", ImageUtilities.loadImage("org/demo/wizard/banner.png", true));
----
Agora que o conteúdo do assistente foi criado, vamos adicionar código para o processamento dos dados que o usuário gerará introduzir.
== Processando os dados do usuário
Nesta seção, você aprende como passar os dados do usuário de um painel a outro e como exibir os resultados para o usuário quando ele clicar em Terminar.
[start=1]
1. Nas classes de ``WizardPanel`` , utilize o método ``storeSettings`` para recuperar os dados definidos no painel visual. Por exemplo, crie getters no arquivo ``DemoVisualPanel1.java`` e, em seguida, acesse-os da seguinte forma a partir do arquivo ``DemoWizardPanel1.java`` :
[source,java]
----
public void storeSettings(Object settings) {
((WizardDescriptor) settings).putProperty("name", ((DemoVisualPanel1)getComponent()).getNameField());
((WizardDescriptor) settings).putProperty("address", ((DemoVisualPanel1)getComponent()).getAddressField());
}
----
[start=2]
1. Depois, utilize o arquivo ``DemoWizardAction.java`` para recuperar as propriedades que você definiu e adote o seguinte procedimento com tais propriedades:
[source,java]
----
public void actionPerformed(ActionEvent e) {
WizardDescriptor wizardDescriptor = new WizardDescriptor(getPanels());
// {0} will be replaced by WizardDesriptor.Panel.getComponent().getName()
wizardDescriptor.setTitleFormat(new MessageFormat("{0}"));
wizardDescriptor.setTitle("Music Selection");
Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor);
dialog.setVisible(true);
dialog.toFront();
boolean cancelled = wizardDescriptor.getValue() != WizardDescriptor.FINISH_OPTION;
if (!cancelled) {
*String name = (String) wizardDescriptor.getProperty("name");
String address = (String) wizardDescriptor.getProperty("address");
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(name + " " + address));*
}
}
----
O ``NotifyDescriptor`` pode ser utilizado também de outras formas, conforme indicado pela caixa de autocompletar código:
image::images/wizard_notifydescriptor.png[]
Agora você já sabe como processar os dados introduzidos pelo usuário.
== Validando os dados do usuário
Nesta seção, você aprende como validar a entrada do usuário quando o botão "Next" for clicado no assistente.
[start=1]
1. Em ``DemoWizardPanel1`` , altere a assinatura de classe, implementando ``WizardDescriptor.ValidatingPanel`` em vez de ``WizardDescriptor.Panel`` :
[source,java]
----
public class DemoWizardPanel1 implements WizardDescriptor.ValidatingPanel
----
[start=2]
1. Na parte superior da classe, altere a declaração ``JComponent`` por uma declaração digitada:
[source,java]
----
private DemoVisualPanel1 component;
----
[start=3]
1. Implemente o método abstrato necessário da seguinte forma:
[source,java]
----
@Override
public void validate() throws WizardValidationException {
String name = component.getNameTextField().getText();
if (name.equals("")){
throw new WizardValidationException(null, "Invalid Name", null);
}
}
----
[start=4]
1. Execute o módulo. Clique em "Next", sem introduzir nada no campo "Name" e você deveria ver o resultado abaixo. Observe também que não é possível mover para o painel seguinte, como consequência da falha na validação:
image::images/wizard_validation1.png[]
[start=5]
1. Como opção, desabilite o botão "Next" se o campo do nome estiver vazio. Comece declarando um boolean na parte superior da classe:
[source,java]
----
private boolean isValid = true;
----
A seguir, substitua ``isValid()`` da seguinte forma:
[source,java]
----
@Override
public boolean isValid() {
return isValid;
}
----
E quando ``validate()`` for chamado, o que ocorre quando o botão "Next" é clicado, retorne falso:
[source,java]
----
@Override
public void validate() throws WizardValidationException {
String name = component.getNameTextField().getText();
if (name.equals("")) {
*isValid = false;*
throw new WizardValidationException(null, "Invalid Name", null);
}
}
----
Alternativamente, defina o boolean inicialmente como falso. A seguir, implemente ``DocumentListener`` , adicione um listener no campo e, quando o usuário digitar algo no campo, defina o boolean como verdadeiro e chame ``isValid()`` .
Agora você já sabe como validar os dados introduzidos pelo usuário.
Para obter mais informações sobre validação da entrada do usuário, consulte a amostra de Tom Wheeler ao final deste tutorial.
== Persistindo dados nas reinicializações
Nesta seção, você aprende como armazenar os dados quando o aplicativo se fecha e como recuperá-los quando o assistente se abre após ser iniciado novamente.
[start=1]
1. Em ``DemoWizardPanel1.java`` , substitua os métodos ``readSettings`` e ``storeSettings`` da seguinte forma:
[source,java]
----
*JTextField nameField = ((DemoVisualPanel1) getComponent()).getNameTextField();
JTextField addressField = ((DemoVisualPanel1) getComponent()).getAddressTextField();*
@Override
public void readSettings(Object settings) {
*nameField.setText(NbPreferences.forModule(DemoWizardPanel1.class).get("namePreference", ""));
addressField.setText(NbPreferences.forModule(DemoWizardPanel1.class).get("addressPreference", ""));*
}
@Override
public void storeSettings(Object settings) {
((WizardDescriptor) settings).putProperty("name", nameField.getText());
((WizardDescriptor) settings).putProperty("address", addressField.getText());
*NbPreferences.forModule(DemoWizardPanel1.class).put("namePreference", nameField.getText());
NbPreferences.forModule(DemoWizardPanel1.class).put("addressPreference", addressField.getText());*
}
----
[start=2]
1. Execute o módulo novamente e digite um nome e endereço no primeiro painel do assistente:
image::images/wizard_nbpref1.png[]
[start=3]
1. Feche o aplicativo, abra a janela Arquivos e analise o arquivo de propriedades dentro da pasta ``build`` do aplicativo. Você deveria encontrar agora as seguintes configurações:
image::images/wizard_nbpref2.png[]
[start=4]
1. Execute o aplicativo novamente e, da próxima vez que o assistente for aberto, as configurações especificadas acima serão automaticamente utilizadas para definir os valores nos campos do assistente.
Agora você já sabe como fazer os dados do assistente persistirem depois das reinicializações.
== Marcando o assistente
Nesta seção, você marca a string do botão "Next" (Próximo), fornecido pela infraestrutura, como "Advance" (Avançar).
O termo "marcação" significa personalização, ou seja, trata-se normalmente de pequenas modificações dentro do mesmo idioma, enquanto que "internacionalização" ou "localização" significam a tradução para outro idioma. Para obter mais informações sobre a localização dos módulos NetBeans, link:http://translatedfiles.netbeans.org/index-l10n.html[consulte aqui].
[start=1]
1. Na janela Arquivos, expanda a pasta ``branding`` do aplicativo e crie a estrutura de pasta/arquivo realçada abaixo:
image::images/wizard_branding-1.png[]
[start=2]
1. Defina o conteúdo do arquivo da seguinte forma:
[source,java]
----
CTL_NEXT=&amp;Advance >
----
Outras strings que poderiam ser marcadas são:
[source,java]
----
CTL_CANCEL
CTL_PREVIOUS
CTL_FINISH
CTL_ContentName
----
A tecla "CTL_ContentName" está definida como "Steps" por padrão, que é utilizada no painel esquerdo do assistente, caso a propriedade "WizardPanel_autoWizardStyle" não tenha sido definida como "FALSE".
[start=3]
1. Execute o aplicativo e o botão "Next" estará marcado como "Advance":
image::images/wizard_branding-2.png[]
Como opção, utilize o arquivo ``DemoWizardAction.java`` , conforme descrito anteriormente, para remover todo o lado esquerdo do painel do assistente da seguinte forma:
[source,java]
----
wizardDescriptor.putProperty("WizardPanel_autoWizardStyle", Boolean.FALSE);
----
As configurações acima têm como resultado um assistente com a seguinte aparência:
image::images/wizard_branding-3.png[]
Agora você já sabe como marcar as strings definidas na infraestrutura do assistente com suas próprias versões marcadas.
== Leituras adicionais
Vários artigos sobre informações relacionadas estão disponíveis on-line:
* O site sobre NetBeans de Tom Wheeler (clique na imagem abaixo):
[.feature]
--
image::images/wizard_tom.png[role="left", link="http://www.tomwheeler.com/netbeans/"]
--
Embora esteja escrito para o NetBeans 5.5, a amostra acima foi testada com êxito no NetBeans IDE 6.5.1 em Ubuntu Linux com JDK 1.6.
A amostra é especialmente útil para mostrar como validar os dados do usuário.
* Blog do Geertjan:
* link:http://blogs.oracle.com/geertjan/entry/how_wizards_work[Como funcionam os assistentes: Parte 1—Introdução]
* link:http://blogs.oracle.com/geertjan/entry/how_wizards_work_part_2[Como funcionam os assistentes: Parte 2—Tipos diferentes]
* link:http://blogs.oracle.com/geertjan/entry/how_wizards_work_part_3[Como funcionam os assistentes: Parte 3—Seu primeiro assistente]
* link:http://blogs.oracle.com/geertjan/entry/how_wizards_work_part_4[Como funcionam os assistentes: Parte 4—Seu próprio repetidor]
* link:http://blogs.oracle.com/geertjan/entry/how_wizards_work_part_5[Como funcionam os assistentes: Parte 5—Reutilizando e incorporando painéis existentes]
* link:http://blogs.oracle.com/geertjan/entry/creating_a_better_java_class[Criando um melhor assistente para classe Java]
== Versionamento
|===
|*Versão* |*Data* |*Alterações*
|1 |31 de março de 2009 |Versão inicial. A fazer:
* [.line-through]#Adicionar uma seção sobre validação da entrada do usuário.#
* [.line-through]#Adicionar uma seção sobre armazenamento/recuperação de dados para/do assistente.#
* Adicionar uma tabela que lista todas as propriedades do WizardDescriptor.
* Adicionar uma tabela que lista e explica todas as classes API do assistente.
* Adicionar links ao Javadoc.
|2 |1 de abril de 2009 |Adicionada uma seção de validação, com o código para a desabilitação do botão "Next" (Próximo). Adicionada também uma seção sobre persistência.
|3 |10 de abril de 2009 |Comentários integrados por Tom Wheeler, reescrevendo a seção sobre marcação para que seja realmente sobre marcação, com uma referência sobre onde as informações sobre localização podem ser encontradas.
|===