Java Swing:将鼠标悬停在矩形上时,光标响应非常慢

时间:2017-09-19 02:19:46

标签: java swing arraylist jpanel java-2d

下面是用户将鼠标光标移动到一堆矩形上的代码,光标应该在矩形上方变为手形光标,并在不在给定矩形顶部时恢复为默认正常光标。

问题: 解决方案有效,但速度很慢。他们有很多种方法可以给猫皮肤做好准备,因此我们可以在很多方面对问题进行建模,解决方案可以是各种各样的,但是什么是常数,是我们必须使用迭代器遍历每个矩形并使用contains()方法确定JPanel上的给定点是否确实在矩形内,并相应地更改光标。

简单到需要实现的声音,即在悬停在特定矩形上时更改光标,程序开始变慢,因为我添加了不同的形状和更多的矩形。

下面的代码简单地显示了与x轴对齐的矩形和与y轴对齐的矩形。我将它们分开(仍然可以将它们组合成一个列表)到两个矩形列表中.I迭代两个列表,在另一个列表中使用while循环,每个循环在适当的位置使用break关键字。

我避免使用一个大的列表来保存两种类型的矩形(或不同类型的形状),因为

  1. 我需要每隔一段时间添加不同的形状,它更好,更具可读性,可以在自己的列表中分类不同的形状。
  2. 我本能地试图通过对不同形状使用不同的列表来缩短漫长的过程,并且如果可能的话 ,只迭代右边的列表而不是迭代其他不必要的形状。一个大的列表将线性增长并迭代*** ***所有形状***一直***到正确的*** ***不是一个大的列表似乎不是一个如此聪明的实现?希望尽我所能避免One-Large-List的努力不是过早优化的情况!!!这一点我认为使用线程to loop over different list concurrently or simultaneously but one thread misbehaves.
  3. 那么,我将形状分类在不同的List中,因为下面的示例有两个Lists.but这个技巧也失败了,因为我必须按顺序迭代每个列表。所以我在另一个中有一个while循环。我没有避免迭代在不必要的列表中,因为一个循环必须在另一个循环中(或者从另一个循环开始),然后内循环(或后面的循环)支付过度的性能开销,因为第一个循环是完全不必要的如果我们可以事先确定一个形状在手之前属于某个组。请注意,确定鼠标光标是否悬停在属于圆形列表或矩形列表的形状上,是我们需要事先知道的 !!所以我们迭代特定列表。它甚至变得更好,如果此时你仍然可以按照我的推理,知道事先哪个列表形状属于必须在没有contains()方法,因为在迭代里面列表时使用contains()!!!

    总而言之,下面的代码只是两个列表上的线性迭代。要访问第二个List,你必须通过第一个。有没有办法可以先通过迭代第一个列表?

    如果我所有的解释和探索都是错误的并且没有意义。 的问题。 那么,如何改进下面代码的光标响应。

    修改

    很抱歉发布了无法编译的代码,我已经从这个代码片段开始,并且正在玩我的新玩具,称为线程,直到我最终将自己绑在一个我无法解开的结中。真相是我选择线程,因为我希望选择矩形并使用setRect()方法移动它们。我设想在预定的运动中移动各种形状,即仿射转换可能需要线程,因为绘画,重新绘制,搜索和各种方式的硬我从一些多线程中获益。不管怎样,下面的代码编译,光标响应实际上是好!!! 。这样!我有一个类似的实现,但可能它的缓慢是由绘制矩形的其他类引起的,不像在这个SSCCE中,它们是由for循环绘制的。

    同时,如果有人有办法通过线程获得这种良好的性能,那将非常感激。谢谢。

        import java.awt.Color;
        import java.awt.Cursor;
        import java.awt.Graphics;
        import java.awt.Graphics2D;
        import java.awt.Point;
        import java.awt.Rectangle;
        import java.awt.event.MouseEvent;
        import java.awt.event.MouseListener;
        import java.awt.event.MouseMotionListener;
        import java.awt.geom.Rectangle2D;
        import java.util.ArrayList;
        import java.util.Iterator;
        import java.util.List;
        import javax.swing.*;
    
        public class FlyingSaucerTwo extends JPanel {
         Rectangle2D.Double rec;
         Rectangle2D.Double rec1; 
         List<Rectangle2D.Double> recList;
         List<Rectangle2D.Double> recList2;
    
         Rectangle2D.Double mouseBoxx;  
         int f = 10;
         int g = 0;
         int s = 10;
         int y = 5;
         int z = 500;
    
         public FlyingSaucerTwo(){
    
        //FlyingSaucer needs to quickly identify specific points over given areas
        //enclosed in rectangles.They use a 'divide and conquer' approach where 
        //different types of rectangles are first identified and a worker thread
        //assigned to each category
    
         mouseBoxx = new Rectangle.Double();
         recList = new ArrayList<>();
         recList2 = new ArrayList<>();
    
         for(int i = 0; i < 15; i++){
             rec = new Rectangle2D.Double(2+f,10+g,5,1000);       
             f +=50;
             recList.add(rec);                
         }
         f = 10;
    
         for(int i = 0; i < 20; i++){
             rec1 = new Rectangle2D.Double(2+y,10+s,1000,5);       
             s +=35;
             recList2.add(rec1);                
         }
         s = 10;
        }
    
    
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            FlyingSaucerTwo fs = new FlyingSaucerTwo();
            Laser laser = new Laser(fs);
            fs.addMouseMotionListener(laser);
            fs.addMouseListener(laser);
            frame.getContentPane().add(fs);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(700,700);
            frame.setVisible(true);     
       }
    
       //@Override
        protected void paintComponent(Graphics g) {
         super.paintComponent(g); 
         ((Graphics2D)g).setColor(Color.RED);
         int a = 10;
         int b = 10;
    
         for(int i = 0;i < recList.size();i++){               
           ((Graphics2D)g).draw(recList.get(i));
         }
    
         for(int i = 0;i < recList2.size();i++){               
            ((Graphics2D)g).draw(recList2.get(i));
         }
        }
        }
    
         class Laser implements MouseListener,MouseMotionListener{
          Rectangle2D.Double mouseBox;
          List<Rectangle2D.Double> recxList;
          Rectangle2D.Double recx;
          List<Rectangle2D.Double> recyList;
          Rectangle2D.Double recy;
          FlyingSaucerTwo fs;
    
         public Laser(FlyingSaucerTwo fs){
          this.fs = fs;
         }
    
         @Override 
         public void mouseClicked (MouseEvent e) { }
         @Override 
         public void mousePressed (MouseEvent e) { }
         @Override 
         public void mouseReleased(MouseEvent e) { }
         @Override 
         public void mouseEntered (MouseEvent e) { }
         @Override 
         public void mouseExited  (MouseEvent e) { }
         @Override 
         public void mouseDragged (MouseEvent e) { }
    
         @Override
          public void mouseMoved(MouseEvent e) {   
            SwingUtilities.invokeLater(new Runnable() { 
                   @Override
                   public void run() { 
                    Point p = e.getPoint();
                    recxList = fs.recList;                        
                    recyList = fs.recList2; 
                    Iterator <Rectangle2D.Double> recX = recxList.iterator();
                    //FIRST LOOP over Y axis rectangles
                    while(recX.hasNext()){
                         recx = recX.next();
                         if( recx.contains(p)){           
                             fs.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); 
    
                             break;                     
                         }
                         else if(recyList.size()>=0){
                             Iterator <Rectangle2D.Double> recY = recyList.iterator(); 
                                 //SECOND LOOP over X axis rectangles
                                while(recY.hasNext()){
                                     recy = recY.next();
                                     if( recy.contains(p)){           
                                         fs.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));                                        
                                         break;                     
                                     }
                                     else{
                                         fs.setCursor(Cursor.getDefaultCursor());
                                     }
                                }
                         }
                         else{
                             fs.setCursor(Cursor.getDefaultCursor());
                         }
                    }                      
                }
            });
        }
        }        
    

