In my application (using java), a button is pushed and then a panel opens up with a graph on it. To create the graph I am using graphics/paint. However, I am unable to get the graphics to show up. For now, I am just trying to paint a circle (instead of the actual graph). It would be much appreciated if someone could explain what I am doing wrong.
public class SeeProgressHandleClass extends JPanel{
public SeeProgressHandleClass(JFrame window) {
this.window = window;
}
public void mouseClicked(MouseEvent e) {
panel = new JPanel();
fillPanel();
window.add(panel);
panel.setBackground(Color.white);
panel.setBounds(50, 40, 1100, 660);
}
public static void fillPanel() {
Graph graph = new Graph();
panel.add(graph);
}
}
public class Graph extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
g.setColor(Color.green);
g.fillOval(50, 50, 50, 50);
}
}
Graph should provide preferredSize hints, which will allow the layout manager to make better determinations about how the component should be displayed. Consider overriding getPreferredSize
Don't call this.setBackground(Color.white); inside paintComponent, each time you do this, it will trigger a potential repaint request, which will eventually consume all your CPU cycles. Set this in the constructor
You're adding Graph into JPanel and then adding this to the screen ... not sure why, but it's making it more confusing
After window.add(panel);, all window.revalidate() and window.repaint() to trigger a new layout and paint pass
Related
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:
I am attempting to make a simple traffic light frame. This is being made by the main frame TrafficBox:
public class TrafficBox extends JFrame {
public TrafficBox() {
setLayout(new BorderLayout(100,100));
add(new TrafficLight(Color.GREEN), BorderLayout.NORTH);
add(new TrafficLight(Color.ORANGE), BorderLayout.CENTER);
add(new TrafficLight(Color.RED), BorderLayout.SOUTH);
setBounds(100, 100, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TrafficBox();
}
});
}
which then as seen, adds in 3 TrafficLight components which are based on JPanel, and have the following code:
public class TrafficLight extends JPanel {
private final int BALL_DIAMETER = 100;
private Color color;
public TrafficLight(Color color) {
//setSize(BALL_DIAMETER, BALL_DIAMETER);
this.color = color;
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
}).start();
}
public void paintComponent(Graphics g) {
g.setColor(color);
g.fillOval(0, 0, BALL_DIAMETER, BALL_DIAMETER);
}
This does sort of what I want, it draws all 3 circles as expected although a majority of the North(green) and south(red) lights are being cut off. I assume this is because the north/south spot are much smaller than the center.
I've tried using setSize(); to set the size of the panels to the size of the circles, however that does not work. Is there a way I can make it so that the full circle will be visible?
So, most layout managers will need some "hints" to be provided by the components in order to know how they want to be laid out.
You will need to override the getPreferredSize and return a size which best meets your needs, for example...
public class TrafficLight extends JPanel {
private final int BALL_DIAMETER = 100;
//...
public Dimension getPreferredSize() {
return new Dimension(BALL_DIAMETER, BALL_DIAMETER);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent();
g.setColor(color);
g.fillOval(0, 0, BALL_DIAMETER, BALL_DIAMETER);
}
Also, paintComponent doesn't ever need to be public no-one else should be calling it and you should call super.paintComponent() before performing any custom painting.
I'd also recommend maybe using GridLayout for this
I'd also argue that TrafficLight doesn't need a Timer of it's own and the should be controlled externally, but that's me
setBounds(100, 100, 800, 600);
Is best avoided, use pack() to size the window to the preferred size of the content and setLocation to position it
Simple fix, needed to be using setPreferredSize() rather than setSize.
I'm working on a project and I just started on the GUI. Since this isn't my most favorite topic, I stumbled real quick on something not working quite right. Everything (PacmanGrid,PacmanScore) is shown correctly but the borders I wrote for the PacmanScore Panel! Anyway here is the code, hope someone can help.
public class PacmanFrame extends JFrame{
public PacmanFrame() {
this.setLayout(new BorderLayout());
this.setTitle("Pacman");
PacmanGrid p1=new PacmanGrid();
PacmanScore p2 = new PacmanScore();
this.add(p1,BorderLayout.CENTER);
this.add(p2,BorderLayout.EAST);
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.repaint();
pack();
super.setVisible(true);
}
public static void main(String[] args) {
PacmanFrame p1 = new PacmanFrame();
}
}
PacmanScore
public class PacmanScore extends JPanel{
private TitledBorder t3 = BorderFactory.createTitledBorder("Menu");
private Border etched = BorderFactory.createEtchedBorder(Color.WHITE, Color.white);
public PacmanScore() {
setLayout(new FlowLayout());
setPreferredSize(new Dimension(100,800));
setBackground(Color.DARK_GRAY);
t3.setBorder(etched);
setBorder(t3);
setVisible(true);
setOpaque(true);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(Color.white);
g2.drawString("Score: ", 20, 400);
}
}
PacmanGrid is also extended by a Panel and draws the classical PacmanGrid using predefined patterns. But I don't think it is relevant since the problem is clearly on the PacmanScore Panel. I will post the code if anyone needs tho.
Thanks in Advance!
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(Color.white);
g2.drawString("Score: ", 20, 400);
}
You didn't override paint() properly because you didn't invoke super.paint() and therefore the border is not painted.
Don't override paint(). Custom painting is done by overriding paintComponent().
Read the section from the Swing tutorial on A Closer Look at the Paint Mechanism for more information.
Why are you even doing custom painting? Just add a JLabel to the panel.
Also, Swing components (except for top level windows) are visible by default so there is no need to make the panel visible.
I wish to draw an HUD of sorts over a 3D OpenGL view, but it seems any drawing done in my panel will be overlooked, although it is done.
Here's some barebones code.
MyFrame;
public class MyFrame extends JFrame{
private static final long serialVersionUID = 1L;
public MyFrame(Labyrinth l){
super();
this.setTitle("My Frame");
this.setSize(512, 384);
this.setContentPane(new MyPanel());
//this.setVisible(true);//If needed here.
}
}
MyPanel;
public class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
public MyPanel(){
super();
this.setLayout(new BorderLayout());
MyCanvas mc=new MyCanvas(l);
mc.setFocusable(false);
this.add(this.mc, BorderLayout.CENTER);
//this.revalidate();//Doesn't seem needed in the instanciation.
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.mc.repaint();
g.setColor(new Color(128,128,128));
g.fillRect(0, 0, this.getWidth()/2,this.getHeight()/2);
//top-left quarter should be greyed away.
}
}
MyCanvas;
public class MyCanvas extends GLCanvas{
private static final long serialVersionUID = 1L;
public MyCanvas(){
super(new GLCapabilities(GLProfile.getDefault()));
}
}
The painting takes place, but isn't shown in the view. I've tried overriding repaint(), paint(Graphics), paintComponent(Graphics) and update(). I've been said that painting over "heavyweight" components was complicated, and that I should either paint directly in the component or use another type. I obviously need the GLCanvas to show a 3D render, and at the same time it does not seem to provide tools to draw an overlay. Someone told me to simply do my drawing in the JFrame's glassPane however that seems rather overkill, and I've been told never to play around the glassPane so I'm not planning on doing that.
I've seen many topics on the paintings call order but I cannot establish which would be correct while overriding such or such method, and I don't even know if or which method I should override. Is there an obvious way I'd have missed to have my simple JPanel paintings shown over its GLCanvas component?
First of all, I really wouldn't recommend getting a HUD through those means. As I can only imagine this hurting performance a lot. Granted I have never tried mixing Java, OpenGL and AWT's Graphics like that.
Now instead of using holding those classes together with duct tape, consider using JLayeredPane.
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.add(new MyCanvas());
layeredPane.add(new MyPanel());
frame.add(layeredPane);
Now the important part is that you must manually set the bounds of both components:
canvas.setBounds(x, y, width, height);
panel.setBounds(x, y, width, height);
If not you'll end up with the same problem as before:
The painting takes place, but isn't shown in the view
To demonstrate it working I created this small TestPanel class similar to your MyPanel.
public static class TestPanel extends JPanel {
private Color color;
public TestPanel(Color color) {
this.color = color;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(color);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
Then creating two instances like this:
JPanel panel1 = new TestPanel(new Color(255, 0, 0));
panel1.setBounds(25, 25, 100, 100);
JPanel panel2 = new TestPanel(new Color(0, 0, 255));
panel2.setBounds(75, 75, 100, 100);
Then adding them to a JLayeredPane and adding that to a JFrame and we see this:
I found using the JFrame glass-panel to be a good solution, I use it to draw debugging text on top of 3D graphics, I haven't experienced any problems with it. Using the glass-panel method is more convenient than using a JLayeredPane because the resizing of the 3D panel will be handled for you. Note the 3D graphics must be drawn in a GLJPanel component or the layering won't work (as opposed to GLCanvas which is not a Swing component). The paintComponent(Graphics g) will be called at the same rate as the frame-rate of the GLJPanel. Note also, the glass-pane is hidden by default so setVisible(true) must be called on it.
import javax.swing.JFrame;
import com.jogamp.opengl.awt.GLJPanel;
// ...
public class ApplicationWindow extends JFrame {
public ApplicationWindow(String title) {
super(title);
GLCapabilities gl_profile = new GLCapabilities(GLProfile.getDefault());
GLJPanel gl_canvas = new GLJPanel(gl_profile);
// ... code here to draw the graphics (supply a GLEventListener to gl_canvas)
setContentPane(gl_canvas);
StatusTextOverlayPanel myGlassPane = new StatusTextOverlayPanel();
setGlassPane(myGlassPane);
myGlassPane.setVisible(true);
setVisible(true);
}
class StatusTextOverlayPanel extends JComponent {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 14));
g2d.setPaint(Color.BLACK);
String statusText = String.format("C-elev: %.2f S-view %.2f D-view %.2f", 1459.0, 17.0, 2.574691);
g2d.drawString(statusText, 10, 20);
}
}
}
Here is an example of what it could look like (You'll need additional code to draw the axis and the square shown)
I have an assignment to create a paint program in Java. I have managed to create something but not exactly what I wanted.
My problem is that I cannot create a JFrame in my IDE(NetBeans 7.0.1) from the options that the IDE gives me, and call the paint classes correctly.
To be more specific I want to press a button from one panel(ex. Panel1) and paint in Panel2,in the same frame.
That's the calling of the class:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
PaintFlower102 f = new PaintFlower102();
}
Part of Class:
super("Drag to Paint");
getContentPane().add(new Label ("Click and Drag"),BorderLayout.SOUTH);
// add(new JButton("Brush 20"),BorderLayout.NORTH);
addMouseMotionListener( new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent event) {
xval=event.getX();
yval=event.getY();
repaint();
}
});
setSize(500, 500);
setVisible(true);
setDefaultCloseOperation(PaintFlower102.DISPOSE_ON_CLOSE);
}
public void paint(Graphics g) {
g.fillOval(xval, yval, 10, 10);
}
The problem is that if I do not put the extend JFrame in the class this doesn't work. And if I do, it creates a new frame in which I can draw.
Suggestions:
Don't ever paint directly in a JFrame except under rare circumstances of absolute need (this isn't one of them).
Instead paint in a JPanel or JComponent or other derivative of JComponent.
Paint in the class's paintComponent(Graphics g) method, not in paint(Graphics g).
Read the Java tutorials on this as it's all explained well there. Check out Trail: 2D Graphics and Performing Custom Painting.
I might be wrong, but I think that you need to include super.paintComponent(g), and override the paintComponent method like Hovercraft Full Of Eels said.
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw Oval
g.fillOval(xval, yval, 10, 10);
}