CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 4 of 4
  1. #1
    Join Date
    Apr 2003
    Location
    Regensburg, Bavaria, Germany
    Posts
    147

    Switching focus from child window to child window

    I just finished this program and one thing that was bothering me was a few nitpick things that made it work, I'm not sure how, maybe I'm just not looking at the problem correctly.
    Code:
    #include <windows.h>
    
    #define DIVISIONS 5
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
    
    int idFocus = 0;
    TCHAR szChildClass[] = TEXT("Checker4_Child");
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
      static TCHAR szAppName[] = TEXT("Checker4");
      HWND hwnd;
      MSG msg;
      WNDCLASS wndclass;
    
      wndclass.style = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc = WndProc;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
      wndclass.hInstance = hInstance;
      wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
      wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.lpszClassName = szAppName;
    
      if(!RegisterClass(&wndclass))
      {
        MessageBox(NULL, TEXT("This program requires a Windows OS that supports Unicode."),
          szAppName, MB_ICONERROR);
    
        return 0;
      }
    
      wndclass.lpfnWndProc = ChildWndProc;
      wndclass.cbWndExtra = sizeof(long);
      wndclass.hIcon = NULL;
      wndclass.lpszClassName = szChildClass;
    
      if(!RegisterClass(&wndclass))
      {
        MessageBox(NULL, TEXT("An error has occured while attempting to register a child window."),
          szAppName, MB_ICONERROR);
    
        return 0;
      }
    
      hwnd = CreateWindow(szAppName, TEXT("Checker4 Mouse Hit-Test Demo"), WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    
      ShowWindow(hwnd, iCmdShow);
      UpdateWindow(hwnd);
    
      while(GetMessage(&msg, NULL, 0, 0))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    
      return msg.wParam;
    }
    
    // handles all of the little child windows together, however, does not control the user input
    //  to each child window
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
      // window handles for 25 child windows
      static HWND hwndChild[DIVISIONS][DIVISIONS];
      // none of the below values are static because they need to be used once whenever the 
      //  WM_SIZE message is processed, they are not used whenever any other message is processed
      // will hold the length of the client area
      int cxBlock;
      // will hold the height of the client area
      int cyBlock;
      // the below 2 values are mostly for loop iterations and keeping track of the focus box
      // will hold the length of the child window
      int x;
      // will hold the height of the child window
      int  y;
    
      switch(message)
      {
      case WM_CREATE:
        for(x = 0; x < DIVISIONS; x++)
        {
          for(y = 0; y < DIVISIONS; y++)
          {
            // create 25 child windows
            hwndChild[x][y] = CreateWindow(szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,
              0, 0, 0, 0, hwnd, (HMENU)(y << 8 | x),
              // get the instance from the parent window using this method with these
              //  values passed into it
              (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 
              NULL);
          }
        }
    
        return 0;
    
      case WM_SIZE:
        // get the size of the entire client area in the parent window and divide it by 5,
        //  this will tell the average height and length of the child windows
        cxBlock = LOWORD(lParam) / DIVISIONS;
        cyBlock = HIWORD(lParam) / DIVISIONS;
    
        for(x = 0; x < DIVISIONS; x++)
        {
          for(y = 0; y < DIVISIONS; y++)
          {
            // realign the child windows so that they would all fit within the client area
            //  of the parent window
            MoveWindow(hwndChild[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE);
          }
        }
    
        return 0;
    
      // if the left-mouse-button is pressed somewhere in the main window, a error message beep
      //  will be given
      case WM_LBUTTONDOWN:
        MessageBeep(0);
    
        return 0;
    
      // On set-focus message, set focus to child window
      case WM_SETFOCUS:
        // get the focus from one child window to another
        SetFocus(GetDlgItem(hwnd, idFocus));
    
        return 0;
    
      // On key-down message, possible change the focus window
      case WM_KEYDOWN:
        x = idFocus & 0xFF;
        y = idFocus >> 8;
    
        switch(wParam)
        {
        // move the focus square up
        case VK_UP:
          y--;
    
          break;
    
        // move the focus square down
        case VK_DOWN:
          y++;
    
          break;
    
        // move the focus square left
        case VK_LEFT:
          x--;
    
          break;
    
        // move the focus square right
        case VK_RIGHT:
          x++;
    
          break;
    
        // move the focus square all the way to the top and to the left
        case VK_HOME:
          x = 0;
          y = 0;
    
          break;
    
        // move the focus square all the way to the bottom and to the right
        case VK_END:
          x = DIVISIONS - 1;
          y = DIVISIONS - 1;
    
          break;
    
        default:
    			
          break;
        }
    
        // calculate the position where the 
        x = (x + DIVISIONS) % DIVISIONS;
        y = (y + DIVISIONS) % DIVISIONS;
    
        // move everything over by eight bits and add to itthe variable x
        idFocus = y << 8 | x;
    
        // set the focus to another child window from a previous one
        SetFocus(GetDlgItem(hwnd, idFocus));
    
        return 0;
    
      case WM_DESTROY:
        PostQuitMessage(0);
    
        return 0;
      }
    
      return DefWindowProc(hwnd, message, wParam, lParam);
    }
    
    LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
      HDC	 hdc;
      PAINTSTRUCT ps;
      RECT rect;
    
      switch(message)
      {
      // passes into the reserved memory a 0, indicating that an X is not to be drawn in a
      //  particular window
      case WM_CREATE:
        SetWindowLong(hwnd, 0, 0); // on/off flag
    
        return 0;
    
      case WM_KEYDOWN:
        // send most key presses to the parent window
        if(wParam != VK_RETURN && wParam != VK_SPACE)
        {
          // first value passed into the function is the window handle to the parent window
          SendMessage(GetParent(hwnd), message, wParam, lParam);
    
          return 0;
        }
    
        // for return and space fall through to toggle the square
    
      case WM_RBUTTONDOWN:
      case WM_LBUTTONDOWN:
        // resets the the special value that is being stored
        //  in this case the value is xored with a 1 and if the original value was 0(no X is
        //    there from the outstart), the new value would be a 1
        //    however, if the previous value was a 1 then a xor with another 1 would yield a 0
        //    and the whole X would be erased across the child window
        SetWindowLong(hwnd, 0, 1 ^ GetWindowLong(hwnd, 0));
        // sets the focus to this particular child window
        SetFocus(hwnd);
        // the entire window will be redrawn
        InvalidateRect(hwnd, NULL, FALSE);
    
        return 0;
    
        // for focus messages, invalidate the window for repaint
      case WM_SETFOCUS:
        // get the id of the particular child window
        idFocus = GetWindowLong(hwnd, GWL_ID);
    
      // fall through
      case WM_KILLFOCUS:
        InvalidateRect(hwnd, NULL, TRUE);
    
        return 0;
    
      case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
    
        GetClientRect(hwnd, &rect);
        Rectangle(hdc, 0, 0, rect.right, rect.bottom);
    
        // draw the X
    
        if(GetWindowLong(hwnd, 0))
        {
          MoveToEx(hdc, 0, 0, NULL);
          LineTo(hdc, rect.right, rect.bottom);
    
          MoveToEx(hdc, 0, rect.bottom, NULL);
          LineTo(hdc, rect.right, 0);
        }
    
        // draw the focus rectangle
        if(hwnd == GetFocus())
        {
          rect.left += rect.right / 10;
          rect.right -= rect.left;
          rect.top += rect.bottom / 10;
          rect.bottom -= rect.top;
    
          // inbetween the dashes there will be nothing drawn
          SelectObject(hdc, GetStockObject(NULL_BRUSH));
          // a dashed line will outline a rectangle
          SelectObject(hdc, CreatePen(PS_DASH, 0, 0));
    
          Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
          DeleteObject(SelectObject(hdc, GetStockObject(BLACK_PEN)));
        }
    
        EndPaint(hwnd, &ps);
    
        return 0;
      }
    
      return DefWindowProc(hwnd, message, wParam, lParam);
    }
    My question is about the 2 different portions that I made bold.

    ---------------------------------------------------------------------------------
    The first one. Since idFocus is initially 0. In the first line of the first bold portion, the entire thing is anded with a 0xFF. Why would one do that? I guess what I'm asking for is a nuts and bolts explanation.
    Then in the first part on the second line, 8 bits are moved over to the right. Again why would you do that(in the context to the entire program)?
    -------------------------------------------------------------------------------
    On the second boldened part, 8 bits in y are moved to the left and then it uses or with x and re-assigns it to idFocus. Why?
    ----------------------------------------------------------------------------------

    Thanks in advance for your comments, I'll keep at this problem for some time.
    Favorite music:
    Rammstein
    E nomine
    Prodigy

    "Beer, the solution and the cause of all of our problems" -- Homer Simpson

  2. #2
    Join Date
    Mar 2004
    Location
    (Upper-) Austria
    Posts
    2,899
    To retrieve the Lo and Hi order of the value? ... I guess so ...
    I am not offering technical guidiance via email or IM
    Come on share your photo with us! CG members photo album!
    Use the Code Tags!

  3. #3
    Join Date
    Apr 2003
    Location
    Regensburg, Bavaria, Germany
    Posts
    147
    My firs theory on this was something like this.....

    For the first boldened part...
    ---------------------------------------------------------------------------------
    My initial thought was that you would first set the values in 'x' to some specific value(in this case 0xFF).

    Then you would move the bytes that were originally stored in 'y' to the left, thereby getting rid of them entirely.
    ---------------------------------------------------------------------------------

    For the second boldened part...
    ---------------------------------------------------------------------------------
    You would move the bytes that were originally stored in 'y' in order to reveal 8 newfound blanks. Then by using the logical or ('|'), you would input some values from 'x' into 'idFocus'. That's atleast what Petzold said(atleast the way that I understood it).
    ---------------------------------------------------------------------------------

    My question is why do you do this, how does it work exactly and how does windows interpret this information? Why were the bits moved over by 8 bytes and not by 2, 4, 16, 32? That's what I'm trying to get at, the nuts-and-bolts explanations why you need to slap these 2 values together, rather than having a function that gets the x and the y-coordinates and then resets the focus for the child windows?
    Favorite music:
    Rammstein
    E nomine
    Prodigy

    "Beer, the solution and the cause of all of our problems" -- Homer Simpson

  4. #4
    Join Date
    Apr 2004
    Location
    In the back seat of New Horizons.
    Posts
    1,238
    I asked Charles Petzold on the response and here it is...
    By Charles Petzold
    Each child window of a particular parent requires a unique child ID number.
    This ID number is first assigned in the 9th argument to the CreateWindow
    call. In this program, I thought it would be convenient to use an ID number
    that could be easily converted to and from the X and Y coordinates of the
    child window.

    When I first wrote this program for Windows 1.0, the ID numbers were 16 bits
    wide. (They are now 32 bits wide.) So, it made sense to put the store the
    X coordinate in the lower 8 bits and the Y coordinate in the upper 8 bits.
    If you have the X and Y coordinates, you can calculate an ID like this:

    id = y << 8 | x

    The Y coordinate is shifted 8 bits to the left and then ORed with the X.
    Each pair of unique X and Y coordinates creates a unique ID. If you have an
    ID, you can extract the X and Y coordinates like this:

    x = id & 0xFF
    y = id >> 8

    The first statement retrieves only the X part of the ID; the second gets the
    Y part. This is a very common technique in C to store multiple pieces of
    information in a single variable.

    I didn't need to shift by 8. I could have shifted by 7 or 6 or 5 or 4 or
    even 3 bits. (If shifting by 3 bits, then you would use 0x07 to extract the
    X coordinate from the ID. But I couldn't shift by just 2 because the number
    of child windows horizontally and vertically is given by the DIVISIONS
    identifier, which is assigned 5, and to store 5 of something you need at
    least 3 bits.

    The advantage of using 8 bits is that you can increase the DIVISIONS
    identifier to anything up to 256 and recompile and the program will still
    work. (Try it!) Versions of Windows prior to Windows 95 could only support
    65,536 child windows, so that was the limit back then.

    Another approach is to use multiplication and addition to create an ID from
    X and Y:

    id = y * DIVISIONS + x

    You can then extract the X and Y coordinates like so:

    x = id % DIVISIONS
    y = id / DIVISIONS

    However, it's generally best to use AND, OR, and shfits rather than
    multiplication and division because they're more efficient.

    The program initializes idFocus to 0, which means that the child with the
    input focus is the one at the upper-left corner. In the WM_KEYDOWN message,
    the program needs to obtain the X and Y coordinates of the child with the
    input focus, change one of the those coordinates, and then reset the input
    focus. It extracts the X and Y coordinates from idFocus, manipulates them,
    then creates a new idFocus from these new coordinates.

    Charles
    I hope this helps someone out in the future .

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured