I'm making a gui in which draw a line using paint component method i know i can do that with extends JPanel. But i really want to know how to do this without extending anything.Like in this program
public class Main {
static JPanel panel;
public static void main(String[] args) {
JFrame frame = new JFrame("Our Frame");
panel = new JPanel();
frame.setSize(600,480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.add(panel);
}
}
And on this Way
public class Main {
public static void main(String[] args) {
Frame obj = new Frame();
}
}
The frame
public class Frame extends JFrame{
private JPanel panel;
public Frame(){
panel = new JPanel();
setSize(600,480);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
add(panel);
}
}
You can do something like this:
JPanel panel = new JPanel(true) {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// do painting
}
}
Well, technically you can use component.getGraphics(); to get the graphics context for a given component, then draw on that. But since the component will also repaint itself, your drawing will vanish as soon as the repaint occurs. So don't even think about doing that, you will only waste your time!
However if you have a component that renders a BufferedImage in paintComponent(), you can draw on the image (with img.getGraphics(); etc.) and the component will then reflect those drawings. This will allow you to have a simple MyPanel class, where paintComponent() will only draw the image. You can then get a reference to the image, and draw on that from whereever you want.
You're already extending something in your code, and in your case it's completely unnecessary. You can remove your Frame class and display a JFrame with the following code.
JFrame f = new JFrame();
f.setSize(600, 480);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.add(panel);
f.setVisible(true);
Related
I don't understand this, I'm currently making a main menu for a game i'm making but for some reason when I hover over a JButton, it flashes up on the top left side of the JFrame. I don't have any mouseAction methods or anything, is it the gif i'm using? I'm not sure...
Here is a screengrab of the error
Here is my code :
import javax.swing.*;
import java.awt.*;
public class MainMenu {
JFrame frame = new JFrame("Frasergatchi");
public void display(){
frame.setSize(400,400);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
public void addComponents(){
JButton play = new JButton("Play");
JButton instructions = new JButton("Instructions");
JButton exit = new JButton("Exit");
JPanel panel = new JPanel();
paintMenu paintMenu = new paintMenu();
panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
frame.add(panel);
play.setAlignmentX(Component.CENTER_ALIGNMENT);
instructions.setAlignmentX(Component.CENTER_ALIGNMENT);
exit.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(paintMenu);
panel.add(play);
panel.add(instructions);
panel.add(exit);
}
public class paintMenu extends JPanel{
public void paintComponent(Graphics graphics){
Image dog = new ImageIcon(getClass().getResource("DogMenuImage.gif")).getImage();
graphics.drawImage(dog,170,240,this);
}
}
}
The first statement in the paintComponent() method should always be:
super.paintComponent(g);
to make sure the background gets cleared.
Also:
Don't do I/O in a painting method. Painting methods are for painting only. Read the image in the constructor of your class and same the image in an instance variable.
Class names SHOULD start with an upper case character. Think of all the classes in the JDK and follow the standards.
There is no need to create a custom class to paint the image. Just use a JLabel with an Icon.
I have a button that when pressed calls a changecolor() method in a different class where some drawing is done. The button listener works fine and I see from some logging that the color was in fact changed but my drawing is not updated. This is my current implementation:
(This method is called when a button is clicked)
public void changeWarningLightColor(){
System.out.println("change color method called");
if(warningLights.equals(Color.GREEN)){
warningLights=Color.RED;
System.out.println(warningLights);
repaint();
}
else{
warningLights=Color.GREEN;
repaint();
}
}
and my drawing is created in the same file in the above method as follows:
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawSomething();
//draw a bunch of lines
}
My question is what is the proper way to call repaint() in order to actually update the drawing? Do I need to somehow call g.repaint() or do something different?
Separate class where the frame is created:
public class MainWindow extends JFrame {
public MainWindow(){
JPanel Window = new JPanel();
JPanel LeftSidePanel = new JPanel();
LeftSidePanel.setLayout(new BorderLayout());
LeftSidePanel.add(new DrawStatus(),BorderLayout.CENTER); //where the drawing is added
Window.setLayout(new BoxLayout(Window,0));
Window.add(LeftSidePanel);
add(Window);
}
public static void main(String[] args) {
//main method for showing the frame we created with the panels, and circles inside it
MainWindow frame = new MainWindow();
frame.setSize((int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getWidth()),(int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getHeight()));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setTitle("DVPWS v1.0");
frame.setResizable(false);
MenuBar menu = new MenuBar();
frame.setJMenuBar(menu);
frame.setVisible(true);
}
}
If you are using a Jframe (most likely are) do
yourFrame.repaint();
Optionally
yourPanel.repaint();
In this case you could do
public MainWindow mw = new MainWindow();
mw.repaint();
If that doesnt work(i had a similar problem) than your going to have to make an instance of JFrame instead of extending it.
I'm currently trying to draw shapes on a JPanel, which is within another JPanel, within a JFrame.
I've searched Google and Youtube and found out how to draw shapes within a JFrame that has one panel, but have found nothing which can help me with what I'm doing. (maybe I'm not seeing something).
Code I've seen so far:
public class GameScreen
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
public static void main(String[] args)
{
GameScreen gs = new GameScreen();
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(gs);
}
This is all good for when I'm dealing with just one panel, but I wanna display shapes on a panel which is within the 1'st panel I've created.
Add a JPanel to the JFrame in the same way as you're doing now, but do it with your own subclass of JPanel.
class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400,400); // As suggested by camickr
}
}
You can add this to a JPanel which sits within the JFrame
public static void main(String[] args)
{
MyPanel mp = new MyPanel();
JPanel jp = new JPanel();
jp.add(mp);
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(jp);
}
This can work for components within components, if you add them as children components. The key is to extend the component and override the methods you wish to change.
This is all good for when I'm dealing with just one panel,
The code you posted works fine because a frame uses a BorderLayout. So, when you add your panel to the frame is will increase in size and your custom painting will be seen.
I wanna display shapes on a panel which is within the 1'st panel I've created.
When you create a panel it uses a FlowLayout by default. When you add a custom painting panel to that panel it will be displayed at its preferred size, which will be (0, 0) since you didn't specify the preferred size.
On the panels that do custom painting you also need to implement the getPreferredSize() method so the layout manager knows how to arrange the panels. For example:
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}
I have the following code. Class KochSnowflakesMenu is a grid JPanel with three buttons. Class KochSnowflakesDraw currently draws a circle using drawOval:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakes
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.repaint();
}
}
This works if I comment out frame.setResizable(false). When I don't the buttons don't appear. Why is that? As you can see, I have tried using repaint(). I had previously the problem that the buttons would not show up until I manually resized the window...
Also, as a bonus question, if anyone can tell me how to get the dimensions of a JPanel that would be great. The reason why I can't use a resizable layout manager such as BorderLayout, which really is what I want to use, is that I can't figure out the dimension of the JPanel that occupies the center (and hence have no idea how to large to draw the things I'm drawing).
EDIT:
As requested, here is the KockSnowflakesMenu class:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesMenu extends JPanel
{
public KochSnowflakesMenu()
{
setLayout(new GridLayout(3,1));
setBounds(0,0,200,400);
JButton button_red = new JButton("Red");
JButton button_yellow = new JButton("Yellow");
JButton button_blue = new JButton("Blue");
add(button_red);
add(button_yellow);
add(button_blue);
}
}
And, just to be sure I didn't mess something up with KochSnowflakesDraw, here's that class as well:
import javax.swing.*;
import java.awt.*;
public class KochSnowflakesDraw extends JPanel
{
public KochSnowflakesDraw()
{
setLayout(null);
setBounds(200, 0, 400, 400);
}
public void paintComponent(Graphics g)
{
g.setColor(Color.RED);
g.drawOval(0,0,400, 400);
}
}
A general point, when using JFrame, you should be using the contentPane, rather than the JFrame itself, so to add items, try
frame.getContentPane().add(.....);
For your first question, try using pack on your JFrame.
http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Window.html#pack()
For your bonus question, JComponent has a getWidth and getHeight method. This will tell you the current size of the JPanel.
http://download.oracle.com/javase/1.4.2/docs/api/javax/swing/JComponent.html#getWidth()
Adding more info to the previous answers...
The size is random until the component is drawn so make sure you have a setVisible(true) on your frame. Here's your code w/some modifications that let you use the BorderLayout and get the size of your drawing panel. I substituted some fake buttons for your interfaces but you'll get the drift.
JFrame frame = new JFrame("Koch Snowflakes");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(new BorderLayout());
JPanel buttons = new JPanel(new FlowLayout());
buttons.add(new JButton("MENU"));
buttons.add(new JButton("DRAW"));
frame.add(buttons, BorderLayout.SOUTH);
JPanel drawArea = new JPanel();
drawArea.setBackground(Color.BLUE);
frame.add(drawArea, BorderLayout.CENTER);
frame.setVisible(true);
Dimension drawAreaDim = drawArea.getSize();
System.out.println(drawAreaDim);
When you add components to a visible frame the code should be something like:
panel.add(...);
panel.revalidate();
panel.repaint(); // sometimes required
Make sure you create your Swing objects on the Event Dispatch Thread (EDT). In your example you aren't, and that is often the candidate when you get weird, inconsistent behavior. Swing isn't thread-safe, and relies on creation and modification of Swing objects on the EDT.
To remedy, just wrap the contents of your main method in a SwingUtilities.invokeLater call like so:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
JFrame frame = new JFrame("Koch Snowflakes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0,0, 600, 425);
frame.setBackground(Color.BLACK);
frame.setResizable(false);
frame.setLayout(null);
// Create the button interface
frame.add(new KochSnowflakesMenu());
frame.add(new KochSnowflakesDraw());
frame.setVisible(true);
}
});
}
That will create your JFrame and other components on the EDT thread. Does that fix the inconsistent "it doesn't work most of the time" behavior?
Also, I prefer to call setVisible last...though it probably doesn't matter.
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){
}