Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使绘制的JPanel上的元素可聚焦_Java_Swing_Focus_Assistive Technology - Fatal编程技术网

Java 如何使绘制的JPanel上的元素可聚焦

Java 如何使绘制的JPanel上的元素可聚焦,java,swing,focus,assistive-technology,Java,Swing,Focus,Assistive Technology,我有一个JPanel和一个覆盖的paintComponent。我想使我在这个面板上手动绘制的某些元素可以聚焦,以便使用辅助技术的人可以使用我的键盘应用程序 如果你能给我一些建议,那就太棒了。你可以做以下几点: 将元素转换为JComponents 将面板的LayoutManager设置为null。然后将所有组件/元素添加到此面板中,您可以使用该方法自由移动它们 在面板中添加一个MouseListener,每次按下鼠标时,它会将焦点转移到所选组件 您可以通过在面板的mouseStener中调用方法来

我有一个
JPanel
和一个覆盖的
paintComponent
。我想使我在这个面板上手动绘制的某些元素可以聚焦,以便使用辅助技术的人可以使用我的键盘应用程序


如果你能给我一些建议,那就太棒了。

你可以做以下几点:

  • 将元素转换为
    JComponent
    s
  • 将面板的
    LayoutManager
    设置为
    null
    。然后将所有组件/元素添加到此面板中,您可以使用该方法自由移动它们
  • 在面板中添加一个
    MouseListener
    ,每次按下鼠标时,它会将焦点转移到所选组件
  • 您可以通过在面板的
    mouseStener
    中调用方法来确定按下了哪个组件
  • 简单的例子:
  • 制作一个具有标准行为的组件,向用户显示是否有焦点。在我的示例中,这个类下面的代码是
    FocusableComponent extensed JComponent
    ,如果组件有焦点,它会在组件周围绘制一个蓝色矩形(这是在方法
    FocusableComponent.paintComponent(Graphics)
    中完成的)
  • 然后,对于您绘制的每个不同的“元素”,子类
    FocusableComponent
    并重写其paintComponent(Graphics)方法来绘制元素。确保在其中调用“
    super.paintComponent(Graphics)
    ”,以便绘制蓝色矩形(如果有焦点) 代码: 截图:

    一些注意事项:
  • 焦点转移的顺序与
    rapaint()
    s在
    mousePressed(…)
    内被调用的顺序有关,确定哪个组件周围有蓝色矩形,而哪个组件周围没有
  • 方法不“透视”透明/非不透明像素 更新: 注意:此更新是上述解决方案的一个可选扩展(但可能是一个更加一致的java契约,让我说一下)。您只能阅读两个实现中的一个(以下“更新”一个为
    RandomLayout
    ,以上“预更新”一个为
    null
    LayoutManager

    按照用户“Andrew Thompson”在注释中的建议,更新上述代码,使用自定义的
    LayoutManager
    来布局容器中的组件。
    与上述代码的唯一区别在于,在构建自定义
    layourtmanager
    时,不必设置为
    null
    而需要设置其大小,而不是设置每个组件的边界

    我已将自定义的
    LayoutManager
    命名为
    RandomLayout
    ,它将容器的所有组件放置在随机位置,考虑到组件的大小和容器的
    插入部分
    (这可以通过
    您的面板
    中添加的
    边框
    来证明)

    更新的“随机布局”: 使用JavaDoc定制的
    LayoutManager
    本身(可能很大,但希望可以重用):

    导入java.awt.Component;
    导入java.awt.Container;
    导入java.awt.Dimension;
    导入java.awt.Insets;
    导入java.awt.LayoutManager;
    导入java.awt.Point;
    导入java.util.Random;
    /**
    *一个{@link java.awt.LayoutManager},它随机列出所有{@link java.awt.Component}
    *考虑到父级的{@link java.awt.Insets},它的父级。
    *
    *使用{@link#setrandomizence(boolean)}方法确定最后布局的父对象是否将
    *只能随机布局一次,而不是针对每个{@link#layoutContainer(java.awt.Container)}
    *对同一父级或相反父级的后续调用。
    *

    */ 公共类RandomLayout实现LayoutManager{ /** *最后布置的{@linkjava.awt.Container}。 */ 父/母私有容器; /** *{@code lastParent}的{@link java.awt.Insets}在上次布局时。 */ 私人插页最后插页; /** *如果{@code true},那么这个{@link java.awt.LayoutManager}将跟踪 *{@link java.awt.Container}的布局,以确保{@code lastParent}是 *仅布局一次。如果布局另一个{@link java.awt.Container},则其他 *而不是{@code lastParent},那么它的组件是随机布局的,并且 *{@link java.awt.Container}成为{@code lastParent}。 */ 私有布尔随机化; /** *{@code RandomLayout}的正规构造函数,具有{@code RANDOMIZENCE}的显式值。 * *@param randomizence{@code true}如果最后一个布局的父对象将仅布局 *随机一次,而不是每次{@link#layoutContainer(java.awt.Container)}后续调用 *对于同一父级,否则为{@code false},并且每次调用 *{@link#layoutContainer(java.awt.Container)}将随机布局{@link java.awt.Container}。 */ 公共随机布局(最终布尔随机){ this.randomizence=randomizence; } /** *{@code randomizeOnce}设置为{@code true}的{@code RandomLayout}的默认构造函数。 */ 公共空间布局(){ 这是真的; } /** *如果{@code true},那么这个{@link java.awt.LayoutManager}将跟踪 *{@link java.awt.Container}的布局,以确保{@code lastParent}是 *仅布局一次。如果布局另一个{@link java.awt.Container},则其他 *而不是{@code lastParent},那么它的组件是随机布局的,并且 *{@link java.awt.Container}成为{@code lastParent}。 * *@param randomizence{@code true}如果最后一个布局的父对象将仅布局 *随机一次而不是f
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class FocusablePaintComps {
        private static abstract class FocusableComponent extends JComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                if (hasFocus()) {
                    final Color prevColor = g.getColor();
                    g.setColor(Color.BLUE);
                    g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
                    g.setColor(prevColor);
                }
            }
        }
    
        private static class FocusableComponent1 extends FocusableComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
            }
        }
    
        private static class FocusableComponent2 extends FocusableComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                final int w = getWidth(), h = getHeight();
                g.fillRect(20, 20, w - 40, h - 40);
                g.fillArc(10, 10, w - 1, h - 1, 60, 150);
            }
        }
    
        private static class YourPanel extends JPanel {
            private Component previousFocusedComponent = null;
    
            private YourPanel() {
                super(null); //Null LayoutManager. This is important to be able to
                //move added components around freelly (with the method setBounds(...)).
    
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(final MouseEvent evt) {
                        final Component src = getComponentAt(evt.getPoint());
                        if (src instanceof FocusableComponent) {
                            final FocusableComponent fc = (FocusableComponent) src;
                            fc.requestFocusInWindow(); //Transfer focus to the pressed component.
                            if (previousFocusedComponent != null)
                                previousFocusedComponent.repaint(); //Repaint the last (without focus now).
                            setComponentZOrder(fc, 0); //Update: To make fc paint over all others as  
                            //the user http://stackoverflow.com/users/131872/camickr commented.  
                            fc.repaint(); //Repaint the new (with focus now).
                            previousFocusedComponent = fc;
                        }
                        else { //If clicked on empty space, or a non-FocusableComponent:
                            requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
                            if (previousFocusedComponent != null) {
                                previousFocusedComponent.repaint(); //Repaint the last (without focus now).
                                previousFocusedComponent = null;
                            }
                        }
                    }
                });
    
                setPreferredSize(new Dimension(250, 250));
    
                add(new FocusableComponent1(), Color.RED, new Rectangle(10, 10, 200, 20));
                add(new FocusableComponent1(), Color.GREEN, new Rectangle(40, 150, 50, 70));
                add(new FocusableComponent2(), Color.GRAY, new Rectangle(60, 125, 90, 100));
                add(new FocusableComponent2(), Color.MAGENTA, new Rectangle(150, 60, 80, 150));
            }
    
            private void add(final FocusableComponent fc, final Color fgColor, final Rectangle bounds) {
                fc.setForeground(fgColor);
                add(fc);
                fc.setBounds(bounds);
            }
        }
    
        public static void main(final String[] args) {
            final JFrame frame = new JFrame("Focused Paint Comps");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new YourPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.border.LineBorder;
    
    public class FocusablePaintComps {
        private static abstract class FocusableComponent extends JComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                if (hasFocus()) {
                    final Color prevColor = g.getColor();
                    g.setColor(Color.BLUE);
                    g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
                    g.setColor(prevColor);
                }
            }
        }
    
        private static class FocusableComponent1 extends FocusableComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
            }
        }
    
        private static class FocusableComponent2 extends FocusableComponent {
            @Override protected void paintComponent(final Graphics g) {
                super.paintComponent(g);
                final int w = getWidth(), h = getHeight();
                g.fillRect(20, 20, w - 40, h - 40);
                g.fillArc(10, 10, w - 1, h - 1, 60, 150);
            }
        }
    
        private static class YourPanel extends JPanel {
            private Component previousFocusedComponent = null;
    
            private YourPanel() {
                super(new RandomLayout()); //RandomLayout: custom LayoutManager which lays
                //out the components in random positions (takes Insets into account).
    
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(final MouseEvent evt) {
                        final Component src = getComponentAt(evt.getPoint());
                        if (src instanceof FocusableComponent) {
                            final FocusableComponent fc = (FocusableComponent) src;
                            fc.requestFocusInWindow(); //Transfer focus to the pressed component.
                            if (previousFocusedComponent != null)
                                previousFocusedComponent.repaint(); //Repaint the last (without focus now).
                            setComponentZOrder(fc, 0); //Update: To make fc paint over all others as  
                            //the user http://stackoverflow.com/users/131872/camickr commented.  
                            fc.repaint(); //Repaint the new (with focus now).
                            previousFocusedComponent = fc;
                        }
                        else { //If clicked on empty space, or a non-FocusableComponent:
                            requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
                            if (previousFocusedComponent != null) {
                                previousFocusedComponent.repaint(); //Repaint the last (without focus now).
                                previousFocusedComponent = null;
                            }
                        }
                    }
                });
    
                setBorder(new LineBorder(Color.LIGHT_GRAY, 20));
                setPreferredSize(new Dimension(300, 250));
    
                add(new FocusableComponent1(), Color.RED, new Dimension(200, 20));
                add(new FocusableComponent1(), Color.GREEN, new Dimension(50, 70));
                add(new FocusableComponent2(), Color.GRAY, new Dimension(90, 100));
                add(new FocusableComponent2(), Color.MAGENTA, new Dimension(80, 150));
            }
    
            private void add(final FocusableComponent fc, final Color fgColor, final Dimension size) {
                add(fc);
                fc.setForeground(fgColor);
                fc.setSize(size);
            }
        }
    
        public static void main(final String[] args) {
            final JFrame frame = new JFrame("Focused Paint Comps");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new YourPanel());
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    
    import java.awt.Component;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.Insets;
    import java.awt.LayoutManager;
    import java.awt.Point;
    import java.util.Random;
    
    /**
     * A {@link java.awt.LayoutManager} which lays out randomly all the {@link java.awt.Component}s
     * of its parent, taking into consideration the parent's {@link java.awt.Insets}.
     * <p>
     * Use {@link #setRandomizeOnce(boolean)} method to determine if the lastly laid-out parent will
     * be only laid-out randomly once and not for each {@link #layoutContainer(java.awt.Container)}
     * subsequent call for the same parent, or the opposite.
     * </p>
     */
    public class RandomLayout implements LayoutManager {
        /**
         * The {@link java.awt.Container} which was lastly laid-out.
         */
        private Container lastParent;
    
        /**
         * The {@link java.awt.Insets} of {@code lastParent} the last time it was laid-out.
         */
        private Insets lastInsets;
    
        /**
         * If {@code true} then this {@link java.awt.LayoutManager} keeps track of the
         * {@link java.awt.Container}s laid-out to make sure that {@code lastParent} is
         * only laid-out once. If the another {@link java.awt.Container} is laid-out, other
         * than {@code lastParent}, then its components are laid-out randomly and the
         * {@link java.awt.Container} becomes the {@code lastParent}.
         */
        private boolean randomizeOnce;
    
        /**
         * Normal constructor of {@code RandomLayout} with explicit value for {@code randomizeOnce}.
         * 
         * @param randomizeOnce {@code true} if the lastly laid-out parent will be only laid-out
         * randomly once and not for each {@link #layoutContainer(java.awt.Container)} subsequent call
         * for the same parent, otherwise {@code false} and each call to
         * {@link #layoutContainer(java.awt.Container)} will lay out randomly the {@link java.awt.Container}.
         */
        public RandomLayout(final boolean randomizeOnce) {
            this.randomizeOnce = randomizeOnce;
        }
    
        /**
         * Default constructor of {@code RandomLayout} with {@code randomizeOnce} set to {@code true}.
         */
        public RandomLayout() {
            this(true);
        }
    
        /**
         * If {@code true} then this {@link java.awt.LayoutManager} keeps track of the
         * {@link java.awt.Container}s laid-out to make sure that {@code lastParent} is
         * only laid-out once. If the another {@link java.awt.Container} is laid-out, other
         * than {@code lastParent}, then its components are laid-out randomly and the
         * {@link java.awt.Container} becomes the {@code lastParent}.
         * 
         * @param randomizeOnce {@code true} if the lastly laid-out parent will be only laid-out
         * randomly once and not for each {@link #layoutContainer(java.awt.Container)} subsequent call
         * for the same parent, otherwise {@code false}.
         */
        public void setRandomizeOnce(final boolean randomizeOnce) {
            this.randomizeOnce = randomizeOnce;
        }
    
        /**
         * Tells if the lastly laid-out parent will be only laid-out randomly once and not for each
         * {@link #layoutContainer(java.awt.Container)} subsequent call for the same parent, or the
         * opposite.
         * 
         * @return {@code true} if the lastly laid-out parent will be only laid-out randomly once and
         * not for each {@link #layoutContainer(java.awt.Container)} subsequent call for the same
         * parent, otherwise {@code false}.
         */
        public boolean isRandomizeOnce() {
            return randomizeOnce;
        }
    
        /**
         * @return The {@link java.awt.Container} which was lastly laid-out.
         */
        protected Container getLastParent() {
            return lastParent;
        }
    
        /**
         * @return The {@link java.awt.Insets} of {@code lastParent} the last time it was laid-out.
         * @see #getLastParent()
         */
        protected Insets getLastInsets() {
            return lastInsets;
        }
    
        /**
         * Adds the specified component with the specified name to the layout.
         * @param name The name of the component.
         * @param comp The {@link java.awt.Component} to be added.
         */
        public void addLayoutComponent(final String name,
                                       final Component comp) {
        }
    
        /**
         * Removes the specified component from the layout.
         * @param comp The {@link java.awt.Component} to be removed.
         */
        public void removeLayoutComponent(final Component comp) {
        }
    
        /** 
         * {@inheritDoc}
         * @return The preferred size dimensions for the specified {@link java.awt.Container}.
         */
        @Override
        public Dimension preferredLayoutSize(final Container parent) {
            final Dimension prefDim = minimumLayoutSize(parent);
            prefDim.width += 2; //+2 to spare.
            prefDim.height += 2; //+2 to spare.
            return prefDim;
        }
    
        /**
         * {@inheritDoc}
         * @return The minimum size dimensions for the specified {@link java.awt.Container}.
         */
        @Override
        public Dimension minimumLayoutSize(final Container parent) {
            final Dimension minDim = new Dimension();
    
            final int childCnt = parent.getComponentCount();
            for (int i=0; i<childCnt; ++i)
                applyBigger(minDim, getPreferredSize(parent, parent.getComponent(i)));
    
            final Insets parInsets = parent.getInsets();
            minDim.width += (parInsets.left + parInsets.right);
            minDim.height += (parInsets.top + parInsets.bottom);
    
            return minDim;
        }
    
        /**
         * {@inheritDoc}. If the another {@link java.awt.Container} is laid-out, other
         * than {@code lastParent}, then its components are laid-out randomly and the
         * {@link java.awt.Container} becomes the {@code lastParent}.
         */
        @Override
        public void layoutContainer(final Container parent) {
            if (parent == null)
                throw new IllegalArgumentException("Cannot lay out null.");
            if (isRandomizeOnce() && lastParent == parent) { //At least take care of insets (if they have changed).
                final Insets parentInsets = parent.getInsets();
                if (!lastInsets.equals(parentInsets)) {
                    final int offx = parentInsets.left - lastInsets.left,
                              offy = parentInsets.top - lastInsets.top;
    
                    final int childCnt = parent.getComponentCount();
                    for (int i=0; i<childCnt; ++i) {
                        final Component child = parent.getComponent(i);
                        final Point childLoca = child.getLocation();
                        childLoca.x += offx;
                        childLoca.y += offy;
                        child.setLocation(childLoca);
                    }
    
                    lastInsets = parentInsets;
                }
            }
            else
                layoutContainerRandomly(parent);
        }
    
        /**
         * Explicitly lays out randomly the specified container.
         * <p>
         * This is equivalent of calling:
         * <pre>
         * boolean isRand1 = randomLayout.isRandomizeOnce();
         * randomLayout.setRandomizeOnce(false);
         * randomLayout.layoutContainer(parent);
         * randomLayout.setRandomizeOnce(isRand1);
         * </pre>
         * {@code parent} becomes {@code lastParent}.
         * </p>
         * @param parent The container to be laid out.
         */
        public void layoutContainerRandomly(final Container parent) { //Place each child at a random location for the "new" parent (lastParent != parent).
            if (parent == null)
                throw new IllegalArgumentException("Cannot lay out null.");
    
            reset();
    
            final Dimension parentSize = parent.getSize();
            final Insets parentInsets = parent.getInsets();
            final Dimension childSize = new Dimension();
            final Point childLoca = new Point();
            final Random rand = new Random();
    
            final int childCnt = parent.getComponentCount();
            for (int i=0; i<childCnt; ++i) {
                final Component child = parent.getComponent(i);
    
                child.getSize(childSize);
    
                childLoca.x = parentInsets.left + 1;
                childLoca.y = parentInsets.top + 1;
    
                final int xBound = parentSize.width - parentInsets.left - parentInsets.right - childSize.width,
                          yBound = parentSize.height - parentInsets.top - parentInsets.bottom - childSize.height;
    
                if (xBound > 0)
                    childLoca.x += rand.nextInt(xBound);
                if (yBound > 0)
                    childLoca.y += rand.nextInt(yBound);
    
                child.setLocation(childLoca);
            }
    
            lastParent = parent;
            lastInsets = parentInsets;
        }
    
        /**
         * Invalidates the tracking of the lastly laid-out {@link java.awt.Container} and its last
         * {@link java.awt.Insets}.
         * @see #getLastParent()
         * @see #getLastInsets()
         */
        protected void reset() {
            lastParent = null;
            lastInsets = null;
        }
    
        private static void applyBigger(final Dimension inputOutput,
                                        final Dimension input) {
            if (inputOutput != null && input != null) {
                inputOutput.width = (int) Math.max(inputOutput.width, input.width);
                inputOutput.height = (int) Math.max(inputOutput.height, input.height);
            }
        }
    
        private static void applyIfBetter(final Dimension inputOutput,
                                          final Dimension input) {
            if (inputOutput != null && input != null
                && (input.width > inputOutput.width
                    || input.height > inputOutput.height)) {
                inputOutput.width = input.width;
                inputOutput.height = input.height;
            }
        }
    
        /**
         * Tries to determine the best size for {@code child}.
         * @param parnt The parent {@link java.awt.Container} being laid-out.
         * @param child The child {@link java.awt.Component} of {@code parnt} being laid-out.
         * @return A preferred size for the {@code child} to be laid-out.
         */
        protected static Dimension getPreferredSize(final Container parnt,
                                                    final Component child) {
            final Dimension minDim = new Dimension();
            if (child != null) {
                applyIfBetter(minDim, child.getMinimumSize());
                applyIfBetter(minDim, child.getSize());
                applyIfBetter(minDim, child.getPreferredSize());
            }
            return minDim;
        }
    }