2013-04-15 17 views
6

nella mia applicazione Ho un'etichetta con una dimensione di carattere superiore a 200. Questa etichetta contiene grandi spazi vuoti e discendenti (irregolari). Come posso rimuoverlo?Come rimuovere il gap nell'etichetta java swing di dimensioni grandi

Questo è il mio codice:

package Core; 

import java.awt.Font; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 

import javax.swing.BorderFactory; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 

public class LabelDemo extends JPanel { 
    public LabelDemo() { 
     super(new GridBagLayout()); 
     JLabel label2; 
     GridBagConstraints c = new GridBagConstraints(); 
     c.gridx = 0; 
     c.gridy = 0; 
     // Create the other labels. 
     label2 = new JLabel("Text-Only Label"); 
     label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa")); 
     label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220)); 
     // label2.setBorder(new EmptyBorder(-50, 0, 0, 0)); 

     // Add the labels. 
     add(label2, c); 
    } 

    /** 
    * Create the GUI and show it. For thread safety, this method should be invoked from the event dispatch thread. 
    */ 
    private static void createAndShowGUI() { 
     // Create and set up the window. 
     JFrame frame = new JFrame("LabelDemo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // Add content to the window. 
     frame.add(new LabelDemo()); 

     // Display the window. 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     // Schedule a job for the event dispatch thread: 
     // creating and showing this application's GUI. 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       // Turn off metal's use of bold fonts 
       UIManager.put("swing.boldMetal", Boolean.FALSE); 

       createAndShowGUI(); 
      } 
     }); 
    } 
} 

Cerco anche mio ultimo post: How to change gap in swing label e sperimentare con inserti, ma questo aspetto diverso in Linux e Windows

c'è qualche modo migliore come rimuovere questa lacuna ?

+0

Vuoi dire che si desidera tutte le lettere devono essere allineate in cima? –

+0

se vuol dire che non ci saranno gap bot allora sì – hudi

+1

Si potrebbe sovrascrivere 'JLabel.getPreferredSize()' per restituire un'altezza molto più bassa e usare 'JLabel.setVerticalAlignment (JLabel.BOTTOM);'. Questo in qualche modo ingannare il 'LabelUI' e renderlo molto più vicino alla cima. Un'altra soluzione è creare il tuo Component in cui potrai restituire le tue dimensioni preferite e dipingere il testo da te stesso ovunque tu voglia –

risposta

9

JDigit può darvi alcune idee:

  • E 'esclusione paintComponent() di down-campione ad alta risoluzione BufferedImage e controllare la geometria.

  • Utilizza setBorderPainted(false) per impostare la proprietà borderPainted.

  • Utilizza uno FocusHandler per l'evidenziazione personalizzata.

image

addendum: Come osservato here, il problema di fondo è del carattere leader, definita FontMetrics come rientranti in altezza del font. Come suggerito in un commento di @Guillaume Polet, puoi renderizzare il testo ovunque tu voglia nel tuo JComponent. TextLayout, discusso here, può essere utilizzato per calcolare i limiti, come mostrato di seguito.

Pro:

  • controllo assoluto sul posizionamento.

  • Geometria di limiti in base a FontMetrics.

Contro:

  • No Icon supporto.

  • Nessun supporto HTML.

Si noti che le JComponent autori "raccomandano che si inserisce il componente in un JPanel e impostare il confine sul JPanel."

Unleaded image

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.font.FontRenderContext; 
import java.awt.font.TextLayout; 
import javax.swing.BorderFactory; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

/** 
* @see https://stackoverflow.com/a/16014525/230513 
*/ 
public class UnleadedTest { 

    private static class Unleaded extends JComponent { 

     private Font font = new Font("Verdana", Font.PLAIN, 144); 
     private FontRenderContext frc = new FontRenderContext(null, true, true); 
     private String text; 
     private TextLayout layout; 
     private Rectangle r; 

     public Unleaded(String text) { 
      this.text = text; 
      calcBounds(); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(r.width, r.height); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g; 
      calcBounds(); 
      layout.draw(g2d, -r.x, -r.y); 
     } 

     private void calcBounds() { 
      layout = new TextLayout(text, font, frc); 
      r = layout.getPixelBounds(null, 0, 0); 
     } 
    } 

    private void display() { 
     JFrame f = new JFrame("Unleaded"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     Unleaded label = new Unleaded("Unleaded"); 

     JPanel panel = new JPanel(); 
     panel.setBorder(BorderFactory.createTitledBorder("Title")); 
     panel.add(label); 
     f.add(panel); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new UnleadedTest().display(); 
      } 
     }); 
    } 
} 
+0

