Avatar billede ng-km Nybegynder
12. april 2003 - 10:05 Der er 13 kommentarer og
1 løsning

Bredde på en String

Jeg har brug for at vide hvor lang en given String er, så jeg ikke skriver længere end til et JTextField's bredde. Til det formål benytter jeg følgende kode, som jeg har forstået er den mest nøjagtige "bredde"-bestemmelse:



            Graphics2D g2 = (Graphics2D)getGraphics()textfield.create();
            TextLayout layout = new TextLayout(textfield.getText(), getFont(), g2.getFontRenderContext());
            Rectangle2D bounds = layout.getBounds();


ud fra bounds kan jeg så få bredden på strengen. Bredden er bare ikke nøjagtig, for det er ikke altid at jeg kan skrive helt udt til enden på tekstfeltet, og andre gange "smutter" den en eller to bogstaver forbi enden.(Jeg checker bredden med en KeyListener)

Er der en mere nøjagtig breddebestemmelse, eller er der en anden måde at sikre, at man ikke kan skrive længere end til tekstfeltets bredde?
Avatar billede =maddog= Nybegynder
12. april 2003 - 16:33 #1
kan du ikke bruge fontmetrics? det er det man plejer at bruge til strings
getFontMetrics(getFont()).stringWidth(textfield.getText())
Avatar billede ng-km Nybegynder
12. april 2003 - 16:53 #2
Jeg prøvede dit eksempel til at starte med, men det var også upræcist. Så læste jeg i Javadoc'en at TextLayout, skulle beregne længden meget præcist. Den var også en smule bedre, men stadig ikke præcis nok til at kun at skrive til enden af tekstfeltet.

Der skrives lidt for kort eller lidt for langt, men indimellem også tilpas, men jeg håber selvfølgelig på noget der er tilpas hvergang.
Avatar billede =maddog= Nybegynder
12. april 2003 - 16:59 #3
så kan jeg ikke hjælpe dig. jeg har aldrig nogensinde haft problemer med fontmetrics. er det en standard font du bruger? den kan jo være din font ikke beregner bredden godt nok på den enkelte Glyph.
Avatar billede ng-km Nybegynder
12. april 2003 - 19:22 #4
Tjaa, jeg har ihvertfald ikke defineret nogen font, så java bruger vel en standard.

Har du lavet noget der sikrer at man ikke kan skrive ud over et JTextField's bredde med fontmetrics, så vil jeg meget gerne se koden, for JEG kan ikke få det til at virke optimalt.

Jeg kan selvfølgelig bare gøre som jeg gør nu. Skrive i et tekstfelt, og så se om der skrives ud over kanten, og hvis der gør så trække lidt fra (eller lægge til) den værdi som fontmetrics giver mig.

Det virker bare lidt bøvlet, og ikke særligt stilfuldt hvis man skal håndtere mange tekstfelter. Det vare nemmere hvis en metode gjorde arbejdet for mig og det virkede ens hver gang.
Avatar billede _carsten Nybegynder
15. april 2003 - 15:10 #5
Sad lige og kedede mig, så jeg har forsøgt at fedte noget sammen, kan nedenstående bruges - synes selv den virker fornuftigt.


import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.Graphics2D;
import java.awt.Font;

public class Test_TextWidth extends javax.swing.JFrame {
 
    public Test_TextWidth() {
        initComponents();
    }
   

    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jTextField1 = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();

