I have a jFrame with a Canvas on it. When I run my program in Windows XP/Vista and resize the window the canvas resizes proportionately along with the window.
However, in Ubuntu linux, when I compile the same java application and resize my window, the Canvas stays the same size.
What do I need to do to make my Canvas resize with my window in both Windows and Linux? What is the deal with the discrepancy?
Main.java
public class Main {
public static void main(String[] args)
{
JFrame frame = new JFrame("BallBounce");
frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
BallCanvas ballCanvas = new BallCanvas();
frame.getContentPane().add(ballCanvas);
frame.getContentPane().add(controlPanel);
frame.pack();
frame.setVisible(true);
}
}
BallCanvas.java
public class BallCavnas extends Canvas {
public BallCanvas()
{
setPreferredSize(new Dimension(640, 400));
setIgnoreRepaint(true);
... various gui controls are wired up here
}
... rest of canvas code
}
Edit: My source code is zipped up here incase someone wants to take a look:
http://www.filedropper.com/ballbounce
I've done the suggestions made by Dave Ray, and it still isn't resizing the Canvas? Remember, it resizes for me fine when I compile this java program and run it in windows. Only in linux does it does this to me. I'm also running Java 6 Sun 1.6.0.10 JVM, if it matters.
alt text http://img158.imageshack.us/img158/7642/screenshotww0.png
Perhaps my canvas is resizing by my BufferStrategy/Graphics aren't resizing ?
Edit 2: From the screenshot, it is definitely set to CENTER:
frame.getContentPane().add(ballCanvas, BorderLayout.CENTER);
frame.getContentPane().add(controlPanel, BorderLayout.SOUTH);
Resolved
Apparently the "Canvas" was getting resized but I was doing something weird with it's buffer strategy that wasn't allowing IT to be resized. I fixed it. Thanks everyone!
Perhaps, the layout manager is just attempting to honor your preferred size.
I would:
A) remove the preferred just to see what happens ( not a very good idea anyway )
or
B) not use canvas in first place but JComponent. After all Canvas is AWT component, and I not pretty sure how they work as today anyway. JComponent is a light weight component and since you're using a JComponent as container they would... mmhhh work better together?
Gee.. I'm giving voodoo programming suggestions now. Better get to work.
C) What have always worked for me. Make an small proof of concept, by adding step by step the stuff in my code. Start with empty canvas, then add the preffered size, then etc. etc. Chances are, the bug is on the paint method :P
Good luck.
:)
Use a border layout instead:
frame.getContentPane().setLayout(new BorderLayout());
BallCanvas ballCanvas = new BallCanvas();
frame.getContentPane().add(ballCanvas, BorderLayout.CENTER);
frame.getContentPane().add(controlPanel, BorderLayout.SOUTH);
Also get rid of setPreferredSize() in favor of frame.setSize() to set the initial size of the display.
Another good solution is put the canvas into an JPanel,
like i did
panel.add(new JPanel() {
#Override
public void paint(Graphics g) {
// do not paint
}
}.add(capture));
and in the canvas function something like
#Override
public void paint(Graphics g) {
Dimension currentSize = getParent().getSize();
int width = currentSize.width;
int height = currentSize.height;
if (offscreenImage == null || !currentSize.equals(offscreenDimension)) {
// call the 'java.awt.Component.createImage(...)' method to get an
// image
offscreenImage = createImage(width, height);
offscreenGraphics = offscreenImage.getGraphics();
offscreenDimension = currentSize;
}
if (image != null) {
offscreenGraphics.drawImage(image, 0, 0, width, height, null);
} else {
offscreenGraphics.setColor(Color.BLACK);
offscreenGraphics.fillRect(0, 0, width, height);
}
//scratch image
g.drawImage(offscreenImage, 0, 0, this);
}
for example. This make it very simple. Take the parent Panel to fit to your needs.
If you followed Dave's advice, esp. putting the ballCanvas in the CENTER, then you must be setting a maximum size for ballCanvas.
Related
I have a JScrollPanel and a JPanel added to it. I would like to draw to the JPanel and make the scrollbars of the JScrollPane appear whenever the drawing exceeds the size of the panel and be able to scroll the drawing both vertically and horizontally.
I have tried consulting with various forums and the official docs and tried a few things (setting the borders, the preferred size, etc.) but none seems to yield the desired effects.
I have a JFrame (with GridBagLayout, btw.) :
JFrame frame1 = new JFrame("Application");
frame1.setVisible(true);
frame1.setMinimumSize(new Dimension(580,620));
frame1.setResizable(false);
frame1.setLocationRelativeTo(null);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The relevant components are :
JPanel panel1 = new JPanel();
JScrollPane scrollPane = new JScrollPane(panel1);
frame1.add(scrollPane, gbc_panel1); //added with layout constraints
JPanel :
panel1.setBackground(Color.BLACK);
panel1.setPreferredSize(new Dimension(500,500));
panel1.setMinimumSize(new Dimension(360,360));
panel1.setMaximumSize(new Dimension(1000,1000));
JScrollPane :
scrollPane.setAutoscrolls(true);
The relevant code from the action event
of a button that does the drawing :
Graphics g;
g = panel1.getGraphics();
panel1.paint(g);
g.setColor(new Color(0,128,0));
/* this is followed by some more code that
does the drawing of a maze with g.drawLine() methods */
The code does the drawing perfectly, I just can't seem to figure it out how to make the scrolling and dynamic resizing happen.
I would appreciate any helpful comments or remarks!
Thank you!
Ultimately rewriting the paint method did the trick as #MadProgrammer suggested. I was just hoping that I could do the painting without having to define my custom JPanel class, but looks like it doesn't work that way.
The custom class looks like this:
class Drawing extends JPanel {
int mazeSize;
public Drawing(JTextField jtf)
{
try {
this.mazeSize = Integer.parseInt(jtf.getText());
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "ERROR! Invalid size value!");
}
} // the constructor gets the size of the drawing from a textField
public Dimension getPreferredSize() {
return new Dimension(mazeSize*10,mazeSize*10);
} //getPreferredSize - this method is used by the scroll pane to adjust its own size automatically
public void drawMaze (Graphics g)
{
/* some irrelevant code that does the desired drawing to the panel by calling g.drawLine()*/
} // drawMaze method that does the de facto drawing
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawMaze(g);
}// paintComponent() #Override method - this was the tricky part
}//Drawing JPanel subclass
It is also worth noting (if some noob like myself happens to stumble upon this question), that after instantiating the new JPanel subclass in the action event, I had to add it to the JScrollPanel in the following way, instead of just simply using its add() method:
Drawing drawPanel = new Drawing(textfield1);
scrollPane.getViewport().add(drawPanel);
Again, thanks for the suggestion!
Once finished with the program (a random maze generator that uses a recursive backtracking algorithm), I will make the source code available at my github profile.
I'm currently trying to create a program that moves a rectangle over a background Image with keyboard keys. The problem I'm facing is that when I draw the components they are simply placed next to each other, instead of the square overlaying the background image. Here's the code to display both the components;
JLayeredPane panel = new JLayeredPane();
panel.setLayout(new FlowLayout());
add(panel);
paintBackground pb = new paintBackground(bimg);
panel.add(pb, 1, 0);
paintPlayer cc = new paintPlayer(startX, startY);
panel.add(cc, 2, 0);
pack();
setVisible(true);
I believe the problem is that the paintPlayer component is set to full size, and there seems to be a background. The paintPlayer component code looks like this:
public Dimension getMinimumSize() {
return new Dimension(800,600);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800,600);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(800,600);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
System.out.println(startX + startY );
g.fillRect(startX, startY, 30, 30);
}
I've had a go at setting the component size to just the size of the rectangle, but that way I can't move the rectangle by using the first two values in fillRect. The background for the rest of the space filled by the component (800x600) seems to be opaque.
When added, the components just display next to each other, like this: https://gyazo.com/57245c518e02778c36ffc89ba75d5a81. How do I go about adding the paintPlayer ontop of the paintBackground, so that it only covers the rectangle on the background Image.
I've done a fair bit of searching but I can't seem to work it out. Perhaps something to do with the layout? One other thing I've noticed is that by doing this, neither the frame or the pane benefit from a setBackground, as it's not visible.
Cheers for any help.
This is the default Constructor of JLayerdPane.
public JLayeredPane() {
setLayout(null);
}
You see it uses normaly AbsolutLayout. And if you read here:
Note: that these layers are simply a logical construct and LayoutManagers will affect all child components of this container without regard for layer settings.
You should understand what is wrong. Check OverlapLayout.
We're about to create an online based Space Invaders-game with implemented graphics. I've been reading about JFrames, JPanels and JLabels in order to create a window with a grid where the ships and monsters will be placed in.
So, here's the thing, I've been looking through the different layouts that exists, but nothing really seems to fit our purpose. I would like a simple JFrame with the possibility of placing JLabel-objects on a certain position (with setBounds(), setLocation() or something similar). This requires setLayout(null) which I've heard isn't a good solution? I was thinking of having objects in a fixed 30x30px size, and a fixed window size of 600x600px (giving me a grid of 20*20).
Anyhow, I've been trying to get it to work with setLayout(null), but without any results. If I apply a layout, say FlowLayout, the ship is visible, but stuck in either LEFT, CENTER or MIDDLE.
public class GUI extends JFrame {
JPanel p = new JPanel(null);
public GUI() {
try{
this.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("graphics/bg.png")))));
}catch(IOException e) {
System.out.println("Image does not exist");
}
this.setLayout(null);
this.setResizable(false);
this.setSize(600,600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void placeShip1() {
ImageIcon ship2 = new ImageIcon("graphics/ship2.png");
JLabel imageLabel = new JLabel(ship2);
imageLabel.setBounds(200,200,30,30);
p.add(imageLabel);
p.setOpaque(false);
p.setSize(600, 600);
this.add(p);
this.setVisible(true);
}
}
I really can't see why it doesn't work. I mean, all I want is my JFrame with a background image and with an object on a certain position, but instead the object doesn't show at all.
The main reason for wanting to use setLayout(null) is because I was thinking of using a method translating our grid coordinates to the JFrame, simply mapping each coordinate to respective cell.
I am fairly new to java programming and I am trying to make a simple game however, I need to render my image I have made here is the code I put in eclipse:
public class MainMenu extends JFrame{
public static void main(String[] args){
new MainMenu();
}
public MainMenu(){
this.setSize(300, 450);
this.setLocationRelativeTo(null);
this.setResizable(true);
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
int xPos = (dim.width / 2) - (this.getWidth() / 2);
int yPos = (dim.height / 2) - (this.getHeight() / 2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(xPos, yPos);
this.setTitle("Frame For Flamedash Testing");
this.setVisible(true);
}
public void paint(Graphics g){
Image img1 = Toolkit.getDefaultToolkit().getImage("mainmenuscreen.png");
g.drawImage(img1, 20, 20, null);
} // public void paint(Graphics g)
public void putit() {
boolean MainMenu = true;
while (MainMenu == true){
repaint();
}
}
}
When I put that it is all fine and it does not give me any errors what so ever then I run it and it shows the frame but shows no picture than I full screen it because I set re-sizable true and it shows the default color in one spot with the size I set the frame too and another one identical but on the corner and black everywhere else. Any help to rendering this .png image will help, thank you in advance.
Don't override paint() in a JFrame.
The easiest way to display an image is to use a JLabel with an Icon.
Read the section from the Swing tutorial on How to Use Icons for more information and examples. The tutorial will show you how to better structure your code.
The tutorial also has a section on Custom Painting, if you really want to paint the image yourself. Custom painting is done by overriding the paintComponent() of a JPanel and then you add the panel to the frame.
First of all, in your paint method you should always call super.paint, else you break the paint chaining.
As for your issue,
You can call the repaint to force the painting. Keep a variable to hold the instance in your main and call repaint :
public MainMenu() {
...
repaint();
}
Note that loading an image from the paint method is a really bad idea as it will be loaded each time the frame is painted.
You've got several problems in that code including:
Drawing directly within the JFrame, something that can have unpleasant side effects
Trying to read in an image from within a painting method.
Your actual problem is often due to specifying the wrong path to the image, and to solve this you need to identify the actual user's directory that Java is looking at as the base of the path. This can be found by calling
System.out.println(System.getProperty("user.dir"));
I'm writing a custom component that displays some bioinformatics data, and I'd like to be able to show additional information about the location the mouse is at when the user holds down a certain key. This seems like an obvious job for a tooltip, but there are a few problems that seem to be preventing this from working. First, I want to have the tooltip follow the mouse and change its text dynamically. This works somewhat by overriding getToolTipText and getToolTipLocation for the component, but the tooltip flickers as the mouse position is updated and doesn't display over the sub-components (it's a JPanel with some JTextPanes inside it). I also don't think there's any way to make it display immediately without a call to the ToolTipManager, which I believe would change the delay for all other components.
It looks like there are workarounds for some of these problems, but they're rather complicated and inelegant so I'm thinking a good solution would be to just create my own component, fill it with the relevant information and show it myself. However, this needs to be some kind of top-level component because it needs to be able to extend slightly beyond the borders of the parent component or even the containing JFrame and be drawn over everything else. The only objects I know of that have this functionality outside of JToolTip are JFrame and JDialog, which have borders with titles and close buttons which I don't want. Is there some way to accomplish this?
One option is to use a glass pane. In this case your tooltip won't be able to go outside of the frame, but you can easily position it relative to how near it is to a side of the frame. Some example code that draws a bubble (which you can fill with text in the paint method) that follows the mouse.
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(new Dimension(500, 500));
JPanel glassPane = new JPanel();
glassPane.setOpaque(false);
glassPane.setLayout(null);
frame.setGlassPane(glassPane);
frame.getGlassPane().setVisible(true);
final MyInfoBubble mib = new MyInfoBubble();
mib.setBounds(10, 30, 100, 50);
((JPanel)frame.getGlassPane()).add(mib);
frame.getContentPane().addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent me) {
mib.setBounds(me.getPoint().x, me.getPoint().y, 100, 50);
}
});
((JPanel)frame.getGlassPane()).validate();
((JPanel)frame.getGlassPane()).repaint();
frame.setVisible(true);
}
static class MyInfoBubble extends JPanel
{
public MyInfoBubble()
{
setVisible(true);
}
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLUE);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 20, 20);
}
}