JTextFieldUI нарисовал в другой вкладке JTabbedPane с моим личным взглядом и ощущением - PullRequest
0 голосов
/ 19 сентября 2019

Я разрабатываю новый внешний вид, и теперь у меня есть ошибка с компонентом JtextField, когда его использовать внутри компонента JTabbledPane.

Итак, ошибка в этом

enter image description here

У меня есть этот код для моего 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: извините за мой большой код

1 Ответ

1 голос
/ 19 сентября 2019

Проблема в том, как вы манипулируете живописью.Внутри changeColorOnFocus (вызываемого FocusListener) метода у вас есть следующие строки:

if (c.getGraphics() != null) {
    c.paint(c.getGraphics());
}

Здесь вы используете графику и выполняете своего рода рисование вне метода, отвечающего за рисование в компоненте.-painting-иерархия.Хотелось бы объяснить это лучше, но вкратце, поиграйте с Graphics только в тех методах, которые дают их вам в качестве аргумента (и вызовите его super метод).В классе UI метод - paintSafely, в компоненте - paintComponent.Они оба дают вам Graphics объект, следовательно, они подходят для пользовательской рисования.

Итак, решение внутри вашего FocusListener - добавить флаг, чтобы узнать, сфокусирован ли компонент, и вызвать * 1015.* внутри paintSafely(Graphics g) метод.Ваш класс пользовательского интерфейса должен быть изменен в следующих частях (я не вставляю все это, так как он довольно большой).

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

Предварительный просмотр:

preview

...