Positioning an edit box in a FlexGrid control

Using the Visual Basic example in MSDN and trying to port it to Visual C++, I have this code:

class CEditGridView : public CView
{
   ...
   CEdit m_editctrl;
   CMSFlexGrid m_gridctrl;
};

int CEditGridView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CView::OnCreate(lpCreateStruct) == -1)
      return -1;
      
   CRect rect(0, 0, 0, 0);
   if (!m_gridctrl.Create(_T("GridCtrlWnd"), WS_CHILD | WS_VISIBLE, rect, this, IDC_GRIDCTRL))
   {
      TRACE("Failed to create grid control\n");
      return -1;
   }
      
   if (!m_editctrl.Create(WS_CHILD | WS_VISIBLE, rect, &m_gridctrl, IDC_EDITCTRL))
   {
      TRACE("Failed to create edit control\n");
      return -1;
   }

   return 0;
}

void CEditGridView::OnInitialUpdate()
{
   CView::OnInitialUpdate();
      
   CRect rect;
   GetClientRect(rect);
      
   m_gridctrl.MoveWindow(rect);
   m_gridctrl.SetCols(m_nColCnt);
   m_gridctrl.SetRows(m_nRowCnt);

   CClientDC dc(&m_gridctrl);
   dc.SetMapMode(MM_TWIPS);

   CSize sizePixel(1, 1);
   dc.DPtoLP(&sizePixel);

   m_nRow = m_gridctrl.GetRow();
   m_nCol = m_gridctrl.GetCol();
   m_nTwipsPerPixelX = sizePixel.cx;
   m_nTwipsPerPixelY = sizePixel.cy;

   TRACE("OnInitialUpdate: m_nRow = %d, m_nCol = %d, m_nTwipsPerPixelX = %d, m_nTwipsPerPixelY = %d\n", m_nRow, m_nCol, m_nTwipsPerPixelX, m_nTwipsPerPixelY);
}

void CEditGridView::OnSize(UINT nType, int cx, int cy)
{
   CView::OnSize(nType, cx, cy);

   m_gridctrl.MoveWindow(0, 0, cx, cy);
}

void CEditGridView::GridTextMove()
{
   // Move a text box to the position of the current cell in a grid:

   int x = m_gridctrl.GetLeftCol(); // x position of current grid cell.
   int y = m_gridctrl.GetTopRow(); // y position of current grid cell.

   // Skip grid border:

   if (1 == m_gridctrl.GetBorderStyle())
   {
      x += m_nTwipsPerPixelX;
      y += m_nTwipsPerPixelY;
   }

   // Skip fixed columns and rows:
   for (int i = 0; i < m_gridctrl.GetFixedCols(); i++)
   {
      x += m_gridctrl.GetColWidth(i);
      if (m_gridctrl.GetGridLines())
      {
         x += m_nTwipsPerPixelX;
      }
   }

   for (i = 0; i < m_gridctrl.GetFixedRows(); i++)
   {
      y += m_gridctrl.GetRowHeight(i);
      if (m_gridctrl.GetGridLines())
      {
         y += m_nTwipsPerPixelY;
      }
   }

   // Find current data cell:

   for (i = m_gridctrl.GetLeftCol(); i < m_gridctrl.GetCol(); i++)
   {
      x += m_gridctrl.GetColWidth(i);
      if (m_gridctrl.GetGridLines())
      {
         x += m_nTwipsPerPixelX;
      }
   }

   for (i = m_gridctrl.GetTopRow(); i < m_gridctrl.GetRow(); i++)
   {
      y += m_gridctrl.GetRowHeight(i);
      if (m_gridctrl.GetGridLines())
      {
         y += m_nTwipsPerPixelY;
      }
   }

   // Move the Text Box, and make small adjustments:

   CClientDC dc(&m_gridctrl);
   dc.SetMapMode(MM_TWIPS);

   CPoint point(x + m_nTwipsPerPixelX, -(y + m_nTwipsPerPixelY));
   TRACE("GridTextMove: point = { %d, %d } Twips\n", point.x, point.y);
   dc.LPtoDP(&point);
   TRACE("GridTextMove: point = { %d, %d } Pixels\n", point.x, point.y);

   m_editctrl.MoveWindow(point.x, point.y, 0, 0); // Relative the parent (this).
}

