Solved

Positioning an edit box in a FlexGrid control

Posted on 1998-02-19
8
1,303 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
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
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

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Strange date stored 22 119
Window placement 17 81
child constructor and parent constructor, overriding and overloading 6 83
Is there a simple front-end menu system. 9 88
Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
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.

806 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