【问题标题】:Aligning components of a JScrollPane to the left?将 JScrollPane 的组件向左对齐?
【发布时间】:2012-09-10 01:02:48
【问题描述】:

目前,我有一个嵌套在具有 BorderLayout 的面板中的 JScrollPane。更重要的是,在 JScrollPane 中,我打算垂直列出多个文本区域,其宽度不超过 JScrollPane 的宽度,以及所需的高度(滚动窗格只有一个垂直滚动条)。

我的问题是文本区域相对于最大的文本区域在 JScrollPane 中似乎居中,并且它们都是一行。

谁能告诉我,看看我的代码,如何让文本区域在滚动窗格右侧之前换行,以及如何左对齐?

private JPanel generateStateView(State state) {
        //Create a new panel, and the info label.
        JPanel container = new JPanel(new BorderLayout());
        JLabel infoLabel = new JLabel("The state of " + state.getName() + 
                ", with " + state.getElectoralVotes() + " Electoral Votes.");
        container.add(infoLabel, BorderLayout.NORTH); //Put the label on top.
        //Will scroll through polls.
        JScrollPane pollViewer = new JScrollPane();
        //This will be the scroll pane's "viewport".
        JViewport pollViewport = new JViewport();
        //And finally, this will actually hold the individual polls.
        JPanel pollPanel = new JPanel(new GridLayout(
                state.getPolls().size(), 1));
        pollPanel.setAlignmentX(LEFT_ALIGNMENT);
        //Iteratively add the polls to the container
        for (Poll poll : state.getPolls()) {
            //Holds individual polls
            Box pollBox = Box.createHorizontalBox();
            //Create the poll's panel and add it to the poll container.
            pollBox.add(generatePollPanel(poll));
            pollBox.add(Box.createHorizontalGlue()); //Fill to the right
            pollBox.setAlignmentX(LEFT_ALIGNMENT);
            pollPanel.add(pollBox); //Put the box into the pollPanel.
        }
        //Put the panel into the viewport.
        pollViewport.add(pollPanel);
        //Put the viewport "into" the scroll pane
        pollViewer.setViewport(pollViewport);
        //Put the pane into the state view.
        container.add(pollViewer, BorderLayout.CENTER);
        return container; //And give back the container.
    }

    /**
     * Method: generatePollPanel
     * Purpose: Generates a panel containing information on a particular poll.
     * @param poll The poll to have information generated from.
     * @return The JPanel.
     */
    private JPanel generatePollPanel(Poll poll) {
        //Create a new panel, then a text area to fill with the info.
        JPanel pollPanel = new JPanel();
        JTextArea pollInfo = new JTextArea("Conducted by " + poll.getAgency() + 
                " on day " + poll.getDate() + " for " + poll.getNumDays() + 
                " days, " + poll.getPercentVoteDem() +
                "% voted Democrat, and " + poll.getPercentVoteRep() +
                "% voted Republican.");
        pollInfo.setEditable(false); //We don't want the user editing this.
        pollPanel.add(pollInfo); //Throw the area in, and return the panel.
        pollPanel.setAlignmentX(LEFT_ALIGNMENT);
        return pollPanel;
    }

    /**
     * Method: valueChanged
     * Purpose: Handle the event of a different list item being selected.
     * @param event The object containing information about this event.
     */
    public void valueChanged(ListSelectionEvent event) {
        //Instantiating JList with a type of ? seems to solve the issue of
        //eclipse complaining about an unchecked cast (originally to
        //JList<String>, so I should be able to cast child values directly
        //to string later on anyways.
        JList<?> stateList = (JList<?>) event.getSource();
        //Account for keyboard and mouse actions
        if (!event.getValueIsAdjusting()) {
            State chosenState; //Keep track of the picked state.
            try {
                //Try to get the currently selected state
                chosenState = db.findState((String) stateList.getSelectedValue());
            }
            catch (NoSuchElementException exception) {
                //Somehow the picked state was not found, notify the user.
                reportError("The selected state is not available.");
                return;
            }
            //Find the container for the gui window.
            Container container = getContentPane();
            //Remove the empty state view container by generating a new one.
            container.remove(currentStateView);
            //Generate the state view and add that to the container.
            currentStateView = generateStateView(chosenState);
            container.add(currentStateView, BorderLayout.CENTER);
            //Redraw everything.
            revalidate();
        }
    }

【问题讨论】:

    标签: java swing layout alignment jscrollpane


    【解决方案1】:

    首先,我不认为Box 应该与BoxLayout 以外的任何东西一起使用(我可能是错的,但我就是这么读的)

    就我个人而言,我会使用来自 SwingLabs 的 GridBagLayoutVerticalLayout

    为了方便横向限制,你也会想看看Scrollable接口,特别是getScrollableTracksViewportWidth

    【讨论】:

    • 我想我不太明白我应该在哪里进行这些修改 - 例如,我是否应该修改方法 generateStateView 中的 JPanel pollPanel 以使用 GridBagLayout?
    • 首先,我将创建一个从实现Scrollable 接口的JPanel 扩展的新类。我有getScrollableTracksViewportWidth 返回true,为了得到你想要的东西,你将不得不使用其他所有东西,但这会让你开始。我会将这个面板布局设置为使用GridBagLayout(或VerticalLayout)之类的东西,并向其中添加文本组件。
    【解决方案2】:

    看起来像一个严重的嵌套丢失 :-)

    虽然嵌套可以作为实现布局要求的一种手段,但如果它没有给出预期的输出,就很难找出到底出了什么问题。此外,还有一般警告信号表明嵌套基本上有问题

    • 具有不同管理器的深层容器
    • 只有一个孩子的容器

    在您的情况下,除了顶级边框布局之外,所有的都有一个“netto”(即,不打算解决布局问题)子级,具有级别:

    BorderLayout (the state view)
       GridLayout (the panel that's the scrollPane's view)
          BoxLayout (the panel that contains a single pollBox)
             FlowLayout (the panel that contains the textArea)
    

    遇到的问题:

    • 文本区域是单行的,无需换行
    • 文本区域居中

    都是由于 LayoutManagers 的特性,部分(第一)或完全(第二):

    • 不属于管理器的部分是 textArea 默认情况下不换行,您必须明确配置它才能这样做。由于管理器 (== FlowLayout) 的部分原因是它总是根据它们的 prefSize 布置其子级,仅此而已。这归结为有一个固定的孩子大小,无论有多少空间可供父母使用。因此,即使 textArea 被配置为换行,它也会保持初始大小,无论其父级可以得到多宽。
    • 内部 FlowLayout 对齐其子级...居中。因此,您在 BoxLayout 级别上设置的任何对齐方式都没有任何效果。胶水不是这样:如果其他孩子/人在该维度上具有最大尺寸(具有 FlowLayout 的面板没有,仅仅是因为它就是那么简单的 LayoutManager,它只会占用 all 多余的空间没有最大值的概念,只有 LayoutManager2 类型的管理器有)

    是时候退后一步并审查最初的要求了:

    垂直列出的多个文本区域,其宽度不 超过 JScrollPane 的高度,并达到他们需要的高度

    零阶解是

    • 根据需要配置 textArea
    • 丢弃所有布局嵌套(在滚动窗格内)

    在代码中:

    JComponent overview = new JPanel(new BorderLayout());
    overview.add(new JLabel("All polls for state XY"), BorderLayout.NORTH);
    
    JComponent pollPanel = new JPanel(); 
    pollPanel.setLayout(new BoxLayout(pollPanel, BoxLayout.PAGE_AXIS));
    for (int i = 0; i < 10; i++) {
        pollPanel.add(generatePollTextArea(i)); //Put the box into the pollPanel.
    }
    pollPanel.add(Box.createVerticalGlue());
    JScrollPane pollViewer = new JScrollPane(pollPanel);
    overview.add(pollViewer);
    showInFrame(overview, "layout text only");
    
    protected JComponent generatePollTextArea(int i) {
        String agency = "agency ";
        // simulates different size text
        for (int j = 0; j < i; j++) {
            agency += i;
        }
        String text = "Conducted by " + agency + 
                " on day " + "today" + " for " + 20 + 
                " days, " + 99 +
                "% voted Democrat, and " + 0.2 +
                "% voted Republican.";
        JTextArea pollInfo = new JTextArea(text); 
        // give it some reasonable initial width
        // in terms of content
        pollInfo.setColumns(20);
        pollInfo.setLineWrap(true);
        pollInfo.setWrapStyleWord(true);
        pollInfo.setEditable(false); //We don't want the user editing this.
        return pollInfo;
    }
    

    “Das Wort zum Dienstag”:嵌套布局并不是一种避免学习嵌套布局的各个级别上使用的 LayoutManager 特征的方法。

    【讨论】:

    • +1 表示Das Wort zum Dienstag,那么每天都是THU
    • 感谢您的精彩回答。恐怕我是从互联网上的某个论坛上养成了嵌套布局的习惯,因为我无法让标签正确居中。似乎不是“最佳”解决方案。我想将您的答案标记为“该”答案,尽管从 MadProgrammer 拿走答案状态我会觉得有点不好......
    • @TGP1994 没问题,他会活下来的投票让未来的读者看到不同的方面:-)
    猜你喜欢
    • 2016-10-01
    • 2021-09-22
    • 1970-01-01
    • 2014-01-13
    • 2015-11-22
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 2018-08-02
    相关资源
    最近更新 更多