Background
Looking to add a scroll-lock button to the corner of JScrollPane without obscuring the view port contents. The following image shows a JScrollPane wrapped in a SwingNode within a JavaFX application:
The lower-right corner shows a button with a lock icon that may be toggled, which is the desired result:
Notice how the content at the very bottom of the view port---the portion beside the lock button---is visible. (Clicking the button will simulate pressing the scroll-lock button on the keyboard. Having a scroll-lock button at the top is perfectly fine, if that's any easier.)
Problem
The JScrollPane API shows the following image:
Enabling the corner component also seems to require adding a column header. The addition of the header obscures part of the view port, in direct proportion to the scroll-lock button height. Here's a screenshot showing the visible column header, which hides part of the document:
Ideas
I've tried making the header view panel transparent, to no avail.
Code
The relevant code within the SwingNode:
// FlyingSaucer subclass
mView = new HtmlPanel();
mScrollPane = new JScrollPane( mView );
setContent( mScrollPane );
final var lock = new JButton( "X" );
mScrollPane.setCorner( UPPER_TRAILING_CORNER, lock );
mScrollPane.setVerticalScrollBarPolicy( VERTICAL_SCROLLBAR_ALWAYS );
final var header = new JPanel();
header.setPreferredSize(
new Dimension( 12, lock.getPreferredSize().height ) );
header.setOpaque( false );
header.setBackground( new Color( 0, 0, 0, 0 ) );
mScrollPane.setColumnHeaderView( header );
See camickr's answer for another example.
Question
How would you add a button to JScrollPane's bottom (or top) corner such that no view port content is obscured?
Related
How to make a corner component always visible in a JScrollPane
I would suggest using "wrapper" panels to achieve you desired layout. Something like:
JButton scrollLock = new JButton("...");
JScrollPane scrollPane = new JScrollPane(...);
JScrollBar verticalBar = scrollPane.getVerticalScrollBar();
JPanel verticalPanel = new JPanel( new BorderLayout() );
verticalPanel.add(verticalBar, BorderLayout.CENTER);
verticalPanel.add(scrollLock, BorderLayout.PAGE_END);
JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(scrollPane, BorderLayout.CENTER);
wrapper.add(verticalPanel, BorderLayout.LINE_END);
setContent(wrapper);
Related
I have two files that I need to display in a program. I need to use JTabbedPane and each file should be displayed in its own tab. I can make the text appear in the tab, but the scroll bar won't appear, so I can't see all of the information in the file. How do I add the scroll bar to the text area?
I made one method that creates a panel with the text in it (this is for one file). Then, I made another method that has JTabbedPane and I added the panel to a tab.
Panel method:
private void makeTextPanel() throws IOException
{
textPanel = new JPanel();
textArea = new JTextArea();
textArea.setEditable(false);
//width: 770 height: 1000
textAreaDimensions = new Dimension(TEXT_AREA_WIDTH, TEXT_AREA_HEIGHT);
textArea.setPreferredSize(textAreaDimensions);
BufferedReader inputFile = new BufferedReader(new FileReader(FILE_ONE));
String lineOfText = inputFile.readLine();
while(lineOfText != null)
{
textArea.append("\n" + lineOfText);
lineOfText = inputFile.readLine();
}
// Add a scroll bar
scrollPane = new JScrollPane(textArea);
// Add the text area and scroll bar to the panel
textPanel.add(textArea);
textPanel.add(scrollPane);
}
Tabbed pane method:
private void makeTabbedPane() throws IOException
{
frame = new JFrame("Project");
tabbedPane = new JTabbedPane();
frame.add(tabbedPane, BorderLayout.PAGE_START);
// add panel to the tab
makeTextPanel();
tabbedPane.addTab("Tab 1", textPanel);
// dimensions
frameDimensions = new Dimension(FRAME_WIDTH, FRAME_HEIGHT);
frame.setPreferredSize(frameDimensions);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
To reiterate:
How do I make the scroll bar visible?
I set the height of the text area to 1000. Will the scroll bar be able to scroll through everything? If not, how do I set the height of the text area to fit everything in the file?
The component you want scroll bars for should always a child of the JScrollPane. Adding the textArea and then the scrollPane to that tabbedPane probably isn't doing what you think it is. Make sure that textArea is the child of scrollPane, and add just the scrollPane to the tabbedPane, ensuring you've specified a layout that dictates how the scrollPane is to take up the space you want within tabbedPane.
The scrollpane will automatically add scrollbars only when it decides the textArea is bigger than it can render in the space it's been given.
Question 1) The JScrollPane methods setVerticalScrollBarPolicy() and setHorizontalScrollBarPolicy() will allow you to force the scrollbars to be always visible.
Question 2) The "preferred" height of the textArea is what your scrollPane will use to determine the scrollbar behaviour (see this example). It's all taken care of for you. If not, you'd be forced yourself to consider font rendering height, how much text you put in the textArea etc.
Generally speaking, just throwing a JTextArea into a JScrollPane will see the desired behaviour you're seeking without you having to do anything "special" with JTextArea size.
So I am trying to add more than one element to a JScrollPane element but so far I haven't been able to pull it of.
I can make it so that the first element shows up ,which in my case is a picture. But after adding in an extra panel to the JScrollPane ,the first element disappears and even the second element ,the new panel , doesnt show on my JScrollPane.
JFrame scherm = new JFrame("t?");
scherm.setVisible(true);
scherm.setSize(300, 300);
scherm.setLocationRelativeTo(null);
scherm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//
String path = "C:\\Users\\Bernard\\Documents\\Paradox Interactive\\Crusader Kings II\\mod\\viking\\map\\provinces.bmp";
Image image = ImageIO.read(new File(path));
ImageIcon icon = new ImageIcon(image);
JLabel label = new JLabel(icon);
JScrollPane scroll = new JScrollPane(label);
JPanel paneel2= new JPanel();
paneel2.setSize(new Dimension(400,400));
scroll.getViewport().add(paneel2,null);
scherm.add(scroll);
Thank you for your time!
By doing this:
scroll.getViewport().add(paneel2,null);
You're trying to add a component to the scroll pane's JViewPort shown in the picture below:
This makes no sense. As stated in How to Use Scroll Panes trial:
A
JScrollPane
provides a scrollable view of a component.
This single component is the view port's view. So if you want to have more than a single component in your scroll pane you must to wrap all those components in a lightweight component such as JPanel and set this one as the scroll pane's view port view:
JPanel content = new JPanel();
content.add(label);
content.add(paneel2);
scroll.setViewportView(content);
Original Top tab orientation setting:
http://dl.dropbox.com/u/3238736/screenshots/Screenshot-PasswordStore-1.png
Problematic Right tab orientation setting:
From the GUI above, my JTabbedPane (the blue colour tab on the right) is overlapping the "Quit" button (which is rendered using a GlassPane).
Note: Quit button is rendered onto top right using GlassPane.
I would like some technical advise on moving the blue colour tab to give some spacing for the "Quit" button ?
Codes for creating the GlassPane to insert the Quit button as shown below:
public void addUniversalQuitBtn() {
// Thanks to http://www.java-forums.org/awt-swing/12267-how-add-jbutton-tabbed-pane-headder.html forum post regarding adding a button on glasspane.
Rectangle tabBounds = mainTabPane.getBoundsAt(0);
Container glassPane = (Container) this.getRootPane().getGlassPane();
glassPane.setVisible(true);
glassPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.NONE;
gbc.insets = new Insets(tabBounds.y, 0, 0, 10);
gbc.anchor = GridBagConstraints.NORTHEAST;
quitBtn.setPreferredSize(new Dimension(quitBtn.getPreferredSize().width, (int) tabBounds.getHeight() - 2));
glassPane.add(quitBtn, gbc);
}
Thanks.
Well, i'd offer you to move the quit button from glasspane to some proper container but with standart Swing JTabbedPane you can't put it that way...
So here is some sort of solution:
public static void main ( String[] args )
{
JFrame frame = new JFrame ();
Insets current = UIManager.getInsets ( "TabbedPane.tabAreaInsets" );
UIManager.put ( "TabbedPane.tabAreaInsets",
new Insets ( current.top, 40, current.bottom, current.right ) );
JTabbedPane tabbedPane = new JTabbedPane ();
tabbedPane.setTabPlacement ( JTabbedPane.RIGHT );
tabbedPane.addTab ( "Tab 1", new JLabel () );
tabbedPane.addTab ( "Tab 2", new JLabel () );
frame.add ( tabbedPane );
UIManager.put ( "TabbedPane.tabAreaInsets", current );
JTabbedPane tabbedPane2 = new JTabbedPane ();
tabbedPane2.setTabPlacement ( JTabbedPane.RIGHT );
tabbedPane2.addTab ( "Tab 3", new JLabel () );
tabbedPane2.addTab ( "Tab 4", new JLabel () );
frame.add ( tabbedPane2, BorderLayout.SOUTH );
frame.setSize ( 400, 400 );
frame.setLocationRelativeTo ( null );
frame.setVisible ( true );
}
First tabbed pane (top one) has 30px gap between top side and tabs. The second tabbed pane has default gap set.
By changing the insets under "TabbedPane.tabAreaInsets" key you can manipulate the spacings between tabs run and tabbed pane sides. Be aware that those insets are rotated when tab position differs from TOP. So if you want to modify the top spacing with RIGHT tabs position you should modify the left one but not the top one, like i did in my example.
And don't forget to put the old Insets value back, otherwise that change will affect ALL tabbed panes created after the change.
Also i cannot guarantee that this will work for all of the native UIs, but i think such basic features should be supported. Atleast it is supported in Windows, Mac OS and Metal LaFs.
One more thing - you won't be able to change tab area Insets in runtime for already created tabbed pane, since it is saved into specific system UI when it is created and it is not possible to update that value (atleast without using Reflection "features" and violently accesing private fields). So you will have to recreate the tabbed pane if you want that gap only in one kind of tab placement.
ok. sounds a bit strange to me... but you could have 2 Buttons: one in the GlassPane (visible if TabbedPane is oriented top) and one in the Bar at the top (visible if TabbedPane is oriented right)
INTRO:
I created a java application using JFrame. I have a JMenuBar at the top and under that I'd like to display rows of text.
PURPOSE:
When I have 50 rows and only 20 are displayable at once, I'd like to be able to scroll down and back up again.
PROBLEM:
Of course, my theory doesn't wanna work as it should. My problem is that I don't know how to add a vertical scroll properly.
QUESTION:
How should I change this code to reach my goal?
public void display(){
Container content = this.window.getContentPane();
content.setLayout(new BorderLayout());
Border border = LineBorder.createGrayLineBorder();
//this is just a sample
for(int i = 0;i<50;i++){
JLabel lab = new JLabel("lonyaladek");
lab.setSize(570, 20);
lab.setBorder(border);
lab.setLocation(10, 20+(i*25));
content.add(lab);
}
//scroll
JScrollBar sb = new JScrollBar(JScrollBar.VERTICAL, 0, 0, 0, 0);
content.add(sb);
}
First you need to start with a layout manager that allows you to add multiple components to the container. Maybe a GridLayout is the best place to start.
Then you add this container to the scrollPane and then you add the scrollpane to the window.
So the basic code would be:
JPanel panel = new JPanel( new GridLayout(0, 1) );
panel.add(...);
panel.add(...);
JScrollPane scrollPane = new JScrollPane( panel );
window.add(scrollPane, BorderLayout.CENTER);
I suggest you read the section from the Swing tutorial on How to Use Scroll Panes for more info.
I am creating a base class for the JFrames of my application. I would like to inject a JXSearchField in the top right and corner of all frames that inherit from this class. I have a web background and know CSS fairly well. The effect I am going for is a float:right; or Fixed position, where other elements are not effected by the height of this component.
An example of what I am talking about would be a JFrame with a JTabbedPane aligned at the top. My tab pane only has three tabs but my frame is 800px wide. This gives me plenty of space for my top right aligned search box but my tabbedpane is reserving that space for additional tabs. I want to float in or fix position my searchbox to overlay that space.
if I understand correctly, you want to paint the TextField over the JTabbedPane beside the Tabs?
There is no easy way in swing doing this. You can use a glassPane-Component which draw the TextField on top right. And set it to the Frame.
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
JFrame frame = new JFrame();
frame.setBounds( 50, 50, 800, 600 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
JPanel glasspane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
frame.setGlassPane( glasspane );
glasspane.setOpaque( false );
JTextField textField = new JTextField("Search");
glasspane.add(textField);
glasspane.setVisible( true );
JTabbedPane tabs = new JTabbedPane();
tabs.setBorder( BorderFactory.createEmptyBorder( 10, 5, 5, 5 ) );
tabs.addTab( "Lorem", null );
tabs.addTab( "Ipsum", null );
tabs.addTab( "Dolor", null );
frame.setContentPane( tabs );
frame.setVisible( true );
A Good Layout that a lot of people use for organizing SWING components is the GridBagLayout
GridBagLayout