I am coding a GUI containing a JScrollPane that displays an image that gets updated (with potential modification of its dimensions). The image is in an ImageIcon in a JLabel. The image size is retrieved using ImageIcon.getIconWith() and getIconHeight(). And the JLabel preferred size is updated with those dimensions.
When the application is started for the first time, the JScrollPane and its scrollbars have the right dimensions to view the whole image (potentially using scrolling). But when the image gets updated the JScrollPane and the scrollbars assume the image has the dimensions of the previous image. How do I get the JScrollPane to update correctly ?
Here is a curated version of my GUI. Visualizer.java uses the GUI VisualizerGUI.java. When the "Run" button is pushed, a new image is randomly generated using ImageDrawer.drawImage() (simulates the behavior of the real application) and the content of the JScrollPane is updated using the function VisualizerGUI.setTransitionsImage(String imgPath).
Visualizer.java:
import java.util.*;
import java.io.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Visualizer implements ActionListener {
private VisualizerGUI gui = null;
public Visualizer() {
gui = VisualizerGUI.createAndStart(this);
}
public static void main(String[] args) {
Visualizer viz = new Visualizer();
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Run command")) {
run();
}
}
public void run() {
updateGUIwithSolution();
}
public void updateGUIwithSolution() {
gui.initGUIupdate();
try {
ImageDrawer.drawImage();
gui.setTransitionsImage("image.png");
} catch (Exception e) {
System.out.println("Error while generating image");
e.printStackTrace();
}
gui.finalizeGUIupdate();
}
}
VisualizerGUI.java:
import java.util.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
public final class VisualizerGUI {
private JFrame frame;
private JButton runButton;
private JButton nextButton;
private JScrollPane transitionsDisplay;
private JTabbedPane executionsDisplay;
private JTabbedPane tracesDisplay;
private JTextArea textInfoArea;
public VisualizerGUI() {}
private void initGUI(ActionListener actionsHandler) {
//Create and set up the window.
frame = new JFrame("Visualizer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel controlPanel = new JPanel(new FlowLayout());
runButton = new JButton("Run");
runButton.addActionListener(actionsHandler);
runButton.setActionCommand("Run command");
controlPanel.add(runButton);
nextButton = new JButton("Next");
nextButton.addActionListener(actionsHandler);
nextButton.setActionCommand("Find next solution");
controlPanel.add(nextButton);
transitionsDisplay = new JScrollPane();
executionsDisplay = new JTabbedPane();
tracesDisplay = new JTabbedPane();
JSplitPane ETspliter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, executionsDisplay, tracesDisplay);
JSplitPane graphsSpliter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, transitionsDisplay, ETspliter);
textInfoArea = new JTextArea();
textInfoArea.setLineWrap(true);
textInfoArea.setWrapStyleWord(true);
textInfoArea.setEditable(false);
JScrollPane textInfoAreaSP = new JScrollPane(textInfoArea);
JSplitPane topSpliter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, graphsSpliter, textInfoAreaSP);
transitionsDisplay.setPreferredSize(new Dimension(200,200));
executionsDisplay.setPreferredSize(new Dimension(200,200));
tracesDisplay.setPreferredSize(new Dimension(200,200));
textInfoAreaSP.setPreferredSize(new Dimension(200,100));
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(controlPanel, BorderLayout.NORTH);
frame.getContentPane().add(topSpliter, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static VisualizerGUI createAndStart(ActionListener actionsHandler) {
VisualizerGUI gui = new VisualizerGUI();
final Runnable guiRunner =
new Runnable() {
public void run() {
gui.initGUI(actionsHandler);
// gui.pack();
}
};
try {
javax.swing.SwingUtilities.invokeAndWait(guiRunner);
} catch (InterruptedException e) {
System.out.println(">>> WARNING <<< InterruptedException while creating the GUI");
} catch (InvocationTargetException e) {
System.out.println(">>> WARNING <<< InvocationTargetException while creating the GUI");
}
return gui;
}
public void clear() {
initGUIupdate();
finalizeGUIupdate();
}
public void initGUIupdate() {
// frame.setVisible(false);
transitionsDisplay.setViewportView(null);
executionsDisplay.removeAll();
tracesDisplay.removeAll();
textInfoArea.setText(null);
}
public void pack() {
frame.pack();
}
public void finalizeGUIupdate() {
// frame.validate();
// frame.repaint();
// frame.setVisible(true);
}
public void setTransitionsImage(String imgPath) {
ImageIcon icon = new ImageIcon(imgPath);
icon.getImage().flush();
int width = icon.getIconWidth();
int height = icon.getIconHeight();
JLabel label = new JLabel();
label.setVerticalAlignment(SwingConstants.CENTER);
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setIcon(icon);
label.setPreferredSize(new Dimension(width,height));
//label.setPreferredSize(null);
transitionsDisplay.setViewportView(label);
label.revalidate();
label.repaint();
transitionsDisplay.getViewport().revalidate();
transitionsDisplay.getViewport().repaint();
transitionsDisplay.revalidate();
// transitionsDisplay.validate();
transitionsDisplay.repaint();
frame.revalidate();
// frame.validate();
frame.repaint();
}
public void setTransitionsImageInED(String imgPath) {
final Runnable guiRunner =
new Runnable() {
public void run() { setTransitionsImage(imgPath); }
};
// javax.swing.SwingUtilities.invokeLater(guiRunner);
try {
javax.swing.SwingUtilities.invokeAndWait(guiRunner);
} catch (InterruptedException e) {
System.out.println(">>> WARNING <<< InterruptedException while creating the GUI");
} catch (InvocationTargetException e) {
System.out.println(">>> WARNING <<< InvocationTargetException while creating the GUI");
}
}
}
ImageDrawer.java:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageDrawer {
public static void drawImage() throws Exception {
try {
int width = 20 + (int)(Math.random() * 1000);
int height = 20 + (int)(Math.random() * 1000);
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D ig2 = bi.createGraphics();
ig2.setPaint(Color.blue);
ig2.fillRect(0, 0, width, height);
ig2.setPaint(Color.red);
ig2.fillRect(5, 5, width - 10, height - 10);
ig2.setPaint(Color.blue);
ig2.drawLine(0, 0, width, height);
ig2.drawLine(0, height, width, 0);
ImageIO.write(bi, "PNG", new File("image.png"));
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
Can someone explain why I have this problem? Thanks!
transitionsDisplay.setPreferredSize(new Dimension(200,200));
executionsDisplay.setPreferredSize(new Dimension(200,200));
tracesDisplay.setPreferredSize(new Dimension(200,200));
textInfoAreaSP.setPreferredSize(new Dimension(200,100));
Don't use setPreferredSize(...). Each Swing component is responsible for determining its own size.
The image size is retrieved using ImageIcon.getIconWith() and getIconHeight(). And the JLabel preferred size is updated with those dimensions.
Not necessary. Again the JLabel will determine its own size based on the size of the Icon. This is done dynamically as the image/icon changes.
The scrollbars of the scrollpane will appear when the preferred size of the label is greater than the size of the scrollpane. Just let the layout managers do their job.
Related
I'm trying to have a JPanel of varying size (potentially much wider than the standard screen) inside of a JScrollPanel. Currently it works out great, and I have configured the scrollbars to work fine manually, however I would like the JPanel to "scroll" constantly to the left, so that over time the whole thing is displayed. All of the answers I found are specific to JTextArea and use Carets, or use rectToVisible. Neither of these will work because I'm trying to scroll internally to a single JPanel.
I've included what I believe to be all of the relevant code below.
center is the JPanel (of which Grid is a subclass, used to paint specifically a grid with some specific cells colored) with a BorderLayout that I would like to autoscroll.
public GuiViewFrame(Song playMe) {
String[][] songArray = playMe.to2DArray();
this.displayPanel = new ConcreteGuiViewPanel(playMe);
main = new JPanel();
main.setLayout(new BorderLayout());
displayPanel.setLayout(new BorderLayout());
center = new Grid(playMe);
labels = new Labels(playMe);
horiz = new Horiz(playMe);
center.setPreferredSize(new Dimension(10 * songArray.length, 10 * songArray[0].length));
horiz.setPreferredSize(new Dimension(10 * songArray.length, 10));
horiz.setVisible(true);
main.add(center, BorderLayout.CENTER);
main.add(horiz, BorderLayout.NORTH);
scroll = new JScrollPane(main,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
add(scroll, BorderLayout.CENTER);
labels.setPreferredSize(new Dimension(20, 10 * songArray[0].length));
labels.setVisible(true);
add(labels, BorderLayout.WEST);
JScrollBar horiz = scroll.getHorizontalScrollBar();
InputMap im = horiz.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("RIGHT"), "positiveUnitIncrement");
im.put(KeyStroke.getKeyStroke("LEFT"), "negativeUnitIncrement");
im.put(KeyStroke.getKeyStroke("HOME"), "minScroll");
im.put(KeyStroke.getKeyStroke("END"), "maxScroll");
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.pack();
}
The project as a whole is to generate a view for playing music that combines MIDI and a GUI, but right now once MIDI plays enough of the song, the relevant notes are off screen. I would like to scroll at a rate to keep pace with MIDI.
You can set the value of the horizontal scrollbar to control what is currently visible:
JScrollBar horizontal = scroll.getHorizontalScrollBar();
horizontal.setValue( horizontal.getValue() + ??? );
You would need to use a Swing Timer to schedule the scrolling at an appropriate interval.
Simple example of using a Timer to scroll text:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class TimerTest extends JPanel implements ActionListener
{
JLabel timeLabel;
JLabel scrollLabel;
public TimerTest()
{
setLayout( new BorderLayout() );
timeLabel = new JLabel( new Date().toString() );
add(timeLabel, BorderLayout.NORTH);
scrollLabel = new JLabel( "Some continuously scrolling text!! " );
add(scrollLabel, BorderLayout.SOUTH);
int time = 1000;
javax.swing.Timer timer = new javax.swing.Timer(time, this);
timer.setInitialDelay(1);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
timeLabel.setText( new Date().toString() );
String oldText = scrollLabel.getText();
// Scroll right to left
String newText = oldText.substring(1) + oldText.substring(0, 1);
// Scroll left to right
// int length = oldText.length();
// String newText = oldText.substring(length-1, length)
// + oldText.substring(0, length-1);
scrollLabel.setText( newText );
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new TimerTest() );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
One possible solution might be to take advantage of JComponent#scrollRectToVisible and a Swing Timer
For example...
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ScrollTest {
public static void main(String[] args) {
new ScrollTest();
}
public ScrollTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(new TestPane()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Scrollable {
public TestPane() {
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JViewport viewport = (JViewport) getParent();
Rectangle viewRect = viewport.getViewRect();
if (viewRect.x + viewRect.width < getWidth()) {
viewRect.x += 2;
scrollRectToVisible(viewRect);
} else {
((Timer)e.getSource()).stop();
}
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(1000, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawLine(0, 0, getWidth(), getHeight());
g2d.dispose();
}
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 200);
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 64;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 64;
}
#Override
public boolean getScrollableTracksViewportWidth() {
return getPreferredSize().width <= getParent().getSize().width;
}
#Override
public boolean getScrollableTracksViewportHeight() {
return getPreferredSize().height <= getParent().getSize().height;
}
}
}
I have a JButton which I want to set the background to a color.
JButton button = new JButton();
button.setVisible(true);
button.setPreferredSize(new Dimension(student_scroll.getWidth(), 50));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
I used this for mac and it showed up as I wanted it to be. However, upon trying it on windows, the foreground is white(as it should) but the background is empty.
Setting background color to JButton
says to add button.setContentAreaFilled(false); which I did but had no effect. Most others say to add button.setOpaque(true);which I also did already.
What else do I have to do so that it will show up with a black background?
EDIT
As requested, the SSCCE:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MainSwing extends JFrame {
private static final long serialVersionUID = -8231889836024827530L;
public static void main(String[] args) {
try {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Test");
UIManager.put("ScrollBarUI", "main.CustomScrollBarUI");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ClassNotFoundException e) {
System.out.println("ClassNotFoundException: " + e.getMessage());
}
catch(InstantiationException e) {
System.out.println("InstantiationException: " + e.getMessage());
}
catch(IllegalAccessException e) {
System.out.println("IllegalAccessException: " + e.getMessage());
}
catch(UnsupportedLookAndFeelException e) {
System.out.println("UnsupportedLookAndFeelException: " + e.getMessage());
}
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JFrame frame = new JFrame() {
Container c = getContentPane();
JButton button = new JButton("Hello");
{
button.setText("Hello");
button.setVisible(true);
button.setPreferredSize(new Dimension(100, 50));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
c.add(button);
}
};
frame.setSize(500, 500);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
It seems that the problem has something to do with the line: UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); as when I remove it, the buttons are black.
I'm guessing from those UIManager key/value pairs that the PLAF is the OS X based Aqua PLAF. And that seems to be part of the problem here. Here it is without the content area filled on Windows.
import java.awt.*;
import javax.swing.*;
public class MainSwing extends JFrame {
public static void main(String[] args) {
try {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Test");
UIManager.put("ScrollBarUI", "main.CustomScrollBarUI");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace(); // more info for less LOC!
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame() {
Container c = getContentPane();
JButton button = new JButton("Hello");
{
c.setLayout(new GridLayout(0,1));
c.add(new JButton("Hi"));
button.setText(UIManager.getSystemLookAndFeelClassName());
button.setVisible(true);
button.setPreferredSize(new Dimension(400, 100));
button.setBorder(BorderFactory.createLineBorder(Color.WHITE, 1));
button.setContentAreaFilled(false);
button.setBackground(Color.BLACK);
button.setForeground(Color.WHITE);
button.setOpaque(true);
c.add(button);
}
};
frame.pack();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
It seems that the problem has something to do with the line: UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); as when I remove it, the buttons are black.
So that is extra information we didn't have before you created the SSCCE (which is why you should always post a SSCCE with your question).
It also tells you the problem is not with your code but with the LAF. The Windows LAF ignores the setBackground(...) method and paints its own background.
One option would be to add an Icon to the button of your desired color. Then you can configure the text to be painted in the center of the button:
import java.awt.*;
import javax.swing.*;
public class ColorIcon implements Icon
{
private Color color;
private int width;
private int height;
public ColorIcon(Color color, int width, int height)
{
this.color = color;
this.width = width;
this.height = height;
}
public int getIconWidth()
{
return width;
}
public int getIconHeight()
{
return height;
}
public void paintIcon(Component c, Graphics g, int x, int y)
{
g.setColor(color);
g.fillRect(x, y, width, height);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI()
{
JPanel panel = new JPanel( new GridLayout(2, 2) );
for (int i = 0; i < 4; i++)
{
Icon icon = new ColorIcon(Color.RED, 50, 50);
JButton label = new JButton( icon );
label.setText("" + i);
label.setHorizontalTextPosition(JButton.CENTER);
label.setVerticalTextPosition(JButton.CENTER);
panel.add(label);
}
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setSize(200, 200);
f.setLocationRelativeTo( null );
f.setVisible(true);
}
}
Then is should work on all LAF's.
How to add an image as a background in JScrollPane?
I tried this but the image doesn't display:
BufferedImage img = null;
try {
img = ImageIO.read(new File("C:\\Users\\Suraj\\Documents\\NetBeansProjects\\JavaApplication2\\src\\javaapplication2\\images\\2.jpg"));
}
catch (IOException e) {
e.printStackTrace();
}
Image imag = img.getScaledInstance(d.width, d.height, Image.SCALE_SMOOTH);
ImageIcon imageBack = new ImageIcon(imag);
FlowLayout fl = new FlowLayout();
frame.getContentPane().setLayout(fl);
fl.addLayoutComponent(null, new JLabel(imageBack));
EDIT : I would like to add jlabels and jbuttons on the JScrollPane with the background
If your goal is to simply show an image in a JScrollPane without showing other components (such as a JTable) in the JScrollPane, then you should:
Make an ImageIcon out of your image via new ImageIcon(myImage)
Add that Icon to a JLabel
Place the JLabel into the JScrollPane's viewport, something that can be done by passing the JLabel into the JScrollPane's constructor.
And your done.
If you need to do something else, then describe your problem in greater detail.
For example,
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ImageInScrollPane extends JPanel {
public static final String IMAGE_PATH = "http://image.desk7.net/"
+ "Space%20Wallpapers/1422_1280x800.jpg";
private static final int PREF_W = 500;
private static final int PREF_H = 400;
public ImageInScrollPane() throws IOException {
URL imageUrl = new URL(IMAGE_PATH);
BufferedImage img = ImageIO.read(imageUrl);
Icon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
JScrollPane scrollPane = new JScrollPane(label);
setLayout(new BorderLayout());
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ImageInScrollPane mainPanel = null;
try {
mainPanel = new ImageInScrollPane();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
JFrame frame = new JFrame("ImageInScrollPane");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You ask in comment:
what if I have to add other objects like buttons?....How do I do it?
In this situation, I'd create a class that extends JPanel and display the image in this JPanel by drawing it within the paintComponent method override (if you search on this, you'll find many examples, some by me), then add the buttons/components to this image-drawing JPanel, and then adding this JPanel into the JScrollPane's viewport as I do with the JLabel above.
I have this application that I am working on, I have a JFrame that uses a BorderLayout. In the JFrame is a JPanel, the JPanel is using a MigLayout.I am trying to make a JButton stay on the bottom left hand side of the screen , achieving a similar effect as the "position:fixed" property in CSS.
Any tips on how I can achieve this effect by code?
Tried JLayeredPane code from a few other sources, but still doesn't work somehow.
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if (info.getName().equals("Nimbus")) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
MainFrame frame = new MainFrame();
ForumMainPage panel = new ForumMainPage(frame);
panel.setFocusable(true);
panel.requestFocusInWindow();
frame.add(jLabelOnJButton());
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public MainFrame() {
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
this.setSize(dim);
this.setUndecorated(true);
this.setExtendedState(Frame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.add(jLabelOnJButton(),BorderLayout.CENTER);
}
private static JComponent jLabelOnJButton(){
JLayeredPane layers = new JLayeredPane();
JLabel label = new JLabel("label");
JButton button = new JButton("button");
label.setBounds(40, 20, 100, 50);
button.setBounds(100, 20, 150, 75);
layers.add(label, new Integer(200));
layers.add(button, new Integer(100));
return layers;
}
}
Thanks in advance!
You could add the button to the frame's glass pane. This takes a little bit of work to make happen, as you need to keep track of the scroll pane relative to the glass pane, but it should achieve the desired effect
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class OverlayButton {
public static void main(String[] args) {
new OverlayButton();
}
public OverlayButton() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JScrollPane sp;
private JButton btn;
private JTextArea ta;
private JPanel glassPane;
public TestPane() {
setLayout(new BorderLayout());
btn = new JButton("Print");
ta = new JTextArea(10, 20);
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File("Script.txt")));
String text = null;
while ((text = br.readLine()) != null) {
ta.append(text + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (Exception e) {
}
}
ta.setCaretPosition(0);
sp = new JScrollPane(ta);
glassPane = new JPanel() {
#Override
public void doLayout() {
Point p = sp.getLocation();
Dimension dim = sp.getSize();
p = SwingUtilities.convertPoint(sp, p, this);
btn.setSize(btn.getPreferredSize());
int barWidth = sp.getVerticalScrollBar().getWidth();
int barHeight = sp.getHorizontalScrollBar().getHeight();
int x = p.x + (dim.width - btn.getWidth()) - barWidth;
int y = p.y + (dim.height - btn.getHeight()) - barHeight;
btn.setLocation(x, y);
}
};
glassPane.setOpaque(false);
glassPane.add(btn);
glassPane.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
e.getComponent().doLayout();
}
});
add(sp);
}
#Override
public void addNotify() {
super.addNotify();
SwingUtilities.getRootPane(this).setGlassPane(glassPane);
glassPane.setVisible(true);
glassPane.revalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
}
Take a look at How to use Root Panes for more details
Try using the OverlayLayout:
JPanel contentPane = new JPanel();
contentPane.setLayout( new OverlayLayout(ContentPane) );
frame.setContentPane( panel );
JButton button = new JButton(...);
button.setAlignmentX(0.0f);
button.setAlignmentY(1.0f);
contentPane.add( button );
ForumMainPage panel = new ForumMainPage(frame);
contentPane.add( panel );
I couldn't explain the question in the title any better, so here goes -
I created a tiled background image. I then set the created background image to my JFrame. However, I added my JScrollPane to said background. Depending on the order I place my code in, 1 of two things will happen. When I have my JScrollPane like so -
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Image;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
public class TestingApp {
public static JFrame programFrame;
public static JLabel projectBackground;
public static JLabel projectLogo;
public static JPanel allContent;
public static JPanel fourRows;
public static JPanel centerPanel;
public static JScrollPane scrollPane;
// Tiled Background
public static void tiledBackground() {
#SuppressWarnings("serial")
class ImagePanel extends JPanel {
public Image image;
public boolean tile;
ImagePanel(Image image) {
this.image = image;
this.tile = true;
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw > 0 && ih > 0) {
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
}
}
}
}
// Making the parts for the GUI
public static void createGUI() {
java.net.URL img1 = null;
try {
img1 = new URL("https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSE6uHn-B_qKtLZOKjQNVeIxhOaxbmfio45VMUq-mVgGKvgmeghKw");
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
Image image = null;
try {
image = ImageIO.read(img1);
} catch (IOException e) {
e.printStackTrace();
}
// programFrame Title and Layout
programFrame = new JFrame("Organizer");
programFrame.setLayout(new BorderLayout());
Icon backgroundIcon = new ImageIcon(img1);
projectBackground = new JLabel(backgroundIcon);
// Logo JLabel
java.net.URL img2 = null;
try {
img2 = new URL("https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcTvXxBQRsJ5NgSb8VOSNU_Qfom6HRV_crcazhD6bSZUh_ux3VHbgQ");
} catch (MalformedURLException e) {
e.printStackTrace();
}
Icon logoIcon = new ImageIcon(img2);
projectLogo = new JLabel(logoIcon);
projectLogo.setBorder(new EmptyBorder(10, 10, 10, 10));
// New JPanel for GridLayouts to hold each JPanel with GridLayouts
fourRows = new JPanel(new GridLayout(1, 4));
fourRows.setLayout(new GridLayout());
fourRows.setOpaque(false);
fourRows.add(new JButton("Button"));
fourRows.add(new JButton("Button"));
fourRows.add(new JButton("Button"));
fourRows.add(new JButton("Button"));
// Makes the Initial BorderLayout (Using allContent JPanel)
allContent = new JPanel();
allContent.setLayout(new BorderLayout());
allContent.add(projectLogo, BorderLayout.NORTH);
allContent.setVisible(true);
allContent.setOpaque(false);
allContent.add(fourRows, BorderLayout.CENTER);
// Add ScrollPane
scrollPane = new JScrollPane(allContent);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
// JFrame programFrame Constructors
programFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
programFrame.setLayout(new BorderLayout());
programFrame.setContentPane(new ImagePanel(image));
programFrame.add(scrollPane);
programFrame.pack();
programFrame.setVisible(true);
programFrame.setResizable(true);
programFrame.setSize(1280, 720);
programFrame.setLocationRelativeTo(null);
} // public static void createGUI() Closing
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
} // public void run() Closing
});
}
}
It doesn't scroll on the entire JFrame, just the contentStuff, and even then, it stretches beyond to the bottom of the content to where the scroll bar isn't there, and you can't scroll.
However, when I rearrange that code, and I put my
programFrame.setContentPane(new ImagePanel(image));
BEFORE
programFrame.add(scrollPane);
I just get the repeated background image, and no content.
EDIT - Added an SSCCE
EDIT2 - Here's a solution I was trying. I tried creating an empty panel to add in the content that should update based on JFrame size. Needless to say, it didn't work. Small snippet of the edited code, nothing else was changed -
// Makes the Initial BorderLayout (Using allContent JPanel)
allContent = new JPanel();
allContent.setLayout(new BorderLayout());
allContent.add(warlordsLogo, BorderLayout.NORTH);
allContent.setVisible(true);
allContent.setOpaque(false);
allContent.add(fourRows, BorderLayout.CENTER);
int widthForCenterPanel = programFrame.getWidth();
int heightForCenterPanel = programFrame.getHeight();
// Makes a Panel to add the ScrollPane to to center is properly
centerPanel = new JPanel();
centerPanel.setOpaque(false);
centerPanel.setBounds(0, 0, widthForCenterPanel, heightForCenterPanel);
centerPanel.add(allContent);
// Add ScrollPane
scrollPane = new JScrollPane(centerPanel);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
EDIT 3 - Fixed my SSCCE. If you notice when you try it, it's dependent on how large the JPanel is, not the JFrame.