I'm trying to make my own custom border, and I have done this through overriding the paint function in the JFrame. The problem which I have run into, is the fact that paint is being called after the constructor, causing it to paint the window over my controls. Because of this, my table only appears when I happen to click on where it is in the JFrame. I was wondering if there is a way to make the paint function happen before my constructor, or if there is a better way to create a custom border. Here is my code:
public class GuiMain extends JFrame {
int posX=0, posY=0;
JTable serverList;
public GuiMain()
{
this.setUndecorated(true);
this.setLayout(new GridBagLayout());
serverList = new JTable(Variables.servers, Variables.serversHeader);
add(serverList);
this.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e)
{
posX = e.getX();
posY = e.getY();
}
});
this.addMouseMotionListener(new MouseAdapter(){
public void mouseDragged(MouseEvent evt)
{
if(posY <= 20) {
setLocation(evt.getXOnScreen()-posX, evt.getYOnScreen()-posY);
}
}
});
}
public void paint(Graphics g)
{
g.setColor(new Color(100, 100, 100));
g.fillRect(0, 0, Main.width, Main.height);
g.setColor(new Color(70, 70, 70));
g.fillRect(0, 0, Main.width, 20);
}
}
Any help is appreciated! Thanks!
You know that it is not the safest thing to do, overriding paint(...) of a top-level window. What type of "border" are you trying to create? Where is your call to super.paint(g);? Myself, I'd create my own class that extended the AbstractBorder class, and then would use that Border on a JPanel that is the JFrame's contentPane.
For example,
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.AbstractBorder;
#SuppressWarnings("serial")
public class FrameEg extends JPanel {
public static final String FRAME_URL_PATH = "http://th02.deviantart.net/"
+ "fs70/PRE/i/2010/199/1/0/Just_Frames_5_by_ScrapBee.png";
public static final int INSET_GAP = 120;
private BufferedImage frameImg;
private BufferedImage smlFrameImg;
public FrameEg() {
try {
URL frameUrl = new URL(FRAME_URL_PATH);
frameImg = ImageIO.read(frameUrl);
final int smlFrameWidth = frameImg.getWidth() / 2;
final int smlFrameHeight = frameImg.getHeight() / 2;
smlFrameImg = new BufferedImage(smlFrameWidth, smlFrameHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics g = smlFrameImg.getGraphics();
g.drawImage(frameImg, 0, 0, smlFrameWidth, smlFrameHeight, null);
g.dispose();
int top = INSET_GAP;
int left = top;
int bottom = top;
int right = left;
Insets insets = new Insets(top, left, bottom, right);
MyBorder myBorder = new MyBorder(frameImg, insets);
JTextArea textArea = new JTextArea(50, 60);
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
for (int i = 0; i < 300; i++) {
textArea.append("Hello world! How is it going? ");
}
setLayout(new BorderLayout(1, 1));
setBackground(Color.black);
Dimension prefSize = new Dimension(frameImg.getWidth(),
frameImg.getHeight());
JPanel centerPanel = new MyPanel(prefSize);
centerPanel.setBorder(myBorder);
centerPanel.setLayout(new BorderLayout(1, 1));
centerPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
MyPanel rightUpperPanel = new MyPanel(new Dimension(smlFrameWidth,
smlFrameHeight));
MyPanel rightLowerPanel = new MyPanel(new Dimension(smlFrameWidth,
smlFrameHeight));
top = top / 2;
left = left / 2;
bottom = bottom / 2;
right = right / 2;
Insets smlInsets = new Insets(top, left, bottom, right);
rightUpperPanel.setBorder(new MyBorder(smlFrameImg, smlInsets));
rightUpperPanel.setLayout(new BorderLayout());
rightLowerPanel.setBorder(new MyBorder(smlFrameImg, smlInsets));
rightLowerPanel.setBackgroundImg(createBackgroundImg(rightLowerPanel
.getPreferredSize()));
JTextArea ruTextArea1 = new JTextArea(textArea.getDocument());
ruTextArea1.setWrapStyleWord(true);
ruTextArea1.setLineWrap(true);
rightUpperPanel.add(new JScrollPane(ruTextArea1), BorderLayout.CENTER);
JPanel rightPanel = new JPanel(new GridLayout(0, 1, 1, 1));
rightPanel.add(rightUpperPanel);
rightPanel.add(rightLowerPanel);
rightPanel.setOpaque(false);
add(centerPanel, BorderLayout.CENTER);
add(rightPanel, BorderLayout.EAST);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private BufferedImage createBackgroundImg(Dimension preferredSize) {
BufferedImage img = new BufferedImage(preferredSize.width,
preferredSize.height, BufferedImage.TYPE_INT_ARGB);
Point2D center = new Point2D.Float(img.getWidth()/2, img.getHeight()/2);
float radius = img.getWidth() / 2;
float[] dist = {0.0f, 1.0f};
Color centerColor = new Color(100, 100, 50);
Color outerColor = new Color(25, 25, 0);
Color[] colors = {centerColor , outerColor };
RadialGradientPaint paint = new RadialGradientPaint(center, radius, dist, colors);
Graphics2D g2 = img.createGraphics();
g2.setPaint(paint);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
g2.dispose();
return img;
}
private static void createAndShowGui() {
FrameEg mainPanel = new FrameEg();
JFrame frame = new JFrame("FrameEg");
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyPanel extends JPanel {
private Dimension prefSize;
private BufferedImage backgroundImg;
public MyPanel(Dimension prefSize) {
this.prefSize = prefSize;
}
public void setBackgroundImg(BufferedImage background) {
this.backgroundImg = background;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return prefSize;
}
}
#SuppressWarnings("serial")
class MyBorder extends AbstractBorder {
private BufferedImage borderImg;
private Insets insets;
public MyBorder(BufferedImage borderImg, Insets insets) {
this.borderImg = borderImg;
this.insets = insets;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width,
int height) {
g.drawImage(borderImg, 0, 0, c);
}
#Override
public Insets getBorderInsets(Component c) {
return insets;
}
}
Which would look like so:
Related
I have two child panels and one parent panel (background). My goal is to resize JLabel icon in firstPanel, when main panel is resized. I tried to use StretchIcon, but it works only when adding JLabel icon to main.
My code now:
import darrylbu.icon.StretchIcon;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class Task {
JFrame frame;
JPanel main;
public static void main(String args[]) {
new Task();
}
public Task() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(600, 400));
main = mainPanel();
frame.add(main);
main.add(firstPanel());
main.add(secondPanel());
frame.pack();
frame.setVisible(true);
}
private JPanel mainPanel(){
JPanel main_panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
BufferedImage background = null;
try {
background = ImageIO.read(new URL("https://jpegshare.net/images/17/b0/17b0bad019ea5e37c84a5147a33b0ce7.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(background, 0, 0, this.getWidth(), this.getHeight(), this);
}
};
main_panel.setLayout(new OverlayLayout(main_panel));
main_panel.setLayout(new GridLayout(1, 2));
return main_panel;
}
private JPanel firstPanel() {
JPanel first_panel = new JPanel();
first_panel.setOpaque(false);
BufferedImage image = null;
try {
image = ImageIO.read(new URL("https://jpegshare.net/images/7a/f3/7af3bfc51cb1170be9f5655d643147d7.png"));
} catch (IOException e) {
e.printStackTrace();
}
StretchIcon img = new StretchIcon(image);
JLabel icon = new JLabel(img);
first_panel.add(icon);
first_panel.setLayout(getLayout());
return first_panel;
}
private JPanel secondPanel(){
JPanel second_panel = new JPanel() {
#Override
public Dimension getMaximumSize() {
return new Dimension(300, 400);
}
#Override
public void paintComponent(Graphics g) {
BufferedImage image = null;
try {
image = ImageIO.read(new URL("https://jpegshare.net/images/17/bc/17bc21f519133ca31f857a65c897925a.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
g.drawImage(image, 0, 0,
getWidth() / 2, getHeight() / 2, this);
}
};
second_panel.setLayout(new BoxLayout(second_panel, BoxLayout.Y_AXIS));
String [] resources = {"flowers", "nyanko", "tutturu~"};
for(String s : resources){
JLabel label = new JLabel(0 + " " + s);
label.setFont(new Font("Serif", Font.BOLD, 18));
second_panel.add(label);
}
return second_panel;
}
private GridBagLayout getLayout() {
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.rowHeights = new int[]{0, 0, 0, 0};
gridBagLayout.rowWeights = new double[]{0.0, 0.0, 1.0, 1.0};
gridBagLayout.columnWidths = new int[]{0, 0, 0, 0};
gridBagLayout.columnWeights = new double[]{0.0, 0.0, 1.0, 1.0};
return gridBagLayout;
}
}
You can solve this with one resize listener attached to main panel. I assume that you want to resize JLabel exactly how much you resized your main panel. Here is how you can achieve that:
private Dimension main_size = null; //Inital Dimension of main JPanel
main.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
//This method is called everytime main panel is resized
if((main_size==null) ||
(main_size.width==0 && main_size.height==0)) {
main_size=main.getSize();
}
updateJLabelSize(icon,e.getComponent().getSize());
}
});
//Method for updating JLabel size
private void updateJLabelSize(JLabel icon,Dimension newSize) {
int heightDifference = newSize.height - main_size.height;
int widthDifference = newSize.width - main_size.width;
icon.setSize(new Dimension(icon.getWidth() + widthDifference,
icon.getHeight()+heightDifference));
main_size = newSize;
}
Hi I need to display a large content(its graphical data) of data in single, so I tried following code.
canvas.setPreferredSize(new Dimension(3000, 300));
canvas.setBackground(Color.blue);
JScrollPane jsp = new JScrollPane(canvas);
setPreferredSize(new Dimension(600, 500));
setLayout(new GridLayout(1, 0, 5, 0));
jsp.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println(e.getValue());
repaint();
}
});
add(jsp);
this is my MyCanvas class
class MyCanvas extends Canvas {
#Override
public void paint(Graphics g) {
super.paint(g);
System.out.println("paint");
g.setColor(Color.YELLOW);
for (int i = 0; i < 100; i++) {
g.drawString(""+i, i*30, 100);
// g.drawLine(10, 10, 20, 20);
}
}
}
but problem is that when I am scrolling window I cannot see full content as I expected it should print 100 numbers but not printed actually, can any one correct me?
see the result here
I recommend that you avoid mixing AWT and Swing components together (or if you absolutely must do this, then you have to make sure you understand the pitfalls and fully jump through all the necessary hoops.
Myself, I'd extend JPanel, I'd be sure that its preferredSize was where I want it, since this will determine how big it will be within the JScrollPane.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyScrollExample extends JPanel {
private static final int MAX = 100;
private MyPanel myPanel = new MyPanel(MAX);
public MyScrollExample() {
JScrollPane scrollPane = new JScrollPane(myPanel);
scrollPane.getViewport().setPreferredSize(new Dimension(600, 200));
add(scrollPane);
}
private static void createAndShowGui() {
MyScrollExample mainPanel = new MyScrollExample();
JFrame frame = new JFrame("MyScrollExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyPanel extends JPanel {
private static final Color BG = Color.BLUE;
private static final Color FG = Color.YELLOW;
private static final int WIDTH_GAP = 30;
private static final int HEIGHT_GAP = 100;
private int max;
public MyPanel(int max) {
setBackground(BG);
this.max = max;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(FG);
for (int i = 0; i < max; i++) {
g.drawString("" + i, i * WIDTH_GAP, HEIGHT_GAP);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
int w = (WIDTH_GAP + 1) * max;
int h = HEIGHT_GAP * 3;
return new Dimension(w, h);
}
}
I've a class extending JLabel. This JLabel has a particolar shape and I draw that in the method paintComponent. I want to show a text in the center of the jLabel but this text is not shown. Could anyone help me.
My simple HLabel class in the following:
private class Scudetto extends JLabel {
private static final long serialVersionUID = 1L;
public Scudetto(String line_point)
{
super(line_point, SwingUtilities.CENTER);
this.setOpaque(true);
this.setBackground(Color.BLACK);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension d = this.getSize();
int[] x = { 0, d.width, d.width, d.width / 2, 0 };
int[] y = { 0, 0, d.height / 2, d.height, d.height / 2 };
g.setColor(Color.WHITE);
g.fillPolygon(x, y, 5);
g.setColor(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(10, 20);
}
}
I want to show a text in the center of the jLabel but this text is not shown.
The super.paintComponent() will paint the text, but then your custom painting will paint the polygon over top of the text.
Don't override the JLabel. Instead you can create a PolygonIcon. Then you add the Icon and text to the JLabel.
You can have the text centered on the label by using:
JLabel label = new JLabel("your text");
label.setIcon( polygonIcon );
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.CENTER);
Here is a simple example of creating a rectangular Icon:
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);
JLabel label = new JLabel( icon );
label.setText("" + i);
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.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);
}
}
I'll let you modify the code for a polygon.
You can also check out Playing With Shapes for some fun ways to create an Icon of different shapes.
I have created a custom JSlider that is used to zoom in and out on an image. I want to add a scroll bar when the image becomes to large to fit into my 400x400 frame so that the user is able to pan across the image, there should not be a scroll bar if the image fits the frame. I am very new to Swing so any help would be greatly appreciated I cant seem to get anything to work.
public class GraphicsOnly extends JComponent implements ChangeListener {
JPanel gui;
/** Displays the image. */
JLabel imageCanvas;
Dimension size;
double scale = 1.0;
private BufferedImage image;
public GraphicsOnly() {
size = new Dimension(10,10);
setBackground(Color.black);
try {
image = ImageIO.read(new File("car.jpg"));
} catch (IOException ex) {
}
}
public void setImage(Image image) {
imageCanvas.setIcon(new ImageIcon(image));
}
public void initComponents() {
if (gui==null) {
gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(5,5,5,5));
imageCanvas = new JLabel();
JPanel imageCenter = new JPanel(new GridBagLayout());
imageCenter.add(imageCanvas);
JScrollPane imageScroll = new JScrollPane(imageCenter);
imageScroll.setPreferredSize(new Dimension(300,100));
gui.add(imageScroll, BorderLayout.CENTER);
}
}
public Container getGui() {
initComponents();
return gui;
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider)e.getSource()).getValue();
scale = value/100.0;
repaint();
revalidate();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double x = (w - scale * imageWidth)/2;
double y = (h - scale * imageHeight)/2;
AffineTransform at = AffineTransform.getTranslateInstance(x,y);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
setImage(image);
}
public Dimension getPreferredSize() {
int w = (int)(scale*size.width);
int h = (int)(scale*size.height);
return new Dimension(w, h);
}
private JSlider getControl() {
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 500, 50);
slider.setMajorTickSpacing(50);
slider.setMinorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(this);
return slider;
}
public static void main(String[] args) {
GraphicsOnly app = new GraphicsOnly();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(app.getGui());
app.setImage(app.image);
// frame.getContentPane().add(new JScrollPane(app));
frame.getContentPane().add(app.getControl(), "Last");
frame.setSize(700, 500);
frame.setLocation(200,200);
frame.setVisible(true);
}
}
This version works. There were a number of problems with the attempt seen above, including that it was now mixing component painting with custom painting. I adapted the paintComponent method to instead paint a scaled image.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;
import java.net.URL;
import javax.imageio.ImageIO;
public class GraphicsOnly extends JComponent implements ChangeListener {
JPanel gui;
/**
* Displays the image.
*/
JLabel imageCanvas;
Dimension size;
double scale = 1.0;
private BufferedImage image;
public GraphicsOnly() {
size = new Dimension(10, 10);
setBackground(Color.black);
try {
image = ImageIO.read(new URL("http://i.stack.imgur.com/7bI1Y.jpg"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setImage(Image image) {
imageCanvas.setIcon(new ImageIcon(image));
}
public void initComponents() {
if (gui == null) {
gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
imageCanvas = new JLabel();
JPanel imageCenter = new JPanel(new GridBagLayout());
imageCenter.add(imageCanvas);
JScrollPane imageScroll = new JScrollPane(imageCenter);
imageScroll.setPreferredSize(new Dimension(300, 100));
gui.add(imageScroll, BorderLayout.CENTER);
}
}
public Container getGui() {
initComponents();
return gui;
}
public void stateChanged(ChangeEvent e) {
int value = ((JSlider) e.getSource()).getValue();
scale = value / 100.0;
paintImage();
}
protected void paintImage() {
int w = getWidth();
int h = getHeight();
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
BufferedImage bi = new BufferedImage(
(int)(imageWidth*scale),
(int)(imageHeight*scale),
image.getType());
Graphics2D g2 = bi.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
double x = (w - scale * imageWidth) / 2;
double y = (h - scale * imageHeight) / 2;
AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
at.scale(scale, scale);
g2.drawRenderedImage(image, at);
setImage(bi);
}
public Dimension getPreferredSize() {
int w = (int) (scale * size.width);
int h = (int) (scale * size.height);
return new Dimension(w, h);
}
private JSlider getControl() {
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 500, 50);
slider.setMajorTickSpacing(50);
slider.setMinorTickSpacing(25);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.addChangeListener(this);
return slider;
}
public static void main(String[] args) {
GraphicsOnly app = new GraphicsOnly();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(app.getGui());
app.setImage(app.image);
// frame.getContentPane().add(new JScrollPane(app));
frame.getContentPane().add(app.getControl(), "Last");
frame.setSize(700, 500);
frame.setLocation(200, 200);
frame.setVisible(true);
}
}
That is what i want to achieve:
As you see, horizontal scroll is changed and a JLabel("text") should be added in the same line. Currently i find the way to change horizontal scroll (like on image), but i can't find any way to add JLabel("text") in the place, where it is placed on the image.
Any suggestions? Thanks in advance!
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneLayout;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(300, 300);
JPanel myPanel = new JPanel();
myPanel.add(new JLabel("Check Check Check Check Check Check Check Check"));
MyScrollPane scrollPane = new MyScrollPane(myPanel);
jFrame.add(scrollPane);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
}
class MyScrollPane extends JScrollPane {
JLabel label = new JLabel("text");
public MyScrollPane(Component view) {
super(view, VERTICAL_SCROLLBAR_ALWAYS, HORIZONTAL_SCROLLBAR_ALWAYS);
this.setLayout(new MyLayout(label));
add(label);
}
}
class MyLayout extends ScrollPaneLayout {
JLabel label;
public MyLayout(JLabel aLabel) {
super();
label = aLabel;
}
public void layoutContainer(Container parent) {
super.layoutContainer(parent);
hsb.setSize(hsb.getWidth() - 100, hsb.getHeight()); // drift
Point location = hsb.getLocation();
label.setLocation(location.x + 12, location.y - 12);
}
}
You might want to consider making your own implementation of JScrollPane. It may sound scary, but in essence all a JScrollPane is is 2 JScrollBars and some graphics logic calling g.translate() If you play around with g.translate you'll see that it's pretty easy to scroll your own stuff.
The advantage of making your own component is that you have full command over layout, display and events. This is the route I would take if I were in your position.
Here's my attempt:
import java.awt.*;
import java.awt.font.*;
import javax.swing.*;
import javax.swing.border.*;
public class Test2 {
public JComponent makeUI() {
JPanel myPanel = new JPanel();
myPanel.add(new JLabel("Check Check Check Check Check Check Check Check"));
JScrollPane scrollPane = new JScrollPane(myPanel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JScrollBar hsb = scrollPane.getHorizontalScrollBar();
hsb.setBorder(new StringBorder(hsb, "Test"));
JPanel p = new JPanel(new BorderLayout());
p.add(scrollPane);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new Test2().makeUI());
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class StringBorder implements Border {
private final JComponent parent;
private final Insets insets;
private final Rectangle rect;
private final String str;
public StringBorder(JComponent parent, String str) {
this.parent = parent;
this.str = str;
FontRenderContext frc = new FontRenderContext(null, true, true);
rect = parent.getFont().getStringBounds(str, frc).getBounds();
rect.width = Math.max(rect.width, 100);
insets = new Insets(0,5,0,rect.width);
}
#Override public Insets getBorderInsets(Component c) {
return insets;
}
#Override public boolean isBorderOpaque() {
return false;
}
#Override public void paintBorder(
Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2 = (Graphics2D)g;
float tx = x + width - insets.right + insets.left;
float ty = y - rect.y + (height - rect.height)/2;
g2.setPaint(Color.BLACK);
g2.drawString(str, tx, ty);
}
}
Probably the best way to achieve something like this would be to use your own layout with a JScrollPane. Here is an example that allows any component as lower-left corner component:
public class CustomScrollPaneLayout extends ScrollPaneLayout {
#Override
public void layoutContainer(Container parent) {
super.layoutContainer(parent);
JScrollBar scrollBar = getHorizontalScrollBar();
if (lowerLeft == null || !lowerLeft.isVisible() || scrollBar == null)
return;
Dimension size = lowerLeft.getPreferredSize();
Rectangle bounds = lowerLeft.isVisible()
? lowerLeft.getBounds() : scrollBar.getBounds();
if (size.width > bounds.getWidth()) {
int right = scrollBar.getX()+scrollBar.getWidth();
if (size.width + scrollBar.getMinimumSize().width > right)
size.width = right - scrollBar.getMinimumSize().width;
if (bounds.x + size.width < scrollBar.getX())
size.width = scrollBar.getX() - bounds.x;
lowerLeft.setBounds(bounds.x, bounds.y, size.width, bounds.height);
int x = bounds.x + size.width;
scrollBar.setBounds(x, bounds.y, right - x, bounds.height);
}
lowerLeft.setVisible(true);
}
}
Please note that you need to use a horizontal scrollbar policy of ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS if you want your control to be always visible.