I'm not quite sure exactly how Graphics work in Java so I having trouble debugging my problem.
I have a Class MyFrame Extends JPanel. Now I do some drawing on MyFrame save and save me properties about that certain frame then add it an ArrayList collection of MyFrames. Later on I want to recall the properties a certain instance of MyFrame and repaint that frame on the screen. Having the the graphic of frame show up again is what I am having trouble with.
Here is a quick bit of code that will demonstrate my problem.
public class MyFrame extends JPanel{
private int property;
private int x;
private int y;
public MyFrame(int xp, int yp){
x = xp;
y = yp;
}
#override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y,5,5);
}
public void setProperty(int p){
property = p;
}
}
public class MainClass() extends JPanel{
private ArrayList<MyFrame> frames = new ArrayList<MyFrame>;
private MyFrame currentFrame = new MyFrame();
public void addFrame(int x, int y){
this.remove(currentFrame);
currentFrame = new MyFrame();
this.add(currentFrame);
frames.add(currentFrame);
}
public void setFrame(int frame){
this.remove(currentFrame);
currentFrame = frames.get(frame);
this.add(currentFrame);
}
}
Summary:
I'd like the panel to display the correct frame when setFrame is called. currently when I do this set frame will be blank.
You seem to be swapping JPanels in and out of another JPanel, and when doing this, you must take into consideration the layout used by the container-JPanel and you would need to call revalidate and repaint on the container-JPanel after the swap.
But rather than mess with all of this, why not go the easy route by just swaping JPanels or perhaps JLabels with ImageIcons holding an image using a CardLayout?
You could also consider adding some states, an enum data member, to a single JPanel and ask it to switch from one state to another, then call its repaint method and, in its paintComponent overriden method, draw some graphics according to its state.
Your architecture (as enhance by #Hovercraft Full of Eels is also good, even better if the draw methods vary quite a lot and have very different purposes. However, my proposal could lay to a faster app, and could allow other fatures such as transition between states, shared double buffer, variable/code reuse in case graphics are close.
What is your app doing ?
Regards,
Stéphane
Related
I'm making a Chess-like game in Java Swing (I know Swing isn't the proper way to go about it but I want to attempt it nevertheless)
I am having a problem with making the chess pieces show up on the display at the proper paces. Due to the nature of the chess pieces physical positions, I cannot use a layout manager.
The code looks something like this (it's admittedly awkwardly designed) :
public class Window extends JFrame {
private JPanel board;
public Window() {
super();
board = new JPanel();
JLabelOrganizer jlo = new JLabelOrganizer();
for (JLabel: JLabelOrganizer) {
JLabel.setBounds(calcX(), calcY(), width, height);
board.add(JLabel);
}
board.setBounds(x, y, width1, height1);
board.setLayout(null);
add(board);
setLayout(null);
}
public class JLabelOrganizer {
public JLabelOrganizer {
instantiate Type1 and Type2 JLabel objects and store them
}
public class Type1 extends JLabel {
}
public class Type2 extends JLabel {
}
}
}
The classes Type1 and Type2 represent the pieces.
When this runs, the JLabels (Type1 and Type2) do not show up at the correct place as designated from setBounds(). However, the board JPanel holding these pieces is set up at the correct place as designated from the call of its own setBounds().
Does anything have an idea as to why this is happening? Could it be because I'm inheriting from JLabel or the JLabel classes are inner classes? Thanks.
Edit: Forgot to specify that the JLabels only show up in the upper left hand corner of where the JPanel is located no matter what x and y positions I set them to.
I found the answer after looking at another post.
My class inheriting JLabel won't show up but if I change the type to JLabel it does
I accidentally overrided JLabel's getX() and getY() for my own purposes. Java Swing uses a component's getX() and getY() which is why the change with setBounds() was not being reflected.
This question already has answers here:
Repaint without clearing
(2 answers)
Closed 3 years ago.
I am implementing a simple Canvas where items can be drawn like a person would in real life with a paper and a pencil, without clearing the entire page every time an object is drawn.
What I have so far...
A Canvas to implement the drawing:
public class Canvas extends JPanel {
private final Random random = new Random();
public Canvas() {
setOpaque(false); // I thought setting this flag makes the drawn pixels be preserved...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(640, 480);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(random.nextInt(getWidth()), random.nextInt(getHeight()), 5, 5);
}
}
The Window as an actual window:
public class Window extends JFrame {
public Window(Canvas canvas) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(canvas);
pack();
setVisible(true);
}
}
And the Controller with an entry-point to the application. Also starts a timer so the repaint on Canvas is called every second to force drawing another circle.
public class Controller {
public static void main(String[] args) {
Canvas canvas = new Canvas();
SwingUtilities.invokeLater(() -> new Window(canvas));
new Timer(1000, e -> canvas.repaint()).start();
}
}
The problem is that whenever a new circle is drawn, the previous one is cleared. Seems like there is still some process filling the JPanel or maybe the entire JFrame with white color.
Painting in Swing is destructive. It is an expected requirement that each time a component is painted, it is painted from scratch, again.
You need to define a model which maintains the information needed in order to restore the state from scratch.
Your paint routines would then iterate this model and draw the elements each time.
This has the benefit of allowing you to modify the model, removing or inserting elements, which would allow you to update what is been painted simply.
Alternatively, you could use a "buffer" (ie a BufferedImage) on to which all you painting is done, you would then simply paint the image to the component each time the component is painted.
This, however, means that you can't undo or layer the paintings, it's drawn directly to the image. It also makes resizing the drawing image area more difficult, as you need to make these updates manually, where as the "model" based implementation is far more adaptable
Consider calling the alternate constructor of repaint(...)
repaint(long tm, int x, int y, int width, int height)
This allows you to set a specified area to be repainted.
Also you can just store what you drew in a list and then reprint the drawing to the canvas after repaint is called.
I'm developing a software which paints 2 different JPanel for my GUI: a score and a mast guitar. The score is a class which extends JPanel and has paintComponent() method like this:
public class PanelPartitura extends JPanel implements MouseListener{
public void paintComponent(Graphics comp){
super.paintComponent(comp);
comp2D = (Graphics2D)comp;
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
paintBackground();
paintStave();
paintNotes();
[...]
}
}
The mast guitar is a class as well:
public class PanelGuitarra extends JPanel implements MouseListener
public void paintComponent(Graphics comp){
super.paintComponent(comp);
comp2D = (Graphics2D)comp;
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//Then I call secondary methods to paint it:
paintBackground();
PaintPoints();
}
[...]
}
It still works fine. I add the class PanelPartitura to a JScrollPane in order to scroll when it's playing:
partitura = new PanelPartitura();
JScrollPartitura = new JScrollPane(partitura, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
Both JPanels mix each others painted components when the software is playing and scrolling. I would like to ask, if somebody has a clue about what on earth is going on? In my opinion:
It could be because I separated the painting methods as we've seen above:
paintBackground();
paintStave();
paintNotes();
then, when the software starts to paint, it paints some parts of the first JPanel (paintBackground() for example) and then some parts of the mast guitar (paintBackground()), then it changes again and the result is a mixture of both.
I think this is because it mixes different parts every time, I mean it doesn't behave in the same way every time it plays.
I really don't want this to be happening, so let me ask you: how can I make atomic methods to be sure this wouldn't be the problem?
I missunderstood the scroll method. I scroll on this way:
//the note playing currently position is saved in positionBar
positionBar = 150 + 50*PGuitarra.composicion.getAcordeSeleccionado().getPosicionXAcorde();
//horizontalScrollBar is moved to this position
PGuitarra.JScrollPartitura.getHorizontalScrollBar().setValue(positionBar);
I see that your paint methods are not using the same Graphics object (at the JPanel scope). Could that be the reason? And if it is, try passing comp (the Graphics object) as a parameter to paintBackground, paintStave and paintNotes.
I am trying to call the paint() method from another class, but it just doesn't work.
Here is the code:
Main.java:
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private int WIDTH = 600;
private int HEIGHT = 400;
private String NAME = "Dark Ages";
private String VERSION = "0.0.1 Pre-Alpha";
static boolean running = false;
private Image dbImage;
private Graphics dbg;
public Main() {
//Initialize window
JFrame frame = new JFrame();
frame.setTitle(NAME + " - " + VERSION);
frame.setSize(WIDTH, HEIGHT);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//Running
running = true;
}
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g) {
// Draw Images
repaint();
}
public static void main(String args[]) {
new Main();
Player player = new Player();
}
}
Player.java:
public class Player {
public void paint(Graphics g) {
g.drawRect(100, 100, 100, 100);
}
}
How do I call the paint() method from another class in java?
In brief, you don't. And in fact, you shouldn't call it directly from the same class either. Instead you should change the state of the class (change its fields), and then call repaint() on it, which will suggest to the JVM that the component should be painted.
Other issues and suggestions:
An obvious issue I see immediately in your code is that your class has a Graphics field, something that is dangerous to do. I suggest that you get rid of that field so that you're not tempted to use it.
Do not draw directly within a JFrame, JDialog or other top-level window. These windows have too many roles to play behind the scenes that you don't really want to mess with how they render themselves or their children (unless you really know what you're doing and have definite need).
Better to draw in the paintComponent(...) method override of a JPanel or other JComponents.
In your paintComponent(...) override, don't forget to call the super's method: super.paintComponent(g);. This will allow Swing to do housekeeping drawing, such as erasing old out of date or deleted images, before you do your drawing.
Run, don't walk to your nearest Swing painting tutorial.
Your current Player class extends no Swing component and is added to no top level window, so its code will do nothing useful. Again, read the tutorials.
Never call repaint() from within paint(...) or paintComponent(...).
Please post modified code if possible.: please don't ask us to create code for you as that's your job. Please understand that the more code you create, the better a coder you'll be, and because of this, most of us don't feel that we should cheat you out of the opportunity to create your own code.
Useful Java Tutorials:
The Really Big Index: The main tutorial where you should start.
Using Swing Components: How to create Swing GUI's
Lesson: Performing Custom Painting: Introductory tutorial to Swing graphics
Painting in AWT and Swing: Advanced tutorial on Swing graphics
The Jlabel is not showing up when I put it in the paint(Graphics2d g) method and I can't figure out why.
My text class:
import java.awt.Color;
import java.awt.Graphics2D;
import javax.swing.JLabel;
public class Text {
int ballX,ballY,squareX,squareY;
Text text;
private Game game;
private Ball ball;
private Racquet racquet;
public void main(){
ballX = ball.getBallX();
ballY = ball.getBallY();
squareX = racquet.getSquareX();
squareY = racquet.getSquareY();
}
public void paint(Graphics2D g) {
g.setColor(Color.red);
JLabel balltext = new JLabel("the ball is at " + ballX + ballY);
balltext.setVisible(true);
g.setColor(Color.green);
JLabel squaretext = new JLabel("the ball is at " + squareX + squareY);
squaretext.setVisible(true);
}
}
There are a few things not quite right with your code.
Firstly, Text does not extend from anything that is paintable, so paint will never be called. Convention tends to favor overriding paintComponent of Swing components anyway.
Also, you should always call super.paintXxx, this would have highlighted the problem in the first place.
Secondly, components are normally added to some kind container which takes care of painting them for you.
If you want to use Swing components in your program, I'd suggest taking a look at Creating a GUI With JFC/Swing.
If you want to paint text, I'd suggest you take a look at 2D Graphics, in particular Working with Text APIs
An bit more information about what it is you're trying to achieve might also help
Also, I'm not sure if this deliberate or not, but public void main(){ ins't going to act as the main entry point of the program, it should be public static void main(String args[]), but you might just be using main as means to call into the class from else where ;)
From the look of things you are missing quite a few paradigms / idioms for a Java Swing gui.
For example:
Text should extend JComponent if you want to override paint / paintComponent to specify how the component should be drawn.
You should create a separate Main class to serve as an entrypoint to your program (you don't have to, but it helps you keep things logically separated for now, which is easier conceptualize mentally for you)
You need to create a JFrame inside your main method, then create the Text class and add it to JFrame and call pack() and setVisible(True) on the JFrame.
I would recommend looking at some examples first to get oriented:
http://zetcode.com/tutorials/javaswingtutorial/firstprograms/
http://www.javabeginner.com/java-swing/java-swing-tutorial