#java #swing #jsplitpane
#ява #swing #jsplitpane
Вопрос:
Я пишу инструмент, который выполняет задачу в текстовом файле. Выполнение задачи занимает некоторое время, поэтому я создал панель, которая отображает имя файла и прогресс в процентах. Пользователь может запустить задачу для одного или нескольких файлов, поэтому мне нужно отобразить панель для каждого файла.
Благодаря помощи, которую я получил здесь, у меня есть этот код, который отображает текстовую область и добавляет панели. Проблема в том, что текстовая область и список панелей растут друг за счет друга при добавлении новых элементов. Вы можете видеть, что это происходит при добавлении строк или нажатии на кнопку создать и добавлении панелей:
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.logging.Logger;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnNew;
JButton btnAbort;
JButton btnClose;
static int i;
JPanel taskPanel;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// should be done AFTER components are added
//pack();
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
taskPanel = new JPanel();
taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnNew = new JButton("New");
panel.add(btnNew);
btnNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addTask( i, "Task " i);
}
});
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea(10,0);
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane scrollPane = new JScrollPane(taskPanel);
getContentPane().add(scrollPane);
for(i = 0; i < 10; i ) {
addTask(i, "Task" i);
}
pack();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
taskPanel.add(newTaskPanel);
validate();
//repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
//setLayout(null);
lblTaskDescription = new JLabel(id " " fileName);
//lblTaskDescription.setPreferredSize(new Dimension(632, 14));
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " id "; File: " fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " e.getMessage());
}
}
}
}
Я хочу, чтобы каждый оставался в своей области и добавлял прокрутку, если это необходимо. Я попытался добавить JSplitPane в приведенный выше пример, но обе панели остаются пустыми.
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.SplitPaneUI;
import java.util.*;
import java.util.logging.Logger;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger
.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnNew;
JButton btnAbort;
JButton btnClose;
static int i;
JPanel taskPanel;
private JSplitPane splitPane;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// should be done AFTER components are added
// pack();
getContentPane().setLayout(
new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
taskPanel = new JPanel();
taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnNew = new JButton("New");
panel.add(btnNew);
btnNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addTask( i, "Task " i);
}
});
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea(10, 0);
txtLog.setLineWrap(true);
//getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane scrollPane = new JScrollPane(taskPanel);
//getContentPane().add(scrollPane);
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, txtLog, scrollPane);
splitPane.setDividerLocation(150);
for (i = 0; i < 10; i ) {
addTask(i, "Task" i);
}
pack();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
taskPanel.add(newTaskPanel);
validate();
// repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
// setLayout(null);
lblTaskDescription = new JLabel(id " " fileName);
// lblTaskDescription.setPreferredSize(new Dimension(632, 14));
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
// lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " id "; File: "
fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " e.getMessage());
}
}
}
}
Вот решение:
package layout.sscce;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.logging.Logger;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger
.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnNew;
JButton btnAbort;
JButton btnClose;
static int i;
JPanel taskPanel;
private JSplitPane splitPane;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// should be done AFTER components are added
// pack();
// getContentPane().setLayout(
// new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
getContentPane().setLayout(
new BorderLayout());
taskPanel = new JPanel();
taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS));
JPanel buttonPanel = new JPanel();
getContentPane().add(buttonPanel);
btnNew = new JButton("New");
buttonPanel.add(btnNew);
btnNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addTask( i, "Task " i);
}
});
btnAbort = new JButton("Abort");
buttonPanel.add(btnAbort);
btnClose = new JButton("Close");
buttonPanel.add(btnClose);
txtLog = new JTextArea(10, 30);
txtLog.setLineWrap(true);
//getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane taskScrollPane = new JScrollPane(taskPanel);
JScrollPane textScrollPane = new JScrollPane(txtLog);
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, textScrollPane, taskScrollPane);
splitPane.setDividerLocation(150);
for (i = 0; i < 10; i ) {
addTask(i, "Task" i);
}
getContentPane().add(buttonPanel, BorderLayout.NORTH);
getContentPane().add(splitPane, BorderLayout.CENTER);
pack();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
taskPanel.add(newTaskPanel);
validate();
// repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
// setLayout(null);
lblTaskDescription = new JLabel(id " " fileName);
// lblTaskDescription.setPreferredSize(new Dimension(632, 14));
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
// lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " id "; File: "
fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " e.getMessage());
}
}
}
}
Ответ №1:
Проблема в BoxLayout. Он делает странные вещи, когда пытается распределить пространство между компонентами. Возможно, BorderLayout было бы лучше. Добавьте кнопки к СЕВЕРУ, а область прокрутки — к ЦЕНТРУ.
Или, используя свой код, вы можете сделать следующее:
txtLog = new JTextArea(10, 30); // changed
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane scrollPane = new JScrollPane(taskPanel);
scrollPane.setPreferredSize( txtLog.getPreferredSize() ); // added
Комментарии:
1. Спасибо. Я сделал одно небольшое дополнение. Текстовая область также помещается внутри области прокрутки.