resizing from paintComponent method - java

I have this little code
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
Test() {
getContentPane().add(new MyPanel());
pack();
setVisible(true);
}
private class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
setSize(640, 480);
setPreferredSize(new Dimension(640, 480));
setMinimumSize(new Dimension(640, 480));
g.fillRect(20, 20, 50, 50);
}
}
Unfortunately the frame is not resized to the size of the nested panel after calling pack(). I already read the related answers for this topic, but none of them helped. Could you provide me a solution, please?

When pack() is executed the panel is still invisible and its paintComponent() was not executed and as a result setPreferredSize() wasnt executed as well.
But don't call setPreferredSize from paintComponent(). Do your painting in paintComponent nothing else. Avoid putting program logic into that method. Painting operations should be fast and optimized for better performance and user experience. See Performing Custom Painting for more details.
Override panel's getPrefferedSize(), or at least execute setPrefferedSize before pack().
Also see Should I avoid the use of set[Preferred|Maximum|Minimum]Size methods in Java Swing.

public MyPanel() {
setPreferredSize(new Dimension(640, 480));
}

Related

Resizing JFrame from JPanel

I'm curious is there a way to resize window from JPanel object. I'm looking for solution for a while. Maybe I'm missing something?
I want to resize window when use changeSize() method (f.e. on button, I deleted lot code).
I've tried different methods like setSize, setPreferredSize and setBorders.
public class MAIN{
public static void main(String[] args) {
new Okno(new Panel_Saper());
}
}
public class Okno extends JFrame{
protected Okno(Panel panel) {
setResizable(true);
getContentPane();
Container cp = getContentPane();
cp.add(panel);
pack();
setDefaultCloseOperation(panel.getClose());//2 - JFrame.DISPOSE_ON_CLOSE, 3 - JFrame.EXIT_ON_CLOSE
setVisible(true);
}
}
public abstract class Panel extends JPanel {
protected int getClose() {return 2;} //2 - JFrame.DISPOSE_ON_CLOSE
}//needed for override in other place
public class Panel_Saper extends Panel {
Panel_Saper() {
setLayout(null);
setPreferredSize(new Dimension(400,400));
}
public void changeSize() {//DOESN'T WORK
SetSize(new Dimension(600,600));
setBounds(0, 0, 600, 600);
repaint();
}
}
For your custom panel it is preferred that you override the getPreferredSize() method. Every Swing component is responsible for knowing its preferred size.
If you want to change the preferred size from 400 to 600 you must have a reason for doing this. So you should have a property for your panel that you can modify.
Then your implementation of the getPreferredSize() method will check this property and return the appropriate size depending on the current state of your panel.
I made work around by closing and reopening window
Now that your component has implemented the getPreferredSize() correctly you can simple invoke pack() on the JFrame.

Can't draw line(method: paintComponent) - Java

I'm trying to draw a line in a JFrame, but line isn't drawn.
I tried to use the method setOpaque(true) for contentPane, lblNewLabel and l but nothing changed. I also tried call repaint(); outside this class but the situation is still the same. Here's the code:
public class DrawingClass extends JFrame
{
private JPanel contentPane;
public DrawingClass(int n, int s, int p) {
Line l= new Line();
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setBounds(700, 300, 480, 640);
contentPane = new JPanel();
contentPane.setOpaque(true);
setResizable(false);
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("");
lblNewLabel.setIcon(new ImageIcon("image.png"));
lblNewLabel.setBounds(0, 0, 480, 640);
contentPane.add(lblNewLabel);
l.setBounds(0,0,480,640);
contentPane.add(l);
repaint();
}
class Line extends JPanel
{
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(10, 10, 15, 12);
}
}
}
I expect a little line on the top left of the JFrame, above the background wallpaper, but nothing happen. It shows only the wallpaper.
There are several errors in your code:
You're extending JFrame but you're not changing its behavior, so why are you doing that? JFrame is a rigid component, so it's never a good idea to extend from it, build your GUI based on JPanels instead. See: Extends JFrame vs. creating it inside the program
Don't explicitly set the size of the JFrame, call pack() on it and instead override getPreferredSize from the JPanel, see: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
You don't need to call setOpaque(...) in this case.
Don't use a null-layout, it might lead to strange errors, because null Layout is Evil and frowned upon
We don't have access to your image so we cannot test the ImageIcon and it's also not related to your question. However you should load your images as resources
Don't explicitly set the bounds of each element, this is related to point (4) and you should use a Layout Manager or combinations of them to get your desired GUI.
Don't call repaint() that way, it has no effect, it is supposed to repaint your UI when there's a change in it. However there is no change at the start of your program.
You're breaking the paint-chain by not calling super.paintComponent(...) inside your paintComponent(...) method. Check the Tutorial on Custom Painting in Swing so that you learn how to do it properly
And be careful, as paintComponents(...) (With a trailing s) is different from paintComponent(...) (Look at your title)
So, after doing all of the above changes, we get to this simple program:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class DrawingClass {
private JPanel contentPane;
private JFrame frame;
public static void main(String args[]) {
SwingUtilities.invokeLater(() -> new DrawingClass().createAndShowGUI());
}
public void createAndShowGUI() {
frame = new JFrame(getClass().getSimpleName());
Line line = new Line();
frame.add(line);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
class Line extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(10, 10, 15, 12);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(480, 640);
}
}
}
Which produces the following output:

Something wrong when using paint() in JFrame

When I try to draw an oval in JFrame, the paint() method doesn't work, but when I change JFrame to Frame it's fine. Can you please explain this problem?
import java.awt.Graphics;
import java.awt.Window;
import javax.swing.JFrame;
public class Oval extends JFrame
{
public Oval()
{
// this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
this.setSize(400, 400);
}
public void paint(Graphics g)
{
g.drawOval(40, 40, 40, 40);
}
public static void main(String []args)
{
new Oval();
}
}
Don't override paint(). Instead add a JPanel to the JFrame and override paintComponent(g)
Call super method. Even if you override paint() call super.paint() (Of course it's better to use paintComponnet())
Well you shouldn't override the paint() method, instead add a JPanel to your JFrame and override the JPanel's paintComponent() method and draw your stuff on the JPanel instead.
Here's a demonstration:
import javax.swing.*;
import java.awt.*;
public class Oval extends JFrame
{
public Oval()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new GridBagLayout());
OvalPanel ovalPanel = new OvalPanel(100); // SIZE of oval is 100
ovalPanel.setPreferredSize(new Dimension(400, 400));
add(ovalPanel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new Oval();
}
});
}
}
class OvalPanel extends JPanel
{
private final int SIZE;
public OvalPanel(final int size)
{
this.SIZE = size;
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g); // Call the super class's paintComponent so that it does its appropriate rendering first.
g.drawOval((getWidth() - SIZE) >> 1, (getHeight() - SIZE) >> 1, SIZE, SIZE); // Center the oval
}
}
Also if you notice, I used SwingUtlities.invokeLater() method and there I called the Oval constructor. That I did because Swing is thread unsafe and so you should call any Swing related methods in the Event Dispatcher Thread which is responsible for handling any Swing related stuff, and that's what the invokeLater() method does.
Note: if you're using JDK 8, you can write the SwingUtilities.invokeLater() statement as:
SwingUtilities.invokeLater(Oval::new); // That's JDK 8 Method reference feature.
You might wonder as to why you shouldn't do stuff directly in the paint() method. The reason has to do with the way paint() method is called. You see, the RepaintManager is responsible for handling the painting of all the Swing based components, and when the paint() method is called, it in turn calls the paintComponent(), paintChildren() and paintBorder() methods. paintComponent() is the best place to handle any component based rendering and that's why its the suggestion. Though, even the following code works:
import javax.swing.*;
import java.awt.*;
public class Oval extends JFrame
{
public Oval()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(400, 400);
setLocationRelativeTo(null);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g); // Calling the super class's paint method first.
// so that it handles its rendering.
g.drawOval(40, 40, 40, 40);
}
public static void main(String[] args)
{
new Oval();
}
}
Even the order in which methods are called is important in Swing. Like:
setSize(400, 400); // Setting the size of JFrame first.
setLocationRelativeTo(null); // Locating the JFrame based on its size then.
setVisible(true); // Finally its made visible
All the above work as expected. But the following won't display the results properly:
setVisible(true); // JFrame is already made visible
setLocationRelativeTo(null); // This first locates the JFrame based on its (0, 0) size
setSize(400, 400); // Then its size is increased. Not as expected as the JFrame appears shifted from center.

