Java JTextFieldUI以我个人的外观和感觉绘制在JTabbedPane的另一个选项卡中

Java JTextFieldUI以我个人的外观和感觉绘制在JTabbedPane的另一个选项卡中,java,swing,look-and-feel,jtabbedpane,Java,Swing,Look And Feel,Jtabbedpane,我正在开发一种新的外观,现在我在JTAbblePane组件中使用组件JtextField时遇到了一个错误 问题是这个 我的JTextFieldUI有这个代码,它扩展了BasicLookAndFell public class MyPersonalFieldUI extends BasicTextFieldUI { protected static final String PROPERTY_LINE_COLOR = "lineColor"; protected static

我正在开发一种新的外观,现在我在JTAbblePane组件中使用组件JtextField时遇到了一个错误

问题是这个

我的JTextFieldUI有这个代码,它扩展了BasicLookAndFell

public class MyPersonalFieldUI extends BasicTextFieldUI {

    protected static final String PROPERTY_LINE_COLOR = "lineColor";
    protected static final String PROPERTY_SELECTION_COLOR = "selectionColor";
    protected static final String PROPERTY_SELECTION_TEXT_COLOR = "selectedTextColor";
    protected static final String ProprietyPrefix = "TextField";

    protected boolean drawLine;
    protected JTextComponent textComponent;
    protected Color background;
    protected Color foreground;
    protected Color activeBackground;
    protected Color activeForeground;
    protected Color inactiveBackground;
    protected Color inactiveForeground;
    protected Color colorLineInactive;
    protected Color colorLineActive;
    protected Color colorLine;
    protected FocusListener focusListenerColorLine;
    protected PropertyChangeListener propertyChangeListener;
    protected PropertyChangeSupport propertyChangeSupport;

    public MyPersonalFieldUI() {
        this(true);
    }

    public MyPersonalFieldUI(boolean drawLine) {
        super();
        this.drawLine = drawLine;
        this.focusListenerColorLine = new FocusListenerColorLine();
        this.propertyChangeListener = new MaterialPropertyChangeListener();
        this.propertyChangeSupport = new PropertyChangeSupport(this);
    }

    @Override
    protected String getPropertyPrefix() {
        return ProprietyPrefix;
    }

    public static ComponentUI createUI(JComponent c) {
        return new MyPersonalFieldUI();
    }

    @Override
    public void installUI(JComponent c) {
        super.installUI(c);
        this.textComponent = (JTextField) c;
    }

    @Override
    protected void installDefaults() {
        super.installDefaults();
        installMyDefaults();
    }

    @Override
    public void uninstallUI(JComponent c) {
        super.uninstallUI(c);

        c.setFont(null);
        c.setBackground(null);
        c.setForeground(null);
        c.setBorder(null);
        c.setCursor(null);

    }

    @Override
    protected void uninstallDefaults() {
        super.uninstallDefaults();
        getComponent().setBorder(null);
    }

    @Override
    protected void installListeners() {
        super.installListeners();
        getComponent().addFocusListener(focusListenerColorLine);
        getComponent().addPropertyChangeListener(propertyChangeListener);
        propertyChangeSupport.addPropertyChangeListener(propertyChangeListener);
    }

    @Override
    protected void uninstallListeners() {
        getComponent().removeFocusListener(focusListenerColorLine);
        getComponent().removePropertyChangeListener(propertyChangeListener);
        propertyChangeSupport.removePropertyChangeListener(propertyChangeListener);
        super.uninstallListeners();
    }

    @Override
    public void paintSafely(Graphics g) {
        super.paintSafely(g);

        paintLine(g);
    }

    protected void logicForChangeColorOnFocus(JComponent component, Color background, Color foreground) {
        if (background == null || foreground == null) {
            return;
        }
        JTextField textField = (JTextField) component;
        if (!this.activeForeground.equals(foreground)) { //TODO this comment resolve the issue but I don't not if it introduce some bug
            textField.setSelectedTextColor(inactiveForeground);
        } else {
            textField.setSelectedTextColor(foreground);
        }
        textField.setSelectionColor(background);
    }

    protected void installMyDefaults() {
        this.background = UIManager.getColor(getPropertyPrefix() + ".background");
        this.foreground = UIManager.getColor(getPropertyPrefix() + ".foreground");
        this.activeBackground = UIManager.getColor(getPropertyPrefix() + ".selectionBackground");
        this.activeForeground = UIManager.getColor(getPropertyPrefix() + ".selectionForeground");
        this.inactiveBackground = UIManager.getColor(getPropertyPrefix() + ".inactiveBackground");
        this.inactiveForeground = UIManager.getColor(getPropertyPrefix() + ".inactiveForeground");
        colorLineInactive = UIManager.getColor(getPropertyPrefix() + "[Line].inactiveColor");
        colorLineActive = UIManager.getColor(getPropertyPrefix() + "[Line].activeColor");
        getComponent().setFont(UIManager.getFont(getPropertyPrefix() + ".font"));
        colorLine = getComponent().hasFocus() && getComponent().isEditable() ? colorLineActive : colorLineInactive;
        getComponent().setSelectionColor(getComponent().hasFocus() && getComponent().isEnabled() ? activeBackground : inactiveBackground);
        getComponent().setSelectedTextColor(getComponent().hasFocus() && getComponent().isEnabled() ? activeForeground : inactiveForeground);
        getComponent().setForeground(getComponent().hasFocus() && getComponent().isEnabled() ? activeForeground : inactiveForeground);
        getComponent().setBorder(UIManager.getBorder(getPropertyPrefix() + ".border"));
    }

    protected void logicForPropertyChange(Color newColor, boolean isForeground) {
        if (newColor == null) {
            return;
        }
        if (isForeground && (!newColor.equals(activeForeground) && !newColor.equals(inactiveForeground))) {
            this.activeForeground = newColor;
            getComponent().repaint();
        }
        if (!isForeground && !newColor.equals(activeBackground) && !newColor.equals(inactiveBackground)) {
            this.activeBackground = newColor;
            getComponent().repaint();
        }
    }

    protected void changeColorOnFocus(boolean hasFocus) {
        JTextComponent c = getComponent();
        if (c == null) {
            return;
        }
        if (hasFocus && (activeBackground != null) && (activeForeground != null)) {
            logicForChangeColorOnFocus(c, activeBackground, activeForeground);
            //TODO create a new changePropriety
            paintLine(c.getGraphics());
        }

        if (!hasFocus && (inactiveBackground != null) && (inactiveForeground != null)) {
            logicForChangeColorOnFocus(c, inactiveBackground, inactiveForeground);
            paintLine(c.getGraphics());
        }
        if (c.getGraphics() != null) {
            c.paint(c.getGraphics());
        }
    }

    protected synchronized void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
        if ((propertyName == null || propertyName.isEmpty()) || oldValue == null || newValue == null) {
            throw new IllegalArgumentException("Some property null");
        }
        //TODO refectoring this code
        if (propertyChangeSupport == null || (oldValue != null && newValue != null && oldValue.equals(newValue))) {
            return;
        }
        if (propertyChangeSupport == null || oldValue == newValue) {
            return;
        }
        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    protected void paintLine(Graphics graphics) {
        if (graphics == null) {
            return;
        }
        JTextComponent c = getComponent();

        if (drawLine) {
            int x = c.getInsets().left;
            int y = c.getInsets().top;
            int w = c.getWidth() - c.getInsets().left - c.getInsets().right;
            graphics.setColor(colorLine);

            graphics.fillRect(x, c.getHeight() - y, w, 1);
        }
    }

    protected class FocusListenerColorLine implements FocusListener {

        @Override
        public void focusGained(FocusEvent e) {
            firePropertyChange(PROPERTY_LINE_COLOR, colorLineInactive, colorLineActive);

            changeColorOnFocus(true);
        }

        @Override
        public void focusLost(FocusEvent e) {
            firePropertyChange(PROPERTY_LINE_COLOR, colorLineActive, colorLineInactive);
            changeColorOnFocus(false);
        }
    }

    protected class MaterialPropertyChangeListener implements PropertyChangeListener {

        @Override
        public void propertyChange(PropertyChangeEvent pce) {
            if (getComponent() == null) {
                return;
            }
            if (pce.getPropertyName().equals(PROPERTY_SELECTION_COLOR)) {
                Color newColor = (Color) pce.getNewValue();
                logicForPropertyChange(newColor, false);
            }

            if (pce.getPropertyName().equals(PROPERTY_SELECTION_TEXT_COLOR)) {
                Color newColor = (Color) pce.getNewValue();
                logicForPropertyChange(newColor, true);
            }

            if (pce.getPropertyName().equals(PROPERTY_LINE_COLOR)) {
                Color newColor = (Color) pce.getNewValue();
                colorLine = newColor;
                getComponent().repaint();
            }

            if (pce.getPropertyName().equals("background")) {
                getComponent().repaint();
            }
        }
    }

}
对不起,我的大代码,但我认为是必要的,以找到我的错误里面

另外,这是我的最小可复制示例

public class DemoLookAndFeel extends JFrame {

    static {
        try {
             UIManager.setLookAndFeel(new MyLookAndFeel());
        } catch (UnsupportedLookAndFeelException ex) {
        }
    }

    public void init() {
        JPanel panelOne = new JPanel();
        panelOne.add(new JTextField("write inside me and change the tab"));

        JPanel panelTwo = new JPanel();
        //panelTwo.add(new Label("Now seee the JTextField?"));

        JTabbedPane tabbedPane = new JTabbedPane();

        tabbedPane.add("One", panelOne);
        tabbedPane.add("Two", panelTwo);

        this.setContentPane(tabbedPane);

        this.setSize(800,800);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    private static class MyLookAndFeel extends BasicLookAndFeel {

        @Override
        public String getName() {
            return "my look and feel";
        }

        @Override
        public String getID() {
            return "qwerty";
        }

        @Override
        public String getDescription() {
            return "";
        }

        @Override
        public boolean isNativeLookAndFeel() {
            return false;
        }

        @Override
        public boolean isSupportedLookAndFeel() {
            return true;
        }

        @Override
        protected void initClassDefaults(UIDefaults table) {
            super.initClassDefaults(table); 
              table.put("TextFieldUI", MyPersonalFieldUI.class.getCanonicalName());
        }



        @Override
        protected void initSystemColorDefaults(UIDefaults table) {
            super.initSystemColorDefaults(table); 

            table.put("TextField.background", Color.GRAY);
            table.put("TextField.foreground", Color.BLACK);
            table.put("TextField.inactiveForeground", Color.BLACK);
            table.put("TextField.inactiveBackground", Color.GRAY);
            table.put("TextField.selectionBackground", Color.BLUE);
            table.put("TextField.selectionForeground", Color.WHITE);
            table.put("TextField[Line].inactiveColor", Color.WHITE);
            table.put("TextField[Line].activeColor", Color.BLUE);
        }

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                DemoLookAndFeel demo = new DemoLookAndFeel();
                demo.init();
            }
        });
    }

}

