Irrelevant change of button size in Right to Left orientation

坚强是说给别人听的谎言 提交于 2019-12-05 18:45:58

Edit 4

(Hopefully the very last :-)

The ultimate culprit seems to be the main viewport of the scrollPane: it gets confused when sizing its view in RToL once it had been smaller than its preferred. Didn't track what exactly goes wrong, but looks like a viable (short of finding the bug in core and nudge snoracle into fixing it ;) solution is to make the view implement Scrollablable, specifically implement

  • getPreferredScrollableViewportSize to return getPreferredSize
  • implement getScrollableTracksViewportHeight/Width to return true if height/width is less than parent height/width and false otherwise

JXPanel (contained in SwingX) is-a Scrollable which does the first by default and can be configured for the latter by setting ScrollableSizeHints as appropriate:

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

With that in place, no further hacky lines needed, simply apply the CO after adding all components:

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

Edit 2

The more we (both @Reza Gh and me) play with options the more I tend to seeing the behaviour as a bug. To sum up our latest findings

  • the scrollPane seems to be a major culprit (Reza)
  • the misbehaviour starts once the panel had been resized at/below its preferredSize (note the arteficial - at least I hope it's not part of Reza's production code - setPreferred when creating the panel)

Edit

Playing a bit more, it looks to me like a very weird behaviour on instantiation. A snippet to play with (at the end of the instantiation)

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);
    }
});

and comment 1, 2 or both

  • comment both: frame comes up in packed size, maximizing it doesn't fill the frame but child is docked at right edge
  • comment 1: frame comes up in maximized size, child fills completed content, then resize to packed and maximize again: child doesn't fill
  • comment 2: frame comes up with nearly (one pixel bigger) packed size, maximizing (and all other resizing) correctly fills the screen

The exact behaviour probably depending on native component orientation as well (mine is LToR). On the whole, I think this is a bug somewhere in core handling of component orientation (not surprisingly, it's not as stable as we would expect after all these years).

Looks like a hack around is to resize (slightly by 1 or so pixel, max alone doesn't work) after a pack and then invoke the applyCO.

Original

This does not solve the original problem (which is to apply the componentOrientation on instantiation of the frame), only demonstrates how to safely toggle CO at runtime

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;
}

configuring an action-aware component with it, will make the frame behave as expected, that is fill the complete area. The many re/in/validates look weird - but turned out to be necessary (in jdk6) as we experienced in SwingX test coverage

Now my expectation would have been, that invoking that same action at the end of frame's instantiation would make it behave as well, that is

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

Unfortunate, it doesn't. Currently no clue as to why not, sorry.

after playing with lots of properties and moving up and down the statements i found the answer. if you put

scpButtons.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);

after

applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

everything will be okay and no need to setSize(getWidth() + 1, getHeight() + 1);

so funny it got a whle day from me :) does c# or other langs have bugs like this?

if you let SwingUtilities bloc to run , befor resizing the window everything are yet 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();
    }

}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!