Scrollbars disappear when constructing JScrollPane with JPanel - java

What I want to do is load an image into a JScrollPane, surrounded by other components, and when the window is smaller than the image, it should be surrounded by scrollbars so that you can view the entire image by scrolling around.
I am doing this by constructing a JScrollPane with my own class ImagePanel, which extends JPanel, which paints the image. The image is loaded and displayed correctly, but the scrollbars disappear. Is there some part of JComponents that I've misunderstood or what is wrong?
public class ImagePanel extends JPanel {
private BufferedImage img;
public ImagePanel () {
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, this);
}
public void setImage(BufferedImage img) {
this.img = img;
}
}
public class MainGUI extends JPanel {
private ImagePanel imgP;
private JScrollPane pane;
public MainGUI () {
setLayout(new GridBagLayout());
//Create local components
//JComponents
JButton hideButton = new JButton("Hide");
JButton hidecategoryButton = new JButton ("Hide Category");
JButton removeButton = new JButton("Remove");
JButton searchButton = new JButton("Search");
JButton whatishereButton = new JButton("What is here?");
JComboBox<String> placeComboBox;
JLabel categoriesLabel = new JLabel("Categories");
JLabel newLabel = new JLabel("New: ");
JTextArea categoriesArea = new JTextArea();
JTextField searchField = new JTextField(10);
//Other
String[] placeTypes = {"Named Place", "Described Place"};
//Initialize and add behaviour
searchButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String s = searchField.getText();
}
});
categoriesArea.setEditable(false);
placeComboBox = new JComboBox<>(placeTypes);
searchField.setToolTipText("Search...");
searchField.setMinimumSize(new Dimension(5, 1));
//Just fileloading test
BufferedImage bi2 = null;
try {
bi2 = ImageIO.read(new File("dafoe.jpg"));
}
catch (Exception ex) {
}
imgP = new ImagePanel();
imgP.setImage(bi2);
pane = new JScrollPane(imgP);
//Add to panel
GridBagConstraints gc;
//Top row
JPanel toprowPanel = new JPanel();
toprowPanel.add(newLabel);
toprowPanel.add(placeComboBox);
toprowPanel.add(searchField);
toprowPanel.add(searchButton);
toprowPanel.add(hideButton);
toprowPanel.add(removeButton);
toprowPanel.add(whatishereButton);
gc = new GridBagConstraints();
gc.gridx = 0;
gc.gridy = 0;
gc.weightx = 1;
//gc.gridwidth = 6;
add(toprowPanel, gc);
//Hide category
gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.NORTH;
gc.gridx = 7;
gc.gridy = 3;
gc.weightx = 0;
gc.weighty = 0;
add(hidecategoryButton, gc);
//Category Label
gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.BELOW_BASELINE;
gc.gridx = 7;
gc.gridy = 1;
gc.weightx = 0;
gc.weighty = 0;
add(categoriesLabel, gc);
//categoriesarea
gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.BASELINE_TRAILING;
gc.fill = GridBagConstraints.BOTH;
gc.gridx = 7;
gc.gridy = 2;
gc.ipadx = 5;
gc.ipady = 70;
gc.weightx = 0;
gc.weighty = 0;
add(categoriesArea, gc);
//Image
gc = getImageConstraints();
add(pane, gc);
}
public void updateImage(BufferedImage bi) {
imgP.setImage(bi);
//imgP.repaint();
pane.repaint();
}
private GridBagConstraints getImageConstraints() {
GridBagConstraints gc = new GridBagConstraints();
gc.fill = GridBagConstraints.BOTH;
gc.gridheight = 3;
gc.gridwidth = 1;
gc.gridx = 0;
gc.gridy = 1;
gc.weightx = 1;
gc.weighty = 1;
return gc;
}
}

my own class ImagePanel, which extends JPanel, which paints the image. The image is loaded and displayed correctly, but the scrollbars disappear.
The scrollbars will appear automatically when the preferred size of the component added to the scroll pane is greater than the size of the scroll pane.
Your custom component has a preferred size of (0, 0) so the scrollbars will never appear.
You need to override the getPreferredSize() of your ImagePanel class to return the size of the image.
Or even easier just use a JLabel with an ImageIcon and add the label to the scroll pane. A JLabel already implements the getPreferredSize() method correctly.

