JTextFieldUI 绘制在 JTabbedPane 的另一个选项卡中,具有我个人的外观和感觉
JTextFieldUI painted in another tab of the JTabbedPane with my personal look and feel
我正在开发一种新的外观和感觉,现在我在 JTabbledPane 组件中使用组件 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());
}
在这里,您使用图形并在组件绘制层次结构中负责绘制的方法之外进行一种自定义绘制。我希望我能更好地解释它,但长话短说,只在将它们作为参数提供给您的方法中使用 Graphics
(并调用其 super
方法)。在 UI
class 中,方法是 paintSafely
,在组件中是 paintComponent
。它们都给你 Graphics
对象,因此它们适合自定义绘画。
因此,解决方案是在您的 FocusListener
中添加一个标志以了解组件是否获得焦点,并在 paintSafely(Graphics g)
方法中调用 changeColorOnFocus
。你的 UI class 应该在以下部分进行更改(我没有全部粘贴,因为它有点大)。
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());
}
}
预览:
我正在开发一种新的外观和感觉,现在我在 JTabbledPane 组件中使用组件 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());
}
在这里,您使用图形并在组件绘制层次结构中负责绘制的方法之外进行一种自定义绘制。我希望我能更好地解释它,但长话短说,只在将它们作为参数提供给您的方法中使用 Graphics
(并调用其 super
方法)。在 UI
class 中,方法是 paintSafely
,在组件中是 paintComponent
。它们都给你 Graphics
对象,因此它们适合自定义绘画。
因此,解决方案是在您的 FocusListener
中添加一个标志以了解组件是否获得焦点,并在 paintSafely(Graphics g)
方法中调用 changeColorOnFocus
。你的 UI class 应该在以下部分进行更改(我没有全部粘贴,因为它有点大)。
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());
}
}
预览: