Paint over all other components (Swing, Java) - java

In my application I need to draw grid lines just like those like Photoshop has - e.g, an user can drag lines over the document to help him align layers. Now, the problem is that I am able to draw such lines (it's just plain simple Java2D painting using Line2D), but I am not being able to keep such lines on top of everything else, because when children components draw themselves, my grid line is erased.
The program structure is something like this: JFrame -> JPanel -> JScrollPane -> JPanel -> [many others JPanels, which are like layers]
As a test, I added the draw code to JFrame, which correctly shows my Line2D instance on top of everything else. However, when I do anything in an child component that requires that child to repaint itself, the line that was drawn in the JFrame is erased.
I understand that this is the expected Swing behavior - that is, it will only repaint those areas that have changed. However, I am looking for some approach that continuously draws line grid lines on top of everything else.
The only way I was able to get it working was to use a Swing Timer that calls repaint() on my root component every 10ms, but it consumes a lot of CPU.
UPDATE
Working code of an example is below. Please mind that in my real application I have dozens of different components that could trigger a repaint(), and none of them have a reference to the component that does the grid line drawing (of course I can pass it to everyone, but that appears to be the latest option)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GridTest extends JFrame {
public static void main(String[] args) {
new GridTest().run();
}
private void run() {
setLayout(null);
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel();
p.setBounds(20, 20, 100, 100);
p.setBackground(Color.white);
add(p);
JButton b = new JButton("Refresh");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// When I call repaint() here, the paint() method of
// JFrame it's not called, thus resulting in part of the
// red line to be erased / overridden.
// In my real application application, I don't have
// easy access to the component that draws the lines
p.repaint();
}
});
b.setBounds(0, 150, 100, 30);
add(b);
pack();
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D gg = (Graphics2D)g.create();
Line2D line = new Line2D.Double(0, 50, getWidth(), 50);
gg.setStroke(new BasicStroke(3));
gg.setColor(Color.red);
gg.draw(line);
gg.dispose();
}
}

if you want to paint over JComponents placed to the JScrollPane then you can paint to the JViewPort, example here
EDIT:
1) beacuse your code painted to the wrong Container, to the JFrame, sure is possible to paint to the JFrame, but you have to extract RootPane or GlassPane
2) you have to learn how to LayoutManagers works, I let your code with original Sizing, not nice and very bad
3) paint to the GlassPane or JViewPort
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import javax.swing.*;
public class GridTest extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
new GridTest().run();
}
private void run() {
setLayout(null);
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D gg = (Graphics2D) g.create();
Line2D line = new Line2D.Double(0, 50, getWidth(), 50);
gg.setStroke(new BasicStroke(3));
gg.setColor(Color.red);
gg.draw(line);
//gg.dispose();
}
};
p.setBounds(20, 20, 100, 100);
p.setBackground(Color.white);
add(p);
JButton b = new JButton("Refresh");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
p.repaint();
}
});
b.setBounds(0, 150, 100, 30);
add(b);
pack();
setVisible(true);
}
}
EDIT: 2, if you expecting single line, on the fixed Bounds
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class GridTest extends JFrame {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
new GridTest().run();
}
private void run() {
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel p = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D gg = (Graphics2D) g.create();
Line2D line = new Line2D.Double(0, 50, getWidth(), 50);
gg.setStroke(new BasicStroke(3));
gg.setColor(Color.red);
gg.draw(line);
gg.dispose();
}
};
JPanel p1 = new JPanel();
p1.setBorder(new LineBorder(Color.black,1));
JPanel p2 = new JPanel();
p2.setBorder(new LineBorder(Color.black,1));
JPanel p3 = new JPanel();
p3.setBorder(new LineBorder(Color.black,1));
p.setLayout(new GridLayout(3,0));
p.add(p1);
p.add(p2);
p.add(p3);
p.setBounds(20, 20, 100, 100);
p.setBackground(Color.white);
add(p, BorderLayout.CENTER);
JButton b = new JButton("Refresh");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
p.repaint();
}
});
add(b, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}

One possible solution is to override the JPanel's repaint method so that it calls the contentPane's repaint method instead. Another point is that you probably shouldn't draw grid lines directly in the JFrame but rather in its contentPane. Counter to what I usually recommend, I think you're better off overriding the either the contentPane's paint method (or that of some other containing JPanel), not its paintComponent method so that it can call after the children have been painted. For example:
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class GridTest2 extends JPanel {
private static final Stroke LINE_STROKE = new BasicStroke(3f);
private boolean drawInPaintComponent = false;
public GridTest2() {
final JPanel panel = new JPanel() {
#Override
public void repaint() {
JRootPane rootPane = SwingUtilities.getRootPane(this);
if (rootPane != null) {
JPanel contentPane = (JPanel) rootPane.getContentPane();
contentPane.repaint();
}
}
};
panel.setBackground(Color.white);
panel.setPreferredSize(new Dimension(100, 100));
JPanel biggerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
biggerPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 0, 0));
biggerPanel.setOpaque(false);
biggerPanel.add(panel);
JButton resetButton = new JButton(new AbstractAction("Reset") {
public void actionPerformed(ActionEvent arg0) {
panel.repaint();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(resetButton);
setLayout(new BorderLayout());
add(biggerPanel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawInPaintComponent ) {
drawRedLine(g);
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
if (!drawInPaintComponent ) {
drawRedLine(g);
}
}
private void drawRedLine(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(LINE_STROKE);
g2.setColor(Color.red);
g2.drawLine(0, 50, getWidth(), 50);
}
private static void createAndShowGui() {
GridTest2 mainPanel = new GridTest2();
JFrame frame = new JFrame("GridTest2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

I know it's an old post, but I've had the same problem recently...
You should override paintChildren instead of paint or paintComponent.
From the JComponent.paint documentation:
Invoked by Swing to draw components. Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.
This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren. They're called in the order listed to ensure that children appear on top of component itself. Generally speaking, the component and its children should not paint in the insets area allocated to the border. Subclasses can just override this method, as always. A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.
So if you
#Override
protected void paintChildren(Graphics g){
super.paintChildren(g);
paintGrid(g);
}
the grid will be on top of your children components ^^

Assuming the parent frame already has a list of all the grid lines it has to draw, what you can do is get each child frame to draw its own personal bits of the lines. In pseudocode:
gridlines = getParentsGridLines()
gridlines.offsetBasedOnRelativePosition()
drawStuff()

Swing uses a JLayeredPane within JFrames (and similar components). Using the layered pane, you can position paint-only components over your main content.
This code uses components placed within the JLayeredPane to position (and automatically repaint) arbitrary decorations above the main content of any component, thus obviating the need to override the paint() method of any given component.

Related

Is there a way to draw geometric shapes on the JPanel of a form created in Intelli J Idea

I just started using Intelli J Idea and one of my first projects is to plot some geometric forms to a JPanel of a GUI defined in a form. In the end I want to plot some graphs. I found a tutorial where a class extending the JPanel was defined and the paintCompontent() method was overloaded.
public class MyPanel extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int y2 = (int)(40 * Math.random());
Line2D line = new Line2D.Double(10, 10, 60, y2);
Rectangle2D rectangle = new Rectangle2D.Double(200, 120, 70, 30);
Ellipse2D oval = new Ellipse2D.Double(400, 200, 40, 60);
g2.draw(line);
g2.setPaint(Color.RED);
g2.fill(rectangle);
g2.setPaint(Color.ORANGE);
g2.fill(oval);
}
}
This would run fine if I use it together with this code:
public class MainClass {
public static void main(String[] args) {
MyPanel s = new MyPanel();
JFrame f = new JFrame();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 400);
}
}
Then I tried combining this with a form I created using Intelli J Idea. And this is where I have problems. I would like to have a form with a button and a JPanel. When I press the button some geometric figures are being drawn on the JPanel defined in the form. I think my best try is like this:
public class MainWindow {
private JPanel panelMain;
private JButton buttonCalculate;
private JPanel panelPlot;
public MainWindow() {
buttonCalculate.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panelPlot = new MyPanel();
panelPlot.setBackground(Color.CYAN);
panelPlot.setSize(200, 200);
panelPlot.setVisible(true);
}
});
}
public static void main(String[] args) {
JFrame f = new JFrame("MyFirstGraphTool");
f.setContentPane(new MainWindow().panelMain);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 400);
f.setVisible(true);
}
}
But simply saving my derived JPlane object to the bound property does not change anything.
And also the setBackgroundColor() method does not change anything.
Do you know any tutorials or more detailed explanation of how this can be done?
EDIT: Please find below an image of the component tree.
Component tree from Intelli J Idea
Thanks and kind regards,
David
You've made lots of mistakes in your code. I try to explain you, what's wrong.
public class MainWindow {
private JPanel panelMain; // panelMain is not initialized, so when you try to add it to any window/panel, you'll get a NullPointerException
private JButton buttonCalculate; // same as before. Also this button is not added to any container (window/panel)
private JPanel panelPlot; // panel is not added to any container
public MainWindow() {
buttonCalculate.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panelPlot = new MyPanel();
panelPlot.setBackground(Color.CYAN);
panelPlot.setSize(200, 200); // this code will not be honored because the layout manager will recalculate panel bounds.
// use setPreferredSize instead.
panelPlot.setVisible(true);
}
});
}
public static void main(String[] args) {
JFrame f = new JFrame("MyFirstGraphTool");
f.setContentPane(new MainWindow().panelMain);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 400);
f.setVisible(true);
}
}
Here is the correct version of your class
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* <code>MainWindow</code>.
*/
public class MainWindow {
private JPanel panelMain = new JPanel();
private JButton buttonCalculate = new JButton("Calculate");
private JPanel panelPlot; // panel is not added to any container
public MainWindow() {
buttonCalculate.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panelPlot = new MyPanel();
panelPlot.setOpaque(true);
panelPlot.setBackground(Color.CYAN);
panelPlot.setPreferredSize(new Dimension(200, 200));
panelMain.add(panelPlot);
panelMain.revalidate(); // cause layout manager to recalculate component bounds
}
});
panelMain.add(buttonCalculate);
}
public static void main(String[] args) {
JFrame f = new JFrame("MyFirstGraphTool");
f.setContentPane(new MainWindow().panelMain);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 400);
f.setVisible(true);
}
static class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int y2 = (int) (40 * Math.random());
Line2D line = new Line2D.Double(10, 10, 60, y2);
Rectangle2D rectangle = new Rectangle2D.Double(200, 120, 70, 30);
Ellipse2D oval = new Ellipse2D.Double(400, 200, 40, 60);
g2.draw(line);
g2.setPaint(Color.RED);
g2.fill(rectangle);
g2.setPaint(Color.ORANGE);
g2.fill(oval);
}
}
}
Please also read about layout managers in Swing

paintComponent() is not working when add to panel

I was working a swing application that can draw graphs of maths function. I was using getGraghics functions but I have no idea how I remove and repaint them so I decided to override the paintComponent() method to implement what I was looking for
what I want to do is drawing function graphs in a panel after user click the button. but it seems paintCompnent() is not working. I have followed exactly on any existing tutorial and similar questions on stack overflow.but none of them working for me :( it just made no sense:(
Please help I have stuck on this problem for over a whole night:(
following were codes for drawing functions graphs but as it is not working so I only left the part of drawing coordinate system for testing and after that is the code of how I create an instance and try to add it to my panel in the main class
class drawfunction extends JPanel{
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.drawLine(0, 200, 400, 200);
g.drawLine(200,0 , 200, 400);
}
}
then is the code in main class
JPanel panel = new JPanel();
panel.setBounds(14, 104, 400, 400);
contentPane.add(panel);
panel.setBackground(Color.white);
JButton btnNewButton = new JButton("View the graph");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//a= Integer.parseInt(cofficient_a.getText());
//b= Integer.parseInt(cofficient_b.getText());
//c= Integer.parseInt(cofficient_c.getText());
//d= Integer.parseInt(cofficient_d.getText());
//e= Integer.parseInt(cofficient_e.getText());
drawfunction a=new drawfunction();
panel.add(a);
});
Can anyone please tell me what I should do to fix this. Thank you !!!!
Two basic things...
A component has a default preferred size of 0x0, so when adding it a container under the control of just about any layout manager will get it sized to 0x0 (or very close)
Swing is generally lazy, it won't update the UI when you add or remove components, that could impede performance, as the UI doesn't know the best to update the UI based on what you are doing, instead, you need to call revalidate and (most of the time) repaint to have the UI updated
For example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel center;
public TestPane() {
setLayout(new BorderLayout());
JButton btnNewButton = new JButton("View the graph");
center = new JPanel();
center.setPreferredSize(new Dimension(400, 400));
add(center);
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
remove(center);
//a= Integer.parseInt(cofficient_a.getText());
//b= Integer.parseInt(cofficient_b.getText());
//c= Integer.parseInt(cofficient_c.getText());
//d= Integer.parseInt(cofficient_d.getText());
//e= Integer.parseInt(cofficient_e.getText());
center = new Drawfunction();
add(center);
revalidate();
repaint();
}
});
add(btnNewButton, BorderLayout.NORTH);
}
public class Drawfunction extends JPanel {
public Drawfunction() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.red);
g2d.drawLine(0, 200, 400, 200);
g2d.drawLine(200, 0, 200, 400);
g2d.dispose();
}
}
}
}

