I'm trying it to display a rectangle at the specified location but it isn't showing up. The background is magenta but the rectangle is not there.
Also: How can I access more colors besides the "Color.(insert very few options here)"
import javax.swing.*;
import java.awt.*;
class Screensaver {
private final static int FRAME_HEIGHT = 600;
private final static int FRAME_WIDTH = 600;
public static void main(String[] args){
JFrame win;
Container contentPane;
Graphics g;
win = new JFrame();
win.setSize(FRAME_WIDTH, FRAME_HEIGHT);
win.setVisible(true);
contentPane = win.getContentPane();
contentPane.setBackground(Color.MAGENTA);
g = contentPane.getGraphics();
g.setColor(Color.BLACK);
g.fillRect(80, 350, 400, 250);
}
}
You shouldn't be painting in main(); it would be better to extend JPanel, change paintComponent(), and add the panel to the JFrame.
public class PaintPanel extends JPanel {
public PaintPanel() {
setBackground(Color.MAGENTA);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g); // This paints the background
g.setColor(Color.BLACK);
g.fillRect(80, 350, 400, 250);
}
}
And in main():
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new PaintPanel());
frame.setVisible(true);
}
If you want to make your own Colors, you can use the new Color(int red, int green, int blue) constructor.
If you're going to draw stuff create a class that inherits from a Swing container, JComponent, JPanel, etc. and override the paint(Graphics g) method. If you see the magenta background then contentPane must have been added. What's probably happening is its painting the magenta background over your rectangle, but that's just a guess. Try this...
public class ContentPane extends JComponent {
public ContentPane() {
}
#Override
public void paint(Graphics g) {
g.setColor(Color.MAGENTA);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
g.fillRect(80, 350, 400, 250);
}
}
Then in your main class instantiate an object of the ContentPane class and add it to your JFrame. The call to repaint() is probably unnecessary but that will make sure it gets painted. You can also try messing around with the paintComponent(Graphics g) method, there is a difference between the two, I believe its the order they're called from the update method but I'm probably wrong about that, however that should solve your problem.
As for colors, consult the API. You can pass RGB values into the Color constructor to create all sorts of colors. Color color = new Color(int red, int green, int blue). I think that is the easiest way to create custom colors but like I said its all in the API. Hope this helps.
Try this :
import javax.swing.*;
import java.awt.*;
class Screensaver {
private final static int FRAME_HEIGHT = 600;
private final static int FRAME_WIDTH = 600;
public static void main(String[] args) {
JFrame win;
Container contentPane;
win = new JFrame();
win.setSize(FRAME_WIDTH, FRAME_HEIGHT);
win.setVisible(true);
Component comp = new Component();
contentPane = (Container) win.getContentPane().add(comp);
}
}
class Component extends JComponent {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.magenta);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
g.fillRect(80, 350, 400, 250);
}
}
and about the color , you van create new Color and set the RED,GREEN,BLUE as you want , Try this :
g.setColor(new Color(red, green, blue));
The rectangle is drawn once, however every time the JFrames repaint() method is called it erases it and draws the basic Components. To add custom drawing in JFrames you have to override the paint method. Here I improved your code slightly to get you started down that path. As you can see you want to draw the box in the Paint method. I made a Container element that does your drawing and removed the background color, adding it to the paint method as well.
try this
import javax.swing.*;
import java.awt.*;
public class JavaApplication10 {
private final static int FRAME_HEIGHT = 600;
private final static int FRAME_WIDTH = 600;
public static void main(String[] args){
JFrame win = new JFrame();
win.setContentPane(new MyBoxContainer());
win.setSize(FRAME_WIDTH, FRAME_HEIGHT);
win.setVisible(true);
}
private static class MyBoxContainer extends Container {
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.MAGENTA);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
g.fillRect(80, 350, 400, 250);
}
}
}
Related
So in the past few days I've tried to implement an easier version of a graph plotter.
One big problem I was confronted with was a bug that occured on repainting.
Basically I've designed my program in one class which is responsible for drawing the whole coordinate system and the given function after clicking a JButton in an other class. The other class contains the JButton which is pressed. After pressing the JButton it calls a function in the coordinate system class which repaints the picture. Both of those classes are extending JPanel.
The bug was that when I was doing the repainting on pressing the button, the button was drawn on the coordinate System and not in its original place, so in other words on the other JPanel even though I didn't change a thing about placements and stuff. Both classes were added to a JFrame which use a GridLayout.
Can anyone tell me why super.paintComponent(g); solved that bug?
Edit: Added Code
Window class
public class main {
public static void main(String[] args) throws SemanticFailureException {
int x = 800;
int y = 600;
JFrame frame = new JFrame();
frame.setLayout(new GridLayout());
frame.setTitle("Function plotter");
frame.setSize(2*x, 2*y);
Surface test = new Surface(x, y, 10);
CommandDraw test1 = new CommandDraw(x/2,y,test);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(test);
frame.add(test1);
frame.setVisible(true);
}
}
Coordinate System class: (changed drawing the coordinate system to a rectangle for simplicity, the bug still occures with only drawing a rectangle)
public class Surface extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
boolean drawFunct;
public Surface(int x1, int y1, int coordLength) {
setSize(x1,y1);
drawFunct = false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // without this the jbutton occures on the left
// create Graphics object to get more functions
Graphics2D g2 = (Graphics2D) g;
// draw Plotter
drawFunction(g2);
if (drawFunct)
g2.drawLine(0, 0, 80, 80);
}
public void drawFunction(Graphics2D g) {
g.drawRect(40, 40, 30, 30);
}
public void redraw() {
drawFunct = true;
repaint();
}
}
The Class with the JButton:
public class CommandDraw extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
JButton makeDraw;
JTextField inputPoly;
Surface surf;
public CommandDraw(int x, int y, Surface surf) {
this.surf = surf;
setSize(x,y);
setLayout(new FlowLayout());
makeDraw = new JButton("draw Function");
makeDraw.setBackground(Color.LIGHT_GRAY);
makeDraw.setFocusable(false);
makeDraw.addActionListener( new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
surf.redraw();
}
});
add(makeDraw);
inputPoly = new JTextField("Input polynomial");
inputPoly.setHorizontalAlignment(JTextField.CENTER);
add(inputPoly);
}
}
Can anyone tell me why super.paintComponent(g); solved that bug?
Because the call to paintComponent(g) of the superclass (JPanel) will guarantee that panel will be rendered as expected before you do your paint operations. You need to make sure that your JPanel will behave, in the Graphics perspective, like any other JPanel.
A template for a customized JPanel to draw should be something like:
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class MyDrawPanel extends JPanel {
#Override
protected void paintComponent( Graphics g ) {
super.paintComponent( g );
// create a new graphics context based on the original one
Graphics2D g2d = (Graphics2D) g.create();
// draw whatever you want...
g2d.dispose();
}
}
EDIT
You need to call super.paintComponent(g) to tell that the JPanel paintComponent(Graphics) version should be execute before you start doind your customized things. It's something like to ask the JPanel to prepare its paint capabilities to be used. A good starting point to these kind of doubts is the documentation: https://docs.oracle.com/javase/10/docs/api/javax/swing/JComponent.html#paintComponent(java.awt.Graphics)
The dispose() method is being called in the copy of the original Graphics. If you dispose the Graphics that is passed to the method, you may have some issues too. You could use the original Graphics to perform you painting operations, but you shouldn't, so a better practice is to make a copy of the original Graphics and dispose it after using.
Take a look here too: How does paintComponent work?
When I work with Jpanel, I see that while Y is below 50 I don`t see objects, as they are hidden under top panel. I need a way to hide top panel or make it possible to not to add 50 to Y each time. In this example, top of the circle is hidden:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
class Draw extends JFrame{
public static int Framesize=1000;
public static void main(String []args){
Draw s=new Draw();
s.setVisible(true);
}
public Draw(){
JPanel panel=new JPanel();
setSize(Framesize,Framesize);
setVisible(true);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (int i=0;i<=1000;i+=50) {
g2.draw(new Line2D.Float(i, 0, i, Framesize));
g2.draw(new Line2D.Float(0, i, Framesize, i));
}
g2.setPaint(Color.RED);
g2.draw(new Ellipse2D.Float(0,0,200,200));
g2.drawString("Test", 100, 150);
}
}
First of all you have to use the JPanel variable you've created (because it's not a good practice to paint directly in the JFrame as you were doing just because It can cause the problem you were having). Here is an example of the panel class:
class panel extends JPanel{
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i <= 1000; i += 50) {
g2.draw(new Line2D.Float(i, 0, i, Draw.Framesize));
g2.draw(new Line2D.Float(0, i, Draw.Framesize, i));
}
g2.setPaint(Color.RED);
g2.draw(new Ellipse2D.Float(0, 0, 200, 200));
g2.drawString("Test", 100, 150);
}
}
Then add the panel class to the frame constructor
panel panel = new panel();
add(panel);
Finally remove the paint function from the main frame (because you have already defined it in the panel class).
However, there is no point in removing the upside bar (because, objects below 50 in Y axis will appear).
But if for some reason you still want to remove the upside bar then, in order to remove it you have to define in the constructor: setExtendedState(JFrame.MAXIMIZED_BOTH);
setUndecorated(true);
Finally remove the paint function from the main frame (because you have already defined it in the panel class).
Im trying to understand a Paint Graphics, but my oval can't be drawn. Can someone tell me what am I doing wrong and oval is not drawing?
Where did I make a mistake?
Main class:
import java.awt.EventQueue;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Frame frame = new Frame();
}
});
}
Frame class:
public class Frame extends JFrame {
private static final long serialVersionUID = 1L;
public static Grafika grafika;
public Frame() {
JFrame frame = new JFrame("Title");
grafika = new Grafika();
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLayout(null);
// frame.addKeyListener(this);
frame.add(grafika);
}
}
And last Grafic class:
public class Grafika extends JComponent {
int x = 200;
int y = 200;
public void paint(Graphics g) {
Graphics2D oval = (Graphics2D) g;
oval.setColor(Color.BLACK);
oval.fillOval(x, y, 100, 100);
oval.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
}
Several issues, but the biggest is that you're using a null layout on your JFrame, and then adding a JComponent whose preferred size and size are both 0,0. So while you're adding your Grafika to the JFrame, it doesn't have a chance of being displayed.
Suggestions:
Never use null layout, except in very specific exceptional circumstances.
Give your Grafika component a preferred size, best by overriding getPreferredSize(), but at this stage, I think that it would be OK to call setPreferredSize(...) on it.
Add it to the JFrame, pack() the JFrame and then lastly, only after all components have been added to the JFrame, make it visible.
Also
You should be overriding paintComponent not paint
You should call the super painting method within your override.
Always use the #Override annotation when you think that you're overriding a parent method. You could be wrong, and you want the compiler to tell you.
Set the RenderingHints before drawing. Else the hints will have no effect on the drawing.
Avoid giving your classes names that clash with the names of core Java classes, such as Frame. This will potentially confuse others and your future self.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.*;
public class MyGrafika extends JComponent {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static final Color OVAL_COLOR = Color.RED;
private int ovalX = 200;
private int ovalY = 200;
private int ovalWidth = 100;
private int ovalHeight = 100;
public MyGrafika() {
setPreferredSize(new Dimension(PREF_W, PREF_H));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(OVAL_COLOR);
g2.fillOval(ovalX, ovalY, ovalWidth, ovalHeight);
}
private static void createAndShowGui() {
MyGrafika mainPanel = new MyGrafika();
JFrame frame = new JFrame("MyGrafika");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Since you are using Swing you should override paintComponent and not paint, you should also take care using null layout. But the point is that you should have added your Grafika component before making the frame visible:
frame.add(grafika);
frame.setVisible(true);
// frame.setLayout(null); REMOVE THIS!
If you really need to add a component after the frame has been made visible, then you should call revalidate+repaint on the frame or the panel that contains the added component:
frame.setVisible(true);
// frame.setLayout(null); REMOVE THIS!
frame.add(grafika);
frame.validate();
frame.repaint();
I have a custom JPanel class and I want it to paint several rectangles and texts in front of it's child components. I have overridden this method:
public void paint(Graphics g){
g = getComponentGraphics(g);
super.paint(g);
//paint my custom content
}
super.paint calls paintChildren whitch draws the child components. But the child components appear in front of my custom content, and they also sometimes Z fight with each other.
I'm absolutely clueless about what might be causing this.
NOTE: I use setComponentZOrder in my code, and my JPanel takes place in a JScrollPane.
EDIT: The components ZFight even if I never call the setComponentZOrder method.
EDIT 2:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleSelection;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel{
private static final long serialVersionUID = 1L;
public static void main(String[] atgs){
JFrame frame = new JFrame("ZFightingExample");
frame.setSize(new Dimension(500,500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ExamplePanel panel = new ExamplePanel();
frame.add(panel);
Example a = new Example(new Rectangle(5,5,50,50)),
b = new Example(new Rectangle(40,40,50,50));
panel.add(a);
panel.add(b);
frame.setVisible(true);
}
public Example(Rectangle bounds){
super();
setBounds(bounds);
}
public void paint(Graphics g){
super.setBackground(Color.GREEN);
g.fillRect(0, 0, getWidth()-1, getHeight()-1);
super.paint(g);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}
}
class ExamplePanel extends JPanel{
private static final long serialVersionUID = 1L;
public ExamplePanel(){
super(null);
accessibleContext = new Accessiblecontext();
};
protected class Accessiblecontext extends AccessibleJPanel implements AccessibleSelection{
private static final long serialVersionUID = 1L;
public int getAccessibleSelectionCount() {return 2;}
public Accessible getAccessibleSelection(int i) {return (Accessible)getComponent(i);}
public boolean isAccessibleChildSelected(int i) {return true;}
public void addAccessibleSelection(int i) {}
public void removeAccessibleSelection(int i) {}
public void clearAccessibleSelection() {}
public void selectAllAccessibleSelection() {}
}
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);//Should be in front of the Green boxes...
g.drawRect(10, 10, 75, 75);
}
}
I want it to paint several rectangles and texts in front of it's child components.
Normally you override paintCompnent() to do custom painting.
The question is what does "in front" mean to you? If it means what I think it means then you need to do the painting after the child components have been painted. So you basic approach to override paint() is correct.
public void paint(Graphics g){
g = getComponentGraphics(g);
super.paint(g);
//paint my custom content
}
The problem with the above code is that you don't use the Graphics object passed to the painting method. So your code should be:
public void paint(Graphics g)
{
//g = getComponentGraphics(g);
super.paint(g); // use the Graphics object passed to the method
//paint my custom content
g.drawRect(10, 10, 20, 20);
}
I use setComponentZOrder in my code,
Why are you playing with ZOrder?
Edit:
g.setColor(Color.BLUE);//Should be in front of the Green boxes...
As I first stated in my answer, normally (99% of the time) custom painting is done by overriding the paintComponent() method of the panel.
The problem is with the Example class:
override paintComponent() not paint()
the first statement when you override a painting method should be super.???.
don't set properties of the class in the painting method.
So the code might look something like:
public Example(Rectangle bounds){
super();
setBounds(bounds);
setBackground(Color.GREEN);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth()-1, getHeight()-1);
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
}
Note you don't event need to do any custom painting with the Example class. Instead your code could be something like:
ExamplePanel panel = new ExamplePanel();
panel.setLayout( null ); // now you set the size/location of any component you add to the panel
JPanel example1 = new JPanel();
example1.setBackground( Color.GREEN );
example1.setBorder( new LineBorder(Color.BLACK) );
example1.setBounds( new Rectangle(....) );
panel.add(example1);
Also, another solution for the ExamplePanel class might be to use a JLayer. The JLayer class allows you to add all kinds of fancy decorations to a component. Check out the Swing tutorial on How to Decorate Components With The JLayer Class.
The idea of the program is that I have some buttons and an icon SOMEWHERE on the frame. I want the buttons to change the color. I'm only worried about making all the elements show up right now. If I comment out lines 11-13, I see "hello," printed out, with a red circle on top of it. Otherwise, I just have the button "red" without "hello" or my red circle. So here's my code:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class ButtonTester
{
public static void main (String[] args)
{
JFrame frame = new ButtonFrame();
frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
JButton redButton = new JButton("Red");
frame.add(redButton);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 200;
public ButtonFrame()
{
setTitle("Hello");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
ButtonPanel panel = new ButtonPanel();
add(panel);
}
}
class ButtonPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
Icon ico = new ColorIcon(32);
ico.paintIcon(null, g, 75, 75);
}
}
I'm 90% sure the problem is lines 11-13, but I'm not sure what to change to make everything visible.
Your problem is that your ButtonPanel's size is 0. Have it override getPreferredSize() and you will see what I mean:
class ButtonPanel extends JPanel {
private static final int PREF_W = 150;
private static final int PREF_H = PREF_W;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
// !! Icon ico = new ColorIcon(32);
// Icon ico = new ImageIcon();
// ico.paintIcon(null, g, 75, 75);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Also as an unrelated aside, why are you creating an Icon inside of the paintComponent method? This doesn't make sense to me and would only serve to needlessly slow your graphics down.
Edit
You state:
Ok, I see the difference after overriding getPreferredSize() But what would be the "better" or "correct" way to create the icon? I'm just trying to follow the directions for an exercise out of a Java textbook: Exercise 4.14. Write a program that shows a frame with three buttons labeled "Red", "Green", and "Blue", and a label containing an icon showing a circle that is initially red. As the user clicks the buttons, the fill color of the circle should change. When you change the color, you need to invoke the repaint method on the label. The call to repaint ensures that the paintIcon method is called so that the icon can be repainted with the new color.
You need to think on this a different way. Myself I'd create three ImageIcons one for a blue circle, one for red, and one for green. I'd then display the ImageIcon in a JLabel on my JFrame. I'd change the color by simply swapping the label's icons via its setIcon(...) method. I wouldn't worry about futzing with paintComponent(...) but rather would try to solve this in as simple a fashion as possible.