2013-04-15 14 views
6

w mojej aplikacji Mam etykietę, która ma rozmiar czcionki powyżej 200. Ta etykieta zawiera dużą w górę iw dół (nieregularną) lukę. Jak mogę go usunąć?Jak usunąć lukę w etykiecie java z dużym rozmiarem

To jest mój kod:

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(); 
      } 
     }); 
    } 
} 

Staram się też mój ostatni wpis: How to change gap in swing label i eksperymentować z wypustkami ale ta wygląda inaczej w środowisku Linux i Windows

Czy jest jakiś lepszy sposób, jak usunąć tę lukę ?

+0

Czy to znaczy, że chcesz wszystkie litery mają być wyrównane do góry? –

+0

jeśli to oznacza, że ​​nie będzie luki bota, to tak – hudi

+1

Można przesłonić 'JLabel.getPreferredSize()', aby zwrócić znacznie niższą wysokość i użyć 'JLabel.setVerticalAlignment (JLabel.BOTTOM);'. To w jakiś sposób oszuka "LabelUI" i sprawi, że będzie dużo bliżej do góry. Innym rozwiązaniem jest stworzenie własnego komponentu, w którym będziesz mógł zwrócić preferowany rozmiar i malować tekst w dowolnym miejscu. –

Odpowiedz

9

JDigit może dać Ci kilka pomysłów:

  • zastąpi on za paintComponent() na dół próbkę wysokiej rozdzielczości BufferedImage i kontrolować geometrię.

  • Używa setBorderPainted(false) do ustawienia właściwości borderPainted.

  • Do podkreślania niestandardowego używa FocusHandler.

image

Uzupełnienie: Jak wspomniano here, Problem polega fontu prowadzi, zdefiniowane w FontMetrics za objęte wysokości fontu. Zgodnie z sugestią zamieszczoną w komentarzu @Guillaume Polet, możesz renderować tekst w dowolnym miejscu we własnym JComponent. TextLayout, omówione here, może być użyty do obliczenia granic, jak pokazano poniżej.

Plusy:

  • absolutną kontrolę nad placement.

  • Geometria z zakresu TexteLayout granic w oparciu o FontMetrics.

Wady:

  • Brak wsparcia Icon.

  • Brak obsługi HTML.

Uwaga że JComponent autorzy „Zaleca się umieszczenie składnika w JPanel i ustawić granicę na 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

Zobacz także ten powiązany [przykład] (http://stackoverflow.com/a/8282330/230513) używając 'TextLayout'. – trashgod

+0

JDigit to przycisk, a nie etykieta, więc nie sądzę, że to mi pomoże – hudi

+0

@Budi undecorated JButton jest lepszy niż JLabel lub JPanel – mKorbel

3

"Prawo way" to zrobić byłoby rozszerzenie "BasicLabelUI" i zastąpić "chronione String layoutCL()" metody. Jest to metoda odpowiedzialna za układanie wszystkiego wewnątrz etykiety i wywoływana, gdy wywoływana jest metoda "getPreferredSize()" JLabel.Ta metoda określa wysokość komponentu.

Jeśli drążyć wystarczająco głęboko zobaczysz, że wysokość jest określona przez następujący wiersz w SwingUtilities: 1021 klasy (który jest używany przez layoutCL):

textR.height = fm.getHeight(); 

Więc etykieta nie jest przyczyną biała przestrzeń, czcionka jest. Etykieta jest zgodna z tym, co mówi obiekt FontMetrics, to maksymalna wysokość czcionki dla tego rozmiaru.

Najprostszym sposobem byłoby prawdopodobnie oszukiwanie; Wymuś obliczenie rozmiaru, aby zrobić coś, czego nie powinno. Poniżej znajduje się przykład z niestandardowym komponentem LabelUI, na którym można eksperymentować. Na przykład, jeśli wymusisz zmienną na "dy" na "-40", tekst będzie na górze. Jeśli chcesz zrobić coś trwalszego, możesz sprawdzić wszystkie literki w łańcuchu etykiety, zmierzyć ich maksymalną wysokość i użyć jej w metodzie layoutCL. Ale to oczywiście więcej pracy.

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 To podejście zachowuje cechy 'JLabel'; podobny przykład jest widoczny [tutaj] (http://stackoverflow.com/a/3597688/230513). – trashgod

0

zmianę przesunięcia granicy może pomóc:

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

To [odpowiedź] (http://stackoverflow.com/a/10158028/230513) na poprzednie pytanie hudi dotyczące tego samego tematu, cytowane w tym pytaniu, sugerowało podobne podejście. Niestety, stałe zależą od charakterystyki czcionek specyficznych dla platformy. – trashgod

Powiązane problemy