【问题标题】:Decorating a JTextField with an image and hint用图像和提示装饰 JTextField
【发布时间】:2011-08-30 16:06:39
【问题描述】:

我正在尝试创建一些带有图像和提示的更好看的 JTextField。为此,我制作了一个覆盖paintComponent 方法的装饰器。我使用装饰器的原因是我想将它应用于其他类型的 JTextField,例如 JPasswordField。

这是我到目前为止所做的;

在左边的表格中看到的问题是,即使我使用了 JPasswordField,paintComponent 似乎也忽略了我假设的密码 paintComponent,它可能是密码屏蔽符号。

所以问题是,我怎样才能避免重复 JTextFields 和 JPasswordFields 的代码,但仍然具有不同的功能,例如密码屏蔽。

这是装饰器代码;

public class JTextFieldHint extends JTextField implements FocusListener{
private JTextField jtf;
private Icon icon;
private String hint;
private Insets dummyInsets;

public JTextFieldHint(JTextField jtf, String icon, String hint){
    this.jtf = jtf;
    setIcon(createImageIcon("icons/"+icon+".png",icon));
    this.hint = hint;

    Border border = UIManager.getBorder("TextField.border");
    JTextField dummy = new JTextField();
    this.dummyInsets = border.getBorderInsets(dummy);

    addFocusListener(this);
}

public void setIcon(Icon newIcon){
    this.icon = newIcon;
}

@Override
protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        int textX = 2;

        if(this.icon!=null){
            int iconWidth = icon.getIconWidth();
            int iconHeight = icon.getIconHeight();
            int x = dummyInsets.left + 5;
            textX = x+iconWidth+2;
            int y = (this.getHeight() - iconHeight)/2;
            icon.paintIcon(this, g, x, y);
        }

        setMargin(new Insets(2, textX, 2, 2));

        if ( this.getText().equals("")) {
            int width = this.getWidth();
            int height = this.getHeight();
            Font prev = g.getFont();
            Font italic = prev.deriveFont(Font.ITALIC);
            Color prevColor = g.getColor();
            g.setFont(italic);
            g.setColor(UIManager.getColor("textInactiveText"));
            int h = g.getFontMetrics().getHeight();
            int textBottom = (height - h) / 2 + h - 4;
            int x = this.getInsets().left;
            Graphics2D g2d = (Graphics2D) g;
            RenderingHints hints = g2d.getRenderingHints();
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2d.drawString(hint, x, textBottom);
            g2d.setRenderingHints(hints);
            g.setFont(prev);
            g.setColor(prevColor);
        }

}

protected ImageIcon createImageIcon(String path, String description) {
    java.net.URL imgURL = getClass().getResource(path);
    if (imgURL != null) {
        return new ImageIcon(imgURL, description);
    } else {
        System.err.println("Couldn't find file: " + path);
        return null;
    }
}

@Override
public void focusGained(FocusEvent arg0) {
    this.repaint();
}

@Override
public void focusLost(FocusEvent arg0) {
    this.repaint();
}


}

这是我创建字段的地方;

JTextField usernameField = new JTextFieldHint(new JTextField(),"user_green","Username");
JTextField passwordField = new JTextFieldHint(new JPasswordField(),"bullet_key","Password");

希望我没有完全走错方向!

谢谢!

编辑:我再看一遍,很明显调用 super.paintComponent(g) 将调用 JTextFields 绘制组件,但如果不复制代码,我看不到如何解决这个问题。