Vedi anche questo relativo [esempio] (http://stackoverflow.com/a/8282330/230513) usando 'TextLayout'. – trashgod

+0

JDigit è il pulsante non etichetta quindi non penso che questo mi aiuti – hudi

+0

@hudi non decorato JButton è meglio che JLabel o JPanel – mKorbel

3

Il "modo giusto" per fare questo sarebbe quello di estendere la "BasicLabelUI" e sovrascrivere il metodo "protetto String layoutCL()". Questo è il metodo che è responsabile della disposizione di tutto ciò che è contenuto nell'etichetta e viene chiamato quando viene chiamato "getPreferredSize()" di JLabel.Quindi questo metodo determina l'altezza del componente.

Se si drill-down abbastanza in profondità vedrete che l'altezza è determinata dalla seguente riga nel SwingUtilities: 1021 Classe (che viene utilizzato da layoutCL):

textR.height = fm.getHeight(); 

Quindi l'etichetta non è causa di lo spazio bianco, il carattere è. L'etichetta è conforme a ciò che l'oggetto FontMetrics dice è l'altezza massima del font per quella dimensione.

Il modo più semplice sarebbe probabilmente quello di imbrogliare; Forza il calcolo della dimensione per fare qualcosa che non dovrebbe. Di seguito è riportato il tuo esempio con un componente LabelUI personalizzato su cui puoi sperimentare. Ad esempio se imponi la variabile a 'dy' a '-40' il testo sarà in alto. Se vuoi fare qualcosa di più durevole puoi controllare tutti i leters nella stringa dell'etichetta, misurare la loro altezza massima e usarla nel metodo layoutCL. Ma questo è più lavoro ovviamente.

package Core; 

import sun.swing.SwingUtilities2; 
import javax.swing.*; 
import javax.swing.plaf.LabelUI; 
import javax.swing.plaf.basic.BasicLabelUI; 
import javax.swing.text.View; 
import java.awt.*; 

public class LabelDemo extends JPanel { 

    public LabelDemo() { 
     super(new GridBagLayout()); 
     JLabel label2; 
     GridBagConstraints c = new GridBagConstraints(); 
     c.gridx = 0; 
     c.gridy = 0; 
     // Create the other labels. 
     label2 = new JLabel("Text-Only Label"); 
     label2.setVerticalAlignment(SwingUtilities.TOP); 
     label2.setVerticalTextPosition(SwingUtilities.TOP); 
     label2.setUI(SkinnyLabelUI.createUI(label2)); 
     label2.setBorder(BorderFactory.createTitledBorder("aaaaaaaa")); 
     label2.setFont(new Font("Verdana", Font.PLAIN, (int) 220)); 
     // label2.setBorder(new EmptyBorder(-50, 0, 0, 0)); 

     // Add the labels. 
     add(label2, c); 
    } 

    /** 
    * Create the GUI and show it. For thread safety, this method should be 
    * invoked from the event dispatch thread. 
    */ 
    private static void createAndShowGUI() { 
     // Create and set up the window. 
     JFrame frame = new JFrame("LabelDemo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     // Add content to the window. 
     frame.add(new LabelDemo()); 

     // Display the window. 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     // Schedule a job for the event dispatch thread: 
     // creating and showing this application's GUI. 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       // Turn off metal's use of bold fonts 
       UIManager.put("swing.boldMetal", Boolean.FALSE); 

       createAndShowGUI(); 
      } 
     }); 
    } 

    private static class SkinnyLabelUI extends BasicLabelUI { 

     private static final SkinnyLabelUI labelUI = new SkinnyLabelUI(); 

     public static LabelUI createUI(JComponent c) { 
      return labelUI; 
     } 

     protected String layoutCL(
      JLabel label, 
      FontMetrics fm, 
      String text, 
      Icon icon, 
      Rectangle viewR, 
      Rectangle iconR, 
      Rectangle textR) { 
      int verticalAlignment = label.getVerticalAlignment(); 
      int horizontalAlignment = label.getHorizontalAlignment(); 
      int verticalTextPosition = label.getVerticalTextPosition(); 
      int horizontalTextPosition = label.getHorizontalTextPosition(); 

      if (icon != null) { 
       iconR.width = icon.getIconWidth(); 
       iconR.height = icon.getIconHeight(); 
      } else { 
       iconR.width = iconR.height = 0; 
      } 

      /* Initialize the text bounds rectangle textR. If a null 
      * or and empty String was specified we substitute "" here 
      * and use 0,0,0,0 for textR. 
      */ 

      boolean textIsEmpty = (text == null) || text.equals(""); 
      int lsb = 0; 
      int rsb = 0; 
      /* Unless both text and icon are non-null, we effectively ignore 
      * the value of textIconGap. 
      */ 
      int gap; 

      View v; 
      if (textIsEmpty) { 
       textR.width = textR.height = 0; 
       text = ""; 
       gap = 0; 
      } else { 
       int availTextWidth; 
       gap = (icon == null) ? 0 : label.getIconTextGap(); 

       if (horizontalTextPosition == SwingUtilities.CENTER) { 
        availTextWidth = viewR.width; 
       } else { 
        availTextWidth = viewR.width - (iconR.width + gap); 
       } 
       v = (label != null) ? (View) label.getClientProperty("html") : null; 
       if (v != null) { 
        textR.width = Math.min(availTextWidth, 
         (int) v.getPreferredSpan(View.X_AXIS)); 
        textR.height = (int) v.getPreferredSpan(View.Y_AXIS); 
       } else { 
        textR.width = SwingUtilities2.stringWidth(label, fm, text); 
        lsb = SwingUtilities2.getLeftSideBearing(label, fm, text); 
        if (lsb < 0) { 
         // If lsb is negative, add it to the width and later 
         // adjust the x location. This gives more space than is 
         // actually needed. 
         // This is done like this for two reasons: 
         // 1. If we set the width to the actual bounds all 
         // callers would have to account for negative lsb 
         // (pref size calculations ONLY look at width of 
         // textR) 
         // 2. You can do a drawString at the returned location 
         // and the text won't be clipped. 
         textR.width -= lsb; 
        } 
        if (textR.width > availTextWidth) { 
         text = SwingUtilities2.clipString(label, fm, text, 
          availTextWidth); 
         textR.width = SwingUtilities2.stringWidth(label, fm, text); 
        } 
        textR.height = fm.getHeight(); 
        System.out.println("font height: " + textR.height); 
       } 
      } 


      /* Compute textR.x,y given the verticalTextPosition and 
      * horizontalTextPosition properties 
      */ 

      if (verticalTextPosition == SwingUtilities.TOP) { 
       if (horizontalTextPosition != SwingUtilities.CENTER) { 
        textR.y = 0; 
       } else { 
        textR.y = -(textR.height + gap); 
       } 
      } else if (verticalTextPosition == SwingUtilities.CENTER) { 
       textR.y = (iconR.height/2) - (textR.height/2); 
      } else { // (verticalTextPosition == BOTTOM) 
       if (horizontalTextPosition != SwingUtilities.CENTER) { 
        textR.y = iconR.height - textR.height; 
       } else { 
        textR.y = (iconR.height + gap); 
       } 
      } 

      if (horizontalTextPosition == SwingUtilities.LEFT) { 
       textR.x = -(textR.width + gap); 
      } else if (horizontalTextPosition == SwingUtilities.CENTER) { 
       textR.x = (iconR.width/2) - (textR.width/2); 
      } else { // (horizontalTextPosition == RIGHT) 
       textR.x = (iconR.width + gap); 
      } 

      // WARNING: DefaultTreeCellEditor uses a shortened version of 
      // this algorithm to position it's Icon. If you change how this 
      // is calculated, be sure and update DefaultTreeCellEditor too. 

      /* labelR is the rectangle that contains iconR and textR. 
      * Move it to its proper position given the labelAlignment 
      * properties. 
      * 
      * To avoid actually allocating a Rectangle, Rectangle.union 
      * has been inlined below. 
      */ 
      int labelR_x = Math.min(iconR.x, textR.x); 
      int labelR_width = Math.max(iconR.x + iconR.width, 
       textR.x + textR.width) - labelR_x; 
      int labelR_y = Math.min(iconR.y, textR.y); 
      int labelR_height = Math.max(iconR.y + iconR.height, 
       textR.y + textR.height) - labelR_y; 

      int dx, dy; 

      if (verticalAlignment == SwingUtilities.TOP) { 
       dy = viewR.y - labelR_y; 
      } else if (verticalAlignment == SwingUtilities.CENTER) { 
       dy = (viewR.y + (viewR.height/2)) - (labelR_y + (labelR_height/2)); 
      } else { // (verticalAlignment == BOTTOM) 
       dy = (viewR.y + viewR.height) - (labelR_y + labelR_height); 
      } 

      if (horizontalAlignment == SwingUtilities.LEFT) { 
       dx = viewR.x - labelR_x; 
      } else if (horizontalAlignment == SwingUtilities.RIGHT) { 
       dx = (viewR.x + viewR.width) - (labelR_x + labelR_width); 
      } else { // (horizontalAlignment == CENTER) 
       dx = (viewR.x + (viewR.width/2)) 
        - (labelR_x + (labelR_width/2)); 
      } 

      /* Translate textR and glypyR by dx,dy. 
      */ 

      textR.x += dx; 
      textR.y += dy; 

      iconR.x += dx; 
      iconR.y += dy; 

      if (lsb < 0) { 
       // lsb is negative. Shift the x location so that the text is 
       // visually drawn at the right location. 
       textR.x -= lsb; 

       textR.width += lsb; 
      } 
      if (rsb > 0) { 
       textR.width -= rsb; 
      } 

      return text; 
     } 
    } 
} 
+0

+1 Questo approccio conserva le caratteristiche di 'JLabel'; un esempio correlato è visto [qui] (http://stackoverflow.com/a/3597688/230513). – trashgod

0

cambiare l'offset potrebbe aiutare confine:

int OFFSET_TOP=50,OFFSET_BOTTOM=50; 
label.setBorder(new TitledBorder(TITLE){ 
    @Override 
    public Insets getBorderInsets(Component c, Insets insets){ 
     return new Insets(insets.top - OFFSET_TOP, insets.left, insets.bottom - OFFSET_BOTTOM, insets.right); 
    } 
}); 
+0

Questa [risposta] (http://stackoverflow.com/a/10158028/230513) alla precedente domanda di hudi sullo stesso argomento, citata in questa domanda, suggeriva un approccio simile. Sfortunatamente, le costanti dipendono da metriche di caratteri specifiche della piattaforma. – trashgod