/ / Проблем с рисуването с JLayer и JPanel - java, swing, jlayer

Живопис с JLayer и JPanel - java, swing, jlayer

Искам да нарисувам икона, когато е въведен потребителневалиден. Намерих пример от Oracle и го промених за моите цели. Картината на Icon работи правилно, но когато променя стойността, за да коригирам иконата, не е напълно невидима: частта, която е изтеглена над JPanel, все още се показва.

Ето моя код:

import java.awt.AlphaComposite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.text.NumberFormat;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.plaf.LayerUI;

public class FieldValidator extends JPanel {
private static final int ICON_SIZE = 12;
private static final Icon ICON = createResizedIcon((ImageIcon) UIManager.getIcon("OptionPane.errorIcon"));
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createUI();
}
});
}

public static void createUI() {
final JFrame f = new JFrame ("FieldValidator");

final JComponent content = createContent();

f.add (content);

f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo (null);
f.setVisible (true);
}

private static JComponent createContent() {
final LayerUI<JPanel> panelUI = new ValidationLayerUI();

// Number field.
final JLabel numberLabel = new JLabel("Number:");

final NumberFormat numberFormat = NumberFormat.getInstance();
final JFormattedTextField numberField = new JFormattedTextField(numberFormat) {
/**
* {@inheritDoc}
*/
@Override
public void replaceSelection(String content) {
super.replaceSelection(content);
getParent().repaint();
}
};
numberField.setColumns(16);
numberField.setFocusLostBehavior(JFormattedTextField.PERSIST);
numberField.setValue(42);

final int i = (ICON_SIZE / 2) + (ICON_SIZE % 2);
final JPanel numberPanel = new JPanel();
numberPanel.add(numberLabel);
final JPanel panel = new JPanel(new GridBagLayout());
final GridBagConstraints constr = new GridBagConstraints();
constr.insets = new Insets(i, i, i, i);
constr.weightx = 1;
constr.weighty = 1;
constr.fill = GridBagConstraints.BOTH;
panel.add(numberField, constr);
numberPanel.add(new JLayer<JPanel>(panel, panelUI));

return numberPanel;
}

//Icon resized to 12x12
private static Icon createResizedIcon(ImageIcon anIcon) {
final BufferedImage result = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g = result.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.drawImage(anIcon.getImage(), 0, 0, ICON_SIZE, ICON_SIZE, null);
g.dispose();
return new ImageIcon(result);

}
static class ValidationLayerUI extends LayerUI<JPanel> {

@Override
public void paint (Graphics g, JComponent c) {
super.paint (g, c);
final JLayer jlayer = (JLayer) c;
final JPanel panel = (JPanel) jlayer.getView();
final JFormattedTextField ftf = (JFormattedTextField) panel.getComponent(0);
if (!ftf.isEditValid()) {
ICON.paintIcon(panel, g, 0, panel.getHeight() - ICON.getIconHeight());
}
}

}
}

Ето екраните: Първоначално всичко е правилно

въведете описанието на изображението тук

Когато рисувам невалиден Icon всичко е все още правилно

въведете описанието на изображението тук

Но когато стойността стане правилна, само текстовото поле ще бъде пребоядисано

въведете описанието на изображението тук

Как мога да принудя JPanel да пребоядиса ???

Послепис Вече открих подход с JLayeredPane, който работи правилно, но искам да знам какво не е наред в моя код?

Отговори:

4 за отговор № 1

Какво ще кажете за използването на DocumentListener:

numberField.getDocument().addDocumentListener(new DocumentListener() {
@Override public void insertUpdate(DocumentEvent e) {
//Container c = numberField.getParent();
Container c = SwingUtilities.getUnwrappedParent(numberField);
if (c != null) {
c.repaint();
}
}
@Override public void removeUpdate(DocumentEvent e) {
insertUpdate(e);
}
@Override public void changedUpdate(DocumentEvent e) {}
});

редактиране

Цитат от този линк: Живопис в AWT и Swing

The RepaintManager Целта на класа на RepaintManager на Swing е да максимално ефективност на пребоядисване на люлкаограничаване йерархия, а също и за прилагане на механизма за "ревалидиране" на Swing (the последната ще бъде тема за отделна статия). Той изпълнява механизъм за пребоядисване чрез прихващане на всички заявки за пребоядисване на Swing компоненти (така че те вече не се обработват от AWT) и поддържане на собствено състояние за това, което трябва да се актуализира (известно като „мръсно“ Най-накрая, той използва invokeLater () за обработка на чакащия заявки на нишката за изпращане на събитието, както е описано в раздела на "Обработка на пребоядисване" (опция Б).

В този случай родителят JPanel не е мръсна област кога isEditValid() състоянието е променено. така оставащи предишни Icon боя.