        getContentPane().setLayout(new java.awt.GridBagLayout());

        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        jTextField1.setPreferredSize(new java.awt.Dimension(100, 20));
        jTextField1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                keyDown(evt);
            }
            public void keyReleased(java.awt.event.KeyEvent evt) {
                keyUp(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        getContentPane().add(jTextField1, gridBagConstraints);

        jLabel1.setText("Skriv i tekstfeltet");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        getContentPane().add(jLabel1, gridBagConstraints);

        pack();
    }

    private void keyUp(java.awt.event.KeyEvent evt) {
        pladder(g1);
    }

    private void keyDown(java.awt.event.KeyEvent evt) {
        pladder(g1);
    }
 
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }
   
    public void pladder(java.awt.Graphics g) {
        g = jTextField1.getGraphics();
        g2 = (Graphics2D)g;
       
        if (g2 == null)
            System.out.println("Grrrr");
       
        Font fonte = new Font("Arial", Font.PLAIN,10);
        g2.setFont(jTextField1.getFont());
        context = g2.getFontRenderContext();
       

        if(jTextField1.getText().length() > 0) {
            layout = new TextLayout(jTextField1.getText(), fonte, context);
           
            if((int)layout.getAdvance() > (jTextField1.getSize().getWidth()-25))
                jLabel1.setText("Shit !!");
            else
                jLabel1.setText("Skriv i tekstfeltet");
        }
    }
   
    public static void main(String args[]) {
        new Test_TextWidth().show();
    }
   
 
    private javax.swing.JTextField jTextField1;
    private javax.swing.JLabel jLabel1;
    TextLayout layout = null;
    Graphics2D g2;
    java.awt.Graphics g1;
    FontRenderContext context;
}
Avatar billede ng-km Nybegynder
22. april 2003 - 13:47 #6
carsten >> Jeg har afprøvet din kode, og den virker lige så godt som min egen kode. For at være sikker på at der ikke skrives ud over enden, har du trukket 25 fra teksfeltets bredde. Det er også den løsning jeg selv har fundet frem til, men jeg ville jo gerne have noget generel kode der  kunne sikre mig at det blev fyldt helt ud i tekstfeltet hverken mere eller mindre, uden at skulle tænke på om der skal trækkes lidt fra eller lægges til.

Følgende kode er den jeg selv har fundet mest hensynsfuld, men den tillader heller ikke noget fast, for jeg skal lægge 12 til teksten, og der kan indimellem godt være ét bogstav mere, men hvis jeg ændrer det, forsvinder der måske et bogstav ud ved næste ord der skrives. Du kan jo selv prøve det ved at gøre framen større eller mindre.

Det må da være muligt at finde noget der er helt nøjagtigt hvergang.


public class Test extends JFrame implements KeyListener
{
  private JTextField tekstfelt;

    public Test()
  {
    setSize(120,50);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    tekstfelt = new JTextField("");
    getContentPane().add(tekstfelt);
        tekstfelt.addKeyListener(this);
  }

  public void keyReleased(KeyEvent e){}
  public void keyPressed(KeyEvent e){}
    public void keyTyped(KeyEvent e)
    {
        if(tekstfelt.getText().length() > 0)
        {
      if(tekstfelt.getSize().width > getFontMetrics(getFont()).stringWidth(tekstfelt.getText())+12)
          return;     
      else
        {
            if(e.getKeyChar() == '')//char for backspace(kender ikke tal-definitionen)
                return;
            else
              e.consume();
        }}}

    public static void main(String args[])
    {
        Test test = new Test();
        test.setVisible(true);
    }
}
Avatar billede _carsten Nybegynder
22. april 2003 - 17:59 #7
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.Graphics2D;
import java.awt.Font;

public class Test_TextWidth extends javax.swing.JFrame {
   
    /** Creates new form Test_TextWidth */
    public Test_TextWidth() {
        initComponents();
       

    }
   
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jTextField1 = new javax.swing.JTextField();
        jLabel1 = new javax.swing.JLabel();

        getContentPane().setLayout(new java.awt.GridBagLayout());

        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        jTextField1.setPreferredSize(new java.awt.Dimension(100, 20));
        jTextField1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                keyAction(evt);
            }
            public void keyReleased(java.awt.event.KeyEvent evt) {
                keyReal(evt);
            }
        });

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        getContentPane().add(jTextField1, gridBagConstraints);

        jLabel1.setText("Skriv i tekstfeltet");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        getContentPane().add(jLabel1, gridBagConstraints);

        pack();
    }

    private void keyReal(java.awt.event.KeyEvent evt) {
        pladder(g1,Character.toString(evt.getKeyChar()) );
    }

    private void keyAction(java.awt.event.KeyEvent evt) {
        pladder(g1,Character.toString(evt.getKeyChar()) );
    }
   
    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }
   
    public void pladder(java.awt.Graphics g, String key1) {
        g = jTextField1.getGraphics();
        g2 = (Graphics2D)g;
       
        if (g2 == null)
            System.out.println("Grrrr");
       
        Font fonte = jTextField1.getFont();
        g2.setFont(fonte);
        context = g2.getFontRenderContext();
       

        if(jTextField1.getText().length() > 0) {
            layout = new TextLayout(jTextField1.getText() + key1, fonte, context);

            if((int)layout.getAdvance() > ((jTextField1.getSize().getWidth())-1))
                jLabel1.setText("Shit !!");
            else
                jLabel1.setText("Skriv i tekstfeltet");
        }
    }
   
    public static void main(String args[]) {
        new Test_TextWidth().show();
    }
   
   
    private javax.swing.JTextField jTextField1;
    private javax.swing.JLabel jLabel1;
    TextLayout layout = null;
    Graphics2D g2;
    java.awt.Graphics g1;
    FontRenderContext context;
}
Avatar billede _carsten Nybegynder
22. april 2003 - 18:03 #8
Jeg havde lavet en stor bøf, defineret min egen font og brugt den til at måle tekstlængden, jeg modificeret min udgave, den er ihverfald væsentlig bedre nu, om det er godt nok ved jeg ikke, men nu bruger jeg ihverfald den aktuelle font.

Jeg tror ikke du slipper for at trække noget(i mit sidste tilfælde kun 1)

Jeg har ikke testet din endnu, men det vil gøre!
Carsten
Avatar billede _carsten Nybegynder
22. april 2003 - 18:08 #9
Da tekstfeltets bredde måles i 'int' og en tekst's længde i float, skal der grundet den casting du er nødt til at foretage, trækkes lidt fra og det er i mit sidste tilfælde kun 1.
Avatar billede ng-km Nybegynder
22. april 2003 - 21:37 #10
I princippet er jeg egentlig ligeglad med om der skal trækkes 1 eller 2000 fra, ideen var at lave noget der ikke skal tilpasses manuelt ved at prøve sig frem, det virker ikke særligt proffesionelt. Desuden kan jeg sagtens få skriften i dit andet eksempel til at smutte 2-3 bogstaver ud over feltlængden på en standard-font, så jeg er faktisk ikke kommet videre end da jeg stillede spørgsmålet.

Men jeg takker naturligvis for svarene alligevel.
Avatar billede _carsten Nybegynder
22. april 2003 - 23:09 #11
Sjovt nok virker den hos mig.

Hvis nedenstående eksempel ikke fungerer hos dig, er jeg villig til at give op!!

Kompiler de 2 classer og prøv, du for IKKE lov til at indsætte flere tegn end dit textfelt er bredt!


public class TestTextLength extends javax.swing.JFrame {
   
    public TestTextLength() {
        initComponents();
        Text t = new Text(10, jTextField1.getGraphics(), jTextField1.getFont(), jTextField1);
        jTextField1.setDocument(t.createDefaultModel());
    }
   

    private void initComponents() {
        jTextField1 = new javax.swing.JTextField();

        getContentPane().setLayout(new java.awt.FlowLayout());

        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        jTextField1.setColumns(10);
        getContentPane().add(jTextField1);

        pack();
    }
   

    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }

    public static void main(String args[]) {
        new TextTextLength().show();
    }
   
   

    private javax.swing.JTextField jTextField1;
   
}




// Class Text