Painting the JPanel which created with own Painter

I need learn the logic how can i change JPanel color which created own Painter method. I create a sample project for illustration;
Issue: Direct color changing code in button action not change anything.
Question 1) Is override the paintComponent method is proper way for paint he JPanel with Gradient colors while panel creation?
Question 2) How can i change the background color of this JPanel with other Gradient color or Direct color?
--CODE--
package tryingproject2;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TryingProject2 {
public static void main(String[] args) {
class ImagePanel extends JPanel{
public void paintComponent( Graphics g ) {
Graphics2D g2d = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
Color color1;
Color color2;
color1 = new Color(223,130,24,255);
color2 = new Color(255,255,255,255);
GradientPaint gp = new GradientPaint(0, 0, color1, w, 0, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
}
JFrame frame = new JFrame();
frame.setLayout(null);
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel userPanel = new ImagePanel();
userPanel.setBounds(100, 40, 200, 200);
userPanel.setLayout(null);
JLabel newLabel = new JLabel("Sample Label");
newLabel.setBounds(50, 10, 100, 100);
userPanel.add(newLabel);
JButton button = new JButton("Change Color To Red");
button.setBounds(100, 300, 200, 40);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
userPanel.setBackground(Color.red);
userPanel.repaint();
System.out.println("Button Pressed.");
}
});
frame.add(userPanel);
frame.add(button);
frame.setVisible(true);
}
}
I rearranged some of your code to get rid of other problems.
Here's the GUI I created.
Here's the GUI after I left clicked the button.
I made the following changes to your code.
I moved all of the JFrame code into a run method, so I could get out of static methods and into object-oriented classes and methods as fast as possible.
I added a call to the SwingUtilitiles invokeLater method to ensure that Swing components are created and modified on the Event Dispatch thread.
I created a createMainPanel method to create the main panel. Instead of using ugly null layouts with pixel precision settings, I used a Swing layout, the BorderLayout, to position the components. This allows the user to expand the GUI to fill the screen, as well as the GUI fitting different computers with different screen sizes.
The ImagePanel class is a complete, first-class Java class. That means you can have class fields and class constructors. I provided a way to set the colors from outside the class. Set both colors to the same color if you don't want a gradient.
The paintComponent method of the ImagePanel class should start with a super call, to maintain the Swing Paint chain. The paintComponent method should do nothing but paint. Period. Full stop. Nothing else. I removed the code that had nothing to do with painting.
Looking in the actionPerformed method inside the createMainPanel method, you see how I change one of the gradient colors and perform a repaint. The action listener is the controller of your GUI. Only controller code should change the model (the colors in ImagePanel) or the view (ImagePanel and the JFrame). Always look for the model / view / controller pattern when creating a Swing GUI.
Here's the revised code.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TryingProject2 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new TryingProject2());
}
#Override
public void run() {
JFrame frame = new JFrame("Color Gradient Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JPanel imageLabelPanel = new JPanel();
imageLabelPanel.setLayout(new BorderLayout());
final ImagePanel imagePanel = new ImagePanel(new Color(223, 130, 24,
255), new Color(255, 255, 255, 255));
imageLabelPanel.add(imagePanel, BorderLayout.CENTER);
JLabel newLabel = new JLabel("Sample Label");
newLabel.setHorizontalAlignment(JLabel.CENTER);
imageLabelPanel.add(newLabel, BorderLayout.SOUTH);
panel.add(imageLabelPanel, BorderLayout.CENTER);
JButton button = new JButton("Change Color To Red");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
imagePanel.setColor1(Color.RED);
imagePanel.repaint();
System.out.println("Button Pressed.");
}
});
panel.add(button, BorderLayout.SOUTH);
return panel;
}
public class ImagePanel extends JPanel {
private static final long serialVersionUID = 6970287820048941335L;
private Color color1;
private Color color2;
public ImagePanel(Color color1, Color color2) {
this.color1 = color1;
this.color2 = color2;
this.setPreferredSize(new Dimension(200, 200));
}
public void setColor1(Color color1) {
this.color1 = color1;
}
public void setColor2(Color color2) {
this.color2 = color2;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(0, 0, color1, w, 0, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
}
}
}

Java - Graphics - adding another shape on JPanel

I've got a class that makes a JFrame and adds a panel on it
and the second one extends the JPanel and paints on it
The first one (JFrame)
class MyWindow {
void qwe() {
JFrame frame = new JFrame("qwe");
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
panel.setLayout(null);
frame.add(panel);}}
and the second one (JPanel)
class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
g.drawRect(50,50,90,70);
}
public void addShape() {
Graphics g = this.getGraphics();
Graphics2D gg = (Graphics2D) g;
gg.drawString("qwe",20,20);}}
how can i add a String on the JPanel by using the addShape() method ?
As a concrete example of #camickr's point, note that MyPanel already override's paintComponent(), so you can pass a reference to the Graphics context to addShape(). Additionally,
Be sure to invoke super.paintComponent(g).
Override getPreferredSize() to establish the component's preferred size.
Swing GUI objects should be constructed and manipulated only on the event dispatch thread.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyWindow {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MyWindow().qwe();
}
});
}
void qwe() {
JFrame frame = new JFrame("qwe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
panel.setLayout(null);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(50, 50, 90, 70);
addShape(g);
}
public void addShape(Graphics g) {
g.drawString("qwe", 20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
}
}
Don't use the getGraphics() method of your component to do custom painting. This type of painting is only temporary and will be lost the next time Swing determines the component needs to be painted.
Custom painting should always be done in the paintComponent() method of your component.
See Custom Painting Approaches for the two commons was to do what you want.

Drawing rectangles on a JPanel

I have a JScrollPane and on top of it I have a JPanel named 'panel1'.
I want some rectangles to be drawn on this JPanel.
I have a class named DrawRectPanel which extends JPanel and does all the drawing stuff.
The problem is that, I tried to draw the rectangles on panel1 by writing the following code :
panel1.add(new DrawRectPanel());
but nothing appeared on panel1
then I tried, just as a test to the class DrawRectPanel :
JFrame frame = new JFrame();
frame.setSize(1000, 500);
Container contentPane = frame.getContentPane();
contentPane.add(new DrawRectPanel());
frame.show();
This worked, and produced the drawings but on a separate JFrame
How can I draw the rectangles on panel1 ?
Thanks in advance.
EDIT :
code for DrawRectPanel
public class DrawRectPanel extends JPanel {
DrawRectPanel() {
Dimension g = new Dimension(400,400);
this.setPreferredSize(g);
System.out.println("label 1");
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("label 2");
g.setColor(Color.red);
g.fillRect(20, 10, 80, 30);
}
}
only label 1 is printed on the screen
still no idea,
for example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class CustomComponent extends JFrame {
private static final long serialVersionUID = 1L;
public CustomComponent() {
setTitle("Custom Component Graphics2D");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void display() {
add(new CustomComponents());
pack();
// enforces the minimum size of both frame and component
setMinimumSize(getSize());
setVisible(true);
}
public static void main(String[] args) {
CustomComponent main = new CustomComponent();
main.display();
}
}
class CustomComponents extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}
instead of adding
contentPane.add(new DrawRectPanel());
you should do
contentPane.add(panel1);
Because you already have new DrawRectPanel in panel1. But in your code you are adding another instance of DrawRectPanel in contentPane. And never added panel1 in none of your container.
to fix your problem, change "paintComponent" to "paint" when the window repaints automatically, it should work.

Categories

Resources