2 个答案:

答案 0 :(得分:0)

恕我直言,你的内部代码应该是这样的:

Cursor cursor = Cursor.getDefaultCursor();
Iterator <Rectangle2D> recs = rowBuffY.iterator();
//FIRST LOOP over Y axis rectangles
while(recs.hasNext()){
    selectRec = recs.next();
    if( selectRec.contains(p)){           
        cursor = Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); 
        dragging = false;
        moveLine = true;
        break;                     
    }
}
Iterator <Rectangle2D> recX = rowBuffX.iterator(); 
//SECOND LOOP over X axis rectangles
while(recX.hasNext()){
     selectRec = recX.next();
     if( selectRec.contains(p)){           
     cursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
     dragging = false;
     moveLine = true;
     break;                     
}
tpp.setCursor(cursor);

此代码只检查每个矩形一次,优先选择X轴矩形,而代码检查每个X轴矩形N次(对于鼠标不悬停的每个Y轴矩形)。

答案 1 :(得分:0)

正如ThomasKläger建议的那样,你应该解开循环。

如果仍然存在问题,则可能与您调用setCursor()的事实有关。特别是,在嵌套循环示例中,如果光标不在矩形中,则调用setCursor()将默认光标设置数百次。每次调用setCursor()时,都会重绘光标,这是一个非常耗时的过程。

每个mousemoved事件最多需要设置一次光标。执行此操作的一种方法是在遍历循环时设置关于所需光标类型的布尔值,然后在两个循环退出后根据布尔值仅在结尾处设置光标。为了进一步提高效率,您还可以检查当前光标是否已经是您想要的光标,只有在需要更改时才调用setCursor()。