import javax.swing.*;
import javax.swing.text.*;
import java.awt.Toolkit;

public class Text extends javax.swing.JTextField {
   
    /** Creates a new instance of Text */
    public Text() {
    }
   
    public Text(int columns, java.awt.Graphics g, java.awt.Font fonte, javax.swing.JTextField jt) {
        super(columns);
        this.jt = jt;
        this.g = g;
        this.g2 = (java.awt.Graphics2D)g;
        this.fonte = fonte;
        g2.setFont(fonte);
        context = g2.getFontRenderContext();

        toolkit = Toolkit.getDefaultToolkit();
    }

    protected Document createDefaultModel() {
        TextControl tc = new TextControl();
        return tc;
    }
   
    public boolean getMyState(String s) {
     
        layout = new java.awt.font.TextLayout(jt.getText() + s, fonte, context);
        System.out.println(jt.getSize().getWidth());
        System.out.println((int)layout.getAdvance());
        if((int)layout.getAdvance() < ((jt.getSize().getWidth())-1))
            return true;
        else
            return false;
    }
       
    protected class TextControl extends PlainDocument {
        public void insertString(int offs,
                                String str,
                                javax.swing.text.AttributeSet a)
                throws BadLocationException {
                   
            char[] source = str.toCharArray();
            char[] result = new char[source.length];
            int j = 0;

            for (int i = 0; i < result.length; i++) {

                if (getMyState(str)) {
                    result[j++] = source[i];
                    super.insertString(offs, new String(result, 0, j), a);
                    System.out.println("Character: " + str + " indsættes");
                }
                else {
                    System.out.println("Character: " + str + " indsættes IKKE");
                    toolkit.beep();
                }
            }
        }
    }
       

   
    private Toolkit toolkit;
    private java.awt.Graphics g;
    private java.awt.Graphics2D g2;
    private java.awt.font.TextLayout layout = null;
    private java.awt.font.FontRenderContext context;
    private java.awt.Font fonte;
    private javax.swing.JTextField jt;
}
Avatar billede ng-km Nybegynder
23. april 2003 - 08:48 #12
Hvis jeg starter med et m og fylder resten op med i, burde det sidste i ikke skrives med, fordi det første m forsvinder næsten halvt. Desuden trækker du jo stadigvæk 1 fra, så alt i alt må jeg indrømme at jeg ikke kan bruge din kode, og den er desuden også ret omfattende for at klare en så "lille" operation. Jeg bibeholder min egen kode, og slår mig til tåls med at problemet ikke kan løses pt.

Desuden er jeg ikke enig i at der skal laves en typecast for at sammenligne en float med en int. Hvis float'en er større end int'en så er den større uanset hvad.

Men da spørgsmålet nu har været åbent forholdsvis længe får du pointene for din ihærdige indsats, så du også i fremtiden har lyst til at deltage i mine spørgsmål.
Avatar billede _carsten Nybegynder
23. april 2003 - 09:32 #13
Takker - men

Du er stadig nødt til at trække, da et default tekstfelt er markeret, d.v.s.
feltets ydre og indre mål IKKE er ens og getWidth() måler det ydre mål -  alternativt kan du bruge "jTextField1.setBorder(null);" så behøver du ikke at trække noget fra.

Jeg kan godt se, at gør man som du siger forsvinder halvdelen af m'et, så teksfeltets grænse er altså tykkere end 1, retter du til 3 er der masser af plads

Det kan godt være du synes operationen er "lille", men class Text skal bare laves én gang, resten af livet kan den anvendes men "kun" 2 linier
Text t = new Text(10, jTextField1.getGraphics(), jTextField1.getFont(), jTextField1);
        jTextField1.setDocument(t.createDefaultModel());

M.h.t. float/int - ja, gammel vane med at sammenligne "identiske" typer!
Avatar billede _carsten Nybegynder
23. april 2003 - 11:45 #14
Jeg synes lige du skulle have den helt perfekte udgave, om det skyldes ihærdighed ved jeg ikke, men jeg kan selv bruge din ide.

