4

我有 9 个 jbuttons 添加到 jpanel 和面板添加到 jscrollpane 并添加到 jframe。

http://www.pic1.iran-forum.ir/images/up9/95426323683658592564.jpg

当我通过以下方式更改框架方向时: applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

面板向右移动并且按钮的大小得到固定并且不会填充面板但是您在下图中看到滚动条填充了面板的所有宽度

http://www.pic1.iran-forum.ir/images/up9/60975202722295688553.jpg

(我使用 gridbaglayout 添加按钮和borderlayout.center 添加滚动窗格)。

这是java中的错误还是?

编辑:它是最简单的视图。它有帮助吗?

import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;

public class MyFrame extends JFrame{
private JButton[] arrayButton = new JButton[9];
private JButton btnLeft = new JButton("<");
private JButton btnRight = new JButton(">");
private JScrollPane scpButtons = new JScrollPane();

public MyFrame() {
    for (int i = 0; i < arrayButton.length; i++) 
        arrayButton[i] = new JButton("btn");

    JPanel pnlButton = initPnlButton();
    scpButtons.setViewportView(pnlButton);
    setLayout(new BorderLayout());
    add(scpButtons, BorderLayout.CENTER);

           // comment it and see the result 
    applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);      
    pack();
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setExtendedState(JFrame.MAXIMIZED_BOTH);
    setVisible(true);
}

private JPanel initPnlButton() {
    JPanel pnlButton = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1, 10,
            1, new Insets(0, 0, 0, 0), 0, 0);

    int ind = 0;
    int row = 3;
    int column = 4;
    for (int i = 0; i < row; i++) {
        for (int j = 1; j < column; j++) {
            gbc.gridx = j;
            gbc.gridy = i;
            pnlButton.add(arrayButton[ind++], gbc);
        }
    }
    gbc.weightx = 0;
    gbc.gridheight = 3;
    gbc.gridx = 0;
    gbc.gridy = 0;
    pnlButton.add(btnLeft, gbc);
    gbc.gridx = 4;
    gbc.gridy = 0;
    pnlButton.add(btnRight, gbc);
    pnlButton.setPreferredSize(new Dimension(1000, 700));
    return pnlButton;
}
public static void main(String[] args) {
    new MyFrame();
}
}
4

2 回答 2

4

编辑 4

(希望是最后一个:-)

最终的罪魁祸首似乎是 scrollPane 的主视口:一旦在 RToL 中调整其视图的大小时,它会变得混乱,一旦它小于它的首选。没有跟踪到底出了什么问题,但看起来是可行的(没有找到核心中的错误并推动 snoracle 修复它;)解决方案是使视图实现可滚动,特别是实现

  • getPreferredScrollableViewportSize 返回 getPreferredSize
  • 如果高度/宽度小于父高度/宽度,则实现 getScrollableTracksViewportHeight/Width 以返回 true,否则返回 false

JXPanel(包含在SwingX中)是一个 Scrollable,它默认执行第一个,并且可以通过适当地设置 ScrollableSizeHints 来为后者配置:

private JPanel initPnlButton() {
    JXPanel pnlButton = new JXPanel(new GridBagLayout());
    pnlButton.setScrollableWidthHint(ScrollableSizeHint.PREFERRED_STRETCH);
    pnlButton.setScrollableHeightHint(ScrollableSizeHint.PREFERRED_STRETCH);
    ...
}

有了它,不需要更多的hacky线,只需在添加所有组件后应用CO:

applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
pack();
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);

编辑 2

我们(@Reza Gh 和我)玩得越多,我就越倾向于将这种行为视为错误。总结我们的最新发现

  • scrollPane 似乎是罪魁祸首(Reza)
  • 一旦面板的大小调整为/低于其preferredSize,不良行为就会开始(注意人工 - 至少我希望它不是Reza的生产代码的一部分 - 创建面板时设置Preferred)

编辑

多玩一点,在我看来,它是一种非常奇怪的实例化行为。一个要玩的片段(在实例化结束时)

pack();
// [1]
setSize(getWidth() + 1, getHeight() + 1);
// [2]
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    }
});

