2

I have java swing chess application. Cursor has custom view - rectangle, sized to fit whole cell. And I need cursor moving only over whole cell. Not in the limits of one cell. Is there some typical solutions for this problem? Or maybe it is possible to set with standard java capabilities step-type cursor moving?

enter image description here

mKorbel
  • 109,525
  • 20
  • 134
  • 319
fland
  • 127
  • 1
  • 9

1 Answers1

5

I wouldn't implement some kind of "stepping" cursor. Instead I would hide the cursor completly and highlight the current cell programmatically.


Full example below that "outputs" this screenshot:

screenshot

public class StepComponent extends JComponent implements MouseMotionListener {
    private Point point = new Point(0, 0);

    public StepComponent() {
        setCursor(Toolkit.getDefaultToolkit().createCustomCursor(
                new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB), 
                new Point(0, 0), "blank cursor"));
        addMouseMotionListener(this);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        int x = 0, y = 0;
        while (x < getWidth()) { g.drawLine(x, 0, x, getHeight()); x += 10; }
        while (y < getHeight()) { g.drawLine(0, y, getWidth(), y); y += 10; }
        if (point != null)
            g.fillRect(point.x, point.y, 10, 10);
    }
    @Override public void mouseDragged(MouseEvent e) { update(e.getPoint()); }
    @Override public void mouseMoved(MouseEvent e) { update(e.getPoint()); }

    private void update(Point p) {
        Point point = new Point(10 * (p.x / 10), 10 * (p.y / 10));
        if (!this.point.equals(point)) {
            Rectangle changed = new Rectangle(this.point,new Dimension(10,10));
            this.point = point;
            changed.add(new Rectangle(this.point, new Dimension(10, 10)));
            repaint(changed);
        }
    }
}

And some test code:

public static void main(String[] args) {

    JFrame frame = new JFrame("Test");

    frame.add(new StepComponent());

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 300);
    frame.setVisible(true);
}
Community
  • 1
  • 1
dacwe
  • 43,066
  • 12
  • 116
  • 140
  • this comment redactor will kill me... Enter works just "perfect" – fland Jan 26 '12 at 14:55
  • Yeah thanks. I tried before such kind of solution, using even Glass Panel - I thought that repainting mostly empty panel will be faster, then repainting panel with chess desk. The main problem is - performance. Repaint method needs a lot of resources. And mouse moving, especially when application maximized, takes all my processor time. So that's why I decided to try with custom mouse cursor. – fland Jan 26 '12 at 15:03
  • Shouldn't take that much time at all, the "background" (in my case the grid) can always be painted on an `Image`. Check out something called double-buffering.. But that is another question! ;) – dacwe Jan 26 '12 at 15:08
  • I tried yours example, even without drawing any grid - just cursor-rectangle. And in maximized window state moving cursor load my processor on 100%. As I understood - repaint() method itself needs a lot of resources – fland Jan 26 '12 at 15:18
  • On my system this code only uses at the most 3% (maximized on my 2560x1440 screen) and then I'm moving my mouse all over the place. ;) – dacwe Jan 26 '12 at 15:20
  • I updated question. And added screen which is showing load on my system. I am using Athlon X2 7850 and I think - it's more then enough for such type of application. Resolution also not so big: 1280x1024 – fland Jan 26 '12 at 15:27
  • The key to fixing the painting performance is two-fold. Only repaint when you KNOW something has changed, when a different square is highlighted. Only repaint the regions, see repaint with rectangle arguments. – basszero Jan 26 '12 at 15:31
  • thanks a lot. That is really makes situation with performance better. But still it takes near to 65-70% of processor time on even smooth cursor moving. Let's wait for maybe some more efficient solution a little. – fland Jan 26 '12 at 15:45
  • @dacwe there is always NPE. It should be smth like this in update: Point point = new Point(10 * (p.x / 10), 10 * (p.y / 10)); if (this.point == null) { this.point = point; repaint(); return; } if (!this.point.equals(point)) { Rectangle changed = new Rectangle(this.point, new Dimension(10, 10)); this.point = point; changed.add(new Rectangle(this.point, new Dimension(10, 10))); repaint(changed); } and with partial repainting it works more faster, near to 20% CPU time – fland Jan 26 '12 at 15:58
  • ... partial update of answer, sorry.. fixed (added `= new Point(0, 0)`) for this test. – dacwe Jan 26 '12 at 16:02
  • @kleopatra: Did you even try the program? It just hides the window managers cursor for this component and draws it inside the component instead.. (On the other hand if there is a better solution I will upvote it!) – dacwe Jan 26 '12 at 18:27