Меня не устраивает стандартный механизм докинга тулбаров в Swing, поэтому делаю свою реализацию.
При перетаскивании тулбара с одного края компонента на другой появляется окно (java.awt.Window), которое принимает размеры перетаскиваемого тулбара с учетом его ориентации.
Положение окна определяется по текущим координатам курсора. В зависимости от того, может ли тулбар быть перемещен в текущее положение, меняется цвет линий и цвет фона в окне.
Вот скриншоты того, как это все выглядит.
Окно около горизонтального края:
Окно показывающее, что тут нельзя разместить тулбар
Окно около вертикального края:
Проблема в следующем. Когда перетаскивается тулбар, и курсор переходит с одной края компонента на другой (например с левого на верхний), на этом окне видно и вновь отрисованное состояние и часть предыдущего. Выглядит так, как-будто рисуется новое состояние, а поверх него старое, но за счет того, что размер окна поменялся на противоположный, отрисованное старое состояние не помещается полностью, и видно только его часть.
Вот скриншот такого состояния:
Вот код:
package ru.kih.gui.toolbar;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import ru.kih.gui.graph.Colors;
public class DragWindowHandler implements DragEffectHandler {
private final ToolbarSupport toolbarSupport;
private final DragWindow dragWindow;
public DragWindowHandler(ToolbarSupport toolbarSupport) {
this.toolbarSupport = toolbarSupport;
this.dragWindow = new DragWindow(SwingUtilities.getWindowAncestor(toolbarSupport.getRoot()));
}
@Override
public void showDragEffect(Dimension size, Point p, final boolean canDock) {
final Point location = getLocation(p, size);
final Rectangle rect = new Rectangle(location, size);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dragWindow.setCanDock(canDock);
dragWindow.setBounds(rect);
if ( !dragWindow.isVisible() ) {
dragWindow.setVisible(true);
}
}
});
}
private Point getLocation(Point p, Dimension size) {
Point location = new Point(p);
SwingUtilities.convertPointToScreen(location, toolbarSupport.getRoot());
int offsetX = size.width / 2;
int offsetY = size.height / 2;
location.x -= offsetX;
location.y -= offsetY;
return location;
}
@Override
public void hideDragEffect() {
dragWindow.setVisible(false);
}
private class DragWindow extends Window {
private boolean canDock;
private Color frameColor;
private int lineTickness = 3;
public DragWindow(Window owner) {
super(owner);
}
public boolean isCanDock() {
return canDock;
}
public void setCanDock(boolean canDock) {
if ( this.canDock == canDock ) {
return;
}
this.canDock = canDock;
repaint();
}
@Override
public void paint(Graphics g) {
//super.paint(g);
Graphics2D g2 = (Graphics2D) g;
Dimension size = getSize();
final Color color = getFrameColor();
Color fillColor = canDock ? new Colors(color).a(.5f).build() : getBackground();
Color lineColor = canDock ? color : new Colors(color).a(.2f).build();
g2.setColor(getBackground());
g2.fillRect(0, 0, size.width, size.height);
g2.setColor(fillColor);
g2.fillRect(0, 0, size.width, size.height);
g2.setColor(lineColor);
g2.setStroke(new BasicStroke(lineTickness));
g2.drawRect(lineTickness / 2, lineTickness / 2, size.width - lineTickness, size.height - lineTickness);
}
private Color getFrameColor() {
if(frameColor == null) {
frameColor = UIManager.getColor("Tree.dropLineColor");
if(frameColor == null) {
frameColor = Color.RED;
}
}
return frameColor;
}
}
}
Бьюсь уже второй день с этим багом и не могу понять, в чем дело. Вначале думал, что проблема в том, что изменение размеров и положения окна вызывается в общем коде, и потом после этого окно где-то еще перерисовывается со старыми значениями. Завернул код в Runnable и вызвал его в SwingUtilities.invokeLater(Runnable) (в методе showDragEffect). Не помогло. Пробовал использовать другие AlphaComposite при отрисовке окна (в DragWindow.paint(Graphics)). Но и это тоже не помогает.
Подскажите, пожалуйста, в чем может быть проблема?