Jscrollpane изменение размера, содержащее JPanel при появлении полос прокрутки
у меня небольшая проблема при использовании JScrollPane
в моем приложении Java.
у меня есть JScrollPane
содержащий JPanel
.
Это JPanel
динамически обновляется с кнопками (вертикальными), которые могут быть любой ширины.
The JPanel
автоматически регулирует свою ширину до самой большой JButton
компонент внутри.
теперь, когда появляется вертикальная полоса прокрутки, она занимает некоторое пространство с правой стороны моего JPanel
, который вызывает наибольшее кнопки не появляются полностью. Я не хочу использовать горизонтальную полосу прокрутки в дополнение к отображению всей кнопки.
есть ли способ изменить размер моего JPanel
когда появляется полоса прокрутки, так что она появляется рядом с моими кнопками? Или есть ли другой способ, чтобы полоса прокрутки появилась рядом с моим JPanel
?
спасибо заранее!
редактировать: вот демонстрация моей проблемы. При изменении размера окна на меньшую высоту, небольшая часть кнопок справа сторона прикрывается.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.GridLayout;
/**
* @author Dylan Kiss
*/
public class Demo {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
JFrame myFrame = new JFrame("Demo");
JPanel sideBar = new JPanel();
JPanel centerPanel = new JPanel();
centerPanel.add(new JLabel("This is the center panel."));
JPanel buttonContainer = new JPanel();
JButton myButton = null;
for (int i = 0; i < 20; i++) {
buttonContainer.setLayout(new GridLayout(20, 1, 0, 0));
myButton = new JButton("This is my button nr. " + i);
buttonContainer.add(myButton);
}
sideBar.setLayout(new BorderLayout(0, 0));
JScrollPane scrollPane = new JScrollPane(buttonContainer);
sideBar.add(scrollPane);
myFrame.getContentPane().add(sideBar, BorderLayout.WEST);
myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER);
myFrame.setLocationByPlatform(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.pack();
myFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
3 ответов
вот простое, не очень, решение:
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
изменить: Я подумал, что в твоем случае это может не сработать. Вот лучшее решение, хотя оно имеет довольно много шаблонных:
private class ButtonContainerHost extends JPanel implements Scrollable {
private static final long serialVersionUID = 1L;
private final JPanel buttonContainer;
public ButtonContainerHost(JPanel buttonContainer) {
super(new BorderLayout());
this.buttonContainer = buttonContainer;
add(buttonContainer);
}
@Override
public Dimension getPreferredScrollableViewportSize() {
Dimension preferredSize = buttonContainer.getPreferredSize();
if (getParent() instanceof JViewport) {
preferredSize.width += ((JScrollPane) getParent().getParent()).getVerticalScrollBar()
.getPreferredSize().width;
}
return preferredSize;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width * 9 / 10, 1)
: Math.max(visibleRect.height * 9 / 10, 1);
}
@Override
public boolean getScrollableTracksViewportHeight() {
if (getParent() instanceof JViewport) {
JViewport viewport = (JViewport) getParent();
return getPreferredSize().height < viewport.getHeight();
}
return false;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width / 10, 1)
: Math.max(visibleRect.height / 10, 1);
}
}
он реализует прокрутку, чтобы получить полный контроль над прокруткой, делает причудливый трюк с отслеживанием высоты видового экрана, чтобы кнопки расширялись, когда пространство доступно, и добавляет ширину вертикальной полосы прокрутки к предпочтительной ширине во все времена. Это может расширяются, когда вертикальная полоса прокрутки, но это все равно выглядит плохо. Используйте его так:
scrollPane = new JScrollPane(new ButtonContainerHost(buttonContainer));
мне кажется, что это обходное решение требуется из-за возможной ошибки в javax.качать.ScrollPaneLayout:
if (canScroll && (viewSize.height > extentSize.height)) {
prefWidth += vsb.getPreferredSize().width;
}
здесь extentSize устанавливается в предпочтительный размер окна просмотра, а viewSize - в окно просмотра.getViewSize (). Это не кажется правильным, AFAIK размер представления внутри окна просмотра всегда должен равняться предпочтительному размеру. Мне кажется, что размер представления следует сравнивать с фактическим размером окна просмотра, а не с его предпочтительным размером.
простой обходной путь, чтобы удовлетворить ваши требования относительно
Is there a way to resize my JPanel when a scrollbar appears, so it
appears nicely next to my buttons?
использование EmptyBorder, это позволит вам достичь того, что вы чувствуете, должно произойти, как показано на рисунке ниже :
Я просто добавил эту строку, написанную ниже после этой строки JPanel buttonContainer = new JPanel();
ДОБАВЛЕНА СТРОКА
buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
вот ваш код с этой добавленной строкой:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.GridLayout;
/**
* @author Dylan Kiss
*/
public class Demo
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
JFrame myFrame = new JFrame("Demo");
JPanel sideBar = new JPanel();
JPanel centerPanel = new JPanel();
centerPanel.add(new JLabel("This is the center panel."));
JPanel buttonContainer = new JPanel();
buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JButton myButton = null;
for (int i = 0; i < 20; i++)
{
buttonContainer.setLayout(new GridLayout(20, 1, 0, 0));
myButton = new JButton("This is my button nr. " + i);
buttonContainer.add(myButton);
}
sideBar.setLayout(new BorderLayout(0, 0));
JScrollPane scrollPane = new JScrollPane(buttonContainer);
sideBar.add(scrollPane);
myFrame.getContentPane().add(sideBar, BorderLayout.WEST);
myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER);
myFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
myFrame.pack();
myFrame.setLocationByPlatform(true);
myFrame.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
}
вы можете изменить размер JPanel, вызвав setPreferredSize, когда JPanel должен быть изменен.
buttonContainer.setPreferredSize(Dimension d);