JScrollPane似乎在从右到左的方向上工作不正常,但我不太确定如何

时间:2014-08-12 07:08:43

标签: java swing jscrollpane look-and-feel

我的脑袋变得如此混乱,使用这种从右到左的东西,我甚至不确定问题出在哪里,但实际上,当我设置为右边时,我发现滚动条似乎“不太正确”左方向。我将其归结为一个测试程序,其工作原理如下:

  1. 滚动条从UP和LEFT开始(感觉不对),你可以看到紫色。
  2. 如果您调整窗口大小以适应所有内容,则会看到红色位于左上方。
  3. 如果您将窗口调整得更小并将滚动条移动到UP和LEFT,则会出现紫色,这似乎是错误的。
  4. 如果滚动条是向上和向右,则会得到红色。
  5. 在鼠标上滑动会将滚动条移动到正确的位置,但似乎会向错误的方向移动内容。
  6. 我无法判断哪些位是向后的,哪些位是正确的,但是视口开始位于右上角似乎是模糊的,但左侧的滚动条肯定是不一致的。但是,如果我试图翻转滚动条的渲染,那么条形图本身就不会被绘制,就像Aqua发现我试图以某种方式作弊一样。

    AquaScrollBarUI不包含对isLeftToRight()的单个调用,但可能滚动条很好,而且窗格本身是错误的?

    我认为这是一个Swing错误,所以我可能会报告它,但是这个烂摊子有一个优雅的解决方案吗?我正在写一个自定义的外观和感觉Aqua的子类,所以我可以把这种修复尽可能接近Aqua。

    import javax.swing.*;
    import java.awt.*;
    
    public class ScrollPaneOrientationTest implements Runnable {
        public static void main(String[] args) throws Exception {
            SwingUtilities.invokeLater(new ScrollPaneOrientationTest());
        }
    
        @Override
        public void run() {
    
            JPanel view = new ViewPanel();
            JScrollPane scrollPane = new JScrollPane(view);
    
            JFrame frame = new JFrame();
            frame.setLayout(new BorderLayout());
            frame.add(scrollPane, BorderLayout.CENTER);
    
            frame.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    
            frame.pack();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
        private class ViewPanel extends JPanel implements Scrollable {
            private static final int SIZE = 1000;
            private final Paint paint = new GradientPaint(new Point(0, 0), Color.RED, new Point(SIZE, SIZE), Color.BLUE);
    
            @Override
            protected void paintComponent(Graphics g) {
                ((Graphics2D) g).setPaint(paint);
                ((Graphics2D) g).fill(new Rectangle(0, 0, SIZE, SIZE));
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(SIZE, SIZE);
            }
    
            @Override
            public Dimension getPreferredScrollableViewportSize() {
                return new Dimension(400, 400);
            }
    
            @Override
            public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
                return 8;
            }
    
            @Override
            public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
                return 400;
            }
    
            @Override
            public boolean getScrollableTracksViewportWidth() {
                return false;
            }
    
            @Override
            public boolean getScrollableTracksViewportHeight() {
                return false;
            }
        }
    }
    

1 个答案:

答案 0 :(得分:0)

这是我最初要解决的问题。如果很长一段时间没有更好的选择,我想我会接受我自己的答案。

public class HaquaScrollPaneUI extends AquaScrollPaneUI {
    @NotNull
    @SuppressWarnings("UnusedDeclaration") // called via reflection
    public static ComponentUI createUI(JComponent component) {
        return new HaquaScrollPaneUI();
    }

    @Override
    protected MouseWheelListener createMouseWheelListener() {
        return new FixedXYMouseWheelHandler();
    }

    protected class FixedXYMouseWheelHandler extends XYMouseWheelHandler {
        @Override
        public void mouseWheelMoved(MouseWheelEvent event) {

            if (event.isShiftDown() &&
                    !scrollpane.getComponentOrientation().isLeftToRight()) {

                // fixes mouse wheel over scroll pane
                event = new MouseWheelEvent(
                        event.getComponent(), event.getID(), event.getWhen(),
                        event.getModifiers(),
                        event.getX(), event.getY(),
                        event.getXOnScreen(), event.getYOnScreen(),
                        event.getClickCount(), event.isPopupTrigger(),
                        event.getScrollType(),
                        -event.getScrollAmount(),
                        -event.getWheelRotation(),
                        -event.getPreciseWheelRotation());
            }

            super.mouseWheelMoved(event);
        }
    }
}

