JProgressbar宽度使用Grid/FlowLayout

5
我正在制作一个下载器,目前它的界面如下所示: Screenshot JFrame使用了BorderLayout布局。在NORTH区域,我有一个JPanel(FlowLayout)。在SOUTH区域,也有一个JPanel(FlowLayout)。在WEST区域,我只有一个带有滚动条的JTextArea。这些都显示正确。但是,在EAST区域,我目前有一个JPanel(GridLayout(10,1))。
我想在EAST区域显示最多10个JProgressBar,并且可以动态地添加和删除。问题是,我无法使它们看起来像我想要的:我希望JProgressBars的宽度填满整个EAST区域,因为1)这会使应用程序更对称,2)进度条可能包含当前不适合的长字符串。我尝试将包含GridLayout(10,1)的JPanel放入FlowLayout中,然后将该FlowLayout放入EAST区域,但这也没有起作用。
我的代码(SSCCE)如下:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

public class Main {

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

    private static class DownloadFrame extends JFrame {

        private JButton downloadButton;
        private JTextField threadIdTextField;
        private JTextArea downloadStatusTextArea;
        private JScrollPane scrollPane;
        private JTextField downloadLocationTextField;
        private JButton downloadLocationButton;

        private JPanel North;
        private JPanel South;
        private JPanel ProgressBarPanel;

        private Map<String, JProgressBar> progressBarMap;

        public DownloadFrame() {
            InitComponents();
            InitLayout();
            AddComponents();
            AddActionListeners();

            setVisible(true);
            setSize(700, 300);
        }

        private void InitComponents() {
            downloadButton = new JButton("Dowload");
            threadIdTextField = new JTextField(6);
            downloadStatusTextArea = new JTextArea(10, 30);
            scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            downloadLocationTextField = new JTextField(40);
            downloadLocationButton = new JButton("...");
            North = new JPanel();
            South = new JPanel();
            ProgressBarPanel = new JPanel();
            progressBarMap = new HashMap<String, JProgressBar>();
        }

        private void InitLayout() {
            North.setLayout(new FlowLayout());
            South.setLayout(new FlowLayout());
            ProgressBarPanel.setLayout(new GridLayout(10, 1));
        }

        private void AddComponents() {
            North.add(threadIdTextField);
            North.add(downloadButton);
            add(North, BorderLayout.NORTH);

            add(ProgressBarPanel, BorderLayout.EAST);

            South.add(downloadLocationTextField);
            South.add(downloadLocationButton);
            add(South, BorderLayout.SOUTH);

            add(scrollPane, BorderLayout.WEST);
        }

        private void AddActionListeners() {
            downloadButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    addNewProgessBar(threadIdTextField.getText());
                }
            });
        }

        public void addNewProgessBar(String threadId) {
            JProgressBar progressBar = new JProgressBar();
            progressBar.setStringPainted(true);
            progressBarMap.put(threadId, progressBar);
            drawProgessBars();
        }

        void drawProgessBars() {
            ProgressBarPanel.removeAll();
            for (JProgressBar progressBar : progressBarMap.values()) {
                ProgressBarPanel.add(progressBar);
            }
            validate();
            repaint();
        }

    }
}

Thanks in advance.

EDIT

Easiest solution: change

add(ProgressBarPanel, BorderLayout.EAST);

为了

add(ProgressBarPanel, BorderLayout.CENTER);
3个回答

7

Screenshot of GUI

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

public class Main {

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

    private static class DownloadFrame extends JFrame {

        private JButton downloadButton;
        private JTextField threadIdTextField;
        private JTextArea downloadStatusTextArea;
        private JScrollPane scrollPane;
        private JTextField downloadLocationTextField;
        private JButton downloadLocationButton;

        private JPanel North;
        private JPanel South;
        private JPanel ProgressBarPanel;

        private Map<String, JProgressBar> progressBarMap;

        public DownloadFrame() {
            InitComponents();
            AddComponents();
            AddActionListeners();

            pack();
            setVisible(true);
            //setSize(700, 300);
        }

        private void InitComponents() {
            setLayout(new BorderLayout());
            downloadButton = new JButton("Dowload");
            threadIdTextField = new JTextField(6);
            downloadStatusTextArea = new JTextArea(10, 30);
            scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            downloadLocationTextField = new JTextField(40);
            downloadLocationButton = new JButton("...");
            North = new JPanel(new FlowLayout());
            South = new JPanel(new FlowLayout());
            ProgressBarPanel = new JPanel(new GridLayout(0, 1));
            ProgressBarPanel.setBorder(new LineBorder(Color.black));
            ProgressBarPanel.setPreferredSize(new Dimension(300,20));
            progressBarMap = new HashMap<String, JProgressBar>();
        }

        private void AddComponents() {
            North.add(threadIdTextField);
            North.add(downloadButton);
            add(North, BorderLayout.NORTH);

            add(ProgressBarPanel, BorderLayout.EAST);

            South.add(downloadLocationTextField);
            South.add(downloadLocationButton);
            add(South, BorderLayout.SOUTH);

            add(scrollPane, BorderLayout.WEST);
        }

        private void AddActionListeners() {
            downloadButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    addNewProgessBar(threadIdTextField.getText());
                }
            });
        }

        public void addNewProgessBar(String threadId) {
            JProgressBar progressBar = new JProgressBar();
            progressBar.setStringPainted(true);
            progressBarMap.put(threadId, progressBar);
            drawProgessBars();
        }

        void drawProgessBars() {
            ProgressBarPanel.removeAll();
            for (JProgressBar progressBar : progressBarMap.values()) {
                ProgressBarPanel.add(progressBar);
            }
            validate();
            repaint();
        }

    }
}

请使用常见的属性和方法命名法。这将是camelCase,而不是EachWordUpperCase - Andrew Thompson
谢谢您的快速回答。但是我刚刚(经过几个小时的搜索,很典型)找到了解决问题的最简单方法。将ProgressBarPanel添加到CENTER而不是EAST可以得到我想要的结果。感觉自己很傻,没有尝试过那个方法关于命名约定,您说得对。我会考虑这一点的。 - Matthias

3
请提供一个可编译可运行的小程序,以获得最快最好的帮助,即SSCCE
建议使用GridLayout(0,1)(可变行数,一列),或在使用自定义渲染器扩展JProgressBar的JList中显示JProgressBars。 编辑1:
我知道Andrew已经发布了被接受的答案(并且得到了一个优秀答案的1+),但我只是想演示这可以很容易地通过JList完成,例如:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.Random;
import javax.swing.*;

public class EastProgressList extends JPanel {
   private DefaultListModel myListModel = new DefaultListModel();
   private JList myList = new JList(myListModel);
   private JTextField downloadUrlField = new JTextField(10);

   public EastProgressList() {
      JButton downLoadBtn = new JButton("Download");
      downLoadBtn.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            downloadAction();
         }
      });
      JPanel northPanel = new JPanel();
      northPanel.add(new JLabel("File to Download:"));
      northPanel.add(downloadUrlField);
      northPanel.add(Box.createHorizontalStrut(15));
      northPanel.add(downLoadBtn);

      myList.setCellRenderer(new ProgressBarCellRenderer());
      JScrollPane eastSPane = new JScrollPane(myList);
      eastSPane.setPreferredSize(new Dimension(200, 100));

      setLayout(new BorderLayout());

      add(new JScrollPane(new JTextArea(20, 30)), BorderLayout.CENTER);
      add(northPanel, BorderLayout.NORTH);
      add(eastSPane, BorderLayout.EAST);
   }

   private void downloadAction() {
      String downloadUrl = downloadUrlField.getText();
      final MyData myData = new MyData(downloadUrl);
      myListModel.addElement(myData);
      myData.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(MyData.VALUE)) {
               myList.repaint();
               if (myData.getValue() >= 100) {
                  myListModel.removeElement(myData);
               }
            }
         }

      });
   }

   private class ProgressBarCellRenderer extends JProgressBar implements ListCellRenderer {
      protected ProgressBarCellRenderer() {
         setBorder(BorderFactory.createLineBorder(Color.blue));
      }

      public Component getListCellRendererComponent(JList list, Object value,
               int index, boolean isSelected, boolean cellHasFocus) {
         //setText(value.toString());
         MyData myData = (MyData)value;
         setValue(myData.getValue());
         setString(myData.getText());
         setStringPainted(true);
         return this;
      }
   }

   private static void createAndShowUI() {
      JFrame frame = new JFrame("EastProgressList");
      frame.getContentPane().add(new EastProgressList());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

class MyData {
   public static final int TIMER_DELAY = 300;
   public static final String VALUE = "value";
   protected static final int MAX_DELTA_VALUE = 5;
   private String text;
   private int value = 0;
   private Random random = new Random();
   private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this);

   public MyData(String text) {
      this.text = text;
      new Timer(TIMER_DELAY, new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            int deltaValue = random.nextInt(MAX_DELTA_VALUE);
            int newValue = value + deltaValue;
            if (newValue >= 100) {
               newValue = 100;
               ((Timer)e.getSource()).stop();
            }
            setValue(newValue);
         }
      }).start();
   }

   public String getText() {
      return text;
   }

   public int getValue() {
      return value;
   }

   public void setValue(int value) {
      int oldValue = this.value;
      this.value = value;

      PropertyChangeEvent pcEvent = new PropertyChangeEvent(this, VALUE, oldValue, value);
      pcSupport.firePropertyChange(pcEvent);
   }

   public void addPropertyChangeListener(PropertyChangeListener pcListener) {
      pcSupport.addPropertyChangeListener(pcListener);
   }


}

这将导致GUI看起来像这样:
enter image description here

而(@Andrew Thompson)告诉我们这里没有太多乐趣+1。 - mKorbel

3
很好。这是可能的,但在您的示例中,CENTER 区域占用了一些 Rectangle,很难将 CENTER 区域缩小/移除到零 Size 在北方的 JPanel (使用 BorderLayout) 放置另一个 JPanel,并将其放置在东侧(使用 LayoutManagerGridLayout(1,2,10,10)),然后在此处放置两个 JComponents JTextField - threadIdTextFieldJButton - downloadButton,您需要为它们设置首选大小 1)对于 JComponents(正确的方法)或 2)对于整个 JPanel(也是可能的方法) JScrollPaneJTextArea 必须放置在 CENTER 区域 JPanel 中的 JProgressBars 放置在 EAST,但再次设置与来自 NORTHJTextFieldJButtonJPanel 相同的 PreferredSize SOUTH JPanel 保持不变

提到首选尺寸是个不错的注意点。尽管我选了“选项2”——可能的方式,而非“选项1”——正确的方式。“电池未包含在内...”;) - Andrew Thompson
@Andrew Thompson,那你一定希望Jeanette或Rob不在附近 :-) - mKorbel
@mKorbel:完全同意,特别是kleopatra/Jeanette(尽管我非常尊重她无与伦比的能力)! - Hovercraft Full Of Eels
@mKorbel 嘿先生,我不想惹麻烦。请不要告诉他们。;) - Andrew Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接