和评论 1、2 或两者

  • 评论两者:框架以打包大小出现,最大化它不会填充框架但孩子停靠在右边缘
  • 评论 1:框架以最大化尺寸出现,子填充完成的内容,然后调整大小以打包并再次最大化:子不填充
  • 评论 2:框架几乎(大一个像素)打包大小,最大化(和所有其他调整大小)正确填充屏幕

确切的行为可能也取决于本机组件的方向(我的是 LToR)。总体而言,我认为这是面向组件的核心处理中的某个错误(毫不奇怪,这些年来它并不像我们预期的那么稳定)。

看起来一个hack是在打包后调整大小(稍微增加1个像素左右,单独最大值不起作用),然后调用applyCO。

原来的

这并不能解决原始问题(即在框架的实例化上应用 componentOrientation),仅演示如何在运行时安全地切换 CO

Action createCOToggle(final JFrame frame) {
    Action toggleComponentOrientation = new AbstractAction("toggle orientation") {

        @Override
        public void actionPerformed(ActionEvent e) {
            ComponentOrientation current = frame.getComponentOrientation();
            if (current.isLeftToRight()) {
                frame.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
            } else {
                frame.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
            }
            frame.getRootPane().revalidate();
            frame.invalidate();
            frame.validate();
            frame.repaint();
        }

    };
    return toggleComponentOrientation;
}

用它配置一个动作感知组件,将使框架按预期运行,即填充整个区域。许多重新/输入/验证看起来很奇怪 - 但事实证明是必要的(在 jdk6 中),正如我们在SwingX 测试覆盖中所经历的那样

现在我的期望是,在帧的实例化结束时调用相同的动作会使它的行为也一样,即

.... // configure/fill frame
setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        createCOToggle(MyFrame.this).actionPerformed(null);
    }
});

不幸的是,它没有。目前不知道为什么不,对不起。

于 2012-08-26T11:34:22.547 回答
1

在玩了很多属性并上下移动语句之后,我找到了答案。如果你把

scpButtons.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);

applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

一切都会好起来的,不需要setSize(getWidth() + 1, getHeight() + 1);

太有趣了,我花了一整天的时间 :) c# 或其他语言有这样的错误吗?

如果你让SwingUtilitiesbloc 运行,在调整窗口大小之前,一切都还没有 LtR。

import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.*;

public class MyFrame extends JFrame {
private JButton[] arrayButton = new JButton[9];
    private JButton btnLeft = new JButton("<");
    private JButton btnRight = new JButton(">");
    private JScrollPane scpButtons = new JScrollPane();

    public MyFrame() {
        for (int i = 0; i < arrayButton.length; i++)
            arrayButton[i] = new JButton("btn");

        JMenu mnuSettings = new JMenu("MENU");
        JMenuBar menubar = new JMenuBar();
        menubar.add(mnuSettings);
        setJMenuBar(menubar);

        JPanel pnlButton = initPnlButton();
        scpButtons.setViewportView(pnlButton);
        setLayout(new BorderLayout());
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        add(scpButtons, BorderLayout.CENTER);

        pack();
        // [1]
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        //setSize(getWidth() + 1, getHeight() + 1);
        // [2]
        setVisible(true);
        // SwingUtilities.invokeLater(new Runnable() {
        // public void run() {
        applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
//here
        scpButtons.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
        // }
        // });
    }

    private JPanel initPnlButton() {
        JPanel pnlButton = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1, 10,
                1, new Insets(0, 0, 0, 0), 0, 0);

        int ind = 0;
        int row = 3;
        int column = 4;
        for (int i = 0; i < row; i++) {
            for (int j = 1; j < column; j++) {
                gbc.gridx = j;
                gbc.gridy = i;
                pnlButton.add(arrayButton[ind++], gbc);
            }
        }
        gbc.weightx = 0;
        gbc.gridheight = 3;
        gbc.gridx = 0;
        gbc.gridy = 0;
        pnlButton.add(btnRight, gbc);
        gbc.gridx = 4;
        gbc.gridy = 0;
        pnlButton.add(btnLeft, gbc);
        pnlButton.setPreferredSize(new Dimension(1000, 700));
        return pnlButton;
    }

    public static void main(String[] args) {
        new MyFrame();
    }

}

于 2012-08-27T02:11:13.433 回答