Session #5
This session, I added some features to the editor that enhance the user interface. The two big ones are 1) using the right mouse button to paint in the empty (background) color and 2) to open a data file by allowing the user to drag and drop from Windows Explorer. I also show how to add another form (an About box in the Help menu, and a configuration form in the Edit menu) to the application.
/*
Handler for the OnMouseDown event. The Shift parameter contains
additional information such as the state of the control/alt/shift keys.
*/
void __fastcall TfrmMain::gridWorldMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y)
{
// If the right mouse button is pressed down
if (Button == mbRight)
{
// Convert the x/y pixel location to a row and column in the grid
TGridCoord coord = gridWorld->MouseCoord(X, Y);
// Update current row/column
FCurrRow = coord.Y;
FCurrColumn = coord.X;
// Set this cell as empty (background color)
FDataMap[FCurrRow][FCurrColumn] = ctEMPTY;
// Paint the cell
HighlightCell(true);
}
}
Technically, adding this feature is trivial, but it enhances the user interface significantly. In fact, as I was "cobbling" this tile editor
together and testing it, I kept wishing that I didn't have to keep switching between the Obstacle color and the Empty color. I thought it
would have been so much more efficient to just toggle between the two colors by using the two mouse buttons. That is a very intuitive action
and many paint programs do something similar. Many times, you'll find that it's the little things like this that distinguish between very good, usable programs,
and programs that won't get used. It's all about the interface. And the more the interface stays out of the user's way, the better.
Remember: Think about the user's work flow.
void __fastcall WMDropFiles(TWMDropFiles &Message);
BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_DROPFILES, TWMDropFiles, WMDropFiles) END_MESSAGE_MAP(TForm)
// Register this window with the OS as a drop target. DragAcceptFiles(this->Handle, true);
// Unregister this window with the OS as a drop target. DragAcceptFiles(this->Handle, false);
/*
Handler for the WM_DROPFILES message from Windows.
*/
void __fastcall TfrmMain::WMDropFiles(TWMDropFiles &Message)
{
int num_files, filename_length;
char file_name[MAX_PATH + 1];
// Refer to the Win SDK documentation about the details
// of DragQueryFile and the HDROP structure
// Get the number of files that are being dropped on the window
num_files = DragQueryFile((HDROP)Message.Drop, -1, NULL, 0);
// Unlikely to happen
if (num_files < 1)
return;
// Retrieve each filename that was dropped
for(int i = 0; i < num_files; i++)
{
// Get the length of the i'th filename
filename_length = DragQueryFile((HDROP)Message.Drop, i, NULL, 0);
// Retrieve the filename from the HDROP structure
DragQueryFile((HDROP)Message.Drop, i, file_name, filename_length + 1);
// Reset the grid
Init();
// Read in the data
ImportMapData(file_name);
// Update the UI
short r = FRows;
short c = FColumns;
spnRows->Position = r;
spnColumns->Position = c;
// We can only deal with one at this point so bail out.
// If we could handle multiple files, we would loop through all of them.
return;
}
}
You can put this code anywhere. The obvious place is to make a Help menu that has an "About..." choice. When the user selects it, the dialog should be displayed. (See the project for details.) Also, if you want the dialog box to be non-modal, call the Show() method instead of ShowModal().AboutBox->ShowModal();
Exercises