这是我的目标:制作一个带有按钮的工具栏,一旦窗口缩小得足够远,这些按钮就会“流动”向下。如有必要,它不应该羞于推动下面的兄弟姐妹
我该怎么做?
这是一个演示。我解决了之前关于使用外部库的问题的一些批评,因此这里没有使用任何外部库
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Objects;
public class FlowToolbarDemo {
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame("Flow Toolbar Demo");
JPanel labelPanel = new JPanel(new BorderLayout());
JLabel label = new JLabel("Click to see action");
label.setOpaque(true);
label.setBackground(new Color(255, 255, 204));
labelPanel.add(label, BorderLayout.CENTER);
JToolBar toolbar = new JToolBar();
LayoutManager toolbarLayout = new FlowLayout();
toolbar.setLayout(toolbarLayout);
JButton heartButton = getHeartButton(e -> label.setText("Heart action performed..."));
JButton starButton = getStarButton(e -> label.setText("Star action performed..."));
toolbar.add(heartButton);
toolbar.add(starButton);
LayoutManager headerPanelLayout = new BorderLayout();
JPanel headerPanel = new JPanel(headerPanelLayout);
headerPanel.add(labelPanel, BorderLayout.NORTH);
headerPanel.add(toolbar, BorderLayout.CENTER);
JPanel businessPanel = getBusinessPanel();
LayoutManager mainPanelLayout = new BorderLayout();
JPanel mainPanel = new JPanel(mainPanelLayout);
mainPanel.add(headerPanel, BorderLayout.NORTH);
mainPanel.add(businessPanel, BorderLayout.CENTER);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
System.out.println();
}
private static JPanel getBusinessPanel() {
LayoutManager businessPanelLayout = new BorderLayout();
JPanel businessPanel = new JPanel(businessPanelLayout);
JTable tableOne = getTableOne();
JScrollPane scrollPaneOne = new JScrollPane(tableOne);
scrollPaneOne.setOpaque(true);
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Business Table One", scrollPaneOne);
JTable tableTwo = getTableTwo();
JScrollPane scrollPaneTwo = new JScrollPane(tableTwo);
scrollPaneTwo.setOpaque(true);
tabbedPane.addTab("Business Table Two", scrollPaneTwo);
businessPanel.add(tabbedPane);
return businessPanel;
}
private static JTable getTableOne() {
Object[][] data = {
{"John Doe", 30, "Male"},
{"Jane Smith", 25, "Female"},
{"Alice Johnson", 35, "Female"}
};
String[] columns = {"Name", "Age", "Gender"};
DefaultTableModel model = new DefaultTableModel(data, columns);
return new JTable(model);
}
private static JTable getTableTwo() {
Object[][] data = {
{"Apple", 30, true},
{"Orange", 25, true},
{"Ackee fruit", 35, false}
};
String[] columns = {"Fruit", "Quantity", "Is Edible"};
DefaultTableModel model = new DefaultTableModel(data, columns);
return new JTable(model);
}
private static JButton getHeartButton(ActionListener heartAction) throws IOException {
return getButton("Do Heart action", "heart.png", heartAction);
}
private static JButton getStarButton(ActionListener starAction) throws IOException {
return getButton("Do Star action", "star.png", starAction);
}
private static JButton getButton(String buttonText, String resourceName, ActionListener actionListener) throws IOException {
URL imageLocation = FlowToolbarDemo.class.getResource(resourceName);
BufferedImage image = ImageIO.read(Objects.requireNonNull(imageLocation, "Requested resource not found"));
Image scaledImage = image.getScaledInstance(20, 20, Image.SCALE_SMOOTH);
ImageIcon icon = new ImageIcon(scaledImage);
JButton button = new JButton(buttonText, icon);
button.addActionListener(actionListener);
button.setFocusPainted(false);
return button;
}
}
heart.png
star.png
按钮确实流动,但它们流动在北组件分配的区域下方,并且几乎不可见。另一方面,
JTabbedPane
窗格标题则流畅。我将其部分包含在内是为了展示我试图通过工具栏按钮实现什么类型的“流动”
选择 BorderLayout
作为主面板,因为它以尊重其北部组件(在本例中为标题面板)的首选高度而闻名。然而,正如我在 IntelliJ 调试器中发现的那样,即使在按钮堆叠之后,标题面板的首选高度也不会改变。这是因为工具栏的首选高度没有改变。如果是的话,我们会得到这样的东西
从技术上来说,用像这样的丑陋的拼凑物是可以实现的
toolbar.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Component firstButton = toolbar.getComponent(0);
double firstButtonY = firstButton.getLocation().getY();
Component secondButton = toolbar.getComponent(1);
double secondButtonY = secondButton.getLocation().getY();
if (firstButtonY < secondButtonY) {
int newHeight = (int) ((firstButton.getHeight() + secondButton.getHeight()) * 1.25);
toolbar.setPreferredSize(new Dimension(toolbar.getPreferredSize().width, newHeight));
} else if (firstButtonY == firstButtonY) {
int oldHeight = (int) (firstButton.getHeight() * 1.25);
toolbar.setPreferredSize(new Dimension(toolbar.getPreferredSize().width, oldHeight));
}
}
});
但显然我不愿意推动它
即使通过用
vGap
访问器替换硬编码乘数来稍微改进它
toolbar.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
FlowLayout flowLayout = (FlowLayout) toolbar.getLayout();
JButton firstButton = (JButton) toolbar.getComponent(0);
JButton secondButton = (JButton) toolbar.getComponent(1);
double firstButtonY = firstButton.getLocation().getY();
double secondButtonY = secondButton.getLocation().getY();
if (firstButtonY < secondButtonY) {
int newHeight = firstButton.getHeight() + secondButton.getHeight() + flowLayout.getVgap() * 3;
toolbar.setPreferredSize(new Dimension(toolbar.getPreferredSize().width, newHeight));
} else if (firstButtonY == firstButtonY) {
int oldHeight = firstButton.getHeight() + flowLayout.getVgap() * 2;
toolbar.setPreferredSize(new Dimension(toolbar.getPreferredSize().width, oldHeight));
}
}
});
仍然存在不支持两个以上按钮的问题。同样,我可以编写一些循环,但对于可能可用的 OOB 来说,它变得太复杂了
下面的变体在
上添加了具有
JToolBar
的
FlowLayout
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FlowToolbarDemo {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame("Flow Toolbar Demo");
JPanel labelPanel = new JPanel(new BorderLayout());
JLabel label = new JLabel("Click to see action");
label.setOpaque(true);
label.setBackground(new Color(255, 255, 204));
labelPanel.add(label, BorderLayout.CENTER);
JToolBar toolbar = new JToolBar();
toolbar.setLayout(new FlowLayout());
JButton heartButton = getHeartButton(e -> label.setText("Heart action performed…"));
JButton starButton = getStarButton(e -> label.setText("Star action performed…"));
toolbar.add(heartButton);
toolbar.add(starButton);
LayoutManager headerPanelLayout = new BorderLayout();
JPanel headerPanel = new JPanel(headerPanelLayout);
headerPanel.add(labelPanel, BorderLayout.NORTH);
headerPanel.add(toolbar, BorderLayout.CENTER);
JPanel businessPanel = getBusinessPanel();
LayoutManager mainPanelLayout = new BorderLayout();
JPanel mainPanel = new JPanel(mainPanelLayout);
mainPanel.add(headerPanel, BorderLayout.CENTER);
mainPanel.add(businessPanel, BorderLayout.SOUTH);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
System.out.println(frame.getWidth() +" " + frame.getHeight());
frame.setSize(240, 240);
frame.setVisible(true);
});
}
private static JPanel getBusinessPanel() {
JPanel businessPanel = new JPanel(new BorderLayout()) {
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 100);
}
};
JTable tableOne = getTableOne();
JScrollPane scrollPaneOne = new JScrollPane(tableOne);
scrollPaneOne.setOpaque(true);
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Business Table One", scrollPaneOne);
JTable tableTwo = getTableTwo();
JScrollPane scrollPaneTwo = new JScrollPane(tableTwo);
scrollPaneTwo.setOpaque(true);
tabbedPane.addTab("Business Table Two", scrollPaneTwo);
businessPanel.add(tabbedPane);
return businessPanel;
}
private static JTable getTableOne() {
Object[][] data = {
{"John Doe", 30, "Male"},
{"Jane Smith", 25, "Female"},
{"Alice Johnson", 35, "Female"}
};
String[] columns = {"Name", "Age", "Gender"};
DefaultTableModel model = new DefaultTableModel(data, columns);
return new JTable(model);
}
private static JTable getTableTwo() {
Object[][] data = {
{"Apple", 30, true},
{"Orange", 25, true},
{"Ackee fruit", 35, false}
};
String[] columns = {"Fruit", "Quantity", "Is Edible"};
DefaultTableModel model = new DefaultTableModel(data, columns);
return new JTable(model);
}
private static JButton getHeartButton(ActionListener heartAction) {
return getButton("Do Heart action", "https://i.sstatic.net/CnC7LVrk.png", heartAction);
}
private static JButton getStarButton(ActionListener starAction) {
return getButton("Do Star action", "https://i.sstatic.net/BHdIKRxz.png", starAction);
}
private static JButton getButton(String buttonText, String resourceName, ActionListener actionListener) {
JButton button = new JButton(buttonText);
button.addActionListener(actionListener);
button.setFocusPainted(false);
try {
URL imageLocation = new URI(resourceName).toURL();
BufferedImage image = ImageIO.read(Objects.requireNonNull(imageLocation, "Requested resource not found"));
Image scaledImage = image.getScaledInstance(32, 32, Image.SCALE_SMOOTH);
ImageIcon icon = new ImageIcon(scaledImage);
button.setIcon(icon);
} catch (URISyntaxException | IOException ex) {
Logger.getLogger(FlowToolbarDemo.class.getName()).log(Level.SEVERE, null, ex);
}
return button;
}
}
```[![enter image description here][1]][1]
[1]: https://i.sstatic.net/kEv4XCGb.png