public class HaquaScrollBarUI extends AquaScrollBarUI {
    @NotNull
    @SuppressWarnings("UnusedDeclaration") // called via reflection
    public static ComponentUI createUI(JComponent component) {
        return new HaquaScrollBarUI();
    }

    @Override
    public void update(Graphics graphics, JComponent component) {
        if (fScrollBar.getOrientation() == Adjustable.HORIZONTAL &&
                !fScrollBar.getComponentOrientation().isLeftToRight()) {

            // fixes painting direction
            Graphics2D graphicsCopy = (Graphics2D) graphics.create();
            try {
                graphicsCopy.translate(fScrollBar.getWidth() - 1, 0);
                graphicsCopy.scale(-1, 1);
                super.update(graphicsCopy, component);
            } finally {
                graphicsCopy.dispose();
            }
        } else {
            super.update(graphics, component);
        }
    }

    @Override
    protected TrackListener createTrackListener() {
        // fixes mouse behaviour
        return new FlippedTrackListener();
    }

    private class FlippedTrackListener extends TrackListener {
        @Override
        public void mouseReleased(MouseEvent event) {
            super.mouseReleased(flipEvent(event));
        }

        @Override
        public void mousePressed(MouseEvent event) {
            super.mousePressed(flipEvent(event));
        }

        @Override
        public void mouseDragged(MouseEvent event) {
            super.mouseDragged(flipEvent(event));
        }

        // These ones aren't used, but I figured it would be sane
        // to override them anyway, just in case.

        @Override
        public void mouseClicked(MouseEvent event) {
            super.mouseClicked(flipEvent(event));
        }

        @Override
        public void mouseEntered(MouseEvent event) {
            super.mouseEntered(flipEvent(event));
        }

        @Override
        public void mouseExited(MouseEvent event) {
            super.mouseExited(flipEvent(event));
        }

        @Override
        public void mouseWheelMoved(MouseWheelEvent event) {
            super.mouseWheelMoved(flipEvent(event));
        }

        @Override
        public void mouseMoved(MouseEvent event) {
            super.mouseMoved(flipEvent(event));
        }

        private MouseEvent flipEvent(MouseEvent event) {
            if (fScrollBar.getOrientation() == Adjustable.HORIZONTAL &&
                    !fScrollBar.getComponentOrientation().isLeftToRight()) {

                int x = fScrollBar.getWidth() - 1 - event.getX();
                int y = event.getY();
                Point scrollBarLocationOnScreen = fScrollBar.getLocationOnScreen();
                int xOnScreen = x + scrollBarLocationOnScreen.x;
                int yOnScreen = y + scrollBarLocationOnScreen.y;
                return new MouseEvent(
                        event.getComponent(), event.getID(), event.getWhen(),
                        event.getModifiersEx(),
                        x, y, xOnScreen, yOnScreen,
                        event.getClickCount(), event.isPopupTrigger(), event.getButton());
            } else {
                return event;
            }
        }

        private MouseWheelEvent flipEvent(MouseWheelEvent event) {
            if (fScrollBar.getOrientation() == Adjustable.HORIZONTAL &&
                    !fScrollBar.getComponentOrientation().isLeftToRight()) {

                int x = event.getX();
                x = fScrollBar.getWidth() - 1 - x;
                int y = event.getY();
                Point scrollBarLocationOnScreen = fScrollBar.getLocationOnScreen();
                int xOnScreen = x + scrollBarLocationOnScreen.x;
                int yOnScreen = y + scrollBarLocationOnScreen.y;
                return new MouseWheelEvent(
                        event.getComponent(), event.getID(), event.getWhen(),
                        event.getModifiersEx(),
                        x, y, xOnScreen, yOnScreen,
                        event.getClickCount(), event.isPopupTrigger(),
                        event.getScrollType(), event.getScrollAmount(),
                        event.getWheelRotation(),
                        event.getPreciseWheelRotation());
            } else {
                return event;
            }
        }
    }
}