You can not use the scrollbar when the layout is GridBagLayout. You must use the BorderLayout or FlowLayout
Link example with jtable (similar to the image):
http://myquestionjava.blogspot.com/2016/04/jscrollbars-and-jtable-in-java.html

Related

How to create an ImageIcon with the exact dimensions of a GridBagLayout cell

For a simple GUI I am currently making I want a design similar to this.
The blue and the green area are supposed to be just text and numbers.
The red area is supposed to be an image. Currently, I am creating scaled instances of an Image, create an ImageIcon out of this and then add this to a label to fit an image into different spaces.
The problem is, that without a width I can not create a scaled instance of the picture.
My current GridBagLayout code looks like this:
private static void createAndShowUI()
{
JFrame frame = new JFrame();
JLabel map = new javax.swing.JLabel();
JLabel data = new javax.swing.JLabel();
JLabel menu = new javax.swing.JLabel();
GridBagConstraints c;
frame = new JFrame("Risiko");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.getContentPane().setLayout(new GridBagLayout());
map.setText("MAP");
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.weightx = 0.75;
c.weighty = 0.75;
frame.getContentPane().add(map, c);
data.setText("DATA");
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.weighty = 0.25;
frame.getContentPane().add(data, c);
menu.setText("MENU");
c = new GridBagConstraints();
c.gridx = 1;
c.gridy = 0;
c.gridheight = 2;
c.weightx = 0.25;
frame.getContentPane().add(menu, c);
frame.setVisible(true);
}
I create the three areas and now I want to create an image with the exact width and height of the red area.
So my question is, how can I get the width and height of the red area so I can create a scaled instance of the picture so that it fits into this area?
Test the dynamic layout of the following mre by resizing the frame.
The background image used as background for MapPane is resized to fill the JPanels width and height.
This is achieved by overriding paintComponent:
import java.awt.*;
import java.awt.image.*;
import java.net.URL;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class SwingTestPane extends JPanel {
public SwingTestPane() {
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.rowWeights = new double[]{0.75, .25};
gridBagLayout.columnWeights = new double[]{0.75, 0.25};
setLayout(gridBagLayout);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 0;
JPanel mapPane = new MapPane();
add(mapPane, c);
c.gridx = 0;
c.gridy = 1;
JLabel data = new javax.swing.JLabel("DATA");
JPanel dataPane = new JPanel();
dataPane.add(data);
dataPane.setBackground(Color.YELLOW);
dataPane.setOpaque(true);
add(dataPane, c);
c.gridx = 1;
c.gridy = 0;
c.gridheight = 2;
JLabel menu = new JLabel("MENU");
JPanel menuPane = new JPanel();
menuPane.add(menu);
menuPane.setBackground(Color.GREEN);
menuPane.setOpaque(true);
add(menuPane, c);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400,400);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.getContentPane().add(new SwingTestPane());
frame.pack();
frame.setVisible(true);
}
}
class MapPane extends JPanel {
String imageUrlString = "https://findicons.com/files/icons/345/summer/128/cake.png";
BufferedImage image = null;
MapPane() {
URL url;
try {
url = new URL(imageUrlString);
image = ImageIO.read(url);
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override //Override to paint image as the background
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}

GridBagLayout components in wrong position

My code is meant to but the JButton at the top but when I add a image it goes on top of the image which is good but instead of being at the top it is in the middle and you can't get a value for gridy so I don't know how to make it go to the top. I have got lots of buttons on the Container but I will just put the code for one to make it shorter but if you need full code I will provide it. Thank you Here is my code
public void add(Container pane){
setBackground(Color.black);
pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
URL resource = getClass().getResource("Graphitebackground.v2.jpg");
ImageIcon i2 = new ImageIcon(resource);
URL resource3 = getClass().getResource("Graphitebackground.v4.jpg");
ImageIcon i3 = new ImageIcon(resource3);
URL resource1 = getClass().getResource("Graphitebackground.v3.jpg");
ImageIcon i1 = new ImageIcon(resource1);
JLabel background = new JLabel(i2);
background.setSize(new Dimension(1000,1000));
background.setVisible(true);
background.setLayout(new GridBagLayout());
JButton button;
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;
JButton label2 = new JButton(i1);
c.weightx = 0.5;
label2.setText("Level1");
label2.setPreferredSize(new Dimension(100,100));
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
label2.setForeground(Color.RED);
label2.setFont(new Font("Arial", Font.BOLD,100));
label2.setHorizontalTextPosition(JButton.CENTER);
label2.setVerticalTextPosition(JButton.CENTER);
label2.setBorderPainted(false);
label2.addMouseListener(new java.awt.event.MouseAdapter(){
public void mouseEntered(java.awt.event.MouseEvent evt){
label2.setBorderPainted(true);
label2.setBorder(BorderFactory.createLineBorder(Color.red,3));
}
public void mouseExited(java.awt.event.MouseEvent evt){
label2.setBorderPainted(false);
}
});
background.add(label2,c);
pane.add(background);
}

Panels take equal space

I have two panels. The first one looks like this.
public class BoardPanel extends JPanel
{
public BoardPanel()
{
setLayout(null);
this.setOpaque(false);
Button button = new JButton("..");
button.setLocation(...);
button.setSize(...);
add(button);
}
public void paintComponent( Graphics g )
{
/*
* Painting some stuff here.
*/
}
}
The other panel is something like this:
public class OtherPanel extends JPanel
{
public OtherPanel()
{
super();
this.setLayout(null);
this.setOpaque(false);
JPanel panel1 = new JPanel();
panel1.setLocation(...);
panel1.setSize(...);
panel1.setOpaque( .. );
JPanel panel2 = new JPanel();
panel2.setLocation(...);
panel2.setSize(...);
panel2.setOpaque( .. );
add(panel1):
add(panel2);
}
}
After that , I put both my panels in a frame. But I want my BoardPanel to occupy more screen than OtherPanel. So I used GridBagLayout for the frame
public class MainFrame extends JFrame
{
private GridBagLayout aGridLayout = new GridBagLayout();
private GridBagConstraints constraints = new GridBagConstraints();
public MainFrame()
{
super("Quoridor");
setLayout(gridLayout);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1366, 768);
setVisible(true);
setResizable(false);
this.getContentPane().setBackground(Color.decode("#b2a6a6"));
BoardPanel boardPanel = new BoardPanel();
OtherPanel otherPanel = new OtherPanel();
this.addComponent(boardPanel, 1, 1, 2, 1);
this.addComponent(otherPanel, 1, 3, 1, 1);
}
public void addComponent(Component component , int row , int column , int width
, int height)
{
constraints.gridx = column;
constraints.gridy = row;
constraints.gridwidth = width;
constraints.gridheight = height;
aGridLayout.setConstraints(component, constraints);
add(component);
}
}
The problem is , that the frame gives equal space to both panels , and dont give more space to the boardPanel.
Why is this happening ? Doest it have to do with the bounds of the panels ?
Here is a good tutorial on GridBagLayout: https://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html . Also see the code below and screenshot. The anchor field positions the component at the first line. The weightx field gives more space to the columns for boardPanel. The ipady field specifies how much to add to the height of the component. Here, boardPanel gets most of the width and all of the height. The otherPanel panel gets half of the height.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridExample {
private JFrame mainFrame;
private JPanel boardPanel, otherPanel;
public GridExample(){
mainFrame = new JFrame();
mainFrame.setSize(600,400);
mainFrame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
boardPanel = new JPanel();
boardPanel.add(new JLabel("board panel"));
boardPanel.setBackground(Color.yellow);
otherPanel = new JPanel();
otherPanel.add(new JLabel("other panel"));
otherPanel.setBackground(Color.green);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.75;
c.ipady = 400;
c.gridx = 0;
c.gridy = 0;
mainFrame.add(boardPanel, c);
c.anchor = GridBagConstraints.FIRST_LINE_START;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.25;
c.ipady = 200;
c.gridx = 1;
c.gridy = 0;
mainFrame.add(otherPanel, c);
mainFrame.setVisible(true);
}
public static void main(String[] args){
GridExample swingContainerDemo = new GridExample();
}
}

