# Perfomance Probleme beim eigenen Editor



## janb14 (10. Jun 2014)

Hey Leute ich brauche einmal euren Rat.Ich arbeite derzeit an einem Editor für mein 2D Adventure Game.Bis vor kurzem lief auch alles wunderbar.Doch seit einiger Zeit habe ich mit heftigen Performance Problemen innerhalb der Editoroberfläche zu kämpfen.Ich könnte es mir an meiner heufigen nutzung verschiedener listener erklären das er etwas bockt,aber ich wollte nochmal eure Meinug einholen.Leider ist der Editor in eriner einzigen Klasse verpackt und umfasst 700 Zeilen was das Lesen hier etwas erschweren könnte  Trotzdem denke ich das es einen Versuch wert ist.
Hier der Code:

```
package com.Game.Screens;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.border.Border;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import com.Game.Controller;
import com.Game.Game;
import com.Game.Entitys.CoreObject;
import com.Game.Entitys.Player;
import com.Game.Enums.GameState;
import com.Game.Objects.Block;
import com.Game.Utils.BufferedImageLoader;
import com.Game.libs.Reference;

public class Leveleditor implements Runnable{
	
	private JFrame frame_editor;
	private int WIDTH = Game.WIDTH;
	private int HEIGHT = Game.HEIGHT;
	private JScrollPane scrollPane_World,scrollPane_Menu;
	private JPanel MenuPanel,ViewPanel,contentPane_world,SelectionPanel,WorldPanel;
	private JButton button_newworld,button_saveworld;
	private String Menu_HoveredObject;
	private BufferedImage ObjectImage,Selection_ObjectImage;
	private selectionObject selection; 
	private Controller edit_controll = new Controller();
	private HashMap<Float, JLabel> displayedObjects = new HashMap<Float, JLabel>();
	
	private float objectcounter = 0;
	private int verticalscrollcount = 0;
	private int horizontalscrollcount = 0;
	
	
	
	BufferedImageLoader imageloader = new BufferedImageLoader();
	
	private void init(){
		//-------------------------------------------------------------------------------------
		frame_editor = new JFrame("World Editor");
		frame_editor.setSize(WIDTH, HEIGHT);
		frame_editor.setFocusable(true);
		frame_editor.setLocationRelativeTo(null);
		frame_editor.setMinimumSize(new Dimension(400,400));
		frame_editor.setResizable(true);
		
		
		WorldPanel = new JPanel(null){
		/**
			 * 
			 */
			private static final long serialVersionUID = 6595017163003318848L;

		public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, WorldPanel.getPreferredSize().width, WorldPanel.getPreferredSize().height);
			}
        };
        
        
        
		WorldPanel.setPreferredSize(new Dimension(500,500));
		
		scrollPane_World = new JScrollPane(WorldPanel);
		scrollPane_World.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scrollPane_World.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		
		scrollPane_World.setBounds(50, 30, WIDTH-300,HEIGHT-100);
        
        
        
        MenuPanel = new JPanel(null);
        MenuPanel.setBounds(WIDTH-230,30, 210,HEIGHT-100);
        Border border_MenuPanel = BorderFactory.createLineBorder(Color.darkGray, 3);
        MenuPanel.setBorder(border_MenuPanel);
        MenuPanel.add(createObjektlist());
        
        ViewPanel = new JPanel(null);
        Border border_ViewPanel = BorderFactory.createLineBorder(Color.RED, 3);
        ViewPanel.setBorder(border_ViewPanel);
        ViewPanel.setBounds(3,HEIGHT/4*1,204,HEIGHT-456);
        MenuPanel.add(ViewPanel);
        
        SelectionPanel = new JPanel(null);
        SelectionPanel.setBounds(3,HEIGHT/4*2,204,HEIGHT-300);
        SelectionPanel.setBorder(border_ViewPanel);
        MenuPanel.add(SelectionPanel);
        
        button_newworld = new JButton("New");
        button_newworld.setBounds(5, 1, WIDTH/15, HEIGHT/22);
        	
       
        
        
        
        button_saveworld = new JButton("Save");
        button_saveworld.setBounds(5+button_newworld.getWidth(), 1, WIDTH/13, HEIGHT/22);
        
       
        
        contentPane_world = new JPanel(null);
        contentPane_world.setPreferredSize(new Dimension(WIDTH, HEIGHT));
       
        
        contentPane_world.add(scrollPane_World);
        contentPane_world.add(MenuPanel);
        
        contentPane_world.add(button_newworld);
        contentPane_world.add(button_saveworld);
        
        frame_editor.setContentPane(contentPane_world);
        
        addlistener();
		
        frame_editor.setVisible(true);
		
		//-------------------------------------------------------------------------------------
		
	}
	
	private void addlistener(){	
		frame_editor.addWindowListener( new WindowAdapter() { 
		    @Override
		    public void windowClosing(WindowEvent e) {
		       Game.state = GameState.Menu;
		       try {
				Game.game.leveledit.join();
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
		       Game.game.leveledit = null;
		    }
		});
		
		frame_editor.addWindowStateListener( new WindowAdapter() {
		    public void windowStateChanged(WindowEvent evt) {
		        int oldState = evt.getOldState();
		        int newState = evt.getNewState();
		    
		        if ((oldState & Frame.ICONIFIED) == 0
		            && (newState & Frame.ICONIFIED) != 0) {
		            // Frame was iconized
		        } else if ((oldState & Frame.ICONIFIED) != 0
		            && (newState & Frame.ICONIFIED) == 0) {
		            // Frame was deiconized
		        }
		        if ((oldState & Frame.MAXIMIZED_BOTH) == 0
		            && (newState & Frame.MAXIMIZED_BOTH) != 0) {
		        	resizeFrame();
		            // Frame was maximized
		        } else if ((oldState & Frame.MAXIMIZED_BOTH) != 0
		            && (newState & Frame.MAXIMIZED_BOTH) == 0) {
		        	resizeFrame();
		            // Frame was minimized
		        }
		    }
		});
		
		frame_editor.addComponentListener(new ComponentListener() {
			@Override
			public void componentShown(ComponentEvent arg0) {
			}
			@Override
			public void componentResized(ComponentEvent arg0) {
				resizeFrame();
			}

			@Override
			public void componentHidden(ComponentEvent e) {	
			}
			@Override
			public void componentMoved(ComponentEvent e) {
			}
		});
		
		scrollPane_World.addMouseListener(new MouseListener(){
			@Override
			public void mouseClicked(MouseEvent arg0) {
				boolean testofintersection = false;
				if (arg0.getButton() == MouseEvent.BUTTON1 && selection != null && edit_controll.intersecObject(new Rectangle(arg0.getX(),arg0.getY(),selection.getWidth(),selection.getHeight())) != null){
					System.err.println("INTERSECTION WITH ANOTHER OBJECT ON SCREEN!!!!");
					testofintersection = true;
				}
				
				if (arg0.getButton() == MouseEvent.BUTTON3 && edit_controll.intersecObject( new Rectangle(arg0.getX(),arg0.getY(),1,1)) != null){
					CoreObject event_oject = edit_controll.intersecObject( new Rectangle(arg0.getX(),arg0.getY(),1,1));
					float id = event_oject.getId();
					edit_controll.removeObject(event_oject);
					System.out.println("Object removed");
					JLabel label = displayedObjects.get(id);
					WorldPanel.remove(label);
					WorldPanel.repaint();
					
				}
		
			    if (arg0.getButton() == MouseEvent.BUTTON1 && selection != null && new Rectangle(WorldPanel.getPreferredSize()).contains(arg0.getPoint()) && testofintersection == false){
			    	if(Controllertranslation(edit_controll,arg0.getPoint(),selection.getType(),selection.getWidth(),selection.getHeight(),selection.getImage())){
			    		JLabel placing_object = new JLabel(new ImageIcon(selection.getImage()));
						placing_object.setBounds(arg0.getX()+horizontalscrollcount,arg0.getY()+verticalscrollcount, selection.getImage().getWidth(), selection.getImage().getHeight());
						
						
						
						WorldPanel.add(placing_object);
						displayedObjects.put(objectcounter-1, placing_object);
						
						WorldPanel.repaint();
						System.out.println("Object "+selection.getName()+" was placed." );
			    	}
				}
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
			}
		});
	
		scrollPane_World.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener(){

			@Override
			public void adjustmentValueChanged(AdjustmentEvent arg0) {
				verticalscrollcount = arg0.getValue();
				
			}
		});;
		
		scrollPane_World.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener(){

			@Override
			public void adjustmentValueChanged(AdjustmentEvent arg0) {
				horizontalscrollcount = arg0.getValue();
			}
		});;

		button_newworld.addActionListener(new ActionListener() {
			 
	            public void actionPerformed(ActionEvent e)
	            {
	            	final JFrame worldcreator = new JFrame("New World");	
	            	worldcreator.setSize(WIDTH/4, HEIGHT/4);
	            	worldcreator.setFocusable(true);
	            	worldcreator.setLocationRelativeTo(null);
	            	worldcreator.setResizable(false);
	            	
	            	JButton button_createworld = new JButton("Save");
	            	
	            	WindowListener exitListener = new WindowAdapter() {

	                    @Override
	                    public void windowClosing(WindowEvent e) {
	                    	 frame_editor.setEnabled(true);
	                    }
	                };
	                worldcreator.addWindowListener(exitListener);
	                
	                JPanel contpane = new JPanel(null);
	                
	                JLabel newwidthinfo = new JLabel("World width:");
	                newwidthinfo.setBounds(5,worldcreator.getHeight()/4,worldcreator.getWidth()/3,worldcreator.getHeight()/5);
	                contpane.add(newwidthinfo);
	                
	                final JTextField newwidth = new JTextField("500");
	                newwidth.setBounds((int) (worldcreator.getWidth()/2.5),worldcreator.getHeight()/4,worldcreator.getWidth()/5,worldcreator.getHeight()/5);
	                contpane.add(newwidth);
	                
	                JLabel newheightinfo = new JLabel("World height:");
	                newheightinfo.setBounds(5,worldcreator.getHeight()/15,worldcreator.getWidth()/3,worldcreator.getHeight()/5);
	                contpane.add(newheightinfo);
	                
	                final JTextField newheight = new JTextField("500");
	                newheight.setBounds((int) (worldcreator.getWidth()/2.5),worldcreator.getHeight()/15,worldcreator.getWidth()/5,worldcreator.getHeight()/5);
	                contpane.add(newheight);
	                
	            	
	            	button_createworld.addActionListener(new ActionListener() {
	        			 
	                     public void actionPerformed(ActionEvent e)
	                     {
	                    	 worldcreator.dispose();
	                    	 frame_editor.setEnabled(true);
	                    	 frame_editor.toFront();
	                    	 WorldPanel.setPreferredSize(new Dimension(Integer.parseInt(newwidth.getText()),Integer.parseInt(newheight.getText())));
	                    	 WorldPanel.repaint();
	                     }
	         		});
	            	button_createworld.setBounds(worldcreator.getWidth()/3,worldcreator.getHeight()/2,worldcreator.getWidth()/3,worldcreator.getHeight()/5);
	            	contpane.add(button_createworld);
	            	
	            	worldcreator.setContentPane(contpane);
	            	worldcreator.setVisible(true);
	            	frame_editor.setEnabled(false);
	            }
			});
	
		button_saveworld.addActionListener(new ActionListener(){
	        	
				@Override
				public void actionPerformed(ActionEvent arg0) {
					File file = new File (Reference.Resourcepath);
					Desktop desktop = Desktop.getDesktop();
					try {
						desktop.open(file);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
	        });
	}
	
	private JScrollPane createObjektlist(){
		
		final JTree tree = new JTree(createTree());
		tree.setDragEnabled(true);
		
		final String[] bannedhoveritems_array = new String[] {"Enviroment","Objects","Entitys"};
		final String[] bannedhoveritemspath_array = new String[] {};// for string which should be erased out of the dynamic generated paths
		
		
		final Set<String> bannedhoveritems = new HashSet<String>(Arrays.asList(
				bannedhoveritems_array
			));
		
		tree.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent e) {
				TreePath tp = ((JTree)e.getSource()).getPathForLocation(e.getX(), e.getY());

	           	 if(tp != null)
	             {
							String test 			= (tp.toString().replace("[","")).replace("]","");;
							String lastSelection 	= (test.substring(test.lastIndexOf(",")+1).replace(" ",""));
	                    	
	                    	if (!bannedhoveritems.contains(lastSelection))
	                    	{
	                    		if (selection == null || selection.getName() != lastSelection){
	                    		
	                    		SelectionPanel.removeAll();
	            				SelectionPanel.repaint();
	            				
	                    		String Objectpath = (Reference.Resourcepath+((tp.toString().replace("[", "")).replace(",", "/")).replace(" ", "").replace("]", "/"));
	                    		for (int k = 0;bannedhoveritemspath_array.length>k;k++){
	                    			Objectpath = Objectpath.replaceAll(bannedhoveritemspath_array[k],"").replace("///", "/");
	                    		}
	                    		try {
	                    			Selection_ObjectImage = imageloader.loadImage(Objectpath+"image.png");
	                    			
	                    		} catch (IOException e1) {
	                    			e1.printStackTrace();
	                    		}
	                    		
	                    		BufferedReader br = null;
	        					String ObjectType = null;
	        			        String ObjectWidth = null;
	        			        String ObjectHeight = null;
	        			        
	        					try {
	        					    br = new BufferedReader(new FileReader(new File(Objectpath+"info.txt")));
	        			            String line = null;
	        			            int counter = 1;
	        			           
	        			            
	        			            while((line = br.readLine()) != null) {
	        			            	System.out.println(line);    
	        			            	switch(counter){
	        			            	case 1:
	        			            		ObjectType = line;
	        			            		counter++;
	        			            		break;
	        			            	case 2:
	        			            		String[] ObjectBounds = line.split("x");
	        			            		ObjectWidth = ObjectBounds[0];
	        			            		ObjectHeight = ObjectBounds[1];
	        			            		counter++;
	        			            		break;
	        			            	}
	        			            }
	        			        } catch(FileNotFoundException er) {
	        			            er.printStackTrace();
	        			        } catch(IOException er) {
	        			            er.printStackTrace();
	        			        } finally {
	        			            if(br != null) {
	        			                try {
	        			                    br.close();
	        			                } catch(IOException er) {
	        			                    er.printStackTrace();
	        			                }
	        			            }
	        			        }
	                    		
	                    		
		                    	selection = new selectionObject(lastSelection, Integer.parseInt(ObjectWidth), Integer.parseInt(ObjectHeight), ObjectType,Objectpath, Selection_ObjectImage);
	                    		//System.out.println("Objected dragged :"+lastSelection);
	                    		//System.out.println(Objectpath);
	                    		
	                    		JLabel selection_label = new JLabel("Object:    "+lastSelection);
	                    		selection_label.setBounds(3,SelectionPanel.getHeight()/4,SelectionPanel.getWidth(),20);
	                    		
	                    		SelectionPanel.add(selection_label);
	                    		
	                    		SelectionPanel.repaint();
	                    		
	                    		}
	                        }
	             }
					
				
				
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
			}
			
			
		});
		
		tree.addMouseMotionListener(new MouseMotionListener() {

            @Override
            public void mouseDragged(MouseEvent e) {
            }
            
            
            

            @Override
            public void mouseMoved(MouseEvent e) {
            	ViewPanel.removeAll();
            	ViewPanel.repaint();

                TreePath tp = ((JTree)e.getSource()).getPathForLocation(e.getX(), e.getY());

                if(tp != null)
                {
                    ((JTree)e.getSource()).setCursor(new Cursor(Cursor.HAND_CURSOR));
                    if (Menu_HoveredObject != tp.toString()){
                    	
						String test 			= (tp.toString().replace("[","")).replace("]","");;
						String lastSelection 	= (test.substring(test.lastIndexOf(",")+1).replace(" ",""));

                    	if (!bannedhoveritems.contains(lastSelection)){
                    		String Objectpath = (Reference.Resourcepath+((tp.toString().replace("[", "")).replace(",", "/")).replace(" ", "").replace("]", "/"))+"image.png";
                    		for (int k = 0;bannedhoveritemspath_array.length>k;k++){
                    			Objectpath = Objectpath.replaceAll(bannedhoveritemspath_array[k],"").replace("///", "/");
                    		}
	                    	creatObjectInfo(Objectpath);
	                    	Menu_HoveredObject = tp.toString();
	                    	       	
	                    	ViewPanel.repaint();
                    	}
                    	else{
                    		
                    	}
                    	
                    	
                    }
                }
                else
                {
                    ((JTree)e.getSource()).setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }
            }
     });
		
		scrollPane_Menu = new JScrollPane(tree);
		scrollPane_Menu.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		scrollPane_Menu.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		scrollPane_Menu.setBounds(3, 3,204,HEIGHT-250);
		
        return scrollPane_Menu;
	}
	
	public static  TreeNode createTree() {
		
	    
        DefaultMutableTreeNode root = new DefaultMutableTreeNode( "Objects" );

        String[] paths = new String[3];
        paths[0] = Reference.Enviromentpath;
        paths[1] = Reference.Entitypath;
        //paths[2] = System.getProperty("user.dir")+"/bin/Players/Sprinters/";
        
        DefaultMutableTreeNode[] object_sorts = new DefaultMutableTreeNode[3];
        object_sorts[0] =  new DefaultMutableTreeNode( "Enviroment" );
        object_sorts[1] = new DefaultMutableTreeNode( "Entitys" );
        //object_sorts[2] = new DefaultMutableTreeNode( "Sprinters" );
        
        
        for (int t = 0; t < 2; t++) {
        	
    	File folder = new File(paths[t]);
    	File[] listOfFiles = folder.listFiles();
    	
    	DefaultMutableTreeNode[] obj  = new DefaultMutableTreeNode[listOfFiles.length];
    	
    	    for (int i = 0; i < listOfFiles.length; i++) {
    	    	obj[i] = new DefaultMutableTreeNode(listOfFiles[i].getName() );
    	    }
    	    
    	    for (int i = 0; i < listOfFiles.length; i++) {
    	    	object_sorts[t].add(obj[i]); 
    	    }
    	    
        }
        
	    
        root.add( object_sorts[0] );
        root.add( object_sorts[1] );
        //root.add( object_sorts[2] );
        
        return root;
    }

	private void creatObjectInfo(String ImagePath){
		if (new File(ImagePath).exists()){
			
		
			try {
				ObjectImage = imageloader.loadImage(ImagePath);
				ImageIcon icon = new ImageIcon(ObjectImage);
				JLabel ObjectImageLabel = new JLabel(icon);
				if (ObjectImage.getWidth() <= 75 && ObjectImage.getHeight() <= 75){
					ObjectImageLabel.setBounds(5,30,ObjectImage.getWidth(),ObjectImage.getHeight());
				}
				
				ViewPanel.add(ObjectImageLabel);
			} catch (IOException e) {
			//	e.printStackTrace();
			}
		}
		else{
			System.err.println("File "+ImagePath+" isnt reachable!!!");
		}
	}
		
	
	private void resizeFrame(){
		Dimension dim = frame_editor.getSize();
		WIDTH = dim.width;
		HEIGHT = dim.height;
		scrollPane_World.setBounds(50, 30, WIDTH-300,HEIGHT-100);
		MenuPanel.setBounds(WIDTH-230,30, 210,HEIGHT-100);
		scrollPane_Menu.setBounds(3, 3,204,HEIGHT/4*2);
        ViewPanel.setBounds(3,(int) (HEIGHT/4*2.05),204,(int) (HEIGHT/4*0.9));
        SelectionPanel.setBounds(3,(int) ((HEIGHT/4*2.05)+(HEIGHT/4*0.9)),204,(int) (HEIGHT/4*0.37));
        
	}
	
	private boolean Controllertranslation(Controller controll,Point location,String type,int width,int height,BufferedImage image){
		
		switch(type){
			case "Block":
				controll.addObject(new Block(location.x, location.y,(int) objectcounter, image));
				System.out.println("Block added to Controller.");
				objectcounter++;
				break;
			case "Player":
				if (!edit_controll.findInstance(edit_controll.getObjects(), "com.Game.Entitys.Player")){
					controll.addObject(new Player(location.x, location.y,(int) objectcounter, Game.game.tex));
					System.out.println("Player added to Controller.");
					objectcounter++;
					break;
				}
				else{
					System.out.println("Player allready added.");
					return false;
				}
		}
		return true;
		
	}

	@Override
	public void run() {
		init();
	}
}	


class selectionObject{
	String name,path,Type;
	int Width,Height;
	BufferedImage image;
	
	public selectionObject (String name,int Width,int Height,String Type,String path,BufferedImage image){
		this.name  = name;
		this.Width = Width;
		this.Height = Height;
		this.Type = Type;
		this.path  = path;
		this.image = image;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public BufferedImage getImage() {
		return image;
	}

	public int getWidth() {
		return Width;
	}

	public int getHeight() {
		return Height;
	}

	public String getType() {
		return Type;
	}	
}
```


----------



## Ruzmanz (10. Jun 2014)

Habe da jetzt nur mal schnell drüber geguckt, viel kann man da nicht verstehen. Bilder läd man zu Beginn der Applikation / des Levels nur einmal und kopiert diese wenn notwendig nur im RAM. In nicht-temporären Schleifen sollte man Festplattenzugriffe und die Initialisierung von größeren Arrays vermeiden.


```
public void mouseMoved(MouseEvent e) {
//...
creatObjectInfo(Objectpath); // <- So nicht.
//...
}
```


----------