【问题讨论】:

    标签: java swing user-interface decorator jtextfield


    【解决方案1】:

    Text Prompt 与 JPasswordField 一起使用。

    一个区别是输入文本时显示的图标会消失。如果您希望图标是永久的,那么我建议您创建一个自定义的“IconBorder* 类来绘制图标,而不是在 paintComponent() 方法中进行自定义绘制。

    除非您复制 JTextField 和 JPasswordField 的代码,否则您的方法将不起作用。

    编辑:

    实际上您不需要创建自定义 IconBorder。 MatteBorder 支持在边框中绘制图标。

    【讨论】:

    • 您可以创建一个复合边框。使用原始边框作为外边框,然后使用带有图标的 MatteBorder 作为内边框
    【解决方案2】:

    为了在文本字段中绘制图标,您需要添加一些插图。 您不想在组件中硬编码插入,而只是为图标添加一点空间,让客户端和子类自行设置。

    在上图中,我将原始插图绘制为绿色,将附加插图绘制为红色。首先要扩展 JTextField。我们跟踪两件事:原始插图(绿色插图)mBorder 和图标。

    public class IconTextField extends JTextField {
        private Border mBorder;
        private Icon mIcon;
    
        // ...
    }
    

    那么你需要重写setBorder()方法。

    @Override
    public void setBorder(Border border) {
        mBorder = border;
    
        if (mIcon == null) {
            super.setBorder(border);
        } else {
            Border margin = BorderFactory.createEmptyBorder(0, mIcon.getIconWidth() + ICON_SPACING, 0, 0);
            Border compound = BorderFactory.createCompoundBorder(border, margin);
            super.setBorder(compound);
        }
    }
    

    在这里,如果我们有一个图标(字段mIcon 不是null),我们使用复合边框添加我们的附加插图。然后,您还应该重写 paintComponent() 方法。

    @Override
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
    
        if (mIcon != null) {
            Insets iconInsets = mBorder.getBorderInsets(this);
            mIcon.paintIcon(this, graphics, iconInsets.left, iconInsets.top);
        }
    }
    

    最后,你需要一个setIcon() 方法。

    public void setIcon(Icon icon) {
        mIcon = icon;
        resetBorder();
    }
    
    private void resetBorder() {
        setBorder(mBorder);
    }
    

    我们在这里所做的是保存图标并重新计算边框。

    如果你想对JPasswordField 做同样的事情,最优雅的事情可能是使用上面讨论的所有方法创建一个帮助类。

    class IconTextComponentHelper {
        private static final int ICON_SPACING = 4;
    
        private Border mBorder;
        private Icon mIcon;
        private Border mOrigBorder;
        private JTextComponent mTextComponent;
    
        IconTextComponentHelper(JTextComponent component) {
            mTextComponent = component;
            mOrigBorder = component.getBorder();
            mBorder = mOrigBorder;
        }
    
        Border getBorder() {
            return mBorder;
        }
    
        void onPaintComponent(Graphics g) {
            if (mIcon != null) {
                Insets iconInsets = mOrigBorder.getBorderInsets(mTextComponent);
                mIcon.paintIcon(mTextComponent, g, iconInsets.left, iconInsets.top);
            }
        }
    
        void onSetBorder(Border border) {
            mOrigBorder = border;
    
            if (mIcon == null) {
                mBorder = border;
            } else {
                Border margin = BorderFactory.createEmptyBorder(0, mIcon.getIconWidth() + ICON_SPACING, 0, 0);
                mBorder = BorderFactory.createCompoundBorder(border, margin);
            }
        }
    
        void onSetIcon(Icon icon) {
            mIcon = icon;
            resetBorder();
        }
    
        private void resetBorder() {
            mTextComponent.setBorder(mOrigBorder);
        }
    }
    

    并像这样使用它:

    public class IconTextField extends JTextField {
        private IconTextComponentHelper mHelper = new IconTextComponentHelper(this);
    
        public IconTextField() {
            super();
        }
    
        public IconTextField(int cols) {
            super(cols);
        }
    
        private IconTextComponentHelper getHelper() {
            if (mHelper == null)
                mHelper = new IconTextComponentHelper(this);
    
            return mHelper;
        }
    
        @Override
        protected void paintComponent(Graphics graphics) {
            super.paintComponent(graphics);
            getHelper().onPaintComponent(graphics);
        }
    
        public void setIcon(Icon icon) {
            getHelper().onSetIcon(icon);
        }
    
        public void setIconSpacing(int spacing) {
            getHelper().onSetIconSpacing(spacing);
        }
    
        @Override
        public void setBorder(Border border) {
            getHelper().onSetBorder(border);
            super.setBorder(getHelper().getBorder());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      • 1970-01-01
      • 2018-04-14
      相关资源
      最近更新 更多