user1725940
user1725940

Reputation: 93

JScrollPane Column Header with Frozen, and Scrollable Components

I have a JScrollPane with a column header consisting of multiple components. One of the components needs to be statically positioned, while the other components need to scroll like normal.

The only thing I could think to do was add a listener to the scrollbar which sets the location of the frozen component like this:

frozenHeader.setLocation(scrollViewport.getVisibleRect().getLocation()).  

However, the location won't actually update until the scrollbar is no long scrolling, so it looks rather unappealing. And yes, I've tried calling revalidate() followed by repaint() on both the frozenHeader, and its parent.

Here is an example to reproduce what I'm talking about:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

/**
 *
 * @author brian
 */
public class TestScroll extends JFrame {
    private JScrollPane scrollPane;
    private JPanel viewport;
    private JPanel colHeader;

    // This should be frozen
    private JPanel frozenHeader;
    // This should scroll
    private JPanel scrollHeader;

    public TestScroll() {
        this.setSize(new Dimension(500, 400));
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Set up the scroll pane
        scrollPane = new JScrollPane();
        viewport = new JPanel();
        viewport.setPreferredSize(new Dimension(1000, 400));
        scrollPane.setViewportView(viewport);

        // Set up the scroll panes column header
        colHeader = new JPanel(new GridBagLayout());
        frozenHeader = new JPanel();
        // Width is equal to the frame's width, as it should stay in the same location
        frozenHeader.setPreferredSize(new Dimension(500, 30));
        frozenHeader.setBackground(Color.RED);

        scrollHeader = new JPanel();
        // Width equal to viewportview's as it should scroll
        scrollHeader.setPreferredSize(new Dimension(1000, 30));
        scrollHeader.setBackground(Color.BLUE);
        JLabel label = new JLabel("Text");
        scrollHeader.add(label);

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.WEST;
        c.gridx = 0;
        c.gridy = 0;
        colHeader.add(frozenHeader, c);
        c.gridy = 1;
        colHeader.add(scrollHeader, c);
        scrollPane.setColumnHeaderView(colHeader);

        add(scrollPane);
    }

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

I want the frozenHeader (Red Panel) to always be centered in the screen instead of scrolling off the screen, and the scrollHeader (Blue Panel) to continue to scroll as it does in the example.

To add a little more context, the reason I am not simply putting the scrollHeader in the viewport, or moving frozenHeader out of the column header and simply placing it above the JScrollPane is because the JScrollPane in my actual application has an upper left corner panel which is the same height as the column header. Due to the nature of what the application does, I need to utilize all of the screen space.

Any advice on how this could be accomplished would be greatly appreciated!

Upvotes: 1

Views: 2789

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209122

"I want the Red Panel to always be centered in the screen, instead of scrolling off the screen."

The problem is that you're setting the columnHeaderView. This could easily be accomplished but just setting the add the colHeader panel as independent entity, and not setting the columnHeaderView

    colHeader = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
    colHeader.add(frozenHeader);
    JPanel panelForScrollPaneAndScrollHeader = new JPanel(new BorderLayout());
    panelForScrollPaneAndScrollHeader.add(scrollHeader, BorderLayout.NORTH);
    panelForScrollPaneAndScrollHeader.add(scrollPane, BorderLayout.CENTER);

    add(colHeader, BorderLayout.NORTH);
    add(panelForScrollPaneAndScrollHeader, BorderLayout.CENTER);

Here is the result when doing this

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class TestScroll1 extends JFrame{
    private JScrollPane scrollPane;
    private JPanel viewport;
    private JPanel colHeader;
    private JPanel frozenHeader;
    private JPanel scrollHeader;

    public TestScroll1() {
        frozenHeader = new JPanel();
        frozenHeader.setPreferredSize(new Dimension(500, 30));
        frozenHeader.setBackground(Color.RED);

        scrollHeader = new JPanel();
        scrollHeader.setPreferredSize(new Dimension(1000, 30));
        scrollHeader.setBackground(Color.BLUE);

        scrollPane = new JScrollPane();
        viewport = new JPanel();
        viewport.setPreferredSize(new Dimension(1000, 400));
        scrollPane.setViewportView(viewport);


        colHeader = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
        colHeader.add(frozenHeader);
        JPanel panelForScrollPaneAndScrollHeader = new JPanel(new BorderLayout());
        panelForScrollPaneAndScrollHeader.add(scrollHeader, BorderLayout.NORTH);
        panelForScrollPaneAndScrollHeader.add(scrollPane, BorderLayout.CENTER);
        add(colHeader, BorderLayout.NORTH);
        add(panelForScrollPaneAndScrollHeader, BorderLayout.CENTER);


        setSize(new Dimension(500, 400));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestScroll1().setVisible(true);
            }
        });
    }
}

Upvotes: 1

Related Questions