Solved

Positioning an edit box in a FlexGrid control

Posted on 1998-02-19
8
1,308 Views
Last Modified: 2013-11-20
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
Comment
Question by:stefanr
8 Comments
 
LVL 15

Expert Comment

by:Tommy Hui
ID: 1316379
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
 
LVL 3

Author Comment

by:stefanr
ID: 1316380
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
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1316381
ScreenToClient converts a single point location, not a RECT, so you need to convert each corner separatly
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

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.

 
LVL 3

Author Comment

by:stefanr
ID: 1316382
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
 
LVL 3

Author Comment

by:stefanr
ID: 1316383
Adjusted points to 200
0
 
LVL 3

Author Comment

by:stefanr
ID: 1316384
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
 
LVL 1

Accepted Solution

by:
guruprasad031298 earned 200 total points
ID: 1316385
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
 
LVL 3

Author Comment

by:stefanr
ID: 1316386
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

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

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.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Need to retreive data from .TFS file exported by DVR 8 217
xyBalance chalenge 58 96
java ^ examples 8 69
Work with App store 7 67
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question