Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1377
  • Last Modified:

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?
0
stefanr
Asked:
stefanr
1 Solution
 
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
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
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
 
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now