?
Solved

Positioning an edit box in a FlexGrid control

Posted on 1998-02-19
8
Medium Priority
?
1,353 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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
Learn how to optimize MySQL for your business need

With the increasing importance of apps & networks in both business & personal interconnections, perfor. has become one of the key metrics of successful communication. This ebook is a hands-on business-case-driven guide to understanding MySQL query parameter tuning & database perf

 
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 400 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

Survive A High-Traffic Event with Percona

Your application or website rely on your database to deliver information about products and services to your customers. You can’t afford to have your database lose performance, lose availability or become unresponsive – even for just a few minutes.

Question has a verified solution.

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

Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
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.
In this video, Percona Solutions Engineer Barrett Chambers discusses some of the basic syntax differences between MySQL and MongoDB. To learn more check out our webinar on MongoDB administration for MySQL DBA: https://www.percona.com/resources/we…

718 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