Finder selv tekstfeltets grænsetykkelse.

public class TestTextLength extends javax.swing.JFrame {
   
    public TestTextLength() {
        initComponents();
        MaxTextLength t = new MaxTextLength(10, jTextField1);
        jTextField1.setDocument(t.createDefaultModel());
        t = new javatest.MaxTextLength(10, jTextField2);
        jTextField2.setDocument(t.createDefaultModel());
        t = new javatest.MaxTextLength(10, jTextField3);
        jTextField3.setDocument(t.createDefaultModel());

        pack();
    }
   

    private void initComponents() {
        jTextField1 = new javax.swing.JTextField();
        jTextField2 = new javax.swing.JTextField();
        jTextField3 = new javax.swing.JTextField();

        getContentPane().setLayout(new java.awt.FlowLayout());

        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                exitForm(evt);
            }
        });

        jTextField1.setBorder(new javax.swing.border.MatteBorder(new java.awt.Insets(1, 25, 1, 5), new java.awt.Color(102, 153, 255)));
        getContentPane().add(jTextField1);

        getContentPane().add(jTextField2);

        jTextField3.setBorder(null);
        getContentPane().add(jTextField3);


    }
   

    private void exitForm(java.awt.event.WindowEvent evt) {
        System.exit(0);
    }

    public static void main(String args[]) {
        new TestTextLength().show();
    }
   
    private javax.swing.JTextField jTextField3;
    private javax.swing.JTextField jTextField2;
    private javax.swing.JTextField jTextField1;
}






// Class MaxTextLength()

public class MaxTextLength extends javax.swing.JTextField {
   
    public MaxTextLength(int column, javax.swing.JTextField jt) {
        jt.setColumns(column);
        this.jt = jt;
        getControls();
    }
   
    public MaxTextLength(int width, int height, javax.swing.JTextField jt) {
        jt.setPreferredSize(new java.awt.Dimension(width, height));
        this.jt = jt;
        getControls();
    }

    private void getControls(){
        this.g = jt.getGraphics();;
        this.g2 = (java.awt.Graphics2D)g;
        this.fonte = jt.getFont();
        g2.setFont(fonte);
       
        javax.swing.border.Border b = jt.getBorder();
        if(b != null) {
            java.awt.Insets i = b.getBorderInsets(jt);
            right = i.right;
            left = i.left;
        }
       
        context = g2.getFontRenderContext();

        toolkit = java.awt.Toolkit.getDefaultToolkit();
    }
   
    protected javax.swing.text.Document createDefaultModel() {
        TextControl tc = new TextControl();
        return tc;
    }
   
    private boolean getMyState(String s) {
        layout = new java.awt.font.TextLayout(jt.getText() + s, fonte, context);
        if((int)layout.getAdvance() < ((jt.getWidth())-(right + left)))
            return true;
        else
            return false;
    }
       
    protected class TextControl extends javax.swing.text.PlainDocument {
        public void insertString(int offs, String str,
                                javax.swing.text.AttributeSet a)
                          throws javax.swing.text.BadLocationException {
                   
            char[] source = str.toCharArray();
            char[] result = new char[source.length];
            int j = 0;

            for (int i = 0; i < result.length; i++) {
                if (getMyState(str)) {
                    result[j++] = source[i];
                    super.insertString(offs, new String(result, 0, j), a);
                }
                else {
                    toolkit.beep();
                }
            }
        }
    }
   
    private java.awt.Toolkit toolkit;
    private java.awt.Graphics g;
    private java.awt.Graphics2D g2;
    private java.awt.font.TextLayout layout = null;
    private java.awt.font.FontRenderContext context;
    private java.awt.Font fonte;
    private javax.swing.JTextField jt;
    private int right = 0, left = 0;
}
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester