Как переопределить поля кнопок Nimbus для одной кнопки - PullRequest
2 голосов
/ 07 января 2012

Я создал компонент текстового поля с кнопкой «x» внутри, которая очистит текст поля. Он отлично работает при использовании внешнего вида системы Windows (для Windows), однако у меня возникают проблемы при попытке получить правильный внешний вид при использовании Nimbus, а именно, я не могу изменить поля на кнопке с помощью button.setMargin(new Inset(0, 0, 0, 0), как могу с система выглядит и ощущается.

Я искал помощи в настройке полей при использовании Nimbus, и, похоже, это общая проблема. Мне удалось найти частичное решение, которое позволяет мне изменять поля, однако оно меняет поля для всех кнопок, и я хочу, чтобы только одна кнопка отличалась от стандартной.

Я установил размер кнопки 'x' явно, рассчитанный по границам строки 'x', чтобы он был достаточно большим, чтобы отобразить 'x'.

Результат при использовании внешнего вида системы Window, который является общим видом, который я ищу:

System look and feel

Результат при использовании внешнего вида Nimbus по умолчанию; 'x' переполняет пространство, которое позволяет ему Nimbus, что приводит к многоточию.

Nimbus look and feel

Результат при использовании Nimbus и переопределении Button.contentMargins: теперь кнопка «x» выглядит правильно, но кнопка «test» выглядит ужасно.

Nimbus look and feel, plus margin overrides

Исходный код:

import java.awt.Graphics;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

public class TextFieldTest {        
    public static void main(String[] args) {
        boolean useNimbusLookAndFeel    = false;
        boolean overrideNimbusDefaults  = false;
        String lafName = UIManager.getSystemLookAndFeelClassName();

        if ( useNimbusLookAndFeel ) {
            for ( LookAndFeelInfo info : UIManager.getInstalledLookAndFeels() ) {
                if ( "Nimbus".equals(info.getName()) ) {
                    lafName = info.getClassName();      
                    break;
                }
            }
        }

        try {
            UIManager.setLookAndFeel(lafName);              
        }
        catch (ClassNotFoundException e) {}
        catch (InstantiationException e) {}
        catch (IllegalAccessException e) {}
        catch (UnsupportedLookAndFeelException e) {}

        //Code to set override default button insets for Nimbus:
        if ( useNimbusLookAndFeel && overrideNimbusDefaults ) {
            LookAndFeel laf = UIManager.getLookAndFeel();               
            if ( laf != null ) {
                UIDefaults def = laf.getDefaults();
                def.put("Button.contentMargins", new Insets(0,0,0,0));
            }
        }       

        //Create frame:
        JPanel panel = new JPanel();        
        panel.add(new JButton("test"));
        panel.add(new DeletableTextField());

        JFrame frame = new JFrame();
        frame.getContentPane().add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }   

    static class DeletableTextField extends JTextField {
        JButton         mButton     = null;

        public DeletableTextField() {
            super(30);
            setup();
        }

        private void setup() {
            mButton = new JButton("x");
            mButton.setMargin(new Insets(0, 0, 0, 0));
            add(mButton);
        }

        @Override
        public void paint(Graphics g) {
            g.setFont(mButton.getFont());
            Rectangle2D rect    = g.getFontMetrics().getStringBounds(mButton.getText(), g);
            int stringWidth     = (int)rect.getWidth();

            int topOffset       = 3;
            int rightOffset     = 3;
            int bottomOffset    = 3;
            int width           = (int)Math.ceil(stringWidth * 2.5);
            int height          = getHeight() - (bottomOffset + topOffset);         
            int x_coord         = getWidth() - (rightOffset + width);

            mButton.setMargin(new Insets(0, 0, 0, 0));
            mButton.setBounds(x_coord, topOffset, width, height);

            super.paint(g);
        }
    }
}

Я знаю, что могу сделать это другими способами, например, нарисовать сверху свой собственный крестик, но я подумал, что было бы неплохо воспользоваться преимуществами нынешних возможностей рисования кнопок в стиле «на ощупь» для унифицированного вида. .

Поэтому я хотел бы спросить, есть ли способ изменить поля одного JButton при использовании внешнего вида и ощущения Nimbus без изменения полей для всех кнопок. В качестве альтернативы, если уже есть компонент Swing, который выглядит аналогично (текстовое поле с кнопкой «x»), я могу использовать его вместо этого.

Ответы [ 3 ]

7 голосов
/ 07 января 2012

Nimbus поддерживает переопределения для каждого свойства LAF , в вашем контексте что-то вроде:

  mButton = new JButton("x");
  UIDefaults def = new UIDefaults();
  def.put("Button.contentMargins", new Insets(0,0,0,0));
  mButton.putClientProperty("Nimbus.Overrides", def);
2 голосов
/ 07 января 2012

Не могли бы вы использовать один из вариантов меньшего размера, а затем позволить кнопке отображаться в ее предпочтительном размере, чтобы гарантированно было место для текста?

http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/size.html

1 голос
/ 07 января 2012

Возможно, в качестве хака, вы можете попробовать поиграть со значениями левой / правой вставки и сделать их ненулевыми, чтобы текст отображался в обоих LAF.

Я знаю, что могу сделать это другими способами, например, нарисовать свой верх "x"

Если дело доходит до этого, то, возможно, вы можете использовать класс Text Icon , чтобы сделать для вас индивидуальный рисунок.

...