Java: Why does paintComponent go through twice?

Discussion in 'Mac Programming' started by jsmwoolf, Sep 22, 2011.

  1. jsmwoolf macrumors regular

    Joined:
    Aug 17, 2011
    #1
    I'm making a Connect 4 game in Java for more complex practice in checking and for an AI. I already input the mechanics of the game and got the graphics to work. When the user clicks on a numbered button, it drops a token with a color based on whether the first player is up. However, even though the repaint method is called before the bool that handles the player's turn(player1 is the variable), it appears that the cell changes color even though I didn't activate it.

    Code:
    import java.awt.event.*;
    import java.util.Random;
    
    public class Control implements ActionListener, ItemListener {
    
    	Connect4 game = null;
    	boolean player1 = true; //Checks which player is up
    	int[][] theBoard = new int[7][6]; //Sets up the board for values [7]-columns, [6]- rows
    	int[] valid = new int[4]; //Grabs 4 in a row. This is use for a win
    	//This is for the AI
    	boolean AI=false; //Is the AI playing or not?
    	boolean AITurn=false; //A value that switches the AI's turn
    	boolean AIMadeUpMind=false; //This is for moves in advance
    	int AINumber=0; //This is for what row the AI will choose
    	Random generator = new Random(); //This is for whether the AI hadn't made up its mind.
    	
    	public Control(Connect4 game)
    	{
    		game = new Connect4(this);
    		this.game=game;
    	}
    	
    	public static void main(String[] args) {
    		Control control = new Control(null);
    	}
    
    	public void actionPerformed(ActionEvent input) {
    		Object current = input.getSource();
    		//This deals with the slot buttons
    		for(int x = 0; x < 7; x++)
    		{
    		if(current.equals(game.rowButton[x]))
    		{
    			dropToken(x);
    		}
    		}
    		//This is for the Start button
    		if(current.equals(game.start))
    		{
    			for(int x = 0; x < 7; x++)
    			{
    				game.rowButton[x].setEnabled(true);
    			}
    			for(int y = 0; y < 7; y++)
    			{
    				for(int z = 0; z < 6; z++)
    				{
    					theBoard[y][z]=0;
    					game.cell[y][z].taken=false;
    					game.cell[y][z].repaint();
    				}
    			}
    			game.start.setEnabled(false);
    			game.AI.setEnabled(false);
    		}
    	}
    	
    	public void itemStateChanged(ItemEvent input) {
    		Object current = input.getSource();
    		//This is for the AI 
    		if(current.equals(game.AI))
    		{
    			if(game.AI.isSelected())
    			{
    			AI = true;	
    			}
    			else
    			{
    				AI = false;
    			}
    			System.out.println("The AI is " + AI);
    		}
    		
    	}
    	
    	//Handle's the AI's behavior
    	void AIMove()
    	{
    		if(AITurn==true)
    		{
    		checkMove(); //First it'll check each move
    		//Then if it didn't find a move, this will randomly pick a move
    		while(AIMadeUpMind==false)
    		{
    			AINumber = generator.nextInt(7);
    			if(game.rowButton[AINumber].isEnabled())
    			{
    				AIMadeUpMind=true;
    			}
    		}
    		dropToken(AINumber); //When the AI found a move, it'll play the token
    		}
    		
    	}
    	
    	//If it's the AI's turn, it'll check the valid array values and determine a move there
    	void AIDetermineMove()
    	{
    		
    	}
    	
    	//Will drop the token
    	void dropToken(int x)
    	{
    		int max=0;
    		//Checks for spaces
    		for(int y = 5; y >= 0; y--)
    		{
    			if(theBoard[x][y]==0)
    			{
    				System.out.println(player1);
    				game.cell[x][y].taken=true;
    				game.cell[x][y].repaint();
    				if(player1==true)
    				{
    					theBoard[x][y]=1;
    					player1=false;
    					if(AI==true)
    					{
    						AITurn=true;
    					}
    					break;
    				}
    				else
    				{
    					theBoard[x][y]=2;
    					player1=true;
    					if(AI==true)
    					{
    						AIMadeUpMind=false;
    						AITurn=false;
    					}
    					break;
    				}
    			}
    			else
    			{
    				max++;
    			}
    			
    		}
    		//If there are no moves in this column, it'll lock the button
    		if(max==5)
    		{
    			game.rowButton[x].setEnabled(false);
    		}
    		//Then it'll need to check every move for a win
    		checkMove();
    		//If the AI is playing, it'll activate the AI's script
    		if((AI==true) && (AITurn==true))
    		{
    			AIMove();
    		}
    	}
    	
    	//The main script for checking wins and for the computer to check for counter/win moves. 
    	void checkMove()
    	{
    		checkHorizontalMoves(); //#1- The game will check Horizontal moves for a win.
    		checkVerticalMoves(); //#2 - The game will check Vertical moves for a win.
    		checkDiagonal1Moves(); //#3 - The game will check Forward Diagonal moves for a win.
    		checkDiagonal2Moves(); //#4 - The game will check Reverse Diagonal moves for a win.
    	}
    	
    	void checkHorizontalMoves()
    	{
    		System.out.println("\nFor Horizontal Wins!");
    		for (int y = 0; y < 6; y++) // Row
    		{
    			System.out.println("For row " + (y+1));
    			for(int x = 0; x < 4; x++) //Column
    			{
    				for(int z = 0; z < 4; z++) //Offset
    				{
    					valid[z] = theBoard[x+z][y];
    					System.out.println("x:" + ((x+z)+1) + ",y:" + (y+1) + " which holds the value " + valid[z]);
    				}
    				System.out.println();
    				checkWin();
    				if(AITurn==true)
    				{
    					
    				}
    			}
    		}
    	}
    	
    	void checkVerticalMoves()
    	{
    		System.out.println("\nFor Vertical Wins!");
    		for (int y = 0; y < 7; y++) //Column
    		{
    			System.out.println("For column " + (y+1));
    			for(int x = 0; x < 3; x++) //Row
    			{
    				for(int z = 0; z < 4; z++) //Offset
    				{
    					valid[z] = theBoard[y][x+z];
    					System.out.println("x:"+ (y+1) + ",y:" + ((x+z)+1) + " which holds the value " + valid[z]);
    				}
    				System.out.println();
    				checkWin();
    				if(AITurn==true)
    				{
    					
    				}
    			}
    		}
    		
    	}
    	
    	void checkDiagonal1Moves()
    	{
    		System.out.println("\nFor Diagonal Wins!");
    		for (int y = 0; y < 4; y++) //Column
    		{
    			System.out.println("For diagonal " + (y+1));
    			for(int x = 0; x < 3; x++) //Row
    			{
    				for(int z = 0; z < 4; z++) //Offset
    				{
    					valid[z] = theBoard[y+z][x+z];
    					System.out.println("x:" + ((y+z)+1) + ",y:" +  ((x+z)+1)+ " which holds the value " + valid[z]);
    				}
    				System.out.println();
    				checkWin();
    				if(AITurn==true)
    				{
    					
    				}
    			}
    		}
    	}
    	
    	void checkDiagonal2Moves()
    	{
    		System.out.println("\nFor Diagonal Wins!");
    		for (int y = 3; y < 7; y++) //Column
    		{
    			System.out.println("For reverse diagonal " + (y-2));
    			for(int x = 0; x < 3; x++) //Row
    			{
    				for(int z = 0; z < 4; z++) //Offset
    				{
    					valid[z] = theBoard[y-z][z+x];
    					System.out.println("x:" + ((y-z)+1) + ",y:" +  ((z+x)+1)+ " which holds the value " + valid[z]);
    				}
    				System.out.println();
    				checkWin();
    				if(AITurn==true)
    				{
    					
    				}
    			}
    		}
    	}
    	
    	void checkWin()
    	{
    		for(int x = 0; x < 2; x++)
    		{
    		if((valid[0]==(x+1)) && (valid[1]==(x+1)) && (valid[2]==(x+1)) && (valid[3]==(x+1)))
    		{
    			System.out.println("Player " + (x+1) + " wins!");
    			for(int z = 0; z < 7; z++)
    			{
    				game.rowButton[z].setEnabled(false);
    			}
    			game.start.setEnabled(true);
    			game.AI.setEnabled(true);
    			AITurn=false;
    		}}
    	}
    
    }
    Code:
    import javax.swing.*;
    import java.awt.*;
    import javax.swing.JPanel;
    
    public class Connect4 {
    	
    	Control control;
    	Cell[][] cell = null;
    	
    	JFrame window = new JFrame("Connect 4");
    	//Row 1
    	JPanel row1 = new JPanel();
    	JCheckBox AI = new JCheckBox("AI");
    	JButton start = new JButton("Start");
    	
    	//Row 2
    	JPanel row2 = new JPanel();
    	JButton[] rowButton = new JButton[7];
    	Dimension rowButtonSize = new Dimension(32,32);
    	
    	//Row3
    	JPanel row3 = new JPanel();
    	
    	
    	public Connect4(Control control)
    	{
    		cell = new Cell[7][6];
    		this.control = control;
    		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		window.setSize(300,365);
    		window.setResizable(false);
    		FlowLayout layout = new FlowLayout();
    		window.setLayout(layout);
    		
    		FlowLayout layout1 = new FlowLayout();
    		row1.setLayout(layout1);
    		row1.add(AI);
    		row1.add(start);
    		window.add(row1);
    		
    		//It'll then draw the slot 1 through 7 buttons
    		FlowLayout layout2 = new FlowLayout();
    		row2.setLayout(layout2);
    		for(int x =0; x < 7; x++)
    		{
    		rowButton[x]= new JButton(Integer.toString(x+1));
    		rowButton[x].setPreferredSize(rowButtonSize);
    		rowButton[x].addActionListener(control);
    		row2.add(rowButton[x]);
    		rowButton[x].setEnabled(false);
    		}
    		window.add(row2);
    		//Then it'll set up the cells for the board
    		GridLayout layout3 = new GridLayout(6,7);
    		row3.setLayout(layout3);
    		for(int y = 0; y < 6; y++)
    		{
    		for(int x = 0; x < 7; x++)
    		{
    			cell[x][y] = new Cell(control);
    			System.out.println(x + "," + y);
    			row3.add(cell[x][y]);
    		}}
    		row3.setPreferredSize(new Dimension(32*7,32*6));
    		window.add(row3);
    		AI.addItemListener(control);
    		start.addActionListener(control);
    window.setVisible(true);
    	}
    	
    }
    
    class Cell extends JComponent
    {
    	boolean taken=false;
    	Control control;
    	public Cell(Control control)
    	{
    this.control = control;
    	}
    	
    	public void paint(Graphics g)
    	{
    		//This'll draw the rectangle for the cell.
    		super.paint(g);
    		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    	}
    	
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);
    		if(taken==true)
    		{
    			drawCircle(g,control.player1); //This'll draw a circle representing the player's token
    		}
    	}
    	
    	void drawCircle(Graphics g, boolean player1Taken)
    	{
    		if(player1Taken==true)
    		{
    			g.setColor(Color.yellow);
    		}
    		else
    		{
    			g.setColor(Color.red);
    		}
    		g.fillOval(0, 0, 31, 31);
    	}
    }
    
    So what's going on?
     
  2. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    A component can be painted at any time. For example, if another window appears on top of your game, when the user closes that window, your game window will be repainted. So it's wrong to use who's turn it is to decide with color to use to paint a Cell.

    Ignoring MVC principles here, Cell needs to have a field so that it knows which player is occupying it. It would use that field to paint appropriately. Control then needs to change this field (via a setter, of course).

    In a proper MVC design, Cell would need to know how to query the game state to find out which player is occupying a cell. It needs to listen to changes to the game state, so that it can repaint itself if appropriately.

    But I get the feeling this will fall on deaf ears, just like the strong, repeated advise not to override paint.
     
  3. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #3
    When you mean Cell, do you mean an argument when calling the Cell's PaintComponent or a variable within the component that is labeled on what player took the spot? Probably the PaintComponent part?

    As for your "Cell needs to have a field so that it knows which player is occupying it." Statement, couldn't you just use a variable within the component and change the color on what the value is? Or are you referring to something else?

    So my question is can you tell a JComponent when to repaint or you can't? I used variables on when to paint, but you're probably suggesting that there's another way on how to do it.

    Is there a specific function within Java.awt.event.*; that deals with query/environment control or did I misunderstand you?

    I understand that I was told on many instances. The thing is that I'm new to drawing Graphics using Swing. Did I get it right this time with not overriding the paint and paintComponent functions? It eventually ticked on me and I now know what to do.
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    I'm afraid you still don't have it right.

    I don't know where you learned that you should write paint() methods for custom JComponents. Wherever you learned that, it's wrong for JComponents.

    You still haven't posted anything about what book or tutorial you're working from, or have worked from in the past. Any Swing tutorial or book that isn't grossly incorrect would not have said to write a paint() method.

    Before Swing, writing paint() methods was one way to make custom Components, but that approach is long dead unless it's for very specific and unique reasons (none of which apply here).


    At this point, it's clear to me that you don't correctly understand what override means when referring to methods.

    The statement quoted above tells me that you believe you are not overriding the paint and paintComponent functions. This is false. On both counts. You are overriding paint(). You are overriding paintComponent(). That's two overrides of two separate methods.

    Any time a subclass defines a new implementation of a superclass method, that new implementation is an override. The whole new method definition is the override.

    The body of the overridden method is just that: the body of the overridden method. What's in the body is the implementation of the override. What the implementation does in the override is simply that: the implementation.

    If the implementation wishes to call the superclass version of the method, it does that using the super.methodName() notation. The use of the keyword super is not an override. It's simply a reference name that ensures access to the superclass method. If you don't correctly understand what superclass means in this context, then I suspect you will misunderstand a large portion of that terse description.

    So in the following excerpt from the posted code:
    Code:
    class Cell extends JComponent
    {
    	boolean taken=false;
    	Control control;
    	public Cell(Control control)
    	{
    this.control = control;
    	}
    	
    [COLOR="Red"]	public void paint(Graphics g)
    	{
    		//This'll draw the rectangle for the cell.
    		super.paint(g);
    		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    	}
    [/COLOR]	
    [COLOR="Blue"]	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);
    		if(taken==true)
    		{
    			drawCircle(g,control.player1); //This'll draw a circle representing the player's token
    		}
    	}
    [/COLOR]
    There are two separate method overrides. There is an override of paint() hilited in red. There is a second override of paintComponent() hilited in blue. The fact that these two methods have a working relationship to one another (i.e. one is expected to call the other) makes no difference: there are two separate method overrides here.

    The fact that each override calls its superclass method is not relevant to the existence of the override. If the body of both methods did nothing, like so:
    Code:
    public void paint(Graphics g)
    {  ;  }
    
    public void paintComponent(Graphics g)
    {  ;  }
    
    there would still be two method overrides.

    If the body of both methods only called the superclass method, like so:
    Code:
    public void paint(Graphics g)
    {  super.paint(g);  }
    
    public void paintComponent(Graphics g)
    {  super.paintComponent(g);  }
    
    there are still two method overrides here. The fact that there is no change in behavior due to the superclass method invocations is irrelevant. The two methods have still been overridden. Their implementation is a completely separate issue.


    Now, re-examining your statement, you also seem to think that you should not override paint() or paintComponent(). This is also wrong.

    I specifically said the following.
    http://forums.macrumors.com/showthread.php?p=13350257&highlight=#post13350257
    Don't override paint() at all. Only override paintComponent().
    Granted, if you don't know what "override" means, then you may not be able to follow those directions correctly. But if you don't say you don't know what "override" means, then we can't explain or clarify, and you go off on a wild-goose chase, continuing to do the wrong thing with no understanding of how wrong it is.

    I also asked these two questions:
    Did you follow the custom JComponent tutorial I pointed you to before? Did they override paint()?
    The answer to the second question is "No". If you had done the tutorial, you would know this, simply by seeing how they did it in the tutorial.


    At this point, I'm not sure how much more help I can provide, nor how much effect it will have.

    You don't understand basic terminology like override, yet you don't say that you don't understand the terms when they're used, so we have no way of knowing when clarification or definition is needed. You don't seem to look things up in online references like Wikipedia (which does have an article on Override of methods), so relying on you to look up undefined terms yourself is demonstrably not working.

    You don't seem to be willing to follow tutorials, even when you're pointed at them more than once. You don't answer plain questions like "Did you follow the tutorial?", and you don't provide any information on which books, tutorials, or other materials you used to learn up to this point.

    Because you haven't told us what you've learned from, we can't determine whether there are errors in your source material, or whether you're misreading or misapprehending what they say. I think I can reliably say that you have some serious fundamental misunderstandings, but exactly what they are is anyone's guess.

    If that seems harsh, I'm sorry. But until you do something to alter these fundamental issues, I don't see how it's worthwhile to try to proceed.
     
  5. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #5
    I will clearly admit, I do take assumptions. The thing is I don't really know how not to override the paint function. Is even putting it in code an override just like in your example? I took the assumption that super prevents it from overriding, but I'm wrong on that too.

    As for the book, I've been looking at Sams Teach Yourself Java in 24 Hours. Graphics are in Chapter 23(Hour 23 in the book) and it clearly says "...init(), paint(), start(), stop(), and destroy(). However, none of these methods do anything. If you want something to happen, you must override these methods with new versions in your applet."(p.236, Hour 17) While I'm not creating an applet, I suppose that this stills applies for anything that you do in Java.

    From the tutorial that you linked me to:
    The thing is that I only used paint for drawing the border, not for drawing the chips. But the ENTIRE TIME you're saying not to even use the paint function at all, only the paintComponent. I took another assumption that use paint only for initial and not for stuff that will change overtime. Can I still do this though or would I be overriding the paint function as well?
    Code:
    game.cell[x][y].repaint
    As you see, I have been looking at tutorial after tutorial looking up paintComponent and I questioned why didn't they use the paint function. But re-looking at one of the post, you defined it
    But the question is why won't it call paintComponent()?

    One of the sites that I looked at was this one:
    http://www.roseindia.net/java/java-tips/GUI-lowlevel/graphics/15who-calls-paintcomponent.shtml If you go to the dice example, there'll be the source code.

    The only coded part that I saw was this:
    Code:
    public void paintComponent(Graphics g) {
            // Let UI Delegate paint first, which 
            // includes background filling since 
            // this component is opaque.
    
            super.paintComponent(g);       
            g.drawString("This is my custom Panel!",10,20);
            redSquare.paintSquare(g);
    }
    I didn't see the paint function in there nor did I understand you at the time.

    I didn't know that there was such an article on wikipedia, but I found it.
    In my case, it seems that just mentioning paint within the code overrides it.

    So in the case of paint() and paintComponent(), mentioning it in code overrides it along with not having super within it. But if I don't mention it, the functions are not overridden. This must be because as you said, the program does this automatically and whenever you need to repaint() the scenery.

    The thing is how can you correctly follow a tutorial if you can't even properly interpret it the first time.
    This part was the last thing that I said on one of my posts.

    It appears that I'm misreading and misapprehending on the information and I bet that these things will cause an error in my source code.

    Don't be. It's my fault that I couldn't grasp on the concept, not yours. I totally deserve it and it hurts to read it.

    Before we proceed, let me get this straight, mentioning paint or any of its subclasses overrides the function while not mentioning it does not override it. The keyword super has no effect on overriding the function, only the superclass version. If I want to, in my case, put a rectangular border then I must only put it in the paintComponent. If I get the info right, I would like to ask another question.
     
  6. chown33, Sep 23, 2011
    Last edited: Sep 23, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    Wrong. It only applies to the Applet class. Not to the JApplet class, in which you should override paintComponent() instead of paint(). Not to any other Java class, which don't have init(), start(), stop(), and destroy() methods.

    Exactly which edition of the book do you have? What is the published date? Because as I said before, overriding paint() has long been outdated, and any book that's still using Applet instead of JApplet is probably equally outdated.


    Nothing has changed in what I wrote. Do not override paint() at all. Only override paintComponent().

    That means put all your drawing code in paintComponent(). You should have no method definition for paint() at all. I'm assuming you know what I mean by a method definition.


    If you don't redefine (i.e override) paint(), it will call paintComponent().

    If you override paint(), then it only does what's in the body of your redefined method.


    Do you see the paint() method called or redefined? I don't.


    First, it's not clear what you mean by "mentioning paint".

    In the code you posted, you don't "mention" paint(), you define a paint method. It looks like this:
    Code:
    	public void paint(Graphics g)
    	{
    		//This'll draw the rectangle for the cell.
    [COLOR="Red"]		super.paint(g);
    [/COLOR]		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    	}
    
    In this code, you also "mention paint" as the hilited red statement. That's not an override, that's "calling paint" or "invoking paint".

    You need to distinguish between "calling paint()" and "defining a paint() method".

    In plain old C, there is a big difference between defining a function and calling a function. Same thing applies in Java. Neither C nor Java calls either of those things "mentioning" a function. I can "mention" a function in a comment and it will have no effect at all.


    Second, paint() is a method. It's not a class. A method can't have subclasses. Only a class can have subclasses. A method can be defined in a subclass, if it's undefined in a superclass. If a method defined in a subclass is also defined in a superclass, then that redefinition in the subclass is called an override.


    I really think you need to start your book over, or maybe find a better book. Preferably one that has an actual explanation of what it means to override a method. And one that has a clear explanation of the difference between an overridden method and a subclass.

    I have no idea which book would be suitable. If I were looking for such a book, I would look on Amazon.com and look at the index sections of books, looking for the words override and subclass.


    EDIT

    The 4th edition of "Sams Teach Yourself Java in 24 Hours" (2005) has beginning GUI and Swing in chapter 13.

    The 5th edition of the book is from 2009. Swing begins in chap 13.

    The 6th edition of the book appears to be nearing publication: Nov 2011.
     
  7. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #7
    Neither did I.

    I believe 2010. He does use JApplet though. EDIT: It's the Fifth Edition.

    Wait, can't you somehow redirect paintComponent in an overridden paint function? I bet the answer is either no or it's just easier not to.

    This would be defining the paint function:
    Code:
    	public void paint(Graphics g)
    	{
    		//This'll draw the rectangle for the cell.
    		super.paint(g);
    		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    	}
    While this doesn't:
    Code:
    	public void paint(Graphics g)
    	{
    
    	}
    As I'm leaving it entirely blank. In my case of "mention", I say don't define or set anything up special, like you said. Correct?

    In C, you always define the function global and always call it either in main or in another function. For example:
    Code:
    void function(void)
    {
    int number=0;
    }
    
    int main()
    {
    function();
    return 0;
    }
    Where function is being defined with an integer and the function() is being called in the main.

    My book only dealing with mostly the general stuff.
     
  8. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #8
    Then why do you have paint() code that wasn't called for?


    Wrong. They both redefine the paint method. The first one redefines it to perform some other method calls. The second one redefines it to do nothing. "Redefined to do nothing" is not the same as "Not redefined at all".

    I don't see why this is so hard to understand. Just don't define a paint() method at all. Then put the drawing code you currently have in your paint() method into your paintComponent() definition. All your drawing code should be in paintComponent(). Period.

    The examples you've given (the one I can look at) have no paint() method at all. So just do the same thing: no paint() method at all. Not an empty paint() method. None at all.

    I don't have the book you're using, so I can't tell you whether it has paint() definition or not. But all the examples I've looked at don't have paint(). At. All.


    I can't answer, because I still don't understand what you're asking.


    Agreed, but you "mention" the function twice. It's "mentioned" once when you define it, and it's "mentioned" again when you call it.

    My point is that there is no meaning in programming for the word "mention". There is a meaning for define, call, or declare.
    Code:
    void nothing(void);  // declaration
    void nonexistent(int);  // declaration
    
    int main()
    {
      nothing();  // call
      nonexistent( 42 );  // call
      return 0;
    }
    
    void nothing(void)  // definition
    {  }  // does nothing, but function exists and can be called
    
    // Notice that nonexistent() is declared but not defined.
    // So calling it will fail.  
    // Specifically, it will compile but won't link (unresolved symbol).
    
     
  9. jsmwoolf, Sep 23, 2011
    Last edited: Sep 23, 2011

    jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #9
    How I see it, when I mean mention paint in my case, I mean put/define the method paint in the code.

    This is what you mean in the code? No paint at all. Only paintComponent. Period. I made this change while typing post #5.
    Code:
    class Cell extends JComponent
    {
    	boolean taken=false;
    	Control control;
    	
    	public Cell(Control control)
    	{
    this.control = control;
    	}
    	
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);
    		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    		if(taken==true)
    		{
    			drawCircle(g,control.player1); //This'll draw a circle representing the player's token
    		}
    	}
    	
    	void drawCircle(Graphics g, boolean player1Taken)
    	{
    		if(player1Taken==true)
    		{
    			g.setColor(Color.yellow);
    		}
    		else
    		{
    			g.setColor(Color.red);
    		}
    		g.fillOval(0, 0, 31, 31);
    	}
    }
    If I'm correct, can we address the main issue of this thread and put this long argument on how not to override paint away?
     
  10. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #10
  11. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #11
    groking? Oh grokking!

    My god, these books cost over $100 unless you get a kindle. Right now, I don't have the money, but I will consider these books in the future.

    Do you know any good websites, as well, that deal with some depth of object-orientation?
     
  12. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #12
    You need to use the conventional terms. Or you need to define the terms you use in terms of the conventional terms. If you don't extribulate using the usual blobula, no one will grok what you harashaw. The converse is also true.


    Correct.

    Now you can address the remaining issues in your code.
     
  13. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #13
    The main issue of this thread is that somehow the cell that I'm specifying is changing color to the second player and vise versa twice even though the repaint() is called before the boolean player1 changes the value to false or vise versa. Player 1 is supposed to be red and player 2 is supposed to be yellow. But in the Cell class, I switched the Color section around in order to get the right color. Obviously this is a bad idea in the first place, but I had no other options at the time. When the AI is activated, both the player and the AI's chip/coin/token is yellow, so it's very confusing. I posted the dropToken function that is responsible for making moves, which I believe that is responsible for this problem.
    Code:
    	//Will drop the token
    	void dropToken(int x)
    	{
    		int max=0;
    		//Checks for spaces
    		for(int y = 5; y >= 0; y--)
    		{
    			if(theBoard[x][y]==0)
    			{
    				System.out.println(player1);
    				game.cell[x][y].taken=true;
    				game.cell[x][y].repaint();
    				if(player1==true)
    				{
    					theBoard[x][y]=1;
    					player1=false;
    					if(AI==true)
    					{
    						AITurn=true;
    					}
    				}
    				else
    				{
    					theBoard[x][y]=2;
    					player1=true;
    					if(AI==true)
    					{
    						AIMadeUpMind=false;
    						AITurn=false;
    					}
    				}
                           break; //Did the job, now exit the loop
    			}
    			else
    			{
    				max++;
    			}
    			
    		}
    		//If there are no moves in this column, it'll lock the button
    		if(max==5)
    		{
    			game.rowButton[x].setEnabled(false);
    		}
    		//Then it'll need to check every move for a win
    		checkMove();
    		//If the AI is playing, it'll activate the AI's script
    		if((AI==true) && (AITurn==true))
    		{
    			AIMove();
    		}
    	}
    The color change part is with the Cell class which is with post #9.
    What's wrong?
     
  14. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #14
    If you need to do this to feel back in power position; yeah, whatever.


    No.

    I was just thinking of adding a boolean field like isOccupiedByPlayer1. But actually I like your idea of having a colour field better.


    For good reason. You're paying for quality content. (Not that you always do with IT books).


    No. At least not at an introductory level. I was well into OO well before the Internet.
     
  15. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #15
    It was a correction, not a bragging right.
     
  16. chown33, Sep 24, 2011
    Last edited: Sep 24, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #16
    You're not having problems with complex object relationships, you're having trouble due to lack of the basics.
    I don't think you need depth. I think you need fundamentals.


    Object-Oriented Programming with Objective-C
    http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/OOP_ObjC/Articles/ooOOP.html
    Although its title suggests it's about Objective-C, there's almost nothing in it exclusive to Objective-C.

    Object-oriented design:
    http://en.wikipedia.org/wiki/Object_oriented_design
    As with any wikipedia article, be sure to read the links. For example, under the Object-oriented concepts heading. "For example" does not mean "exclusively".

    Masters of the Void
    http://masters-of-the-void.com/home.htm
    Basic C, but I don't think it would hurt. Especially some of the examples that show how a design is done in C.

    Objective-C: A Primer http://developer.apple.com/library/...rted/Learning_Objective-C_A_Primer/index.html
    .. "This document doesn’t attempt to teach any aspects of the C language.
    If you’re not familiar with C, you should learn about the basics before you proceed."​


    You seem to think that repaint() immediately repaints the target component. It doesn't. Read the Java-docs for the repaint() method of JComponent. If you can't find the Java-docs for JComponent, try googling: JComponent java docs

    If the docs for repaint() don't make sense, it suggests you need to study the fundamentals of how Swing draws components. I.e. you may need to read a Swing tutorial for beginners.


    As a fundamental design issue of your posted code, theBoard appears to hold the current state for the entire game board. That is, theBoard is the fundamental Model object of your game. Your Cell class, however, seems to be completely unaware of theBoard, and equally unaware of any values stored there.

    If each Cell is supposed to be a View to a single corresponding location on theBoard, then where is the coupling between the Model (theBoard) and the View (Cell instances), so the View knows what it should draw? It's not Model-View-Controller. It's not even Model-View. Even considered as a procedural-program design, it's sorely lacking.
     
  17. jsmwoolf thread starter macrumors regular

    Joined:
    Aug 17, 2011
    #17
    What kind of basic are you referring to? Objects? The Language itself? In general? It's very vague to just say "you're having trouble due to lack of the basics" as that can have many meanings.

    The document of JComponent doesn't have a repaint() method with no arguments, but only a repaint(long tm, int x, int y, int width, int height) and a repaint(Rectangle r). Component, however, has a repaint() method with no arguments. How repaint is executed depends and it only does so as soon as possible. If its lightweight, it'll invoke paint(). Otherwise, it'll invoke update() or updateUI().

    As for my problem, I was eventually able to solve it
    Code:
    class Cell extends JComponent
    {
    	Control control;
    	private Color thisColor;
    	private boolean taken = false;
    	int whatPlayer=0;
    	
    	public Cell(Control control)
    	{
    this.control = control;
    	}
    	
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);
    		g.setColor(Color.black);
    		g.drawRect(0, 0, 31, 31);
    		switch(whatPlayer)
    		{
    		case 1:
    		{
    			thisColor = Color.red;
    			taken=true;
    			break;
    		}
    		case 2:
    		{
    			thisColor = Color.yellow;
    			taken=true;
    			break;
    		}
    		case 0:
    		{
    			thisColor =getBackground();
    			taken=false;
    			break;
    		}
    		}
    		drawCircle(g); //This'll draw a circle representing the player's token
    	}
    	
    	void drawCircle(Graphics g)
    	{
    		g.setColor(thisColor);
    		if(taken==true)
    		{
    		g.fillOval(0, 0, 31, 31);
    		}
    	}
    }
    Code:
    //Will drop the token
    	void dropToken(int x)
    	{
    		int max=0;
    		//Checks for spaces
    		for(int y = 5; y >= 0; y--)
    		{
    			if(theBoard[x][y]==0)
    			{
    				System.out.println(player1);
    				if(player1==true)
    				{
    					game.cell[x][y].whatPlayer=1;
    					theBoard[x][y]=1;
    					player1=false;
    					if(AI==true)
    					{
    						AITurn=true;
    					}
    				}
    				else
    				{
    					game.cell[x][y].whatPlayer=2;
    					theBoard[x][y]=2;
    					player1=true;
    					if(AI==true)
    					{
    						AIMadeUpMind=false;
    						AITurn=false;
    					}
    				}
    				game.cell[x][y].repaint();
    				break; //Did the job, now exit the loop
    			}
    			else
    			{
    				max++;
    			}
    			
    		}
    		//If there are no moves in this column, it'll lock the button
    		if(max==5)
    		{
    			game.rowButton[x].setEnabled(false);
    		}
    		//Then it'll need to check every move for a win
    		checkMove();
    		//If the AI is playing, it'll activate the AI's script
    		if((AI==true) && (AITurn==true))
    		{
    			AIMove();
    		}
    	}
    Compared to the last time, I used an integer to determine which player controlled what spot. Taken is still used, but it's a private variable and is only used on whether that spot is taken by anyone.

    However, I bet that even this approach is still lacking.

    The thing is, I thought you always put the mechanics in a control class, never in a view class.

    I also booked the links as a reference.
     
  18. chown33, Sep 24, 2011
    Last edited: Sep 24, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #18
    The basics of object relationships.

    You're also having trouble with the basics of Swing, such as its fundamental drawing model, the relationship between a JComponent and its Model object, and how repaint() really works.

    The documents for a class include those of its superclass. For example, referring to Component's paint() method:
    http://download.oracle.com/javase/1,5,0/docs/api/java/awt/Component.html#paint(java.awt.Graphics)

    we see a link to Painting in AWT and Swing. The same link is present in the docs for all the Component repaint() methods.


    Component.repaint() with no args is defined as:
    Code:
        public void repaint() {
    	repaint(0, 0, 0, width, height);
        }
    
    You can get the source and see for yourself.

    You'd then also see that all the repaint() methods post an event to the AWT event queue, which only leads to a paint() later, in the event-processing thread. "As soon as possible" is never immediately.

    This "deferred drawing" is a fundamental characteristic of AWT and Swing's drawing model. It's discussed in the above-referenced Painting in AWT and Swing.


    You could eliminate the separate taken variable with this code:
    Code:
    		if (whatplayer != 0)
    
    Why store a variable for something that can be so easily determined?

    You can do a similar thing with thisColor. In the 'case', simply set the color of the Graphics to what the desired color should be. Why have an intermediate variable just to pass it to drawCircle()? You can also eliminate the switch by using a Color[] indexed by whatPlayer. The Color[] can be static, shared by all Cell instances. I'll leave that as an exercise.

    And the Cell never actually uses the Control object either. More excess baggage to be eliminated.


    The state being presented by a View should be in the Model. You're confusing a Controller with the Model.

    Here's a basic MVC article:
    http://en.wikipedia.org/wiki/Model–view–controller
    You can see how Swing varies the basics by searching for "swing" or "java" in that article.

    Here's an article on MVC in Java:
    http://www.oracle.com/technetwork/articles/javase/mvc-136693.html
    It's in the top few hits googling: java model view controller

    Here's another, on Swing architecture (linked from the above article on MVC):
    http://www.oracle.com/technetwork/java/architecture-142923.html


    When the model is simple, it sometimes makes sense to put its represented state in the View object. There's no single answer. It depends on the overall design.
     

Share This Page