Reputation: 93
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
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
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