how to put components in the center in a CardLayout panel

I have a frame that has couple of panels and they change by CardLayout.
Inside each panel i will have different components. To design the GUI of the panel I used GridBagLayout. But the problem is any component or Layout I use for these paneles, they all stay at the top of the page. So basically the panel size of the CardLayout is some small amount of the frame. I want to make the sub panel size as large as the main CardLayout size.
Code for main CardLayout:
public class MainPanel extends JPanel {
private CardLayout cl = new CardLayout();
private JPanel panelHolder = new JPanel(cl);
public MainPanel() {
NewSession session = new NewSession(this);
ChooseSource chooseSource = new ChooseSource(this);
panelHolder.add(session, "1");
panelHolder.add(chooseSource, "2");
cl.show(panelHolder, "dan");
add(panelHolder);
}
public void showPanel(String panelIdentifier){
cl.show(panelHolder, panelIdentifier);
}
}
A sub panel:
public class ChooseSource extends JPanel {
MainPanel ob2;
JButton btn;
JLabel label;
JTextField field;
public ChooseSource(MainPanel mainPanel){
this.ob2 = mainPanel;
btn = new JButton("Browse");
label = new JLabel("Folder ");
field = new JTextField();
btn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
ob2.showPanel("1");
}
});
GridBagLayout layout = new GridBagLayout();
setLayout(layout);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.ipady = 20;
c.gridheight = 2;
add(btn, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 0;
c.ipady = 10;
c.gridheight = 1;
c.insets = new Insets(0,10,0,0);
add(label, c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 1;
c.gridy = 1;
c.ipady = 0;
c.gridheight = 1;
c.insets = new Insets(0,10,0,0);
add(field, c);
}
}
The left image shows how it is not, and right one is the one I am trying to make. basically I want to have access to all the available space of the panel.
Any idea?
Change the layout manager of MainPanel to something like BorderLayout or GridBagLayout

Show 30px high JPanel, then fill rest of space with minecraft

I am trying to make a JFrame with a 30px JPanel at the top, then add the Minecraft Applet underneath, Both need to resize automatically, I am trying to achieve this with a GridBagLayout, so far I have:
public void start(Applet mcApplet, String user, String session) throws MalformedURLException {
JLabel label = new JLabel();
Thread animation = new Thread();
Dimension size = new Dimension(900, 540);
JPanel basic = new JPanel(new GridBagLayout());
basic.setPreferredSize(size);
GridBagConstraints c = new GridBagConstraints();
// ADD MINEBOOK MENU
JLabel menu = new JLabel(new ImageIcon(new URL("http://modpacks.minebook.co.uk/images/menu.png")));
if(!animationname.equalsIgnoreCase("empty")) {
try {
animation.start();
label = new JLabel(new ImageIcon(animationname));
label.setBounds(0, 0, size.width, size.height);
fixSize(size);
getContentPane().setBackground(Color.black);
add(label);
animation.sleep(3000);
animation.stop();
} catch (Exception e) {
label.add(label);
} finally {
remove(label);
}
}
try {
appletWrap = new Launcher(mcApplet, new URL("http://www.minecraft.net/game"));
} catch (MalformedURLException ignored) { }
appletWrap.setParameter("username", user);
appletWrap.setParameter("sessionid", session);
appletWrap.setParameter("stand-alone", "true");
mcApplet.setStub(appletWrap);
mcApplet.setPreferredSize(size);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
c.ipady = 30;
basic.add(menu, c);
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 1;
c.ipady = 0;
basic.add(appletWrap, c);
add(basic);
pack();
validate();
appletWrap.init();
appletWrap.start();
fixSize(size);
setVisible(true);
}
I suggest that you use a BorderLayout, and place your 30px panel in the NORTH position, while your Minecraft applet in the CENTER position.

Categories