package popupRepaintIssue;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class JPopupRepaintIssue extends JFrame {
private class CustomDrawing extends JComponent {
private Color color = Color.RED;
public void paintComponent(Graphics g) {
Dimension d = getSize();
Graphics2D g2 = (Graphics2D) g;
g2.setClip(getBounds());
g2.setColor(color);
g2.drawRect(d.width/4, d.height/4, d.width/2, d.height/2);
log("PERFORMING CUSTOM DRAWING, " + color);
log(g2.getClipBounds().toString());
log(g2.getTransform().toString());
}
public void setColor(Color colour) {
color = colour;
}
public Color getColor() {
return color;
}
};
public JPopupRepaintIssue() throws HeadlessException {
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLayout(new GridBagLayout());
final JLabel statusBar = new JLabel(" ");
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.HORIZONTAL;
gc.weightx = 1.0;
gc.gridy = 1;
add(statusBar,gc);
final JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem("Item1"));
/* *********** customDrawing setup *********** */
final CustomDrawing drawing = new CustomDrawing();
drawing.setPreferredSize(new Dimension(400, 400));
JScrollPane sp = new JScrollPane(
drawing,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
);
gc.fill = GridBagConstraints.BOTH;
gc.gridy = 0;
gc.weightx = 1.0;
gc.weighty = 1.0;
add(sp, gc);
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
popup.show(e.getComponent(), e.getX(), e.getY());
}
//if (!e.isPopupTrigger() && !popup.isShowing()) {
drawing.setColor(Color.RED);
log("changing to red");
//}
}
@Override
public void mouseMoved(MouseEvent e) {
if (!popup.isShowing()) {
Dimension d = drawing.getSize();
Rectangle r2 = new Rectangle(
d.width/4, d.height/4,
d.width/2, d.height/2
);
if (r2.contains(e.getPoint())) {
if (!drawing.getColor().equals(Color.GREEN)) {
drawing.setColor(Color.GREEN);
drawing.repaint();
}
} else {
if (!drawing.getColor().equals(Color.RED)) {
drawing.setColor(Color.RED);
drawing.repaint();
}
}
}
statusBar.setText("Pointer location: "
+ e.getX() + ", " + e.getY());
}
};
sp.getViewport().addMouseListener(adapter);
sp.getViewport().addMouseMotionListener(adapter);
/* END *********** customDrawing setup *********** */
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void log(String s) {
System.err.print(s + "\n");
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JPopupRepaintIssue();
}
});
}
}
Swing.RepaintManager + PopupMenu + CustomDrawing
При закрытии popupMenu RepaintManager выполняет перерисовку прямоугольника, который занимало это меню. Поскольку меню открывается поверх компонента, в котором происходит отрисовка различных фигур средствами java.awt.geom, то хотелось бы заменить перерисовку прямоугольника, освобождаемого меню, отрисовкой фигуры, которую перекрывало меню, либо еще что-то посложнее, если понадобится в будущем.
Никакими манипуляциями с передаваемым объектом Graphics расширить область прорисовки не получается — что ни делай, отрисовка за пределами изначальной clipping области не выходит.
Собственно, хотелось бы узнать, как правильно изменять clipping область на большую для объекта Graphics/Graphics2D и можно ли это сделать в принципе. Переопределять методы RepaintManager не хотелось бы.
Ниже привожу код, который воспроизводит проблему.
Код:
Если открыть popup меню поверх линии прямоугольника, а затем кликом где-нибудь за пределами прямоугольника это меню сбросить, то перерисуется в новом цвете только то, что попало под меню.
Логики в такой смене цвета не ищите, хотелось бы разобраться с задачей в целом, а не с частным случаем (источником такой выборочной перерисовки, наверняка, может служить не только popup).
На скриншоте во вложении результат последовательного закрытия и открытия popup, не покидая прямоугольника.
Ну и все верно, зачем перерисовывать то, что не изменялось?
Да, понимание пришло не сразу. =)