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

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

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

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

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

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

  1. 我需要每隔一段时间添加不同的形状,并且它更好,更易读,可以在自己的列表中分类不同的形状。
  2. 我本能地试图通过对不同的形状使用不同的列表来缩短漫长的过程, 如果可能的话 ,只迭代正确的列表而不是迭代其他不必要的形状。一个大的列表将线性增长并迭代***所有塑造***以一直***到正确的***。***一个大的列表似乎不是一个如此聪明的实现? 希望尽我所能避免One-Large-List的努力不是过早优化的情况!!!这一点我认为使用线程同时或同时循环遍历不同的列表但是一个线程行为不端。

那么,我将形状分类在不同的List中,因为下面的示例有两个Lists.but这个技巧也失败了,因为我必须按顺序遍历每个列表。所以我在另一个列表中有一个while循环。我没有避免迭代不必要的列表,因为一个循环必须在另一个循环中(或者从另一个循环开始),那么内循环(或后面的循环)会支付过度的性能开销,因为如果我们可以事先确定一个形状属于一个形状,那么第一个循环是完全没有必要的。手上的某个组。请注意,确定鼠标光标是否hover在属于圆形列表或矩形列表的形状上,是我们事先需要知道的! 这样我们就可以遍历特定的列表。 它甚至变得更好,如果在这一点上你仍然可以按照我的推理, 事先知道哪个List属于一个必须在没有contains()方法的情况下完成,因为在List 内部迭代时要使用contains()! !

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

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

编辑

很抱歉发布了无法编译的代码,我已经从这个代码片段开始,并且正在玩我的新玩具,称为线程,直到我最终将自己绑在一个我无法解开的结中。真相是我选择的线程,因为我希望选择矩形并使用setRect()方法移动它们。我设想在预定的运动中移动各种形状,即仿射转换可能需要线程,因为我的绘画,重新绘制,搜索和各种努力工作从一些multithreading中受益。总之,下面的代码编译,光标响应实际上是好的! 。哎哟! 我有一个类似的实现,但可能它的缓慢是由绘制矩形的其他类引起的,不像在这个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 recList; List 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 recxList; Rectangle2D.Double recx; List 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  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  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  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  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次(对于鼠标未hover的每个Y轴矩形)。

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

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

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