Inside my paintComponent() method, I have a drawRect() that paints the background of a jpanel. But because the jbutton is drawn on the screen before the paintComponent() method gets called, the jbutton is blocked out by the drawRect. Does anyone know how to fix this? My guess is to add the jbutton before repaint gets called, but I don't know how to do that?
Some code:
public Frame(){
add(new JButton());
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawRect(0,0,screenwidth,screenheight); //paints the background with a color
//but blocks out the jbutton.
}
Now, firstly, I will tell you what you're doing wrong here -- JFrame is not a JComponent, and has no paintComponent for you to override. Your code will probably never be called. Aside from that, drawRect merely draws a rectangle -- it does not fill one.
However, I believe there is a proper way to do this.
Since you're using a JFrame, you should take advantage of the container's layered pane via JFrame.getLayeredPane.
A layered pane is a container with depth such that overlapping components can appear one on top of the other. General information about layered panes is in How to Use Layered Panes. This section discusses the particulars of how root panes use layered panes.
Root panes are covered in How to Use Root Panes, a part of the Java Tutorials. A layered pane is a child of the root pane, and a JFrame, as a top-level container, utilizes an underlying JRootPane.
Anyways, since you're interested in creating a background, see the following diagram for how a layered pane generally looks inside a top-level container:
The table below describes the intended use for each layer and lists the JLayeredPane constant that corresponds to each layer:
Layer Name - Value - Description
FRAME_CONTENT_LAYER - new Integer(-30000) - The root pane adds the menu bar and content pane to its layered pane at this depth.
Since we want to specify our background is behind the content, we first add it to the same layer (JLayeredPane.FRAME_CONTENT_LAYER), as follows:
final JComponent background = new JComponent() {
private final Dimension size = new Dimension(screenwidth, screenheight);
private Dimension determineSize() {
Insets insets = super.getInsets();
return size = new Dimension(screenwidth + insets.left + insets.right,
screenheight + insets.bottom + insets.top);
}
public Dimension getPreferredSize() {
return size == null ? determineSize() : size;
}
public Dimension getMinimumSize() {
return size == null ? determineSize() : size;
}
protected void paintComponent(final Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, screenwidth, screenheight);
}
};
final JLayeredPane layeredPane = frame.getLayeredPane();
layeredPane.add(background, JLayeredPane.FRAME_CONTENT_LAYER);
Now, to make sure we draw our background before the content, we use JLayeredPane.moveToBack:
layeredPane.moveToBack(background);
I did this really quick test. As HovercraftFullOfEels has pointed out. JFrame does not have a paintComponent, so I used a JPanel instead.
Which was produced by this code
public class PanelTest extends JPanel {
private JButton button;
public PanelTest() {
setLayout(new GridBagLayout());
button = new JButton("Can you see me ?");
add(button);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle bounds = button.getBounds();
bounds.x -= 10;
bounds.y -= 10;
bounds.width += 20;
bounds.height += 20;
g.setColor(Color.RED);
((Graphics2D)g).fill(bounds);
}
}
I've I try and replicate the issue by using paintComponents on the JFrame, I don't see the rectangle. Even if I overwrite paint on the JFrame, the rectangle is still painted under the button (Not that I would ever recommend doing either).
The problem is, you haven't given us enough code to know what's going wrong
ps - drawRect won't "fill" anything
I encountered this before, although not jframe specifically and not the kind of the scenario that you have. Try this code,
this.getContentPane.repaint();
on your jframe. Im not sure about this, but give it a try.
Related
I have been experimenting with drawing on a JFrame, so I could use these experiments in the future for a program I might create. However, I have found a problem that I am not able to solve:
How to draw stuff while having a timer set up.
public static void MyTimer() {
JFrame frame = new JFrame("Colors");
int width = 700;
int height = 700;
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.BLACK);
frame.pack();
frame.setSize(width, height);
frame.setVisible(true);
frame.setResizable(false);
TimerTask task;
task = new TimerTask() {
int a = 2;
#Override
public void run(Graphics g) {
g.drawRect(a, 2, a + 66, 68);
g.fillRect(a, 2, a + 66, 68);
a = a + 20;
}
};
timer.schedule(task, 0, 1000);
}
As you can see, I am trying to draw a new square every second. The problem is, I get an error in the code:
method does not override or implement a method from a supertype
How can I fix this?
How can I fix this?
The run() method does not take a parameter. Get rid of the Graphics parameter. That will get rid of the compile error.
However, that still will not help with your painting.
Instead you need to override the paintComponent(...) method of a JPanel then you add the panel to the frame. Then you use the Graphics object passed to the paintComponent() method to do your painting.
Read the section from the Swing tutorial on Custom Painting for more information and working examples to get you started.
Also you should NOT be using a TimerTask for animation. You should be using a Swing Timer. Then in the actionPerformed(...) method of the ActionListener you would change the properties of your custom painting (ie in your case add a new square object to be painted) and then invoke repaint() on the panel.
, I am trying to draw a new square every second
Check out the DrawOnImage example found in Custom Painting Approaches. It will show you how to add a Rectangle object to a BufferedImage.
I use a JLabel to view an image in a JFrame. I load it from a file with an ImageIcon.
JFrame frame = new JFrame(String);
frame.setLocationByPlatform(true);
frame.setSize(500, 500);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel cpu = new JLabel(new ImageIcon(String));
cpu.setLocation(20, 20);
cpu.setSize(20, 460);
frame.add(cpu);
frame.setVisible(true);
I can't set location and size of the JLabel because it is done automatically.
I have to manually set these values because I want to truncate the image (vertical progress bar).
One way is to just paint the image:
final ImageIcon icon = new ImageIcon(path);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(icon.getImage(), 0, 0, getWidth(), getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
};
frame.add(panel);
The getWidth() and getHeight() in drawImage will force the image to stretch the size of the panel. Also the getPreferredSize() will give a size to the panel.
If want the panel to stay that size, then make sure it's parent container has a layout manager that will respect preferred sizes, like FlowLayout or GridBagLayout. If you want the panel to be stretched, the make sure it's parent container has a layout manager that disregards the preferred size, like BorderLayout or GridLayout
See Performing Custom Painting for more info on painting.
See Laying Out Components Within a Container to learn more about layout managers (which you should be using). Also see Why is it frowned upon to use a null layout in SWING? and What's wrong with the Null Layout in Java?
The size of your original is (58 x 510). If you want to display the image at a fixed size of 20 x 420, then you should scale your image to that size to you don't truncate any of the image. One way to do that is to use the Image.getScaledImage(...) method. Then you just add the scaled image to the label.
If you want to position your label (20, 20) from the top left of the panel, then you can add an EmptyBorder to the panel or the label.
Use the features of Swing.
Edit:
I want to truncate the image
Read your Image into a BufferedImage. Then you can use the getSubImage(...) method to get an image any size you want. Then you can use the sub image to create your ImageIcon and add it to a label.
The LayoutManager is auto-sizing your components, not allowing you to resize manually.
If you want to get away from this, you can turn off the LayoutManager.
frame.setLayout(null);
Please note that you should not use the null layout.
I am trying to add a JLabel under the boards that is painted with graphics. I set the x and y position of JLabel somewhere under the board
pName = new JLabel("Yoooooo");
pName.setBounds(180,500,50,50);
this.add(pName);
However I can't view it when I run the code. What can be the reason?
Edit: Now I can view it thx to Andrew but I can't locate it to the position that I want.
JLabel should be under the board.
pName.setBounds(180,500,50,50);
seems not working. Why can it be?
public class EnemyPanel extends JPanel{
private char enemyBoard[][] = new char[10][10]; //to keep state of squares
private Rectangle r[][] = new Rectangle[10][10];//to give coordinates and boundaries to squares
private int size;
private JLabel pName;
public EnemyPanel()
{
size=Constant.rectSize;
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
enemyBoard[i][j]='*'; //initialization type
r[i][j]= new Rectangle(j*size+30,i*size+30, size, size);
}
}
pName = new JLabel("Yoooooo");
pName.setBounds(180,500,50,50);
this.add(pName);
}
public void paint(Graphics g){
super.paintComponent(g);
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
if(enemyBoard[i][j]=='!'){
//hit square's color is changed to white
g.setColor(Color.white);
}
else if(enemyBoard[i][j]=='$')
//miss square's color is changed to gray
g.setColor(Color.gray);
else
//undiscovered ones are green
g.setColor(Color.green);
g.fill3DRect((int)r[i][j].getX() ,(int)r[i][j].getY(),(int)r[i][j].getWidth(), (int)r[i][j].getHeight(), true);
}
}
}
}
Here is the output:
Once you override paint(Graphics g) you are on your own on painting the component. This means that no matter what other stuff you do outside paint, it may not count much as the real paint happens in your custom implementation and not in the default JPanel one.
My first problem was that I couldn't view the JLabel component.
According to Andrew's comment, I solved this problem.
If you are using other components in your panel, you should use paintComponent other than paint.
Secondly, I couldn't view my JLabel where I wanted. So In order to set a specific position to JLabel, you should set the JPanel layout to null.
this.setLayout(null) solved my second problem.
So, I have a grid layout which stores JScrollPane's in each cell. These are also put into an array for other purposes. The "View" extends "JPanel" so it's just a regular panel with image support. The application starts up with cell's filled with scrollPane's that contain the View which doesn't have a image yet.
At that point I see no scrollbar, but that doesn't matter since there is nothing inside the JPanel. As soon as I open an image and use drawImage in the paintComponenet of the JPanel I don't see scrollbar's showing up. Here's how I create the grid and the Scrollpane
private void createContentPane()
{
GridLayout gridLay = new GridLayout(GRID_ROWS, GRID_COLUMNS);
perspectiveTbl = new JScrollPane[NUM_PERSPECTIVE];
mainPane = new JPanel();
mainPane.setLayout(gridLay);
int idx = 0;
while(idx < perspectiveTbl.length)
{
perspectiveTbl[idx] = new JScrollPane(new View(modelImage));
mainPane.add(perspectiveTbl[idx]);
idx++;
}
this.getContentPane().add(mainPane, BorderLayout.CENTER);
}
I'm not exactly sure why the scrollbar's aren't showing up, should they have been set inside the panel for the image?
Here's an image of the application, as you can see the picture of the shoe does not receive scrollbar's so there is no way to view the rest of the picture:
Picture
You can either user not JPanel with image but usual JLabel with the image
or
call setPreferredSize() for the panels to reflect the image's size.
Thanks for the hint Stanislav, I actually figured it out and got it working an hour ago, but you did give the right path to fix it with the preferredSize attribute. I ended up re-implemented getPreferredSize with the size of the image inside the panel, added revalidate to the paint event so that the bars show up as soon as the image is loaded.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
this.getViewScrollPane().revalidate();
}
public Dimension getPreferredSize()
{
if(image != null)
return new Dimension(image.getWidth(),image.getHeight());
else
return super.getPreferredSize();
}
I'm attempting to create my own custom ToolTip for a program I've ported to Java, I'm trying to match the original programs ToolTips (it was written in Delphi). I've got some code that allows me to draw "inside" a ToolTip but for some reason, if I Override paint(Graphics g, JComponent c) and leave it blank it still draws a ToolTip, and anything I attempt to draw will be drawn "inside" this little boxed ToolTip and I can't draw "outside" of it.
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.basic.BasicToolTipUI;
class MultiLineToolTipUI extends BasicToolTipUI {
#Override
public void paint(Graphics g, JComponent c) {
//int mY = 0;
//int mX = 0;
//int xPoints[] = {mX, mX, mX + 15};
//int yPoints[] = {mY, mY + 25, mY + 25};
//Polygon p = new Polygon(xPoints, yPoints, 3);
//g.setColor(Color.BLACK);
//g.fillPolygon(p);
//g.fillRoundRect(mX, mY, 100, 50, 30, 30);
}
public static void main (String args[])
{
JButton button = new JButton ("Mouse Over ME!") {
public JToolTip createToolTip() {
MultiLineToolTip tip = new MultiLineToolTip();
tip.setComponent(this);
return tip;
}
};
//JButton button = new JButton("Mouse Over ME!");
button.setToolTipText("Hello, World");
JFrame frame = new JFrame("Basic SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( button );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
static class MultiLineToolTip extends JToolTip
{
public MultiLineToolTip()
{
setUI(new MultiLineToolTipUI());
}
}
}
This is what I have, and like I said, even without the lines in paint it's drawing on it's own.
Any advice to get around this? Or a better way to go about what I'm trying to do?
CLARIFICATION: The first answer by Camickr was very helpful, however I should clarify my goal is to get the box that is automatically drawn from somewhere outside of paint to go away, or be invisible.
The size of the tool tip is determined by the text. Add:
System.out.println( c.getSize() );
to the paint(...) method to see the size of the tool tip. You are trying to paint outside its bounds. If you want to override the default size then you need to set the preferred size yourself. I think you want:
public Dimension getPreferredSize(JComponent c)
{
return new Dimension(100, 50);
}
Edit: A tooltip is a component with a border and a background. If you want to remove them you can use:
tip.setOpaque(false);
tip.setBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0));
This will only work when to tooltip is fully contained withing the frame. When the tooltip is displayed outside the bounds of the frame, then the tooltip is added to a JWindow, in which case you will see the background of the window. I don't know how to disable this behaviour because all Swing components must be painted within the bounds of a top level container.