I am having problems with scrolling on a JScrollPane.
I have a list of images in a JList which I am placing on a JScrollPane. The list can be very long, sometimes hundreds or thousands of images. I add the JScrollPane to a JPanel, and the image gets drawn successfully, the JScrollPane adds scroll bars when needed and the scroll bars can move the image. The response from the scrollbars are good if the list of images is simple (10 - 20).
However, lists that run into the hundreds cause the vertical scrolling to initially run very slowly until all the images have been shown, then the scrolling speed returns to normal.
Can anyone suggest a technique to speed the initial scrolling response? I have experimented with adjusting the viewport settings (eg JViewport.BACKINGSTORE_SCROLL_MODE, JViewport.BLIT_SCROLL_MODE) but these did not lead to any improvement in the initial scrolling response.
The code that I am using is represented below.
prList = new JList(prListModel); // a list of interactive images for the JScrollPane
MouseAdapter listener = new PrChangeListener(prList, this);
prList.addMouseListener(listener);
prList.addMouseMotionListener(listener);
renderer = new PrRenderer();
renderer.setPreferredSize(getIconPreferredSize());
prList.setCellRenderer(renderer);
prList.setBackground(Color.WHITE);
prList.setSelectionBackground(new Color(225,225,225));
setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
//try separate linked scroll bar for scale bar ...
prListModel scaleBarListModel = new prListModel();
scaleBarListModel.addElement(intArray[0]); // a scale bar to sit above the JScrollPane
scaleBarList = new JList(scaleBarListModel);
scaleBarList.setCellRenderer(renderer);
scaleBarList.setBackground(Color.WHITE);
scaleBarList.setSelectionBackground(Color.WHITE);
scaleBarScrollPane = new JScrollPane(scaleBarList,JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
prListModel.removeElementAt(0);
prScrollPane = new JScrollPane(prList);
prScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
prScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scaleBarScrollPane.getHorizontalScrollBar().setModel(prScrollPane.getHorizontalScrollBar().getModel());
JPanel twoPanePanel= new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.VERTICAL;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx=0;
gbc.gridy=0;
gbc.weightx=1;
gbc.weighty=0.1;
twoPanePanel.add(scaleBarScrollPane, gbc);
gbc.gridx=0;
gbc.gridy=1;
gbc.weighty=0.9;
twoPanePanel.add(prScrollPane,gbc);
add(twoPanePanel);
Related
I have an assignment which requires me to create the layout that you see in the image as part of the development of a game. I've never worked with Java for desktop applications before so i'm a complete noob when it comes to using the Swing & AWT libraries. The image suggests that we use a JLayeredPane as our root container and then add the rest on top of it. My issue is that i've tried starting with the background image and the gridLayout but i can't seem to make anything other than the background show up. The grid doesn't show up at all (no border line, no background of the cells) and any other component i've added to it has failed. Can somebody point me in the right direction here? I've read the docs & saw some example of various layouts,containers and components but i can't seem to make all of them work together.
Here's my code so far:
public class BoardView extends JFrame{
// Constructor
public BoardView() {
JFrame window = new JFrame("Sorry Game"); // create a new Jwindow instance
ImageIcon appIcon = new ImageIcon(getClass().getClassLoader().getResource("res/icon.png")); // create the icon for the app
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the 'X' button is clicked, the app stops
window.setSize(new Dimension(1000, 700)); // setting the size of the window
window.setResizable(false); // Window won't be resizable
window.setIconImage(appIcon.getImage()); // set the icon for the app
window.setLayout(new BorderLayout());
JLayeredPane layeredPane = new JLayeredPane();
JLabel background = new JLabel();
background.setSize(1000,700);
background.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/background.png"))); for the JLabel
layeredPane.add(background,0);
JPanel gridPanel = new JPanel(new GridLayout(16,16));
gridPanel.setSize(650,700);
layeredPane.add(gridPanel);
for(int i = 0; i < 256; i++) {
JLabel tile = new JLabel();
tile.setBackground(Color.red);
tile.setBorder(new LineBorder(Color.black));
gridPanel.add(tile);
}
JLabel logo = new JLabel();
logo.setIcon(new ImageIcon(getClass().getClassLoader().getResource("res/sorryImage.png")));
layeredPane.add(logo);
window.add(layeredPane);
window.setLocationRelativeTo(null); // centers the window to the screen
window.setVisible(true); // make the window visible
}
}
My thought process was that i could set the JFrame's layout to a BorderLayout so that i can brake the final layout down into two parts, the West one and the East one. The West one would contain the Grid and the various JLabels and Buttons and the East one would contain the rest of the components. I've tried using the BorderLayout.WEST & EAST parameters when adding components to the JFrame but none has worked or changed a single thing. I've also tried using an index for the depth when adding components to the JLayeredPane as per the docs but again nothing changes.
P.S. Please note that i'm not looking for someone to create the layout for me. I want someone to help me understand what i'm doing wrong and what the best way of creating such layouts is.
In order to initialize the cells of the grid that i want to have images in, don't i need to add them manually in those positions?
If you use a GridLayout every cell must have a component and the components must be added in sequential order. That is as components are added they will wrap automatically to the next row as required.
So even if you don't want an image in a cell you would need to add a dummy component, lets say a JLabel with no text/icon.
An easier approach might be to use a GridBagLayout. The GridBagLayout can be configured to "reserve" space for cells that don't have components. So you can add a component to a specific cell.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class GridBagLayoutSparse extends JPanel
{
public GridBagLayoutSparse()
{
setBorder( new LineBorder(Color.RED) );
GridBagLayout gbl = new GridBagLayout();
setLayout( gbl );
/*
// Set up a grid with 5 rows and columns.
// The minimimum width of a column is 50 pixels
// and the minimum height of a row is 20 pixels.
int[] columns = new int[5];
Arrays.fill(columns, 50);
gbl.columnWidths = columns;
int[] rows = new int[5];
Arrays.fill(rows, 20);
gbl.rowHeights = rows;
*/
// Add components to the grid at top/left and bottom/right
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
addLabel("Cell 0:0", gbc);
gbc.gridx = 3;
gbc.gridy = 4;
addLabel("Cell 3:4", gbc);
}
private void addLabel(String text, GridBagConstraints gbc)
{
JLabel label = new JLabel(text);
label.setBorder( new LineBorder(Color.BLUE) );
add(label, gbc);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("GridBagLayoutSparse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout( new GridBagLayout() );
frame.add(new GridBagLayoutSparse());
frame.setSize(300, 300);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Run the code as is and the components will be grouped together in the center.
Uncomment the block comment and run again. The components will be positioned in the appropriate cell.
Using GridbagLayout, I am trying to orient a text area under a JFreeChart Chart. However, when I try to do so the two objects are placed side by side instead. Here is how I am approaching the problem:
//Set Gridbag constraints for chart
GridBagLayout gridbag3 = new GridBagLayout();
GridBagConstraints c3 = new GridBagConstraints();
c3.anchor = GridBagConstraints.NORTH;
GridBagConstraints c3a = new GridBagConstraints();
c3a.anchor = GridBagConstraints.SOUTH;
gridbag3.setConstraints(chartPanel3,c3);
gridbag3.setConstraints(scrollPane,c3a);
tab3.setLayout(gridbag3);
tab3.add(chartPanel3);
tab3.add(scrollPane);
The dimensions of the objects were defined as:
chartPanel3.setPreferredSize(new Dimension(800, 600));
final JTextArea errorLog = new JTextArea("Error Log:");
errorLog.setPreferredSize(new Dimension(300,100));
JScrollPane scrollPane = new JScrollPane(errorLog);
scrollPane.setBounds(10,60,780,500);
The view that I'm seeing is the following:
How can I go about placing this graph on top of this text area?
You need to set your constraints: specifically set gridy so the scrollpane is placed in a row below the chart.
Have you tried using WindowBuilder for Eclipse. It is really good with this type of stuff.
I am trying to achieve a layout similar to that of a carousel. It needs to have images added horizontally with a checkbox field in the second row. I have a panel within a jscrollpane and individual images are added to the panel as labels. Please see screen shot.
screenshot
When I scroll the pane , the first row containing the images stays well within the panel..but if you notice the second row of checkboxes , it scrolls out of the panel. Here is the code ...
JLabel lab1=new JLabel();
for (int ii=0; ii<imageFiles.length; ii++) {
GridBagConstraints constraint = new GridBagConstraints();
lab1 = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
constraint.gridx = ii;
constraint.gridy =0;
jPanel9.add(lab1,constraint);
}
for (int ii=0; ii<imageFiles.length; ii++) {
GridBagConstraints constraint1 = new GridBagConstraints();
constraint1.anchor = GridBagConstraints.SOUTH;
chkbox = new Checkbox("asdasdada");
constraint1.gridx = ii;
constraint1.gridy =1;
jPanel9.add(chkbox, constraint1);
}
Not sure what is wrong..Any help is much appreciated..Thanks..
The problem is that you are mixing AWT components (heavyweight) with Swing components (lightweight). I have 2 recommendations:
Don't mix heavyweight and lightweight components
Try to use lightweight components as much as possible
So in your code, replace Checkbox by JCheckbox and it should work just fine.
I've five lists (enclosed in a jscrollpane) added to a jpanel in a group layout. The problem with the lists is that when a scrollbar appears automatically, the border on the bottom/top disappears (lists 2,3,4). How do I make sure that all lists look the same w.r.t border just like the first/last lists?
I've tried setting viewportborder using setViewPortBroder, but it doesn't change things much. 2,3,4 appear with light border while the rest of the lists have double borders.
EDIT
Adding code sample:
Each list you see is created using this code:
MyJList jList = new MyJList(value);
jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jList.setModel(listModel);
jList.setMinimumSize(new Dimension(135, 300));
jList.setMaximumSize(new Dimension(135, 300));
jList.clearSelection();
jList.setSelectionBackground(Color.darkGray);
jList.setSelectionForeground(Color.white);
jList.setBorder(new LineBorder(Color.darkGray, 1));
jList.setFixedCellHeight(30);
jList.setFixedCellWidth(100);
Font font = jList.getFont();
jList.addListSelectionListener(new ListListener());
return jList;
MyList is an extension of JList. It does nothing special, other than storing some domain related metadata. And, then lists are added to the middle panel like this:
private void layoutLists(JLabel[] labels, JList[] lists) {
panel.removeAll();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
JScrollPane[] jScrollPanes = new JScrollPane[lists.length];
for (int index = 0; index < lists.length; index++) {
jScrollPanes[index] = new JScrollPane(lists[index]);
jScrollPanes[index].setBorder(BorderFactory.createEmptyBorder());
jScrollPanes[index].setMinimumSize(new Dimension(135, 300));
jScrollPanes[index].setMaximumSize(new Dimension(135, 300));
jScrollPanes[index].setPreferredSize(new Dimension(135, 300));
}
for (int index = 0; index < labels.length; index++) {
gbc.gridx = index;
gbc.gridy = 0;
gbc.insets = new Insets(8, 8, 8, 8);
panel.add(labels[index], gbc);
gbc.gridy = 1;
if (index == labels.length - 1) {
gbc.insets = new Insets(8, 8, 8, 13);
}
panel.add(jScrollPanes[index], gbc);
}}
The explanation of the top/bottom part of the inner (JList) border not being visible is that ... they are not visible if the vertical scrollBar appears (the list is scrolled off)
If you insist, either:
switch the borders - empty on the list itself and lineBorder on the scrollPane or
set the viewportBorderProperty of the scrollPane to the lineBorder
Beware: it's not recommended to fiddle with the default LAF settings - where-to or not the components have a border should be left to the ui to guarantee consistent visuals across your application. Nor does it look exactly good to have the left border line beside (either outside or inside) the scrollPane's vertical scrollbar.
Edit
Just noticed that you already tried the second option (and are not satisfied with the result :-) But then: where do you want the vertical border line if the scrollBar is visible? Anyway, back to the beware: the outcome is highly LAF dependent ...
I am using a GridBagLayout to (currently) display two rows. I am aware this layout is overkill for this task, but am trying to learn how to use it. The problem is that I have added the two panels to the two separate rows and there is a huge gap around the content (see image and code below):
alt text http://www.imagechicken.com/uploads/1264533379009864500.png
Image background;
public Table(){
super();
ImageIcon ii = new ImageIcon(this.getClass().getResource("pokerTableV2.png"));
background = ii.getImage();
setSize(Constants.FRAME_WIDTH, Constants.TABLE_HEIGHT);
setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
constraints.fill = GridBagConstraints.HORIZONTAL;
JButton button = new JButton("hello world");
JPanel panel1 = new JPanel();
panel1.setPreferredSize(new Dimension(800,100));
panel1.add(button, BorderLayout.CENTER);
panel1.setBackground(Color.yellow);
add(panel1, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
JPanel middlePanel = new JPanel();
middlePanel.setPreferredSize(new Dimension(800,350));
middlePanel.add(button, BorderLayout.CENTER);
middlePanel.setBackground(Color.blue);
add(middlePanel, constraints);
}
Use
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1d;
constraints.weighty = 1d;
JavaDoc for weightx/weighty says:
Specifies how to distribute extra horizontal/vertical space.
JavaDoc for fill:
This field is used when the component's display area is larger
than the component's requested size. It determines whether to
resize the component, and if so, how.
Unfortunately, with GridBagLayout, if the contents do not fill the entire container that it is in, it will automatically center all its contents within its container. That is why you are getting a really large gap.
There are essentially two ways to fix this:
The hard way: Fiddle with the GridBagConstraints. I had limited success with this when trying to avoid the centre-ing behaviour.
The easy way: Put the GridBagLayout inside of a FlowLayout, and then set the alignment of the FlowLayout to top-left, or whatever you wish.
I have asked, and answered, this question myself sometime last week.
So in your case you are adding your panel1 and middlePanel directly to the JFrame (?), with a GridBagLayout
JFrame (GridBagLayout)
- panel1
- middlePanel
I would suggest this alternative structure instead, to get rid of all the extra space (and centre alignment as well, if you like).
JFrame (FlowLayout)
- JPanel (GridBagLayout)
- panel1
- middlePanel
HTH