Intro
I created a class ChatView that extends JPanel. I added it as a parameter to my JScrollPane (to get the scrolling effect) and overrode the paintComponent method in hope of setting a background image:
new JScrollPane(new ChatView){
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon background = new ImageIcon("files/background.png");
Image image = background.getImage();
image.getScaledInstance(980, 600, java.awt.Image.SCALE_SMOOTH);
if (image != null)
{
g.drawImage(image,0,0,this.getWidth(),this.getHeight(),null);
}
}
}
problem
This doesn't seem to do anything; however, the same method works on my class ChatView, which extends JPanel. the problem with adding it to my JPanel is that it stretches every time I add a new component that extends outside of the setPrefferredSize() of my JScrollPane; If I do not revalidate() and repaint() my JPanel, it cuts off or doesn't add the components. That's why I think it is necessary to add it to the JScrollPane, but how? or am i on the wrong track?
Code: attributes of my JScrollPane
public void addScroll(JScrollPane pnl, String str, int w, int h){
pnl.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
pnl.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
pnl.setSize(new Dimension(w, h));
pnl.setMinimumSize(new Dimension(w, h));
pnl.setPreferredSize(new Dimension(w, h));
pnl.getVerticalScrollBar().setUnitIncrement(16);
pnl.setBorder(BorderFactory.createLineBorder(black));
this.add(pnl, str);
}
Static Image behind JTextPane text in JScrollPane
^^link where I found the solution!! Below is a clean cheatsheet :)
JPanel jPanel = new JPanel() {
this.setOpaque(false);
};
JViewport viewport = new JViewport() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon background = new ImageIcon("images/background.png");
Image image = background.getImage();
image.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH);
if (image != null) {
g.drawImage(image, 0, 0, w, h, null);
}
}
};
jScrollPane.setViewport(viewport);
jScrollPane.setViewportView(jPanel);
Related
//Calling function
ImagePanel Panel_2 = new ImagePanel(new ImageIcon("C:/Users/kagarwal/Downloads/intacct_logo_standard_web.png").getImage());
Panel_2.add(new JButton());
Panel_2.revalidate();
//Called function
public class ImagePanel extends JPanel {
private Image img;
public ImagePanel(String img) {
this(new ImageIcon(img).getImage());
}
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
Requirement is: that JPanel2 needs to have a background image, and on top of that we need to add JButton. But, issue here is that the newly added JButton does not appears in the given JPanel, it only shows background image. Am i missing refresh ?
The problem is in paintComponent, where you only ask the graphics object to draw the image.
But you should call the superclass paintComponent method by invoking super.paintComponent() passing the graphics object, in order to have all the components of the panel correctly displayed.
I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).
I tried all these options:
text.setEditable(false);
text.setFocusable(false);
text.setEnabled(false);
text.setHighlighter(null);
but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?
You can't simply set the background color of a component to "transparent" and expect Swing to deal with it. You need to flag the component as transparent (setOpaque(false)), only then will Swing's repaint manager know that it has to update the components under it.
This then leads you to the problem of how to paint the background (as Swing only has the concept of fully opaque or fully transparent).
To do this, you need to supply your own paint routines (override paintComponent, fill the background, update the component)...this is essentially what Rob Camick's solution is doing, it just provides a nice wrapper component for you...
Below is an example of using a JLabel using text wrapped in HTML and a JTextArea, both updated to support "translucency"...
Using a JLabel
Using a JTextArea
Now, it would be a lot easier to achieve using Rob's wrapper class, but this provides you with the idea of what is going wrong and what you would need to do to fix it.
public class MultiLineLabel {
public static void main(String[] args) {
new MultiLineLabel();
}
public MultiLineLabel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new BackgroundPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TransclucentLabel extends JLabel {
public TransclucentLabel(String text) {
super(text);
setVerticalAlignment(TOP);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Insets insets = getInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fillRect(x, y, width, height);
super.paintComponent(g);
}
}
public class TransclucentTextArea extends JTextArea {
public TransclucentTextArea(String text) {
super(text);
setOpaque(false);
setLineWrap(true);
setWrapStyleWord(true);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Insets insets = getInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fillRect(x, y, width, height);
super.paintComponent(g);
}
}
public class BackgroundPane extends JPanel {
private BufferedImage background;
public BackgroundPane() {
setLayout(new BorderLayout());
// addLabel();
addTextArea();
setBorder(new EmptyBorder(24, 24, 24, 24));
try {
background = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
protected void addTextArea() {
StringBuilder sb = new StringBuilder(128);
sb.append("I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).\n\n");
sb.append("I tried all these options:\n\n");
sb.append("text.setEditable(false);\n");
sb.append("text.setFocusable(false);\n");
sb.append("text.setEnabled(false);\n");
sb.append("text.setHighlighter(null);\n\n");
sb.append("but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?\n");
add(new TransclucentTextArea(sb.toString()));
}
protected void addLabel() {
StringBuilder sb = new StringBuilder(128);
sb.append("<html>");
sb.append("<p>I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).</p><br>");
sb.append("<p>I tried all these options:</p><br>");
sb.append("<p>text.setEditable(false);<br>");
sb.append("text.setFocusable(false);<br>");
sb.append("text.setEnabled(false);<br>");
sb.append("text.setHighlighter(null);</p><br>");
sb.append("<p>but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?</p>");
add(new TransclucentLabel(sb.toString()));
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
}
}
}
I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).
I tried all these options:
text.setEditable(false);
text.setFocusable(false);
text.setEnabled(false);
text.setHighlighter(null);
but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?
You can't simply set the background color of a component to "transparent" and expect Swing to deal with it. You need to flag the component as transparent (setOpaque(false)), only then will Swing's repaint manager know that it has to update the components under it.
This then leads you to the problem of how to paint the background (as Swing only has the concept of fully opaque or fully transparent).
To do this, you need to supply your own paint routines (override paintComponent, fill the background, update the component)...this is essentially what Rob Camick's solution is doing, it just provides a nice wrapper component for you...
Below is an example of using a JLabel using text wrapped in HTML and a JTextArea, both updated to support "translucency"...
Using a JLabel
Using a JTextArea
Now, it would be a lot easier to achieve using Rob's wrapper class, but this provides you with the idea of what is going wrong and what you would need to do to fix it.
public class MultiLineLabel {
public static void main(String[] args) {
new MultiLineLabel();
}
public MultiLineLabel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new BackgroundPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TransclucentLabel extends JLabel {
public TransclucentLabel(String text) {
super(text);
setVerticalAlignment(TOP);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Insets insets = getInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fillRect(x, y, width, height);
super.paintComponent(g);
}
}
public class TransclucentTextArea extends JTextArea {
public TransclucentTextArea(String text) {
super(text);
setOpaque(false);
setLineWrap(true);
setWrapStyleWord(true);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Insets insets = getInsets();
int x = insets.left;
int y = insets.top;
int width = getWidth() - (insets.left + insets.right);
int height = getHeight() - (insets.top + insets.bottom);
g2d.setColor(new Color(255, 0, 0, 128));
g2d.fillRect(x, y, width, height);
super.paintComponent(g);
}
}
public class BackgroundPane extends JPanel {
private BufferedImage background;
public BackgroundPane() {
setLayout(new BorderLayout());
// addLabel();
addTextArea();
setBorder(new EmptyBorder(24, 24, 24, 24));
try {
background = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
protected void addTextArea() {
StringBuilder sb = new StringBuilder(128);
sb.append("I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).\n\n");
sb.append("I tried all these options:\n\n");
sb.append("text.setEditable(false);\n");
sb.append("text.setFocusable(false);\n");
sb.append("text.setEnabled(false);\n");
sb.append("text.setHighlighter(null);\n\n");
sb.append("but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?\n");
add(new TransclucentTextArea(sb.toString()));
}
protected void addLabel() {
StringBuilder sb = new StringBuilder(128);
sb.append("<html>");
sb.append("<p>I put a JTextArea in a JPanel. This JPanel has a picture on the background, and the JTextArea is translucent (translucid red) to show the background through. I don't want the user to be able to edit or select the text, I want it to act just as a JLabel (but with multiple lines and easy to word wrap and adjust to screen resize).</p><br>");
sb.append("<p>I tried all these options:</p><br>");
sb.append("<p>text.setEditable(false);<br>");
sb.append("text.setFocusable(false);<br>");
sb.append("text.setEnabled(false);<br>");
sb.append("text.setHighlighter(null);</p><br>");
sb.append("<p>but still some change of color happens as the user drags the mouse over the JTextArea. Anyone knows what is going on?</p>");
add(new TransclucentLabel(sb.toString()));
}
#Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
}
}
}
I am trying to program a board game. I want to load an image of the game board and then load a transparent grid over it. I wrote a custom panel to draw the image and added it to a layered panel as level 0. Then I make a JPanel with a GridLayout and added it at level 1. The layered pane is then put into a scroll pane to account for the background image being kinda large. The hope is to have most of the grid be transparent at any given time but if a player piece enters a square then I will set that square to be a color representing the piece. However when I set the top panel to transparent (by making a call to setOpaque(false)) I just get a white background, no image is present. Why is this?
public class ImagePanel extends JPanel
{
private Image image;
public ImagePanel(Image image)
{
this.image = image;
this.setPreferredSize(new Dimension(936,889));
}
protected void paintComponent(Graphics g)
{
g.drawImage(image, 0, 0, null);
}
}
Here is the code in the main program which creates the panels and nests them. backBoard is the outer frame. It is setVisible later on so that's not an issue.
BufferedImage boardImage = null;
try
{
boardImage = ImageIO.read(new File("Clue Board.jpg"));
}
catch(IOException e)
{
}
ImagePanel background = new ImagePanel(boardImage); //load clue board image
JPanel gameBoard = new JPanel (new GridLayout(24,24)); //yet to add actual squares
gameBoard.setSize(936,889);
gameBoard.setOpaque(false);
JLayeredPane lPane = new JLayeredPane();
lPane.setPreferredSize(new Dimension(936,889));
lPane.add(background, new Integer(0));
lPane.add(gameBoard, new Integer(1));
JScrollPane layerScroller = new JScrollPane(lPane,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
backBoard.add(layerScroller, BorderLayout.CENTER);
Try calling super.paintComponent(..) like so:
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
Dont call JFrame#setSize(..) use an appropriate LayoutManager and override getPrefferedSize(..) of JPanel which will return the correct size and then call pack() on JFrame instance before setting it visible.
Here is an example of how your ImagePanel class should look:
public class ImagePanel extends JPanel
{
private int width,height;
private Image image;
public ImagePanel(Image image)
{
this.image = image;
//so we can set the JPanel preferred size to the image width and height
ImageIcon ii = new ImageIcon(this.image);
width = ii.getIconWidth();
height = ii.getIconHeight();
}
//so our panel is the same size as image
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
}
I'm making an utility to define footholds in a map for my game and i am displaying the preview of the map inside a JPanel that's inside a JScrollPane. I would like to be able to scroll when the map is bigger than the JScrollPane. How should i do that?
Here's a picture
Bigger version
The image of the map fits inside of the scrollpane but the image is actually larger so we don't get to see the whole map.
Some code:
The JPanel class which holds the image inside of the scrollPane
public class MapDisplay extends JPanel {
public MapDisplay() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(0xDFDFDF));
g2d.fillRect(0, 0, 2000, 2000);
if (mapinfo != null) {
if (mapinfo.img != null) {
g2d.drawImage(mapinfo.img, 0, 0, null);
}
}
repaint();
}
}
the scrollPane's declaration
final JScrollPane scrollPane_1 = new JScrollPane(mapDisplay);
scrollPane_1.setBounds(10, 11, 989, 553);
getContentPane().add(scrollPane_1);
add(scrollPane_1);
The MapDisplay has to 'tell' the JScrollPane how big it wants to be. You can do so by implementing the getPreferredSize method of MapDisplay.
public Dimension getPreferredSize() {
return new Dimension(widthOfMap, heightOfMap);
}
Further, do not call repaint() from inside the paintComponent() method, as this results in an infinite loop.