How can I make my GUI Frame larger?

The problem is, I am unable to make it a dimension with 800x600. In other words, when I run the program, the frame is so small that I can not do anything with it.
How can I make the frame larger?
I have set the preferred size already ans set the canvas bounds.
Then what is the problem?
public class GameCanvas extends Canvas
{
private BufferStrategy buffer = null;
public GameCanvas()
{
setBounds(0, 0, 800, 600);
setIgnoreRepaint(true);
addKeyListener(new KeyInputHandler());
requestFocus();
}
public void addNotify()
{
super.addNotify();
this.createBufferStrategy(2);
buffer = this.getBufferStrategy();
setBounds(0, 0, 800, 600);
}
}
public class GameGuiFrame extends JFrame
{
private JPanel panel = new JPanel();
private GameCanvas canvas = new GameCanvas();
public GameGuiFrame()
{
this.setName("My Game");
this.pack();
this.setResizable(false);
this.setVisible(true);
panel = (JPanel) this.getContentPane();
panel.setPreferredSize(new Dimension(750,500));
panel.setLayout(null);
panel.add(canvas);
}
}
public class GameManager
{
public static void runGameLoop()
{
GameGuiFrame container = new GameGuiFrame();
container.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
}
public class Main
{
public static void main(String [] args)
{
GameManager.runGameLoop();
}
}
Try packing the Frame after you set the preferred size of the content pane.
Not related to your question but based on the code you posted it looks like you've copied some old AWT code and are trying to use it in a Swing application.
I would suggest you only use Swing components. There is no need to use a Canvas with a BufferStrategy. Just use a JPanel it is double buffered by default. The code snippet you copied is old and that is not the way it is done in Swing.
Don't use a null layout. Swing was designed to be using with layout managers. Then the pack() method will be able to do its job properly.
There is no need to use a WindowListener to close the frame. These days people just use:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Also, the frame should be made visible AFTER components have been added to the frame.
Generally you should be use Key Bindings, not a KeyListener to listen for key events in a Swing application.
I suggest you look at the Swing tutorial for more information about the above concepts.
You call to pack() will set the frame (and components within it) to their preferred size. However, you haven't specified a preferred size. I would suggest removing your two calls to setBounds() and calling setBounds() within the main method instead of pack().

drawing on Jframe

I cannot get this oval to draw on the JFrame.
static JFrame frame = new JFrame("New Frame");
public static void main(String[] args) {
makeframe();
paint(10,10,30,30);
}
//make frame
public static void makeframe(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(375, 300));
frame.getContentPane().add(emptyLabel , BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
// draw oval
public static void paint(int x,int y,int XSIZE,int YSIZE) {
Graphics g = frame.getGraphics();
g.setColor(Color.red);
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
The frame displays but nothing is drawn in it. What am I doing wrong here?
You have created a static method that does not override the paint method. Now others have already pointed out that you need to override paintComponent etc. But for a quick fix you need to do this:
public class MyFrame extends JFrame {
public MyFrame() {
super("My Frame");
// You can set the content pane of the frame to your custom class.
setContentPane(new DrawPane());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
}
// Create a component that you can actually draw on.
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
g.fillRect(20, 20, 100, 200); // Draw on g here e.g.
}
}
public static void main(String args[]){
new MyFrame();
}
}
However, as someone else pointed out...drawing on a JFrame is very tricky. Better to draw on a JPanel.
Several items come to mind:
Never override paint(), do paintComponent() instead
Why are you drawing on a JFrame directly? Why not extends JComponent (or JPanel) and draw on that instead? it provides more flexibility
What's the purpose of that JLabel? If it sits on top of the JFrame and covers the entire thing then your painting will be hidden behind the label.
The painting code shouldn't rely on the x,y values passed in paint() to determine the drawing routine's start point. paint() is used to paint a section of the component. Draw the oval on the canvas where you want it.
Also, you're not seeing the JLabel because the paint() method is responsible for drawing the component itself as well as child components. Overriding paint() is evil =)
You are overriding the wrong paint() method, you should override the method named paintComponent like this:
#Override
public void paintComponent(Graphics g)
You need to Override an exist paint method that actually up to dates your Frame. In your case you just created your custom new method that is not called by Frame default.
So change your method to this:
public void paint(Graphics g){
}

Categories