So I'm working on a somewhat interactive painting of a chess game. Basically, for now, there are only 2 buttons: next move and previous move. The next move button adds 1 to the int variable moveNum, and the previous move button subtracts 1 from the int variable moveNum. Basically like this:
int moveNum = 0;
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("Next Move"))
{
moveNum++;
Display.instance.repaint();
}
else if(e.getActionCommand().equals("Previous Move"))
{
moveNum--;
Display.instance.repaint();
}
}
I then just have a ton of graphics, one for each value of moveNum. It looks somewhat like this:
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLACK);
if (moveNum == 0)
{
g2d.fill(new Rectangle2D.Double(0, 0, 10, 10));//just for simplicity
}
else if (moveNum == 1)
{
g2d.fill(new Rectangle2D.Double(0, 0, 10, 10));
g2d.fill(new Rectangle2D.Double(0, 0, 20, 10)); //again for simplicity
}
else if (moveNum ==2)
{
g2d.fill(new Rectangle2D.Double(0, 0, 10, 10));
g2d.fill(new Rectangle2D.Double(0, 0, 20, 10));
g2d.fill(new Rectangle2D.Double(0, 0, 30, 10)); //simplicity
}
...
}
But the graphics are not changing when I press the buttons. What could I be missing?
Update: I have tried to call Display.instance.repaint() after the moveNum stuff, but now I get no graphics at all. What could be the problem?
Update #2: The paint component is being executed because when I put System.out.println("Test"); to the method, it is being printed. I also now see the infinite recursion problem (not sure how I did not see it before). But even after fixing it, I still don't get the graphics I want. I realized that I can get some graphics when I go full-screen for some reason. But the buttons still don't change the graphics. Using the System.out.println("Test"); method, I found that "Test" is printed once when I run the program, two more times when I go full screen and get graphics, and 12 more times when I press the next button. I'm not really sure what's going on there, are my buttons set up incorrectly?
Final update: I do not have a MRE/SSCE, but I have figured out my problem. I have realized I'm one of the biggest idiots in the universe and my problem was capitalization. My buttons were not working because I capitalized the wrong thing in both of them in the segment e.getActionCommand().equals("Next Move")). Anyways, thanks a ton for your help. I don't think I would have found the infinite recursion problem, so special thanks for helping with that.
Try adding component.repaint() after moveNum++; and after moveNum--;.
When component is the component that you want to update.
Also, remove the repaint() inside paintComponent(Graphics g)
Related
in my application I have a cross road picture in the background and I want to draw traffic lights on the top of it (black rectangle with 3 circles)
The problem is, I cannot see the rectangle at all, as if it was under the image or something. And if I switch the order in which the items are painted, I get all black image.
Do you have any idea how this can be solved?I am new to graphics and searched similar questions, but none helped me.
Thank you.
public MainFrame() throws HeadlessException {
super("semafor");
crossroad = new ImageIcon("cross.png");
initFrame();
initComponents();
sem1 = new Semafor(true, 100, 100);
add(sem1);
repaint();
setVisible(true);
}
//here I paint the image
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(crossroad.getImage(), 0, 45, this);
}
//and in class Semafor i paint the actual traffic lights
#Override
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.darkGray);
//and then the circles
}
The first thing I'm noticing is that you are calling <unknown>.getWidth() and <unknown>.getHeight() for the rectangle size. If it's covering the entire image, this suggests that it is getting that width and height from the panel it is being drawn on.
A simple stack trace,
(new Exception).printStackTrace();
or
Thread.dumpStack();
will tell you as much. You could also query the width and height with a System.out call to verify that you're getting the values you're expecting, or, if this really gets out of control, learn to use JUnit and the assert statement. Honestly, though, it looks like you're just accidentally calling the wrong method.
So I'm making a simple pause function in my game, and I want to have a grey transparent background, the problem is, the rectangle keeps overlapping and is just causing a fade out look. I've tried g2.dispose, and it works, but I can't draw anything else over that.
I have my render method, which is being called 60 times a second. (I issume the rectangle is being drawn 60 times a second)
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
}
Thanks!
Edit: I feel like an idiot... I just had to draw my ingame screen underneath that!
If I understand correctly what you mean by "causing a fade out look" (although I'm not sure I do), you want to fill a background with a transparent color without blending the new transparent color with pixels that are already present. You can do this by setting the composite mode to "source":
g2.setComposite(AlphaComposite.Src);
You can set it back to the default "source over destination" rule to return to normal drawing afterwards by doing:
g2.setComposite(AlphaComposite.SrcOver);
Edit: Or perhaps you do want to blend the transparent color, but with the rest of the game graphics and not with itself? In that case, just make sure that you're redrawing the game background each time you draw the transparency over the top, although I'd suggest pausing the 60fps refresh during game pause if nothing on the screen is changing, just to avoid wasting CPU/battery.
Consider trying to create a copy of the Graphics context first and then disposing of it when your finished...
public void render(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(new Color(0, 0, 0, 50));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
g2.drawImage(paused, 0, 0, null);
g2.dispose();
}
This way, the changes to the Graphics state remain isolated between the create and dispose calls and don't affect anything else painted after it
Also, remember, unless you are clearing what was previously painted to the Graphics context, it will accumulate on repeated calls.
I couldn't find any other questions like this, but if someone finds a question like it, feel free to mark it as a duplicate.
I am wondering how to keep only some of the drawings that are on screen. As some preface, I am trying to make a small paint like program (I am making this with the Leap Motion). I want it so that if the Z if less than -80 then draw a line that stays on the screen (As if you were clicking the mouse) and if not, then don't draw a line, just show a 'cursor' (A little white dot). The method I am using to draw things to the screen is as follows:
protected void render() {
BufferStrategy bStrategy = getBufferStrategy();
if (bStrategy == null) {
createBufferStrategy(3);
return;
}
Graphics graphics = bStrategy.getDrawGraphics();
{
Drawing.getInstance(graphics).drawBackground(Color.BLACK, getWidth(), getHeight());
{
List<Coordinate> list = Drawing.getInstance(graphics).drawColorBox(3, 25, 25, 0, 50, Color.DARK_GRAY, Color.BLUE);
List<Coordinate> listII = Drawing.getInstance(graphics).drawColorBox(3, 25, 25, 0, 25, Color.DARK_GRAY, Color.RED);
Drawing.getInstance(graphics).drawDot(loc.getX(), loc.getY(), 5, 5, currentColor);
getCollision(list, Color.BLUE, graphics);
getCollision(listII, Color.RED, graphics);
}
}
graphics.dispose();
bStrategy.show();
}
Drawing is another class that just deals with the drawing of items to the screen. If you need the class just ask.
Summary:
I want to draw some lines to the screen, but not others and want to be able to control which ones to draw and not to draw.
If this doesn't make sense just say and I will try and reword it. Any help is appreciated.
~Ryan
I would recommend making a Line class with an isVisible instance variable. Keep track of all the lines in an ArrayList<Line>, and then toggle them on or off with the isVisible variable.
I have a panel on which I want to draw stuff.
Painting on it when it is beeing created is no problem.
canvas = new Panel() {
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawLine(0, 0, 10, 10);
}
};
But then I want to draw on it during runtime.
By instinct, I've created something like this:
Graphics g = canvas.getGraphics();
g.setColor(Color.GREEN);
g.drawLine(10, 10, 20, 20);
canvas.paint(g);
Sadly, this doesn't work.
This is probably a simple question but I cannot find a satisfying result by searching.
So how can I do what I want to do?
Sorry for the question above.
I just added the paint code on a button click event and it works.
It just doesn't work on the windowOpened event of the parent frame.
Any ideas why?
The problem is that the paint() method can be called at any time whenever the window system (or OS) decides that the particular graphical component needs to be repainted on screen. This may happen at any moment (most often when resizing, moving, switching windows, etc). To see how often it happens just add a log message at the beginning of paint() method. If you paint something on canvas just once it's very likely that it's painted, but then another repaint request comes from OS/window system and your green line gets "overdrawn" by object's paint() .
So the answer is that any custom painting should be done in paint(). You can add extra attributes to your subclass (eg. boolean drawGreenLine), check it in paint() and take any appropriate action, eg:
class MyPanel extends JPanel {
boolean drawGreenLine;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.drawLine(0, 0, 10, 10);
if (drawGreenLine) {
g.setColor(Color.GREEN);
g.drawLine(10, 10, 20, 20);
}
}
};
EDIT: As suggested by #MadProgrammer the example has been changed to override paintComponent(). This way the component is only responsible for drawing itself (and not any children or borders).
try g.dispose() to release the GraphicsContext's ressources
I've created a custom swing component. I can see it (the grid from the paint method is drawn), but the buttons that are added (verified by println) aren't shown. What am I doing wrong?
Background information: I'm trying to build a tree of visible objects like the Flash/AS3 display list.
public class MapPanel extends JComponent { // or extends JPanel, same effect
private static final long serialVersionUID = 4844990579260312742L;
public MapPanel(ShapeMap map) {
setBackground(Color.LIGHT_GRAY);
setPreferredSize(new Dimension(1000,1000));
setLayout(null);
for (Layer l : map.getLayers()) {
// LayerView layerView = new LayerView(l);
// add(layerView);
System.out.println(l);
JButton test = new JButton(l.getName());
add(test);
validate();
}
}
#Override
protected void paintComponent(Graphics g) {
// necessary?
super.paintComponent(g);
// background
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
// grid
g.setColor(Color.GRAY);
for (double x = 0; x < getWidth(); x += 10) {
g.drawLine((int)x, 0, (int)x, getHeight());
}
for (double y = 0; y < getHeight(); y += 10) {
g.drawLine(0, (int)y, getWidth(), (int)y);
}
}
}
Setting null as the layout manager and then adding buttons will not have any effect. A layout manager is responsible for computing the bounds of the children components, and setting layout manager to null effectively leaves all your buttons with bounds = (0,0,0,0).
Try calling test.setBounds(10, 10, 50, 20) as a quick test to see if the buttons appear. If they do, they will be shown at exactly the same spot. From there you can either install a custom layout manager that gives each button the required bounds, or use one of the core / third party layout managers.
It would be easier for us to diagnose your problem if you gave us a SSCCE. As it stands, we may not have enough information to fix your problem.
I can see it (the grid from the paint
method is drawn),
I don't know what that means, there is no paint() method in the posted code. (But I suppose it is easy enough to assume that you meant paintComponent(g))
However, it looks like the problem is that you are uisng a "null layout". The children will not paint unless you manually set the size and location of the children.
You should probably read a quick tutorial on LayoutManagers. It may make things easier for you when drawing components.