Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 4 of 4

Thread: Help with Swing applet

  1. #1
    Member
    Join Date
    May 2011
    Posts
    61
    My Mood
    Busy
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Help with Swing applet

    Hi, I'm trying to build a heap sort Swing applet, and at the moment I just want to output the binary heap and except for the positioning of the nodes which I'll have to mess around later, it's fine, but I'm unsure why the items in the node_arr array are displaying null if I call the print_heap method from main, BUT if I call print_heap method directly inside the paintComponent method of the Heap class, it prints out all the data?

    Also, another issue, I have the main frame (JFrame in the main method), to hold the JPanel, but when I set layout to flow layout, and I run the program, the graphics no longer show up so I had to comment out that line ( Why can't I set the JFrame's layout manager before I insert the Heap object? Heap_Node is another class I have that just has an integer key and represents each individual yellow node to draw.

    Here is Heap class:
    import javax.swing.*;//The AWT is imported since it defines many classes that GUIs use.
    import java.awt.*;
     
    @SuppressWarnings("serial")
    public class Heap extends JPanel{
     
    	private int start_x;
    	private int start_y;
    	private int width;
    	private int height;
    	private int num_nodes;
    	private int[] array;//array to read from to display on each node
    	private Heap_Node[] node_arr;//arr of Heap Node objs which stores data from this.array (passed as parameter in constructor)
     
    	public Heap(int n, int startX, int startY, int width, int height, int[] arr )
    	{
    		this.array = arr;
    		this.num_nodes = n;
    		this.start_x = startX;
    		this.start_y = startY;
    		this.width = width;
    		this.height = height;
    		this.node_arr = new Heap_Node[ arr.length ];
    	}
     
    	public int get_num_nodes(){return this.num_nodes;}
     
    	public void paintComponent(Graphics g)
    	{
    		super.paintComponent(g);//why do I need this again?
     
    		Graphics2D g2d = (Graphics2D)g;
     
    		int links_start_pt = this.width / 2;//each L, R links (the lines) starting point (which is half width of invisible square used to draw circle
     
    		int cur_num_nodes_at_this_level = 0;//reset to 0 for each new level b/c no node inserted in the new level yet
     
    		int level_capacity = 1;//doubles for each next level
     
    		int first_node_startX = this.start_x;//x position for each level's first node
    		int rem_node_startX = this.start_x;//x position for each level's non-first nodes
     
    		int first_node_startY = this.start_y;
     
    		int i = 1;//current array index (index 0 not being used here)
    		int first_label_startX = this.start_x + 10;//starting x position for node data
    		int first_label_startY = this.start_y + 16;//starting y position " "
    		int rem_label_startX = first_label_startX;
    		int j = 0;//cur level
     
     
    		System.out.println("level " + j + "'s capac
     
     
    		while ( this.num_nodes > 0 && this.num_nodes <= 15 )//draw the black outline around yellow nodes which is a slightly larger black filled circle drawn first
    		{			
    			if ( cur_num_nodes_at_this_level == 0 )//if this is the first node of current level
    			{
    				//draw black border around yellow circle (it's really a slightly black circle)
    				g2d.setColor(Color.black);
    				g2d.fillOval(first_node_startX - 2, first_node_startY - 2, this.width + 2, this.height + 2 );
     
    				//draw yellow node
    				g2d.setColor(Color.yellow);
    				g2d.fillOval( first_node_startX, first_node_startY, this.width, this.height );
     
    				//add this position to cur Heap_Node obj (most important is the data and color to change during heap sort)
    				this.node_arr[i] = new Heap_Node( first_node_startX, first_node_startY, this.width , this.height, this.array[i] ,"yellow" );
    				System.out.println("Node " + i + ": " + this.node_arr[i].get_data());
     
    				//draw JLabel with cur array elem
    				g2d.setColor(Color.black);
    				g2d.drawString("" + this.node_arr[i].get_data(),  first_label_startX, first_label_startY);//draw the node keys\data
     
    				//draw cur node's L, R links
    				g2d.setColor(Color.black);
    				g2d.drawLine(first_node_startX + links_start_pt, first_node_startY + this.height, first_node_startX - links_start_pt, first_node_startY + 50 );
    				g2d.drawLine(first_node_startX + links_start_pt, first_node_startY + this.height, first_node_startX + this.width + links_start_pt , first_node_startY + 50 );
    				cur_num_nodes_at_this_level++;
    				this.num_nodes--;
    			}
    			else//draw at remaining nodes startX since first_node_start_x needs to be kept for updating startX for next level's first node
    			{
    				rem_node_startX = rem_node_startX + 68;//Q: what's the offset?
    				rem_label_startX = rem_label_startX + 70;
    				//draw black border around yellow circle (it's really a slightly black circle)
    				g2d.setColor(Color.black);
    				g2d.fillOval(rem_node_startX - 2, first_node_startY - 2, this.width + 2, this.height + 2 );
     
    				//draw yellow node
    				g2d.setColor(Color.yellow);
    				g2d.fillOval( rem_node_startX, first_node_startY, this.width, this.height );
     
    				//add this position to cur Heap_Node obj (most important is the data and color to change during heap sort)
    				this.node_arr[i] = new Heap_Node( rem_node_startX, first_node_startY, this.width , this.height, this.array[i] ,"yellow" );
    				System.out.println("Node " + i + ": " +  this.node_arr[i].get_data() );
     
    				//draw JLabel with cur array elem
    				g2d.setColor(Color.black);
    				g2d.drawString(""+this.node_arr[i].get_data(),  rem_label_startX, first_label_startY);//draw the node keys\data
     
    				//draw cur node's L, R links
    				g2d.setColor(Color.black);
    				g2d.drawLine(rem_node_startX + links_start_pt, first_node_startY + this.height, rem_node_startX - links_start_pt, first_node_startY + 50 );
    				g2d.drawLine(rem_node_startX + links_start_pt, first_node_startY + this.height, rem_node_startX + this.width + links_start_pt, first_node_startY + 50 );
    				cur_num_nodes_at_this_level++;
    				this.num_nodes--;
    			}
     
    			if ( cur_num_nodes_at_this_level == level_capacity )//once level capacity reached, we'll proceed to draw nodes @ next level (where capacity is twice cur level's)
    			{
    				level_capacity = 2 * level_capacity;
    				cur_num_nodes_at_this_level = 0;//reset cur nodes inserted in current level
     
    				//update positions for next level's node's startX, startY
    				first_node_startX = first_node_startX - 44;//Q: how much to offset?
    				first_node_startY = first_node_startY + 68;//Q: how much to offset?
    				rem_node_startX = first_node_startX;
     
    				//update startX, startY for labels (i.e. node keys\data) for next level
    				first_label_startX = first_node_startX + 2;
    				first_label_startY = first_node_startY + 20;
    				rem_label_startX = first_label_startX;
    				j++;
    				System.out.println("level " + j + "'s capacity: " + level_capacity);
    			}
     
    			i++;
    		}
     
    		System.out.println("Final value of i: " + i );
    		System.out.println("Array size: " + this.array.length );
    		System.out.println("Heap size: " + this.node_arr.length );
    		System.out.println(this.num_nodes);
    //		print_heap();//PROBLEM: why do I have to print inside the paintComponent, but if I call this method in main, it prints null for this node_arr (arr of Heap_Node objs)?
    	}
     
    	public void print_heap()//Problem here, I am unsure why it outputs null if I am inserting into this.node_arr in the paintComponents method above
    	{
    		for ( int i = 1; i < this.node_arr.length; ++i )
    		{
    			if ( this.node_arr[i] != null )
    				System.out.println("Current Data: " + this.node_arr[i].get_data() );
    			else
    				System.out.println("Current Data: " + null);//PROBLEM I have is here: why is it null if I'm inserting into this.node_arr array in the paintComponents method above??
    		}
    	}
    }

    here is the main method:
    public class Heap_Main
    {
          public static void main(String[] args)
         {
    			int[] arr = {0,16,16,14,3,4,7,14};//index 0 NOT USED so arr size: 8, but heap_size: 7 so last index is: 7
     
    			JFrame f = new JFrame("Heap sort animation");
    			//f.setLayout(new FlowLayout() );//PROBLEM: why can't I set the layout manager before inserting the Heap object?
    			Heap h = new Heap(7,200,20,30,30, arr);
    			f.add( h );
    			f.setVisible(true);
    			f.setSize(700, 500);
    			f.setResizable(false);//NB:idk why if I resize window, all nodes except 1 remain(I'll look up but for now make JFrame fixed size)
     
    			h.print_heap();//PROBLEM here: why is it null, but if I call print directly in paintComponent method, it's not???
      }
    }
    Any help appreciated.


  2. #2
    Super Moderator pbrockway2's Avatar
    Join Date
    Jan 2012
    Posts
    939
    Thanks
    6
    Thanked 202 Times in 178 Posts

    Default Re: Help with Swing applet

    h.print_heap();//PROBLEM here: why is it null, but if I call print directly in paintComponent method, it's not???
    There are two threads involved here. You calll print_heap() within main() and "it" (== the contents of the Heap instance's node_arr) is null because paintComponent() has not run and the array has not been populated. You also call print_heap() within paintComponent(): but that occurs in a different thread (the so-called "event dispatch thread") and, significantly, it occurs after you have populated the array.

    There are a couple of general rules to bear in mind with Swing:

    (1) Do everything thing that alters the graphial user interface on the event dispatch thread. This has a consequence for your main() method: it should do next to nothing. The only thing of any substance it need do is cause the gui to be created and made visible later (on the event dispatch thread). See HelloWorldSwing.java for an example of code that does this.

    (2) The event dispatch thread where painting and event handling occurs should be fast. This means that methods like paintComponent() should be lean and mean. (I haven't read the code closely, but your paintComponent() is long: too long for a single method.) A 60Hz refresh rate on a monitor gives your program 0.016 seconds to get its painting done - or rather its share of 0.016 seconds, as other things might well be going on.

    ---

    Before diving into Swing applications, you should take the time to read up on the basic structure of the technology (you don't need to know the ins and outs of every component, but you do need a basic understanding of how painting and event handling is done). Oracle has a Tutorial.

  3. #3
    Member
    Join Date
    May 2011
    Posts
    61
    My Mood
    Busy
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Re: Help with Swing applet

    Appreciate it, I have took time to learn background behind it, so now new problem, I understand everything being done for this example from Oracle's tutorials on custom graphics but I'm unsure why they neede an OFFSET, I mean I noticed that if I removed it (set it to 0), then when I drag the red square, there are artifacts left over. I thought that by calling repaint with arguments, the first repaint method will repaint to the current background color (so paint over where red square previously was, and the second repaint (in moveSquare() method I'm referring to) paints where the clipped area where red square currently is.

    import javax.swing.SwingUtilities;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.BorderFactory;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseMotionListener;
    import java.awt.event.MouseMotionAdapter;
    /**
     * src: http://docs.oracle.com/javase/tutorial/uiswing/painting/step3.html
     */
     
     
    public class MyPanel extends JPanel {
     
        private int squareX = 50;
        private int squareY = 50;
        private int squareW = 20;
        private int squareH = 20;
     
        public MyPanel() {
     
            setBorder(BorderFactory.createLineBorder(Color.black));
     
            addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    moveSquare(e.getX(),e.getY());
                }
            });
     
            addMouseMotionListener(new MouseAdapter() {
                public void mouseDragged(MouseEvent e) {
                    moveSquare(e.getX(),e.getY());
                }
            });
     
        }
     
     
        private void moveSquare(int x, int y) {
            int OFFSET = 1;//PROBLEM HERE:Why do we need an offset? (I see the problem in the application when I drag the red square if I set OFFSET to 0 because there's artifacts but why, I thought first invoking of repaint
    		//	takes care of that???
            if ((squareX!=x) || (squareY!=y)) {
                repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);//tells Swing to repaint the area of the component where the square PREVIOUSLY WAS (to repaint
    			//	w/ the background color, ahh, I get it; NB: this is inherited behaviour using the UI Delegate to fill that area w/ cur bg color)
                squareX=x;
                squareY=y;
                repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);//this 2nd invocation paints the area of the component where the square CURRENTLY IS
            } 
        }
     
     
        public Dimension getPreferredSize() {
            return new Dimension(250,200);
        }
     
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);       
            g.drawString("This is my custom Panel!",10,20);
            g.setColor(Color.RED);
            g.fillRect(squareX,squareY,squareW,squareH);
            g.setColor(Color.BLACK);
            g.drawRect(squareX,squareY,squareW,squareH);
        }  
    }

    Main below:
    import javax.swing.SwingUtilities;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.BorderFactory;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseMotionListener;
    import java.awt.event.MouseMotionAdapter;
    /**
     * src: http://docs.oracle.com/javase/tutorial/uiswing/painting/step3.html
     */
     
    public class SwingPaintDemo3 {
     
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGUI(); 
                }
            });
        }
     
        private static void createAndShowGUI() {
            System.out.println("Created GUI on EDT? "+
            SwingUtilities.isEventDispatchThread());
            JFrame f = new JFrame("Swing Paint Demo");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
            f.add(new MyPanel());
            f.pack();
            f.setVisible(true);
        } 
    }

  4. #4
    Super Moderator pbrockway2's Avatar
    Join Date
    Jan 2012
    Posts
    939
    Thanks
    6
    Thanked 202 Times in 178 Posts

    Default Re: Help with Swing applet

    Notice the subtle difference between drawRect() and fillRect(). drawRect() outlines a rectangle that is squareW+1 pixels wide ie from squareX to squareX+squareW inclusive. On the other hand fillRect() - and repaint() - paints a region only squareW pixels wide: the "right hand" edge is not included. The same in the vertical direction.

    You can see this visually by reversing the order of painting and put the red filled region on top of the black outline:

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);       
        g.drawString("This is my custom Panel!",10,20);
        g.setColor(Color.BLACK);
        g.drawRect(squareX,squareY,squareW,squareH);
        g.setColor(Color.RED);
        g.fillRect(squareX,squareY,squareW,squareH);
    }

    The extra +1 (I don't know why they called it "offset") is there to take this into account. Ie, the region to repaint is one pixel wider and taller than the square to take account of the fact that the outline is also 1 pixel wider.

Similar Threads

  1. Replies: 29
    Last Post: May 18th, 2012, 02:16 PM
  2. Replies: 0
    Last Post: October 13th, 2011, 07:42 PM
  3. HTML in Swing Components in Cached Applet
    By KevinWorkman in forum Java Applets
    Replies: 6
    Last Post: August 1st, 2011, 07:46 AM
  4. Swing
    By waboke in forum AWT / Java Swing
    Replies: 2
    Last Post: November 3rd, 2010, 08:55 AM
  5. applet + swing + arraylist = exception??
    By wolfgar in forum What's Wrong With My Code?
    Replies: 2
    Last Post: April 1st, 2010, 11:38 PM