IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants Java Discussion :

Problème d'overlap sur composant étendant un JTextField


Sujet :

Composants Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5
    Par défaut Problème d'overlap sur composant étendant un JTextField
    Bonjour à tous,

    Je souhaiterai étendre les fonctionnalités d'un JTextField en lui ajoutant un bouton lié
    agissant uniquement le JTextField.

    Pour ce faire j'ai créé un nouveau composant étendant la classe JTextField qui ajoute le
    bouton et sa fonction.

    Le nouveau composant réagit bien comme un JTextField et le bouton fonctionne.

    Le problème est à l'affichage.
    Le bouton créé recouvre le JTextField au lieu d'être placé après sans overlap.

    J'ai essayé différents layout sans résultat.

    Quelqu'un aurait il une idée de solution à ce problème d'affichage ?

    Faut il redéfinir la méthode paintComponent ?

    Toute idée sera la bienvenue.



    Ci joint un exemple qui permet de reproduire le problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
     
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
     
    public class TestJtfldBtApp extends JFrame
    {
     
        JPanel pan;
        JTextFieldBt tfb1;
        JTextFieldBt tfb2;
        JTextArea affichage;
        JButton showbutton;
     
        TestJtfldBtApp()
        {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
            pan = new JPanel();
            pan.setLayout(new FlowLayout(FlowLayout.CENTER, 50, 10));
     
            // 1er JTextField avec bouton
            tfb1 = new JTextFieldBt();
     
            pan.add(tfb1);
     
            // 2eme JTextField avec bouton
            tfb2 = new JTextFieldBt();
            pan.add(tfb2);
     
            // JTextArea pour affichage resultat sur clic showbutton
            affichage = new JTextArea();
            affichage.setPreferredSize(new Dimension(200, 100));
            pan.add(affichage);
     
            // création boutton affichage
            showbutton = new JButton("Display");
            pan.add(showbutton);
     
            // listener pour action du showbutton
            showbutton.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    affichage.append("\nTBF1 <"+tfb1.getText()+">");
                    affichage.append("\nTBF2 <"+tfb2.getText()+">");
                }
            });
     
            getContentPane().add(pan);
            setSize(300, 300);
            setVisible(true);
        }
     
        private class JTextFieldBt extends JTextField
        {
            private JTextField jtf;
            private JButton    button;
     
            JTextFieldBt()
            {
     
                // le constructeur par defaut créé un JTextField de 10 cars
                super(null, 10);
                jtf = this;
     
                this.setLayout(new FlowLayout(FlowLayout.RIGHT, 2, 0));
     
                // création boutton lié au JTextField
                button = new JButton("Eff.");
     
                this.add(button);
     
                // listener pour action du boutton
                button.addActionListener(new java.awt.event.ActionListener()
                {
                    public void actionPerformed(java.awt.event.ActionEvent evt)
                    {
                        // exemple action - efface le text du JTextField
                        jtf.setText("");
                    }
                });
     
            }
     
        }
     
     
        public static void main(String[] args) 
        {
            new TestJtfldBtApp();
     
        }
     
    }

  2. #2
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Bah en même temps tu ajoutes ton JButton à ton JTexField, normal que le JButton se trouve dans le JTextField.
    Pour faire vite autant directement créer un JComponent contenant ton JTextField et ton JButton.

    Genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    package swing.tests;
     
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.event.ActionListener;
     
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
     
    public class MyButtonTextField {
     
        private JTextField myTextField;
        private JButton myButton;
        private JPanel myPanel;
     
        public MyButtonTextField() {
            myPanel = new JPanel(new BorderLayout());
            myTextField = new JTextField(10);
            myButton = new JButton("Eff.");
     
            myPanel.setBackground(new Color(myTextField.getBackground().getRGB()));
            myPanel.setBorder(myTextField.getBorder());
            myTextField.setBorder(BorderFactory.createEmptyBorder());
     
            myPanel.add(myTextField);
            myPanel.add(myButton, BorderLayout.LINE_END);
            myButton.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    myTextField.setText("");
                    myTextField.requestFocus();
                }
            });
        }
     
        public JComponent getComponent() {
            return myPanel;
        }
     
        public void addButtonListener(ActionListener a) {
            myButton.addActionListener(a);
        }
     
        public JTextField getEditor() {
            return myTextField;
        }
     
        public static void main(String[] args) {
            JFrame frm = new JFrame();
            frm.add(new MyButtonTextField().getComponent());
            frm.pack();
            frm.setLocationRelativeTo(null);
            frm.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frm.setVisible(true);
        }
    }

  3. #3
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    +1 étends plutot JPanel ou JComponent pour créer des composants composite. tout le code du textfield assume qu'il prend tout la place, pas qu'un satané bouton va venir l'emmerder . du coup sa bordure prend toute la place, son fond tout la place etc.

    Par contre, justement, étends JTextfield si tu veux faire apparaitre des bouton sur le textfield qui n'apparaitrait, par exemple, que si le curseur est sur le textfield....

    Bref, ca dépend du besoin. A coté = créer un conteneur pour l'ensemble.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5
    Par défaut
    Merci pour vos réponses.

    Je suis d'accord avec les 2 solutions suivant le besoin.

    Je suis d'accord avec la solution de sinok si mon composant n'a pas besoin d'être considéré comme un jtextfield en amont (avec toutes ses fonctions) sinon cela obligerait à passer systématiquement par la méthode getEditor().

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyButtonTextField mbtf1 = new MyButtonTextField();
    PanelAmont.add(mbtf1.getComponent());
    puis faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     mbtf1.getEditor().getText()  ou mbtf1.getEditor().setText()
    pour lire ou écrire dans ce composant par la suite
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    au lieu de mbtf1.getText() ou mbtf1.setText()
    s'il était vu comme un jtextfield

    Cette solution est bonne dans le cas où adapter le code en amont ne pose pas de problème particulier.



    Je suis aussi d'accord avec tchize, il faudrait encapsuler le jtextfield et le jbutton dans un conteneur si je souhaite que mon composant résultant étend jtextfield.

    Pour le besoin actuel, le composant résultant doit être vu comme un jtextfield, le bouton associé devant être transparent en amont.
    Ce composant pourra être utilisé à différents endroits de l'application.

    Je vais creuser cette 2ème piste.

  5. #5
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Bah il te suffit de créer les méthodes setText dont tu as besoin qui délèguent ensuite au JTextField.

    Ca a de plus le gros avantage de simplifier l'utilisation de la classe niveau autocompletion car on diminue le nombre de méthodes au strict nécessaire (qui a vraiment besoin des 10000 méthodes issues de JComponen & cie).

    Il te suffit de rajouter les quelques méthodes qui t'intéressent et le tour est joué.

  6. #6
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut
    Quid de faire étendre son composant du JTextField et d'adapter le paintComponent pour tenir compte du bouton ?

  7. #7
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Citation Envoyé par lvr Voir le message
    Quid de faire étendre son composant du JTextField et d'adapter le paintComponent pour tenir compte du bouton ?
    Je rephrase ta proposition: pourquoi faire simple et sans bug alors qu'on peut faire compliqué et plein de bug?

    Puis de toute façon étendre paintComponent dans ce cas ne servirait absolument à rien car ce n'est pas paintComponent qui gère la taille des composants, de fait paintComponent ne fait que dessiner en fonction de la taille qui est affectée au composant par le LayoutManager.

  8. #8
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    sans compter qu'une grosse partie du boulot est déléguée au JTextfieldUI du UIManager ....

  9. #9
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut
    Citation Envoyé par sinok Voir le message
    Puis de toute façon étendre paintComponent dans ce cas ne servirait absolument à rien car ce n'est pas paintComponent qui gère la taille des composants, de fait paintComponent ne fait que dessiner en fonction de la taille qui est affectée au composant par le LayoutManager.
    Mon idée était dans le paintComponent de faire un super.paintComponent avec la taille allouée par le LayoutManager réduite de la taille du bouton, puis de peindre le bouton dans la place libérée. L'avantage c'est que le composant reste un JTextfield à part entière, donc plus polyvant/réutilisable. Mais ce n'était qu'une idée comme ça. Je prends note que c'est foireux

  10. #10
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5
    Par défaut
    Bonjour à tous,

    Je souhaitais étendre les fonctionnalités d'un composant "basic" (ici un JTextField) en lui ajoutant un bouton qui n'agit que sur le JTextField tout en conservant les fonctions du composant basic.

    Après quelques recherches sur le net, je pense avoir trouvé une piste en encapsulant le JTextField et le bouton dans un javax.swing.border.CompoundBorder.
    Avec cette solution il n'y a pas besoin d'adapter le paintComponent du JTextField.

    Je mettrai un exemple dans les prochains jours pour ceux que cela peut intéresser.

  11. #11
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut
    Tu connais ceci ?
    http://www.jidesoft.com/products/oss.htm

    Il y a les "overlayble" qui font peut-être ce que tu veux.

  12. #12
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5
    Par défaut Exemple de classe étendant un JTextField avec un JButton
    Bonjour à tous,

    Merci Ivr pour le pointeur, je ne connaissais pas.

    Comme promis ci joint un exemple résultant de mes différentes recherches pour ceux que cela peut intéresser.

    Cet exemple demande 3 sources :
    - Main.java
    - MonBorder.java
    - MonJtextfieldButton.java


    Main.java
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
     
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextArea;
     
     
    public class Main
    {
     
        public static void main(String[] args)
        {
            JFrame mainFrame = new JFrame();
            mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
            JPanel mainPanel = new JPanel();
            mainPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 50, 10));
     
            // ajout 1er JTextField avec bouton
            final MonJtextfieldButton jtfldbt1 = new MonJtextfieldButton();
            mainPanel.add(jtfldbt1);
     
            // ajout 2ème JTextField avec bouton
            final MonJtextfieldButton jtfldbt2 = new MonJtextfieldButton();
            mainPanel.add(jtfldbt2);
     
            // ajout JTextArea pour affichage du contenu des JTextField
            final JTextArea affichage = new JTextArea();
            affichage.setPreferredSize(new Dimension(200, 100));
            affichage.setFocusable(false);
            mainPanel.add(affichage);
     
            // ajout bouton pour affichage du contenu des JTextField
            JButton affichebutton = new JButton("Affiche");
            mainPanel.add(affichebutton);
     
            // listener pour action sur affichebutton
            affichebutton.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    affichage.setText("");
                    affichage.append("\nTBF1 <"+jtfldbt1.getText()+">");
                    affichage.append("\nTBF2 <"+jtfldbt2.getText()+">");
                }
            });
     
            mainFrame.getContentPane().add(mainPanel);
            mainFrame.setSize(300, 300);
            mainFrame.setVisible(true);
     
        }

    MonBorder.java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
     
    import java.awt.Component;
    import java.awt.Graphics;
    import java.awt.Insets;
    import javax.swing.JComponent;
    import javax.swing.border.Border;
    import javax.swing.border.CompoundBorder;
     
    public class MonBorder implements Border
    {
        public static final int TOP      = 1;
        public static final int LEFT     = 2;
        public static final int BOTTOM   = 3;
        public static final int RIGHT    = 4;
     
        public static final float LEADING  = 0.0f;
        public static final float CENTER   = 0.5f;
        public static final float TRAILING = 1.0f;
     
        private JComponent component;
        private int side;
        private float alignment;
        private Insets borderInsets = new Insets(0, 0, 0, 0);
        //private int gap = 5;
        private int gap = 0;
     
        public MonBorder(JComponent component, int side, float alignment )
        {
     
            if (side == TOP
            ||  side == LEFT
            ||  side == BOTTOM
            ||  side == RIGHT)
            {
                    this.side = side;
            }
            else
            {
                    String message = "Side doit être TOP, LEFT, BOTTOM, ou RIGHT";
                    throw new IllegalArgumentException(message);
            }
     
            this.component = component;
            component.setSize( component.getPreferredSize() );
            this.alignment = alignment > 1.0f ? 1.0f : alignment < 0.0f ? 0.0f : alignment;
            updateAndAlign();
        }
     
        private void updateAndAlign()
        {
            if (side == TOP)
            {
                    borderInsets.top = component.getPreferredSize().height + gap;
                    component.setAlignmentX(alignment);
                    component.setAlignmentY(0.0f);
            }
            else if (side == BOTTOM)
            {
                    borderInsets.bottom = component.getPreferredSize().height + gap;
                    component.setAlignmentX(alignment);
                    component.setAlignmentY(1.0f);
            }
            else if (side == LEFT)
            {
                    borderInsets.left = component.getPreferredSize().width + gap;
                    component.setAlignmentX(0.0f);
                    component.setAlignmentY(alignment);
            }
            else if (side == RIGHT)
            {
                    borderInsets.right = component.getPreferredSize().width + gap;
                    component.setAlignmentX(1.0f);
                    component.setAlignmentY(alignment);
     
            }
    	}
     
        @Override
        public Insets getBorderInsets(Component c)
        {
            return borderInsets;
        }
     
        @Override
        public boolean isBorderOpaque()
        {
            return false;
        }
     
        @Override
        public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
        {
            float x2 = (width  - component.getWidth())  * component.getAlignmentX() + x;
    	float y2 = (height - component.getHeight()) * component.getAlignmentY() + y;
    	component.setLocation((int)x2, (int)y2);
        }
     
        /*
         *  Remplace le Border existant avec un CompoundBorder contenant le
         *  Border original et le ComponentBorder
         */
        public void installe(JComponent parent)
        {
    	adjusteBorder(parent);
     
    	Border current = parent.getBorder();
     
    	if (current == null)
    	{
                parent.setBorder(this);
    	}
    	else
    	{
                CompoundBorder compound = new CompoundBorder(current, this);
                parent.setBorder(compound);
    	}
     
    	parent.add(component);
     
        }
     
        /*
         *  Le nouveau Border doit être ajusté pour permettre au composant
         *  de s'insérer dans les limites du composant parent
         */
        private void adjusteBorder(JComponent parent)
        {
     
            Insets parentInsets = parent.getInsets();
     
            // ajustement de la hauteur
            if (side == RIGHT || side == LEFT)
            {
                    int parentHeight = parent.getPreferredSize().height - parentInsets.top - parentInsets.bottom;
                    int diff = component.getHeight() - parentHeight;
     
                    if (diff > 0)
                    {
                            if (alignment == LEADING)
                            {
                                    borderInsets.bottom += diff;
                            }
                            else if (alignment == TRAILING)
                            {
                                    borderInsets.top += diff;
                            }
                            else
                            {
                                    int half = diff / 2;
                                    borderInsets.top += half;
                                    borderInsets.bottom += (diff - half);
                            }
                    }
            }
     
            //  ajustement de la largeur
     
            if (side == TOP || side == BOTTOM)
            {
                    int parentWidth = parent.getPreferredSize().width - parentInsets.left - parentInsets.right;
                    int diff = component.getWidth() - parentWidth;
     
                    if (diff > 0)
                    {
                            if (alignment == LEADING)
                            {
                                    borderInsets.right += diff;
                            }
                            else if (alignment == TRAILING)
                            {
                                    borderInsets.left += diff;
                            }
                            else
                            {
                                    int half = diff / 2;
                                    borderInsets.left += half;
                                    borderInsets.right += (diff - half);
                            }
                    }
            }
        }
     
     
    }
    enfin MonJtextfieldButton.java

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
     
    import java.awt.Dimension;
    import javax.swing.JButton;
    import javax.swing.JTextField;
    import javax.swing.border.EmptyBorder;
     
    /**
     * Exemple : class extendant un JTextField avec un bouton
     * 
     */
    public class MonJtextfieldButton extends JTextField
    {
        private JTextField MonJtextField;
        private JButton    MonJButton;
     
     
        /**
         * Constructeur par defaut.
         */
        public MonJtextfieldButton()
        {
            super(null, 10);
            MonJtextField = this;
            initComponent();
     
        }
     
     
        /**
         * Constructeur avec texte
         * 
         * @param text String
         */
        public MonJtextfieldButton(String text)
        {       
            super(text);
            MonJtextField = this;
            initComponent();    
        }
     
     
        /**
         * Constructeur avec nombre de colonnes.
         * 
         *
         * @param columns int
         */
        public MonJtextfieldButton(int columns)
        {
            super(columns);
            MonJtextField = this;
            initComponent();
        }
     
     
        /**
         * Constructeur avec texte et nombre de colonnes
         *
         * @param text
         * @param columns
         */
        public MonJtextfieldButton(String text,int columns)
        {
            super(text,columns);
            MonJtextField = this;
            initComponent();
        }
     
     
        /**
         * Initialisation
         */
        private void initComponent()
        {
     
            // creation du JButton lié au JTextField
            MonJButton = new JButton("...");
     
            MonJButton.setBorder( new EmptyBorder(1, 3, 1, 3) );
            MonJButton.setPreferredSize( new Dimension(18, 16) );
            MonJButton.setFocusable(false);
     
            MonBorder cpnBorder =
                     new MonBorder(MonJButton, MonBorder.RIGHT, MonBorder.CENTER);
            cpnBorder.installe(MonJtextField);
     
            // ajout listener
            MonJButton.addActionListener(new java.awt.event.ActionListener()
            {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    ButtonAction();
                }
     
            });
     
            return;
        }
     
     
        /**
         * Action executée sur clic sur le bouton
         */
        private void ButtonAction()
        {
            // exemple action - on efface le texte du JTextField
            // cette partie doit être adaptée suivant la fonction du bouton
            MonJtextField.setText("");        
        }
     
    }

  13. #13
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut
    J'ai pas essayé ton code, mais ça semble pas mal.
    Pourquoi ne pas intégrer la classe MonBorder dans MonJTextFieldButton, comme ça tu as un composant simple à "transporter" ?

  14. #14
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    a vérifier si ca passe bien avec d'autres l&f, mais j'admet que la solution du border est assez élégante.

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    5
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5
    Par défaut
    Oui c'est possible.

    L'intérêt de laisser la classe MonBorder public est de pouvoir éventuellement la
    réutiliser avec d'autres composants.

    Si il n'y a pas ce besoin la classe MonBorder peut être intégrée dans MonJTextFieldButton.

    On peut clore ce point.


  16. #16
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut Essai
    J'ai essayé la solution proposée par pjg0657 pour adapter un JFileChooser en lui ajoutant une drop down des derniers répertoires utilisés, valable et constant pour tous les file chooser de mon projet.

    Voilà ce que ça donne

    [en haut: sans l'ajout du border spécial, en bas: avec le border spécial englobant la combobox]

    tchize_ parlait d'éventuel problèmes de rendus.... Les voilà.

    Là où ça foire, c'est au paint de la combobox, puisque tout le reste à l'air nickel, le filechooser étant bien paint en-dessous de la PreferredHeight de la ComboBox.

    J'ai essayé d'influencer la taille de la combobox en disant que la MaximumSize==PreferredSize, mais ça n'a pas marché.

    Des idées sur comment arranger ce problème ?

  17. #17
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    919
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 919
    Par défaut
    Compris et résolu.
    Il faut adapter le code de MonBorder.

    Le problème est au niveau du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
       /*
         *  Remplace le Border existant avec un CompoundBorder contenant le
         *  Border original et le ComponentBorder
         */
        public void installe(JComponent parent) {
    	adjusteBorder(parent);
     	Border current = parent.getBorder();
     	if (current == null) {
                parent.setBorder(this);
    	} else {
                CompoundBorder compound = new CompoundBorder(current, this);
                parent.setBorder(compound);
    	}
    	parent.add(component);
        }
    et plus spécifiquement du "parent.add(component)".
    Dans le cas du JFileChooser le parent a comme layout un BorderLayout. Donc ajouter le composant au parent via "parent.add(component)" l'ajoute au centre tout en virant ce qui s'y trouvait avant (dans le cas du FileChooser, la liste des fichiers). Il faut donc ajouter le composant en indiquant une contrainte.
    J'ai adapté le code comme ceci (rem: cas de l'ajout en haut et alignement 0.0f):
    1) détecter si le layout du parent est un BorderLayout,
    2) si non, faire un "parent.add(component)"
    3) si oui, voir ce qu'il y a dans la cellule PAGE_START ou NORTH
    4) s'il n'y a rien, faire un "parent.add(component,BorderLayout.PAGE_START)"
    5) s'il y a quelque chose, faire un JPanel de type BoxLayout PAGE_AXIS dans lequel on place le composant puis ce qui se trouvait dans le PAGE_START et faire "parent.add(tmppanel,BorderLayout.PAGE_START)"
    Plus quelques adaptations dans les Insets

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
        private class MonBorder implements Border {
            private JComponent component;
            private Insets borderInsets = new Insets(0, 0, 0, 0);
            private int gap = 5;
            private boolean isBorderLayout = false;
     
            public MonBorder(JComponent component) {
     
                this.component = component;
                component.setSize(component.getPreferredSize());
                updateAndAlign();
            }
     
            private void updateAndAlign() {
                if (!isBorderLayout) {
                    borderInsets.top = component.getPreferredSize().height + gap;
                } else {
                    borderInsets.top = 0;
                }
                component.setAlignmentX(0.0f);
                component.setAlignmentY(0.0f);
            }
     
            public Insets getBorderInsets(Component c) {
                return borderInsets;
            }
     
            public boolean isBorderOpaque() {
                return false;
            }
     
            public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
                if (!isBorderLayout) {
                    float x2 = (width - component.getWidth()) * component.getAlignmentX() + x;
                    float y2 = (height - component.getHeight()) * component.getAlignmentY() + y;
                    component.setLocation((int) x2, (int) y2);
                }
            }
     
            /*
             *  Remplace le Border existant avec un CompoundBorder contenant le
             *  Border original et le ComponentBorder
             */
            public void installe(JComponent parent) {
                adjusteBorder(parent);
                Border current = parent.getBorder();
                if (current == null) {
                    parent.setBorder(this);
                } else {
                    CompoundBorder compound = new CompoundBorder(current, this);
                    parent.setBorder(compound);
                }
     
                LayoutManager layout = parent.getLayout();
                if (layout instanceof BorderLayout) {
                    isBorderLayout = true;
                    JComponent top = (JComponent)((BorderLayout) layout).getLayoutComponent(BorderLayout.NORTH);
                    if (top == null) top = (JComponent)((BorderLayout) layout).getLayoutComponent(BorderLayout.PAGE_START);
                    if (top != null) {
                        JPanel tmp = new JPanel();
                        tmp.setLayout(new BoxLayout(tmp, BoxLayout.PAGE_AXIS));
                        tmp.add(component);
                        tmp.add(Box.createVerticalStrut(gap));
                        tmp.add(top);
                        top.setAlignmentX(0.0f);
                        top = tmp;
                    } else top = component;
                    parent.add(top, BorderLayout.PAGE_START);
                } else {
                    isBorderLayout = false;
                    parent.add(component);
                }
     
                updateAndAlign();
            }
     
            /*
             *  Le nouveau Border doit être ajusté pour permettre au composant
             *  de s'insérer dans les limites du composant parent
             */
            private void adjusteBorder(JComponent parent) {
     
                Insets parentInsets = parent.getInsets();
     
                int parentWidth = parent.getPreferredSize().width - parentInsets.left - parentInsets.right;
                int diff = component.getWidth() - parentWidth;
     
                if (diff > 0) {
                    borderInsets.right += diff;
                }
            }
    Dans le install(component), je regarde si le layout du parent est un borderlayout. Si oui je mets le composant dans la partie PAGE_START (où je l'y ajoute s'il y avait déjà quelque chose) et je remets le inset.top à 0. Sinon, je continue comme dans la version d'origine.

Discussions similaires

  1. Réponses: 2
    Dernier message: 19/01/2007, 10h09
  2. Réponses: 1
    Dernier message: 06/07/2006, 19h20
  3. Problème d'événements sur un composant TChart
    Par 3nTiC dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/07/2006, 16h26
  4. [C#]Problème sur composant perso (Bouton Transparent)
    Par SLE dans le forum Windows Forms
    Réponses: 1
    Dernier message: 06/10/2005, 00h12
  5. [VB.NET] Problème sur composant comboBox hérité
    Par SergeF dans le forum Windows Forms
    Réponses: 3
    Dernier message: 08/06/2004, 14h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo