How to move maximized window

I wanted to write JFrame that maximizes only horizontally, and move it up and down by using mouse drag.

Here is the initial version.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MaxMove1 extends JFrame 
    implements WindowListener, WindowStateListener,
           MouseListener, MouseMotionListener
{
    static final int W = 200;
    static final int H = 100;

    private Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    private Point startPoint;

    // WindowListener.
    public void windowClosing(WindowEvent e) {}
    public void windowStateChanged(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}

    // MouseListener.
    public void mousePressed(MouseEvent me) {
    startPoint = me.getPoint();
    }
    public void mouseReleased(MouseEvent me) {}
    public void mouseDragged(MouseEvent me) {
    Point loc = getLocation();
    int xx = loc.x + me.getX() - startPoint.x;
    int yy = loc.y + me.getY() - startPoint.y;
    if (getExtendedState() != NORMAL) xx = 0;
    setLocation(xx, yy);
    setMaximizedBounds(new Rectangle(0, yy, screen.width, H));
    }
    public void mouseMoved(MouseEvent me) {}
    public void mouseClicked(MouseEvent me) {}
    public void mouseEntered(MouseEvent me) {}
    public void mouseExited(MouseEvent me) {}

    // Appearance.
    class MyCanvas extends JComponent {
    public void paint(Graphics g) {
        g.setColor(Color.gray);
        g.fillRect(0, 0, getWidth(), getHeight());
    }
    }

    // Main program.
    public MaxMove1(){
    JComponent canvas = new MyCanvas();
    canvas.setVisible(true);
    add(canvas);

    addWindowListener(this);
    addWindowStateListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setSize(W, H);
    setMaximizedBounds(new Rectangle(0, 0, screen.width, H));
    setUndecorated(true);
    setVisible(true);
    }

    public static void main(String[] args) {
    new MaxMove1();
    }
}import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MaxMove1 extends JFrame 
    implements WindowListener, WindowStateListener,
           MouseListener, MouseMotionListener
{
    static final int W = 200;
    static final int H = 100;

    private Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    private Point startPoint;

    // WindowListener.
    public void windowClosing(WindowEvent e) {}
    public void windowStateChanged(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}

    // MouseListener.
    public void mousePressed(MouseEvent me) {
    startPoint = me.getPoint();
    }
    public void mouseReleased(MouseEvent me) {}
    public void mouseDragged(MouseEvent me) {
    Point loc = getLocation();
    int xx = loc.x + me.getX() - startPoint.x;
    int yy = loc.y + me.getY() - startPoint.y;
    if (getExtendedState() != NORMAL) xx = 0;
    setLocation(xx, yy);
    setMaximizedBounds(new Rectangle(0, yy, screen.width, H));
    }
    public void mouseMoved(MouseEvent me) {}
    public void mouseClicked(MouseEvent me) {}
    public void mouseEntered(MouseEvent me) {}
    public void mouseExited(MouseEvent me) {}

    // Appearance.
    class MyCanvas extends JComponent {
    public void paint(Graphics g) {
        g.setColor(Color.gray);
        g.fillRect(0, 0, getWidth(), getHeight());
    }
    }

    // Main program.
    public MaxMove1(){
    JComponent canvas = new MyCanvas();
    canvas.setVisible(true);
    add(canvas);

    addWindowListener(this);
    addWindowStateListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setSize(W, H);
    setMaximizedBounds(new Rectangle(0, 0, screen.width, H));
    setUndecorated(true);
    setVisible(true);
    }

    public static void main(String[] args) {
    new MaxMove1();
    }
}

Try this:
– Drag by mouse.
– Maximize by using task bar menu.
– Restore by using task bar menu.
– Maximize again by using task bar menu.
– Drag by mouse. Nicely goes up and down.
– Restore by using task bar menu. (Oops.)

The problem is setLocation(). By doing this Windows is told that the Frame is not maximized any more. But Java still thinks it is maximized. Probably I went into a glitch on the spec or imprementation.

So I should avoid setLocation() when Frame is maximized, and I am probably supposed to use setMaximizedBounds() to tell where the Frame should go. setMaximizedBounds() doesn’t move Frame until the Frame is maximized again. I don’t want to perform Restore/Maximize combo because it may show a flicker.

So I decided as follows:

– Use setLocation() even if maximized.
– Remember the maximized state when I start dragging.
– Keep the non-maximized location in Frame.
– When the mouse is released, I restore the condition.
– When the Frame is un-maximized, I restore the condition.

Here is the final version:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MaxMove2 extends JFrame 
    implements WindowListener, WindowStateListener,
           MouseListener, MouseMotionListener
{
    static final int W = 200;
    static final int H = 100;

    private Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    private Point startPoint;
    private boolean startMaximized;
    private boolean dragged = false;
    private int x = 0;
    private int y = 0;
    private int w = W;
    private int h = H;

    // WindowListener.
    public void windowClosing(WindowEvent e) {}
    public void windowStateChanged(WindowEvent e) {
    if (e.getNewState() == NORMAL) {
        setLocation(x, y);
        setSize(w, h);
    }
    }
    public void windowActivated(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}

    // MouseListener.
    public void mousePressed(MouseEvent me) {
    startPoint = me.getPoint();
    startMaximized = (getExtendedState() != NORMAL);
    }
    public void mouseReleased(MouseEvent me) {
    if (startMaximized && dragged) {
        setExtendedState(NORMAL);
        setExtendedState(MAXIMIZED_BOTH);
    }
    dragged = false;
    }
    public void mouseDragged(MouseEvent me) {
    Point loc = getLocation();
    int xx = loc.x + me.getX() - startPoint.x;
    int yy = loc.y + me.getY() - startPoint.y;
    setLocation((getExtendedState() == NORMAL)? xx : 0, yy);
    setMaximizedBounds(new Rectangle(0, yy, screen.width, H));

    if (! startMaximized) x = xx;
    y = yy;
    dragged = true;
    }
    public void mouseMoved(MouseEvent me) {}
    public void mouseClicked(MouseEvent me) {}
    public void mouseEntered(MouseEvent me) {}
    public void mouseExited(MouseEvent me) {}

    // Appearance.
    class MyCanvas extends JComponent {
    public void paint(Graphics g) {
        g.setColor(Color.gray);
        g.fillRect(0, 0, getWidth(), getHeight());
    }
    }

    // Main program.
    public MaxMove2(){
    JComponent canvas = new MyCanvas();
    canvas.setVisible(true);
    add(canvas);

    addWindowListener(this);
    addWindowStateListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setLocation(x, y);
    setSize(w, h);
    setMaximizedBounds(new Rectangle(0, 0, screen.width, H));
    setUndecorated(true);
    setVisible(true);
    }

    public static void main(String[] args) {
    new MaxMove2();
    }
}

I had to do Restore/Maximize combo when the Frame is un-maximized. But it doesn’t cause flicker because the window is same as maximized size before the operation.

This is always the way when I program in Java: I find shortcomings or glitches in the spec or implementation, then I have to move the wrinkle caused by the glitch around to fit some place where it doesn’t matter.

Advertisements

Note with outline mode

Suppose your boss asks the result of the experiment performed about one year ago. Can you give him an answer within 10 minutes? – I can.

The reason is I have a note, which is written in plain text and saved in one giant file: ~/Note. The file is written in Emacs outline mode.

* 2/6 flash problem…
* 2/6 OHCI bringup note…
* 2/5 todo for project X…

Each section can be anything: a report, program snippet, session log, or even a memo of random thoughts. My rule is like this:

– Anything can be in ~/Note.
– Write a short section title with a date.
– It is OK to be dirty in a section.
– No memo should not be saved in other places.

Then whenever I want to remember something, I know that’s in ~/Note. And I can grep through it.

I don’t write on a paper because the power of paper notebook is too short for what we are doing. When I have to write on a paper, I type it later in ~/Note.

Binary serarch for two step bug

I talked about debugging as binary search in
https://droid7c2.wordpress.com/2009/02/10/debugging-as-binary-searchdebugging-as-binary-search/

What if the problem happens in two steps. For example, if your program goes south by performing action1 first, then action2?

The OK-NG chart would be like this.

    ----------OK------------------------------------- NG---------
                |<--action1-->|                |<--action2-->|

Now you have to divide this into two. One for looking into action1.

    -----------------------------------------OK------ NG---------
                |<--action1-->|                |<--action2-->|

We know that “OK” here is not actually OK because something is already caused by performing action1. But for the sake of binary search, we call it OK. Then you divide between OK and NG until you find what was really NG in action 2.

And the other for action2. This time you do not touch action 2, and look into action 1. We know that things were OK before action 1, and NG after action 1. You reduce the amount of code in action 1, and see when the symptom seen in action 2 happens or not.

    ----------OK---------------NG-------------------- NG---------
                |<--action1-->|                |<--action2-->|

You can start digging in either one of those two. However, do not forget that you have two OK-NG chart now. Otherwise, you might forget the other one and waste time.

Write things to do

Our brain work responding to the external input. That is the way we think. You tend to think more when more external input comes. Our thoughts slow down when we don’t have input. So we have to come up with a way to keep input flowing into us for efficient work.

I use a piece of memo, actually a page on Emacs, to direct myself.

For programming, I write what I have to do. I break down the list until they become concrete enough, usually the line is going to be translated into a few lines of program. Then I start writing the program whichever order I like. Because everything is listed, I would not drop anything. As programming makes progress I cross out the lines from the memo. I may add some lines when the new items come up. In the end, the memo becomes empty and the program is done.

For debugging, I write all the findings and possible experiments, so that I don’t drop any possibilities. Then I start looking at each of the possibilities in any order I would like. Not like for programming, I do not erase the lines as debug goes on. I only write more findings and possibilities. Obsolete lines goes to the bottom of the memo. At the end of the debugging, I get a messy
debug note, which I just keep for future reference.

Who handles errors

You have learned somewhere that a function should return error codes.  When you become a team leader, you take it serious and let everyone write functions to return error codes.

Then the program tends to be like this:

bad:

    int func1() {
        .....
        if (error) return -1;
        .....
    }

    int func2() {
        .....
        status = func1();
        if (status != 0) return status;
        .....
    }

    int func3() {
        .....
        status = func2();
        status = func2();
        .....
    }

    int func4() {
        .....
        status = func3();
        if (status != 0) return status;
        .....
    }

You set up a rule and let everybody follow. Your program will be robust.

Wrong. You only have false sense of assurance. Error code works only if all the caller check the error code and pass it along accordingly. That is very unlikely; for example, in the example above, the error code returned from func2() is ignored in func3().

This is more dangerous than doing nothing, and creates lots of unnecessary coding work.

More realistic way is just to stop at error, and not returning error code at all.

good:

    void func1() {
        .....
        assert(!error);
        .....
    }

    void func2() {
        .....
        func1();
        .....
    }

    void func3() {
        .....
        func2();
        .....
    }

    void func4() {
        .....
        func3();
        .....
    }

This looks brutal for production level program. But in reality it is much better than the first example because it catches the error.

But what if you want to continue even if the error occurs? I recommend error logging. There is no need to propagate the error during the call tree. And the error is guaranteed to be checked eventually.

good:

    void func1() {
        .....
        if (error) logWrite(error);
        .....
    }

    void func2() {
        .....
        func1();
        .....
    }

    void func3() {
        .....
        func2();
        .....
    }

    void func4() {
        .....
        func3();
    if (logShowsError()) {
            // Take some action.
        .....
        logClear();
    }
        .....
    }

As a rule of thumb, error return is OK only for a simple functions.

By the way I didn’t mention about exception (the try and catch construct). I use exception for my private programming. However, I found it too difficult for the group of ordinary people which I have been working with. Only a few of them would understand what they are told to do.

Real estate wasted by indent

Indentation is a nice way to show the structure. But note that you can not write anything in the space wasted by the indentation. Your precious writing space comes after indentation. So you should use minimum indentation.

For example, I think the following way is bad because the real work is indented.

bad:

    int result = -1;

    while (result < 0) {
        // Do the real work here.
    }

The real work would be several lines long, and include complex math. So we want to give it as much space as possible.

good:

    int result = -1;

  retry:
    // Do the real work here.

    if (result < 0) goto retry;

You say goto is bad? I don’t think so. In this kind of case, retry is only an exceptional path, and looping around is not important point of  the work. Using while() is rather misleading and overkill.

Real estate of a page

A page is a unit of our thinking, what we can glance at a time, and what we can grasp at a time. Unless you are a mutant genious, you can not think more than that at a once.

So for programming, we should write as much as possible in a page, so that one chunk of work do not continue to the next page. The real estate on a page is precious.
You should not waste.

– Do not use unnecessary long name.
– Use shorter, cleaner, regular name.
– Write a simple thing in a simple way.

Here is an example.
bad:

    if ( GCX_CMLIB_check_frame_status( pGCXFrame, frame_num )
         == GCX_CMLIB_NORERROR )
    {
        frame_count++;
    }

good:

    if ( frameStatus( pGCXFrame, frame_num ) ) {
        frame_count++;
    }

better:

    if ( frameStatus(pFrame, iFrame) ) nFrame++;