• Aucun résultat trouvé

Placement des composants

N/A
N/A
Protected

Academic year: 2021

Partager "Placement des composants"

Copied!
16
0
0

Texte intégral

(1)

Placement des composants

Chaque conteneur gère le placement de ses composants à l'aide d'un LayoutManager qui se charge des calculs de placement.

La méthode setLayout(LayoutManager) de la classe Container permet de spécifier le gestionnaire de placement utilisé.

Le placement de chaque composant dépend de sa position voulue et de ses dimensions qui sont gérées par :

- les méthodes Rectangle getBounds() et setBounds(Rectangle) pour le rectangle englobant

- les méthodes Point getLocation() et setLocation(Point) pour le coin haut-gauche

- les méthodes Dimension getSize() , setSize(Dimension) et autres méthodes concernant les tailles minimum, maximum et préférée.

Le placement dépend aussi des marges ( Insets ) placées autour du composant.

(2)

Un FlowLayout place les composants de gauche à droite puis de bas en haut.

FlowLayout

public class FlowTest {

public static void main(String[] args) { Frame f = new Frame("FlowTest");

f.setLayout(new FlowLayout());

for(int i=0;i<12;i++) f.add(new Button("But"+i));

f.setSize(new Dimension(100,100));

f.setVisible(true);

} }

(3)

BorderLayout

public class BorderTest{

public static void main(String[] args){

Frame f = new Frame("BorderTest1");

f.setLayout(new BorderLayout());

f.add(new Button("Nord"), BorderLayout.NORTH);

f.add(new Button("Sud"), BorderLayout.SOUTH);

f.add(new Button("Est"), BorderLayout.EAST);

f.add(new Button("Ouest"), BorderLayout.WEST);

f.add(new Button("Centre"), BorderLayout.CENTER);

f.setSize(new Dimension(500,500));

f.setVisible(true);

} }

Un BorderLayout gère cinq zones sur le container, on doit spécifier dans quelle

zone on ajoute les composants

(4)

GridLayout

public class GridLayoutTest extends Frame { public GridLayoutTest() {

super("GridLayoutTest");

Panel c = new Panel();

c.setLayout(new GridLayout(2,4,3,3));

c.setBackground(Color.blue);

List l = new List();

c.add(new Button("1"));

l.add("un");

l.add("deux");

l.add("trois");

c.add(l);

c.add(new Button("2"));

c.add(new Button("3"));

c.add(new Button("5"));

c.add(new Button("6"));

c.add(new Button("extra-large"));

this.add(c);

this.pack();

this.setVisible(true);

} }

Un GridLayout gère une grille de composants.

(5)

GridBagLayout

public GridBagLayoutTest(){

super("GridbagLayoutTest");

JButton button;

this.setLayout(new GridBagLayout());

GridBagConstraints c = new GridBagConstraints();

c.fill = GridBagConstraints.BOTH; c.weightx = 1.0;

button = new JButton("Bouton 1"); this.add(button, c);

button = new JButton("Bouton 2"); this.add(button, c);

button = new JButton("Bouton 3"); this.add(button, c);

button = new JButton("Bouton 4");

c.gridwidth = GridBagConstraints.REMAINDER;

this.add(button, c);

button = new JButton("Bouton 5"); this.add(button, c);

c.gridwidth = GridBagConstraints.RELATIVE;

button = new JButton("Bouton 6") ; this.add(button, c);

button = new JButton("Bouton 7");

c.gridwidth = GridBagConstraints.REMAINDER;

this.add(button, c);

button = new JButton("Bouton 8");

c.gridwidth = 1; c.gridheight = 2; c.weighty = 1.0;

this.add(button, c);

button = new JButton("Bouton 9");

c.gridwidth = GridBagConstraints.REMAINDER;

c.gridheight = 1; this.add(button, c);

button = new JButton("Bouton 10");

c.weighty = 0.0; this.add(button, c);

this.pack();

this.setVisible(true);

}

(6)

BoxLayout

public BoxLayoutTest() { super("BoxLayoutTest");

Box b1 = new Box(BoxLayout.Y_AXIS);

Button button = new Button("Button 1");

b1.add(button);

button = new Button("Button 2");

button.setPreferredSize(new Dimension(200,100));

b1.add(button);

Box b2 = new Box(BoxLayout.X_AXIS);

button = new Button("Button 3");

b2.add(button);

button = new Button("Button 4");

button.setPreferredSize(new Dimension(200, 100));

b2.add(button);

b1.add(b2);

this.add(b1);

this.pack();

this.setVisible(true);

}

Un BoxLayout place les composants en ligne verticale ou horizontale. Il permet aussi

d'ajouter des blocs invisibles de taille fixe ou variable. Un composant Box est un

conteneur géré par BoxLayout.

(7)

Autres gestionnaires de géométrie

- CardLayout : les composants sont affichés comme un tas de cartes avec seulement le composant du dessus visible

- SpringLayout : positionnement par contraintes

- ScrollPaneLayout : pour les conteneurs avec ascenceurs - GroupLayout : organisation hiérarchique des composants

Il est bien sur possible d'écrire ses propres gestionnaires de placement en implémentant l'interface LayoutManager (ou la sous-interface LayoutManager2 ).

Par défaut, un JPanel possède un FlowLayout , le panneau de contenu d'une

JFrame est par défaut un BorderLayout

(8)

Gestion des événements

L'interface doit réagir à des événements :

- action de l'utilisateur : clic souris, appui sur une touche du clavier, … - changement d'état d'un composant, …

Le pattern de réaction est du type Observer : - un composant est la source d'événement - un objet représente l'événement ( AWTEvent )

- l'objet événement est transmis à un écouteur ( EventListener )

Les écouteurs définissent le comportement via des méthodes spécifiées dans des interfaces et appelées par la source.

Tout composant peut produire des événements de divers types ( FocusEvent , ActionEvent , KeyEvent , MouseEvent , WindowEvent , ...)

Les événéments encapsulent des informations sur le type de l'événement, sa

source, le contexte (touche SHIFT, CTRL, ... appuyée, etc)

(9)

Exemple ActionListener

public class ListenerTest extends JFrame implements ActionListener{

private JButton but;

private boolean state = true;

public ListenerTest(){

super("Test ecouteur");

this.but = new JButton("Cap?");

this.but.setBackground(Color.RED);

this.but.addActionListener(this);

this.getContentPane().add(this.but);

this.setSize(200,200);

this.setVisible(true);

}

public void actionPerformed(ActionEvent ae){

this.state = ! this.state;

if(!this.state) this.but.setBackground(Color.BLUE);

else this.but.setBackground(Color.RED);

} }

Source : un bouton

Événement : clic sur le bouton ( ActionEvent )

Écouteur : la frame elle même qui implémente l'interface ActionListener

Attention : l'écouteur doit s'enregistrer comme tel auprès de la source

(10)

Ecouteurs (1/2)

Tout objet peut être écouteur, il suffit qu'il implémente l'interface correspondante et s'enregistre auprès d'une source d'événement.

Plusieurs écouteurs peuvent écouter une même source et un même objet peut écouter plusieurs sources.

Exemple : une zone texte s'écoute elle-même pour gérer les événements clavier

public class MyTextField extends JTextField implements KeyListener{

private boolean state = true;

public MyTextField(){

super(20);

this.setBackground(Color.WHITE);

this.addKeyListener(this);

}

public void keyPressed(KeyEvent e){

if(e.getKeyCode()==KeyEvent.VK_ENTER){

this.state = ! this.state;

if(!this.state) this.setBackground(Color.CYAN);

else this.setBackground(Color.WHITE);

} }

public void keyReleased(KeyEvent e){}

(11)

Ecouteurs (2/2)

Exemple : une fenêtre écoute les événements de focus sur la zone texte

public class TestFocus extends JFrame implements FocusListener{

private MyTextField mtf;

public TestFocus(){

super("Test focus");

this.mtf = new MyTextField();

this.mtf.setFocusable(true);

this.mtf.addFocusListener(this);

this.add(this.mtf,BorderLayout.NORTH);

this.add(new JButton("OK"),BorderLayout.SOUTH);

this.setSize(500,500);

this.setVisible(true);

}

public void focusGained(FocusEvent e){

this.mtf.setText("Focus");

}

public void focusLost(FocusEvent e){

this.mtf.setText("Pas Focus");

} }

(12)

Adapteurs

On peut ne pas redéfinir toutes les méthodes en utilisant un Adapter , une classe qui redéfinit les méthodes avec des corps vides. Les Adapter sont généralement spécialisés et instanciés par une classe anonyme.

public class MyTextField extends JTextField{

private boolean state = true;

public MyTextField(){

super(20);

this.setBackground(Color.WHITE);

this.addKeyListener(new KeyAdapter(){

public void keyPressed(KeyEvent e){

if(e.getKeyCode()==KeyEvent.VK_ENTER) changeState();

} });

}

private void changeState(){

this.state = ! this.state;

if(!this.state) this.setBackground(Color.CYAN);

else this.setBackground(Color.WHITE);

} }

(13)

Actions (1/2)

La classe AbstractAction implémente l'interface ActionListener et permet de définir et de décrire un comportement partagé par plusieurs composants.

public class MyAction extends AbstractAction{

public MyAction(){

super("MonAction");

this.putValue(SHORT_DESCRIPTION,"C'est mon action"); // infobulle this.putValue(MNEMONIC_KEY,KeyEvent.VK_A); // raccourci alt+A

}

public void actionPerformed(ActionEvent e){

System.out.println("blabla");

} }

...

MyAction ma = new MyAction() ; JButton b = new JButton("OK");

b.setAction(ma);

...

JMenuItem jmi = new JMenuItem("OK");

jmi.setAction(ma);

...

(14)

Actions (2/2)

On peut créer différentes actions sur un même composant et les gérer via une carte d'actions et une carte d'entrées.

public class AnnulAction extends AbstractAction{

public AnnulAction(){

super("AnnulAction");

this.putValue(MNEMONIC_KEY,KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));

}

public void actionPerformed(ActionEvent e){

...

} }

...

monComposant.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)

.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z,ActionEvent.CTRL_MASK), "Annulation");

monComposant.getActionMap().put("Annulation",new AnnulAction());

...

(15)

Evénements et Threads

La gestion des événements se fait dans un thread spécial de la JVM : Event Dispatch Thread. Un traitement long lors d'un événement peut bloquer l'interface, et doit donc être lancé de façon asynchrone :

...

public void actionPerformed(ActionEvent e) { new Thread(new Runnable() {

grosCalculSuperLong();

SwingUtilities.invokeLater(new Runnable() { public void run() {

miseAJourdInterface();

} });

}).start();

} ...

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() { public void run() {

new MaJFrame();

} });

}

Pour garantir le bon fonctionnement d'une interface, il vaut mieux la lancer dans

l'Event Dispatch Thread (et non dans le thread du main ).

(16)

Il reste tant à découvrir ...

- gestion fine des événements : on peut travailler sur la file d'événements, intercepter des événements, forcer le lancement d'événements, …

- un mécanisme de gestion des undo/redo existe : classe UndoManager

- un mécanisme de drag&drop existe : TransferHandler , ...

Références

Documents relatifs

QUEL(S) accompagne les noms masculins et QUELLE(S) ceux féminins.. Ce sont donc des déterminants (interrogatifs

Parce que si je commence à faire des grands gestes expressionnistes, avec des grands costumes et un langage très artificiel, en m’éloignant de ce que je pourrais faire dans la

Comme cette autonomie les amène à être seuls, sans aide humaine, ils doivent être « intelligents» pour fonctionner.. Ainsi, une voiture sans conducteur peut circuler seule, et un

1 - 2. Il nous semble donc que ce n'est pas parce que nous ne disposons pas d'une théorie générale, ou d'une pédagogie établie à l'efficacité avérée, que l'université ne doit

Mais le lycée s’impli- que également dans de nombreuses manifestations comme dernièrement en as- surant le service d’une soirée caritative au Zénith de Saint-Etienne ou

Au contraire, il nous paraît davantage pertinent de réfléchir globalement aux relations qui existent entre le tutorat, le scénario pédagogique et le contexte global dans

Ce n'est pas une attaque pratique, elle n'est même pas dangereuse pour la transmission des données (cette déclaration dans mon livre [3,5.7.2], est fausse – elle a

Le retour au lycée peut être source d’inquiétude pour vous ou vos enfants.. Vous trouverez dans ce guide le protocole sanitaire auquel nous devons tous