2012-04-26 83 views
8

Tôi gặp sự cố nhỏ khi sử dụng JScrollPane trong ứng dụng Java của mình.Thay đổi kích cỡ JScrollPane chứa JPanel khi thanh cuộn xuất hiện

Tôi có một số JScrollPane có chứa JPanel. JPanel này được cập nhật động bằng các nút (theo thứ tự theo chiều dọc) có thể có chiều rộng bất kỳ. Các JPanel tự động điều chỉnh chiều rộng của nó thành lớn nhất JButton thành phần bên trong.

Bây giờ khi thanh cuộn dọc xuất hiện, nó sẽ lấy một số khoảng trống ở bên phải của JPanel, làm cho các nút lớn nhất không xuất hiện hoàn toàn. Tôi không muốn sử dụng thanh cuộn ngang ngoài việc hiển thị toàn bộ nút.

Có cách nào để thay đổi kích thước JPanel khi thanh cuộn xuất hiện, để thanh xuất hiện độc đáo bên cạnh các nút của tôi không? Hoặc có cách nào khác để thanh cuộn xuất hiện bên cạnh JPanel của tôi không?

Cảm ơn trước!

EDIT: Đây là bản trình diễn về sự cố của tôi. Khi bạn thay đổi kích thước cửa sổ thành chiều cao nhỏ hơn, một phần nhỏ của các nút ở bên phải sẽ được che phủ.

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(); 
       } 
      } 
     }); 
    } 
} 
+1

bạn có thể cung cấp SSCCE? – StanislavL

+0

Đó là một phần của một dự án lớn. Tôi sẽ cố gắng cung cấp một bản trình diễn ngắn gọn về vấn đề này. – dylan202

+1

@StanislavL cho người dùng mới, tôi cho rằng tốt hơn nên liên kết những gì [SSCCE] (http://sscce.org/) là! :) – COD3BOY

Trả lời

6

Đây là một đơn giản, không đẹp, giải pháp:

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 

EDIT: Tôi nghĩ rằng có thể không thực hiện công việc trong trường hợp của bạn. Đây là một giải pháp tốt hơn mặc dù nó có khá nhiều soạn sẵn:

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); 
    } 
} 

Nó thực hiện cuộn để có được kiểm soát toàn bộ di chuyển, không một thủ thuật lạ mắt với theo dõi chiều cao khung nhìn để đảm bảo các nút mở rộng khi không gian có sẵn và thêm vào chiều rộng của thanh cuộn dọc đến chiều rộng được ưu tiên ở mọi thời điểm. Nó có thể mở rộng khi thanh cuộn dọc có thể nhìn thấy nhưng có vẻ xấu. Sử dụng nó như thế này:

scrollPane = new JScrollPane(new ButtonContainerHost(buttonContainer)); 

Có vẻ với tôi như workaround này là cần thiết vì một lỗi có thể trong javax.swing.ScrollPaneLayout:

if (canScroll && (viewSize.height > extentSize.height)) { 
    prefWidth += vsb.getPreferredSize().width; 
} 

Đây extentSize được thiết lập để kích thước ưa thích của viewport và viewSize được đặt thành viewport.getViewSize(). Điều này có vẻ không đúng, AFAIK kích thước của chế độ xem trong chế độ xem phải luôn bằng kích thước ưa thích. Dường như với tôi rằng kích thước khung nhìn nên được so sánh với kích thước thực tế của chế độ xem thay vì kích thước ưa thích của nó.

+0

Tôi chỉ muốn hiển thị thanh cuộn khi cần:/ – dylan202

+0

Cảm ơn bạn vì giải pháp này khá. Nó hoạt động hoàn hảo như tôi muốn. – dylan202

0

Bạn có thể thay đổi kích thước JPanel bằng cách gọi setPreferredSize khi JPanel cần được thay đổi kích thước.

buttonContainer.setPreferredSize(Dimension d); 
2

Một cách giải quyết đơn giản để đáp ứng nhu cầu của bạn về

Is there a way to resize my JPanel when a scrollbar appears, so it 
appears nicely next to my buttons? 

là việc sử dụng EmptyBorder, điều này sẽ cho phép bạn đạt được những gì bạn cảm thấy như thế nào, nên xảy ra, như thể hiện trong hình dưới đây:

SCROLLBAR SETTING

Tôi vừa thêm dòng này được viết bên dưới sau dòng này JPanel buttonContainer = new JPanel();

TĂNG ĐƯỜNG DÂY

buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); 

Dưới đây là mã của bạn với dòng thêm:

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(); 
       } 
      } 
     }); 
    } 
} 
Các vấn đề liên quan