Задать вопрос

Почему неправильно перерисовывается окно (java.awt.Window)?

Меня не устраивает стандартный механизм докинга тулбаров в Swing, поэтому делаю свою реализацию.
При перетаскивании тулбара с одного края компонента на другой появляется окно (java.awt.Window), которое принимает размеры перетаскиваемого тулбара с учетом его ориентации.

Положение окна определяется по текущим координатам курсора. В зависимости от того, может ли тулбар быть перемещен в текущее положение, меняется цвет линий и цвет фона в окне.

Вот скриншоты того, как это все выглядит.
Окно около горизонтального края:
4100bf89d1794525856baa77445d551d.png

Окно показывающее, что тут нельзя разместить тулбар
a254f23f4a0648cc8929be8ec7311665.png

Окно около вертикального края:
a004a802556644849343d4139d13197b.png

Проблема в следующем. Когда перетаскивается тулбар, и курсор переходит с одной края компонента на другой (например с левого на верхний), на этом окне видно и вновь отрисованное состояние и часть предыдущего. Выглядит так, как-будто рисуется новое состояние, а поверх него старое, но за счет того, что размер окна поменялся на противоположный, отрисованное старое состояние не помещается полностью, и видно только его часть.

Вот скриншот такого состояния:
3419359802f9493d8753a7ffa86ae077.png

Вот код:
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)). Но и это тоже не помогает.
Подскажите, пожалуйста, в чем может быть проблема?
  • Вопрос задан
  • 2931 просмотр
Подписаться 2 Оценить Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы