MTG beta 1.2

Jar file here. Code here. Patch notes here. Java SE 7 required, download from here.

I have started playing a bit more with graphics and drawings. It’s a great fun, but requires good mathematical skills and a lot of patience and paper for calculations. Good 3D imagination is also important – most of problems I encountered with it was not because of incorrect calculations, but because I didn’t know what I really want to do and how it should behave. I have implemented two (in my opinion nice) features. First of them is zooming like in Google maps – i.e. the object does not only changes its sizes, but also is moved so that the mouse pointer is all the time pointing the same part of it. In other words, when you zoom in, you zoom into an area where you points. I spent two days and used six sheets of paper to write those four crucial lines of code. The second feature is using an image as a background of the area, but when area is much bigger than the image. The idea is simple – background image cannot remain static, but has to move with displaying part of the area. It was much easier to implement than the first feature, but still I needed to do a lot of calculations to write a proper formula. Code for both of them at the bottom of the post.

Also one advice to Swing programmers – be careful with adding components to a JLabel. It seems that JLabel behaves like a JPanel with not LayoutManager and you can add Components to it and specify their Bounds, but I have encountered some strange problems. First thing was that a Component added has been multiplied – i.e. after addition to it was only one instance of it, but at some point later, JLabel.getComponents() returns this Component not once, but few times. The number of instances has been increasing in unexplained wait while adding or removing other Components. Also, that Component could not be removed from a JLabel – JLabel.isAncestor(Component) has been returning true, but JLabel.remove(Component) was not removing it, claiming that there is not there.

What I have learnt this time? I have improved my skills in using Netbeans Debugger and quite a lot about drawing on Component’s Graphics, what I am going to improve further.


 * This approach uses Component inside a JScrollPane. It changes the sizes
 * of Component and scrolls JScrollPane to the proper position.
 * Remember of resizing and repositioning all of Components of that
 * Component which is a ViewportView of JScrollPane.
 * Table.this is a JScrollPane, table is its ViewportView.

private static final int ZOOM_MIN = 25; //minimum zoom in %
private static final int ZOOM_MAX = 200; //maximum zoom in %
static int zoom = 100; //current zoom in %

 * Add a MouseWheelListener to the JScrollPane. Dont' forget about JScrollPane.setWheelScrollingEnabled(false).
public synchronized void mouseWheelMoved(MouseWheelEvent e) {
    int oldV = zoom;
    //default getUnitsToScroll() is 5 or -5, multiply it to zoom faster or slower
    int newV = oldV - 3 * e.getUnitsToScroll();
    //do not let to zoom outside range
    if (newV < oldV) { //zoom out
        if (oldV == ZOOM_MIN) {
        } else if (newV < ZOOM_MIN) {
            newV = ZOOM_MIN;
    } else { //zoom in
        if (oldV == ZOOM_MAX) {
        } else if (newV > ZOOM_MAX) {
            newV = ZOOM_MAX;

    zoom = newV; //change current zoom level
    table.setPreferredSize(new Dimension(
            SIZE.width * zoom / 100,
            SIZE.height * zoom / 100)); //resize ViewportView

    final int fnewV = newV;
    final int foldV = oldV;
    recalculatePosition(fnewV, foldV);

    //resize and reposition all of table's components here

 * This method scrolls to JScrollPane to the proper position.
 * It does not use Jcomponent.getMousePosition() because
 * of its unreliability.
private void recalculatePosition(int newV, int oldV) {
    class Point extends java.awt.Point {
        public Point(java.awt.Point p) {
        public Point(Rectangle r) {
            super(r.x, r.y);
        public Point(int x, int y) {
            super(x, y);
        Point substract(java.awt.Point o) {
            this.x -= o.x;
            this.y -= o.y;
            return this;
        Point add(java.awt.Point o) {
            this.x += o.x;
            this.y += o.y;
            return this;

    Point sp = new Point(MouseInfo.getPointerInfo().getLocation())
    Point tp = new Point(table.getVisibleRect())
    int changex = tp.x - tp.x * newV / oldV;
    int changey = tp.y - tp.y * newV / oldV;

    JScrollBar h = Table.this.getHorizontalScrollBar();
    JScrollBar v = Table.this.getVerticalScrollBar();
    h.setValue(table.getVisibleRect().x - changex);
    v.setValue(table.getVisibleRect().y - changey);


 * Override Component's paint method. tableBackground is a BufferedImage,
 * and 2000 is half of its width or height.
public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    Rectangle r = this.getVisibleRect();
    Dimension ts = table.getPreferredSize();
            2 * r.x * (ts.width / 2 - 2000) / (ts.width - r.width),
            2 * r.y * (ts.height / 2 - 2000) / (ts.height - r.height),

About Jaroslaw Pawlak

I have done MSci in Computer Science at King’s College London and currently work as Software Engineer specialising in Java. I spend most of my time in front of computer improving my programming (and other) skills or just relaxing with a good game. I also train some sports but at the moment I am not a member of any club. I love cycling and volleyball, but I have also played a lot of football, tennis and trained martial arts.

Posted on October 9, 2011, in Magic the Gathering - Virtual Table, My Projects. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: