我只是不明白为什么在调用validate()和repaint()方法时要调整大小。我正在努力理解这一点。本质上,我的程序应该这样显示。我有一个主框架,可以将要扩展的各种JPanels插入其中,以实现相册的各种功能。下面的类是NewAlbum类,该类应允许用户选择文件并从中创建新专辑。

选择文件的代码效果很好。一旦选择了文件,对NewAlbum面板所做的更改应该是将“选择文件”按钮替换为“完成”按钮。在“完成”按钮下面是一个JSplitPane,水平分离器刚好偏离中心,右侧比左侧大。随着有关照片的元数据输入到右侧,最终将在左侧留下每张照片的缩略图。

右侧窗格将是带有单个JPanel的JScrollPane,该JPanel以网格形式具有向用户询问有关其数据的4个条目。添加完所有内容后,尺寸就是我想要的位置,但是当我调用validate / repaint组合时,尺寸就会变得“混乱”。我很确定这是因为我不了解我正在使用或扩展的各个类的默认布局管理器。请帮助我理解。另外,请告诉我GridBagLayout是我想要的,还是我正在寻找其他的东西。

NewAlbum代码如下。


对于无法编译的代码,我深表歉意。我认为您可以看一下课然后告诉我,“哦,是的,这就是问题所在。”下面是可编译的,并演示了该问题。一旦选择了文件,拆分窗格窗口将变得太薄且太长。我希望它适合框架。实际上,它应该适合JFrame内部的JPanel。


谢谢,
安迪

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

class Main extends JFrame {
   static JPanel transientPanel = null;

   public Main() {
      super();
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setSize(640, 480);
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Example");
      JMenuItem albumMenu = new JMenuItem("New Album");
      albumMenu.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            transientPanel = new NewAlbum();
            add(transientPanel);
            validate();
            repaint();
         }
      });
      menu.add(albumMenu);
      menuBar.add(menu);

      setJMenuBar(menuBar);
      validate();
   }

   public static void main(String[] args) {
      final Main m = new Main();
      m.setVisible(true);
   }
}
/**
 * @description NewAlbum is the window that is presented to the user
 * to select new photographs for the album.  Once selected, the user
 * will be presented a form, of sorts, to complete the metadata for this
 * album.
 * @author Andy
 */
class NewAlbum extends JPanel {
    JButton selectFiles;
    JButton done;
    JButton nextButton = new JButton("Next Image");

    ArrayList<File> filesArray;

    JSplitPane splitWindow = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
    JScrollPane scrollWindow;
    JPanel rightSidePanel = new JPanel();
    JPanel leftSidePanel = new JPanel();

    JLabel subjectLabel = new JLabel("Image subject:");
    JLabel locationLabel = new JLabel("Image location:");
    JLabel commentLabel = new JLabel("Comments:");
    JLabel dateLabel = new JLabel("Date (mm/dd/yyyy):");

    JTextField subjectText = new JTextField(25);
    JTextField locationText = new JTextField(25);
    JTextArea commentText = new JTextArea(4, 25);
    JTextField dateText = new JTextField(10);

    public NewAlbum() {
        super();

        selectFiles = new JButton("Select Photos");

        selectFiles.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                selectFilesForAlbum();
            }
        });
        add(selectFiles);
    }

    private void configureRightPanel() {
        int jPanelX = getParent().getWidth();
        int jPanelY = getParent().getHeight() - 30; // this should account for buttons

        // now, resize this panel so that it will be the right size for the split pane
        jPanelX = jPanelX - (int)(jPanelX * .31);
        rightSidePanel.setSize(jPanelX, jPanelY);

        rightSidePanel.add(subjectLabel);
        rightSidePanel.add(subjectText);
        rightSidePanel.add(locationLabel);
        rightSidePanel.add(locationText);
        rightSidePanel.add(commentLabel);
        rightSidePanel.add(commentText);
        rightSidePanel.add(dateLabel);
        rightSidePanel.add(dateText);
        rightSidePanel.add(nextButton);

        // iterate over the photos selected, make bogus info for now
    }

    private ArrayList<File> makeFileIntoArrayList(File[] f) {
        ArrayList<File> a = new ArrayList<File>();
        a.addAll(Arrays.asList(f));

        return filesArray = a;
    }

    /**
     * selectFilesForAlbum
     * This method is private to the NewAlbum class.  It is the handler for
     * when the user clicks on the "select photos" button.  When the function
     * executes, it displays the JFileChooser so that the user may select
     * the desired photos.  The files selected are assigned to a class variable
     * of type File[] which is used by the enterPhotoInfo method.
     *
     * @return void
     */
    private void selectFilesForAlbum() {
        JFileChooser jfc = new JFileChooser();
        jfc.setMultiSelectionEnabled(true);
        jfc.showOpenDialog(this);
        makeFileIntoArrayList(jfc.getSelectedFiles());

        changeButtonToDone();
        enterPhotoInfo();

        // TODO write the photo album to the disk
    }

    private void changeButtonToDone() {
        remove(selectFiles);
        done = new JButton("Done");
        add(done);

        // by the time this gets called, we'll have a parent container
        getParent().validate();
        getParent().repaint();
    }

    private void enterPhotoInfo() {
        splitWindow.setSize(this.getWidth(), this.getHeight() - 30);

        // remove when the left side panel actually has something
        Dimension iewDims = splitWindow.getSize();
        int leftX = iewDims.width - (int)(iewDims.width * .69);
        int leftY = iewDims.height;

        leftSidePanel.setSize(leftX, leftY);

        configureRightPanel();

        scrollWindow = new JScrollPane(rightSidePanel);
        scrollWindow.setSize(rightSidePanel.getSize());

        splitWindow.setRightComponent(scrollWindow);
        splitWindow.setLeftComponent(leftSidePanel);
        splitWindow.setDividerLocation(.31);

        System.out.println("Printing dimensions of before validate/repaint: this, splitWindow, scrollWindow, LSP, RSP");
        debugPrintDimensions(this);
        debugPrintDimensions(splitWindow);
        debugPrintDimensions(scrollWindow);
        debugPrintDimensions(leftSidePanel);
        debugPrintDimensions(rightSidePanel);

        //infoEntryWindow.add(infoScroller);
        this.add(splitWindow);
        this.validate();
        this.repaint();

        System.out.println("Printing dimensions of: this, splitWindow, scrollWindow, LSP, RSP");
        debugPrintDimensions(this);
        debugPrintDimensions(splitWindow);
        debugPrintDimensions(scrollWindow);
        debugPrintDimensions(leftSidePanel);
        debugPrintDimensions(rightSidePanel);
    }

    private void debugPrintDimensions(Container c) {
        System.out.println("DEBUG: Containers (x,y): (" +
                String.valueOf(c.getWidth()) +
                "," +
                String.valueOf(c.getHeight()) +
                ")");
    }
}

最佳答案

另外,请告诉我GridBagLayout是我想要的,还是我正在寻找其他的东西。


您为作业使用适当的布局管理器。这也可能意味着在不同的面板上使用不同的布局管理器。

splitWindow.setSize(this.getWidth(), this.getHeight() - 30);


您永远不要使用setSize()。这是布局管理器的工作,用于根据布局管理器的规则确定组件的大小。

所有组件均具有首选大小,布局管理器将使用该首选大小。有时您可以使用setPreferredSize()更改默认值。

10-05 21:15