ps:对不起,我的代码太大了

问题在于如何操作绘画。在
changeColorOnFocus
(由
FocusListener
调用)方法中,您有以下几行代码:

if (c.getGraphics() != null) {
    c.paint(c.getGraphics());
}
在这里,您使用图形并在负责在“组件绘制继承人”中绘制的方法之外进行一种自定义绘制。我希望我能更好地解释它,但长话短说,只在将它们作为参数的方法中使用
图形
(并称其为
超级
方法)。在
UI
类中,方法是
paintsafe
,在组件中是
paintComponent
。它们都为您提供
图形
对象,因此它们适合于自定义绘制

因此,解决方案位于
FocusListener
中,添加一个标志以了解组件是否已聚焦,并在
paintsafe(Graphics g)
方法中调用
changeColorOnFocus
。您的UI类应该在以下部分进行更改(我不会全部粘贴,因为它有点大)

预览:


对不起,我只能向上投票,如果你愿意,你能更好地解释这个问题吗?@vincenzopalazzo我希望我知道如何更好地解释它。考虑一下:为了绘制组件,API调用方法a、B和C。如果您在这些方法之外绘制,您将遇到问题,因为它不在顺序中。因此,您必须重写其中一个方法才能“进入序列”。因此,我们更喜欢重写C方法,以便最后进行自定义绘制。(1-)交叉发布:tab JTabbedPane personal。所以你有一个答案。为什么你没有更新你的另一个问题,表明你找到了答案,这样人们就不会花时间回答一个已经有答案的问题?@camickr我一回到家就会这么做,因为我没有电脑,在其他场合,我总是更新我的问题,以防在其他论坛上找到解决方案。我只是需要一些时间,几个小时的问题,对不起
private boolean focused; //a field
protected class FocusListenerColorLine implements FocusListener {

    @Override
    public void focusGained(FocusEvent e) {
        firePropertyChange(PROPERTY_LINE_COLOR, colorLineInactive, colorLineActive);
        focused = true;
    }

    @Override
    public void focusLost(FocusEvent e) {
        firePropertyChange(PROPERTY_LINE_COLOR, colorLineActive, colorLineInactive);
        focused = false;
    }
}



@Override
public void paintSafely(Graphics g) {
    super.paintSafely(g);
    paintLine(g);
    changeColorOnFocus(g);
}

protected void changeColorOnFocus(Graphics g) {
    boolean hasFocus = focused;
    JTextComponent c = getComponent();
    if (c == null) {
        return;
    }
    if (hasFocus && (activeBackground != null) && (activeForeground != null)) {
        logicForChangeColorOnFocus(c, activeBackground, activeForeground);
        //TODO create a new changePropriety
        paintLine(c.getGraphics());
    }

    if (!hasFocus && (inactiveBackground != null) && (inactiveForeground != null)) {
        logicForChangeColorOnFocus(c, inactiveBackground, inactiveForeground);
        paintLine(c.getGraphics());
    }
}