void CEditGridView::OnKeyPressGridctrl(short FAR* KeyAscii)
{
   // Move the text box to the current grid cell:

   GridTextMove();

   // Save the position of the grids Row and Col for later:

   m_nRow = m_gridctrl.GetRow();
   m_nCol = m_gridctrl.GetCol();

   TRACE("OnKeyPressGridctrl: m_nRow = %d, m_nCol = %d\n", m_nRow, m_nCol);

   // Make text box same size as current grid cell:

   CClientDC dc(&m_gridctrl);
   dc.SetMapMode(MM_TWIPS);

   CSize sizeEdit(m_gridctrl.GetColWidth(m_nCol) - 2 * m_nTwipsPerPixelX,
                  m_gridctrl.GetRowHeight(m_nRow) - 2 * m_nTwipsPerPixelY);
   TRACE("OnKeyPressGridctrl: sizeEdit = { %d, %d } Twips\n", sizeEdit.cx, sizeEdit.cy);
   dc.LPtoDP(&sizeEdit);
   TRACE("OnKeyPressGridctrl: sizeEdit = { %d, %d } Pixels\n", sizeEdit.cx, sizeEdit.cy);

   CRect rectEdit(0, 0, 0, 0);
   m_editctrl.GetWindowRect(rectEdit);

   CRect rectGrid(0, 0, 0, 0);
   m_gridctrl.GetWindowRect(rectGrid);

   rectEdit.left -= rectGrid.left;
   rectEdit.top -= rectGrid.top;
   rectEdit.right -= rectGrid.left;
   rectEdit.bottom -= rectGrid.top;

   TRACE("OnKeyPressGridctrl: rectEdit = { left = %d, top = %d, right = %d, bottom = %d } Pixels\n", rectEdit.left, rectEdit.top, rectEdit.right, rectEdit.bottom);
   m_editctrl.MoveWindow(rectEdit.left, rectEdit.top, sizeEdit.cx, sizeEdit.cy); // Relative the parent (this).

   // Transfer the grid cell text:

   m_editctrl.SetWindowText(m_gridctrl.GetText());

   // Show the text box:

   m_editctrl.ShowWindow(SW_SHOW);
   m_editctrl.SetFocus();

   // Redirect this KeyPress event to the text box:
   m_editctrl.SendMessage(WM_CHAR, WPARAM(*KeyAscii), 0);
}

However, the edit control does not position exactly on the selected grid cell, and the further away from the upper left corner, the worse. What is wrong here?
LVL 3
stefanrAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Tommy HuiEngineerCommented:
The problem is your using GetWindowRect() to retrieve the coordinates, which is using screen coordinates. After you get the screen coord., use ScreenToClient() to get client coord, which is what you pass to MoveWindow().
0
stefanrAuthor Commented:
I tried that, but the result is exactly as before:

...
   CRect rectEdit(0, 0, 0, 0);
   m_editctrl.GetWindowRect(rectEdit);

   //CRect rectGrid(0, 0, 0, 0);
   //m_gridctrl.GetWindowRect(rectGrid);

   //rectEdit.left -= rectGrid.left;
   //rectEdit.top -= rectGrid.top;
   //rectEdit.right -= rectGrid.left;
   //rectEdit.bottom -= rectGrid.top;

   m_gridctrl.ScreenToClient(rectEdit);

   TRACE("OnKeyPressGridctrl: rectEdit = { left = %d, top = %d, right = %d, bottom = %d } Pixels\n", rectEdit.left, rectEdit.top, rectEdit.right, rectEdit.bottom);
   m_editctrl.MoveWindow(rectEdit.left, rectEdit.top, sizeEdit.cx, sizeEdit.cy); // Relative the parent (this).
...

And furthermore, the edit box's position is determined in GridTextMove(), which not is calling GetWindowRect() ...
0
MikeP090797Commented:
ScreenToClient converts a single point location, not a RECT, so you need to convert each corner separatly
0
Amazon Web Services

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

stefanrAuthor Commented:
Copied directly from the online help:

"CWnd::ScreenToClient
void ScreenToClient( LPPOINT lpPoint ) const;
void ScreenToClient( LPRECT lpRect ) const;

Parameters

lpPoint   Points to a CPoint object or POINT structure that contains the screen coordinates to be converted.

lpRect   Points to a CRect object or RECT structure that contains the screen coordinates to be converted.

Remarks

Converts the screen coordinates of a given point or rectangle on the display to client coordinates.

The ScreenToClient member function replaces the screen coordinates given in lpPoint or lpRect with client coordinates. The new coordinates are relative to the upper-left corner of the CWnd client area."

I see no point (!) in handling each corner separatly (CRect has a LPRECT() operator).
0
stefanrAuthor Commented:
Adjusted points to 200
0
stefanrAuthor Commented:
I have simplified the code somewhat, to use the built-in functions to retrieve the current selected cell position and size. The error is still there, however. I have tried to (through experiment) find a "rectifying constant", but it seems to be more complicated than that:

void CEditGridView::OnKeyPressGridctrl(short FAR* KeyAscii)
{
   // Save the position of the grids Row and Col for later:

   m_nRow = m_gridctrl.GetRow();
   m_nCol = m_gridctrl.GetCol();

   // Move the text box to the current grid cell:

   TRACE("OnKeyPressGridctrl: m_nRow = %d, m_nCol = %d\n", m_nRow, m_nCol);

   long lCellLeft = m_gridctrl.GetCellLeft();
   long lCellTop = m_gridctrl.GetCellTop();
   long lCellWidth = m_gridctrl.GetCellWidth();
   long lCellHeight = m_gridctrl.GetCellHeight();

   CPoint pointEdit(lCellLeft, -lCellTop); // Relative to m_gridctrl.
   TRACE("OnKeyPressGridctrl: pointEdit = { %d, %d } Twips\n", pointEdit.x, pointEdit.y);

   // Make text box same size as current grid cell:

   CSize sizeEdit(lCellWidth, lCellHeight);
   TRACE("OnKeyPressGridctrl: sizeEdit = { %d, %d } Twips\n", sizeEdit.cx, sizeEdit.cy);

   CRect rectEdit(pointEdit.x, pointEdit.y, pointEdit.x + sizeEdit.cx, pointEdit.y - sizeEdit.cy); // Relative to m_gridctrl

   CClientDC dc(&m_gridctrl);
   dc.SetMapMode(MM_TWIPS);

   dc.LPtoDP(rectEdit);

   const double kdScaleFacX = 1.048; // Pretty good at large distances from upper left corner, not soo good close to it.
   const double kdScaleFacY = 1.046; // Pretty good at large distances from upper left corner, not soo good close to it.
   rectEdit.left = int(kdScaleFacX * rectEdit.left);
   rectEdit.top = int(kdScaleFacY * rectEdit.top);
   rectEdit.right = int(kdScaleFacX * rectEdit.right);
   rectEdit.bottom = int(kdScaleFacY * rectEdit.bottom);

   TRACE("OnKeyPressGridctrl: rectEdit = { left = %d, top = %d, right = %d, bottom = %d } Pixels\n", rectEdit.left, rectEdit.top, rectEdit.right, rectEdit.bottom);
   m_editctrl.MoveWindow(rectEdit); // Relative the parent (m_gridctrl).

   // Transfer the grid cell text:

   m_editctrl.SetWindowText(m_gridctrl.GetText());

   // Show the text box:

   m_editctrl.ShowWindow(SW_SHOW);
   m_editctrl.SetFocus();

   // Redirect this KeyPress event to the text box:
   m_editctrl.SendMessage(WM_CHAR, WPARAM(*KeyAscii), 0);
}

0
guruprasad031298Commented:
I've had this problem before. I tried all generic methods to get the thing working. Bad luck.
It doesn't. The problem is because, MSFlexGrid returns position in TWIPS, whereas VC++ works with PIXELS. This incompatibility causes all the problem. I also tried setting
the mode to twips. It doesn't work either.

So, I wrote my own conversion routine (with some silly hard codings). I don't know whether it will work for you. Try it anyway and update me of the result.

void CMyView::OnDblClickStdgrid()
{
// Embed editable CEdit Control

// Construct edit control
pEdit = new CStdEqpEdit(&m_StdGrid, row);

/*
 * Conversion from Twips to Pixel scale. Divisor values are specific to this
 * grid and may not work for others. Generic conversion routine couldn't be
 * written for this purpose. Make sure not to change this
 */

long lLeft = (long) (m_StdGrid.GetCellLeft () / 15);
long lTop = (long) (m_StdGrid.GetCellTop () / 15);
long lHeight = (long) (m_StdGrid.GetCellHeight() / 15);
long lWidth = (long) (m_StdGrid.GetCellWidth() / 14.3);

CRect rect (lLeft, lTop, lLeft + lWidth, lTop + lHeight);
            
// Create the edit control on the fly
pEdit->Create (WS_CHILD | WS_VISIBLE | WS_BORDER, rect, this,                       IDC_SEQ_NUM_EDIT);
pEdit->SetWindowText (m_StdGrid.GetText());

// Change the font of the edit control to that of the grid cell for consistency
CString sFontName = m_StdGrid.GetCellFontName();
int iFontSize = (int) (m_StdGrid.GetCellFontSize() * FONT_SCALE);
CFont *pFontEdit = new CFont();
pFontEdit->CreatePointFont (iFontSize, sFontName);
pEdit->SetFont (pFontEdit);

// Set the focus to the edit control
pEdit->SetFocus();
}

Hope this helps
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
stefanrAuthor Commented:
It worked with a little adjustment. As you mentioned, it seems that there is some hardware dependent factor involved. It would be interesting if someone could find what that factor is. As for now, I have to try it on some different hardware configurations to see what constants I need to use, and somehow adjust these constants according to the tested platforms.

Thanks!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.