Java Swing:将鼠标悬停在矩形上时,光标响应会非常缓慢 [英] Java Swing: Awfully slow cursor response when hovering over rectangles

查看:109
本文介绍了Java Swing:将鼠标悬停在矩形上时,光标响应会非常缓慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码是用户将鼠标光标移到一堆矩形上,并且当光标移到矩形上方时,该光标应变为手形光标,当光标不在给定的矩形上方时,该光标将恢复为默认的普通光标.

Below is code where a user is moving the mouse cursor over a bunch of rectangles and the cursor is supposed to change to a hand cursor while over the rectangles and revert to a default normal cursor when not on top of the given rectangles.

问题: 解决方案有效,但痛苦的缓慢.它们有许多种给猫咪剥皮"的方法,因此我们可以对问题进行多种建模,并且解决方案可以是各种各样的,但是什么是恒定的,是我们必须循环使用迭代器遍历每个矩形,并使用contain()方法确定JPanel上的给定点是否确实在矩形内,并相应地更改光标.

Problem: The solution works,but painfully slow.They are many ways "to skin a cat", therefore we can model the question in many variants and solutions could be of all kinds, but what is constant,is that we have to loop over each rectangle using an iterator and use the contain() method to ascertain if indeed a given point on the JPanel is within a rectangle or not,and change the cursor accordingly.

就像实现声音所需要的一样简单,即在将鼠标悬停在特定矩形上时更改光标,随着我添加不同的形状和更多矩形,该程序开始明显变慢.

As simple as what is needed to be implemented sounds,i.e change cursor while hovering over specific rectangles, the program starts to slow considerably as I add different shapes and more rectangles.

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

The code below simply shows rectangles aligned to the x-axis and rectangles aligned to the y-axis.I split them(still can combine them into one list) into two List of rectangles.I iterate over the two lists with a while loop within another,each with the break keyword at the appropriate place.

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

I avoid using just one large list to hold both types of rectangle (or different types of shapes) because

  1. 我需要每隔一次添加不同的形状,并且更好地,更具可读性地将不同的形状归类到自己的列表中.
  2. 我本能地尝试通过对不同形状使用不同的列表来缩短较长的过程,并且如果可能,仅在正确的列表上进行迭代,而不对不需要的其他形状进行迭代.即一个大列表会线性增长并遍历***所有形状***一直保持正确的形状.***这么大的列表似乎不是一个聪明的实现吗?希望我能避免避免过大优化的清单不是过早优化的情况!!这一点我认为应该使用线程
  1. I need to add different shapes every other time, and its better and more readable to have different shapes categorized in there own list.
  2. I am instinctively trying to shorten a long process by using different list for different shapes and if possible,iterate over the right list only and not iterate over other shapes that are unnecessary.i.e One large list will grow linearly and iterate over ***all shapes***to get to the right one ***all the time.***Doesn't the one large list seem not a so smart implementation? Hoping my best that efforts to avoid the One-Large-List is not a case of premature optimization!!!This the point I thought to use threads to loop over different list concurrently or simultaneously but one thread misbehaves.

然后,我将形状分类到不同的List中,如下面的示例中有两个Lists,但是这个技巧也失败了,因为我必须顺序地遍历每个列表,所以我在另一个列表中有一个while循环,我一直在避免迭代在不必要的列表上,因为一个循环必须在另一个循环内(或在另一个循环之后开始),则内部循环(或随后的循环)会付出不必要的性能开销,因为如果我们可以事先确定,则第一个循环是完全不必要的. 标记您,以确保鼠标光标悬停在属于圆形列表或矩形列表的形状上,这是我们需要知道的. em>!这样我们就可以遍历特定列表.甚至会变得更好,如果此时您仍然可以按照我的推理,必须先知道形状属于哪个列表,之所以使用contain()方法,是因为在迭代内部列表时将使用contain()!!!

So then, I categorize shapes in different List, as the example below has two Lists.but this trick also fails as I have to iterate over each list sequentially.So I have a while loop within another.I have not avoided iterating over unnecessary list,as one loop must be within another(or start after another), then the inner loop (or the one that follows) pays an undue performance overhead since the first loop is totally unnecessary if we can ascertain before hand that a shape belongs to a certain group before hand.Mark you,to ascertain if a mouse cursor is hovering over a shape belonging to a List of circle,or a List of rectangles,is what we need to know beforehand !! so that we iterate over the specific list. It even gets better,if at this point you can still follow my reasoning, to know beforehand which List a shape belongs to has to been done without the contain() method, since contain() is to be used while iterating inside the List!!!

总而言之,下面的代码只是在两个列表上的线性迭代.要访问第二个列表,您必须先通过第一个列表.有人可以通过首先迭代第一个列表来进行访问吗?

To summarize, the code below is simply a linear iteration over two list. To access the second List,you have to pass through the first.Is there a way one can by pass iterating the 1st list first?

如果我所有的解释和探索都是错误的,并且没有任何意义. 问题. 然后,如何改善下面代码的游标响应.

If all my explanations and explorations are all wrong and don't make sense. Question. Then,how do I improve the cursor response of the code below.

编辑

很抱歉发布了无法编译的代码,我已经离开了这段代码片段,开始玩我称为线程的新玩具,直到最终我结成了一个无法解开自己的结.我是否选择了线程,因为我希望选择矩形并使用setRect()方法移动它们.我设想以预定的运动(即仿射变换)移动各种形状,这可能是由于绘画,重绘,搜索和各种方式造成的.我的工作得益于多线程.无论如何,下面的代码可以编译,并且光标响应实际上是好!!! .我有一个类似的实现,但是它的缓慢可能是由其他绘制矩形的类引起的,这与本SSCCE中的for循环绘制不同.

Sorry for posting code that does not compile, i has so moved on from this code snippet and was playing with my new toys called threads,till i ended up tying myself in an knot which i could not disentangle myself from.The truth is i choose threads as I hope to select the rectangles and move them about using setRect() method.I envisioned that moving around shapes of all kinds in predetermined motions i.e affinetransformation may require threads due to painting, repainting , searching and all manner of hard work that my benefit from some multi-threading.Anyways, the code below compiles and the cursor response is actually good!!!.Ouch! I have a similar implementation but probably its slowness is being caused by other classes which draw the rectangles, unlike in this SSCCE where they are drawn by a for loop.

同时,如果有人能够通过线程获得这种良好的性能,我们将不胜感激.

Mean while, if anyone has a way to get this good performance through threads, it would be highly appreciated.Thanks in advance.

    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());
                     }
                }                      
            }
        });
    }
    }        

推荐答案

正如ThomasKläger所建议的那样,您应该取消嵌套循环的操作.

As Thomas Kläger suggests, you should un-nest the loops.

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

If there is still an issue, it probably has to do with the fact that you are calling setCursor() too much. In particular, in the nested loop example, if the cursor is not in a rectangle, you are calling setCursor() to set the default cursor hundreds of times. Each time you call setCursor(), the cursor is redrawn, which is a time consuming process.

每个鼠标移动的事件最多需要设置一次光标.一种方法是在遍历循环时为所需的游标类型设置一个布尔值,然后根据布尔值在两个循环都退出后仅在最后设置游标.为了进一步提高效率,您还可以检查当前光标是否已经是所需的光标,并且仅在需要更改时才调用setCursor().

You need to set the cursor at most once per mousemoved event. One way of doing this would be to set a boolean value about the desired cursor type while going through the loops, then setting the cursor only at the end, after both loops have exited, based on the boolean value. For further efficiency, you could also check whether the current cursor is already the one you want, and only call setCursor() if you need to change it.

这篇关于Java Swing:将鼠标悬停在矩形上时,光标响应会非常缓慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