簡體   English   中英

Java Swing:將鼠標懸停在矩形上時,光標響應會非常緩慢

[英]Java Swing: Awfully slow cursor response when hovering over rectangles

下面是代碼,其中用戶將鼠標光標移到一堆矩形上,並且當光標移到矩形上方時,光標應更改為手形光標,當光標不在給定矩形上方時,將恢復為默認的普通光標。

問題:解決方案有效,但速度很慢。它們有許多種“給貓咪剝皮”的方法,因此我們可以對問題進行多種建模,並且解決方案可以是各種各樣的,但是恆定的是,我們必須循環每個矩形都使用迭代器,並使用contain()方法確定JPanel上的給定點是否確實在矩形內,並相應地更改光標。

就像實現聲音所需要的一樣簡單,即在將鼠標懸停在特定矩形上的同時更改光標,隨着我添加不同的形狀和更多的矩形,程序開始明顯變慢。

下面的代碼簡單地顯示了與x軸對齊的矩形和與y軸對齊的矩形。我將它們拆分 (仍然可以將它們組合成一個列表)成兩個矩形列表。我在其中的一個while循環內遍歷兩個列表另一個,在適當的位置分別帶有break關鍵字。

我避免只使用一個大列表來容納兩種類型的矩形(或不同類型的形狀),因為

  1. 我需要每隔一次添加不同的形狀,並且將其更好地且更具可讀性地將不同的形狀歸類到自己的列表中。
  2. 我本能地嘗試通過對不同形狀使用不同的列表來縮短一個漫長的過程,並且如果可能的話 ,僅在正確的列表上進行迭代,而不是對不必要的其他形狀進行迭代。即,一個大列表將線性增長並在*** all上進行迭代形狀***始終保持正確狀態。***一個大列表似乎不是一個聰明的實現嗎? 希望我能盡最大努力避免過大的列表不是過早的優化!!!這一點我認為使用線程同時或同時循環遍歷不同的列表是一個問題。

因此,我將形狀分類到不同的List中,如下面的示例中有兩個Lists,但是此技巧也失敗了,因為我必須順序地遍歷每個列表,所以我在另一個列表中有一個while循環。 ,因為一個循環必須在另一個循環之內(或在另一個循環之后開始),所以內部循環(或隨后的循環)會付出不必要的性能開銷,因為如果我們可以事先確定形狀屬於一個循環,則完全不需要第一個循環我們需要事先知道!標記您,以確保鼠標光標懸停在屬於圓形列表或矩形列表的形狀上! 這樣我們就可以遍歷特定列表。 甚至會變得更好,如果此時您仍可以按照我的推理進行操作,則無需使用contain()方法就可以事先知道形狀屬於哪個列表,因為在列表內部進行迭代時將使用contain()! !!

總而言之,下面的代碼只是兩個列表的線性迭代。 要訪問第二個列表,您必須先通過第一個列表。有人可以通過首先迭代第一個列表來進行訪問嗎?

如果我所有的解釋和探索都是錯誤的,那是沒有道理的。 題。 然后,如何改善下面代碼的游標響應。

編輯

很抱歉張貼無法編譯的代碼,我已經離開了這段代碼,開始玩我稱為線程的新玩具,直到最后我結成了一個無法解開的結。事實是我選擇了我希望選擇矩形並使用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());
                     }
                }                      
            }
        });
    }
    }        

恕我直言,您的內部代碼應如下所示:

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軸矩形)。

正如ThomasKläger所建議的那樣,您應該取消嵌套循環。

如果仍然存在問題,則可能與您對setCursor()的調用過多有關。 特別是,在嵌套循環示例中,如果光標不在矩形中,則調用setCursor()來設置默認光標數百次。 每次調用setCursor()時,都會重新繪制光標,這是一個耗時的過程。

每個鼠標移動事件最多需要設置一次光標。 一種方法是在遍歷循環時為所需的游標類型設置一個布爾值,然后根據布爾值在兩個循環都退出后僅在最后設置游標。 為了提高效率,您還可以檢查當前光標是否已經是所需的光標,並且僅在需要更改時才調用setCursor()。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM