MSFLEXGRID-based editable tables in VC6.0
Solutions for production and several issues
Swimmingfish2004, April 21, 2005
I. Overview
In the user interface we make, you will use the form many times, of course, we first think of the use of controls, such as MSFLEXGRID. We can easily call the control itself to operate the elements in the table, but what should we do if we want to design a table that can be edited? In fact, there is really a lot of applications for this editable table, mainly the interactivity of its user operation. The author encountered this problem when developing a project in the previous stage, and the following introduces the author's implementation.
Second, the initial implementation of editable form
1. Create a new class cctrleditgrid
First create a single document project EditGrid.
The MSFLEXGRID control is then added to the project. This is an ActiveX control, and the Components and Controls Gallery options for add -toproject can join the control.
Then create a new class CCTRLITGRID as the base class with MSFlexGrid, and add member function void initGrid () (this function is currently just empty) and member variables CEDIT * m_PEDIT;
CSPINBUTTONCTRL * m_pspinbuttonctrl; the entity class of the table later is the class.
2, display the form in the view class of the project file
First add member variables ceditgrid * m_pctrleditgrid in the view class CEDITGRIDVIEW.
Then add the CEDITGRIDVIEW message corresponding to the function oncreate, where the form is created.
m_pctrleditgrid = new cctrleditgrid;
M_pctrleditGrid-> Create (NULL, WS_CHILD | WS_VISIBLE, CRECT (0, 0, 0, 0), this, ID_EDITGRID);
m_pctrleditgrid-> initGrid ();
Then consistent with the size of the view in accordance with the size of the CEDITGRIDVIEW, add code in the CEDITGRIDVIEW message.
IF (m_pctrleditgrid! = null)
m_pctrleditGrid-> MoveWindow (0, 0, CX, CY);
3. Implement the function of cctrleditgrid's initGrid
InitGrid completes the property settings of the table, fill in the initial content of the table, edit the creation of the control. Here the editable controls such as CEDIT, CCOMBOX, CSPINBUTTONCTRL, CDATETIMECTRL .... In this case, only CEDIT and CSINBUTTONCTRL are used in this example. If the editing control between the different columns in the table can determine what controls are used by detecting the column number in the program, in fact, between the different columns in the author's project is also used in different editing controls. In this case, use a control to illustrate the implementation method of the table editing, the reader wants to change other controls.
Void cctrleditgrid :: initGrid ()
{
/ / Set the number of lines, the number of columns
Setcols (col_initnumber);
SetRows (row_initnumber);
/ / Set to boundless box
SetBordersTyle (0);
/ / Set to change the linear collar width
SetAllowuserResizing (3);
/ / Set line wide column wide
CDC * PDC = Getdc ();
Setrowheightmin ((long) (row_height_pixel * 1440.0 / pdc-> getDevicecaps (logpixelsy)))); // Coordinate units To convert
For (int i = 0; i
ReleaseDC (PDC);
// Set the text alignment of the column
For (i = 0; i SetColalignment (i, 4); / / Set the name of the fixed line For (i = 1; i { Cstring strnum; INT nnum = i; Strnum.format ("% d", i); SetTextMatrix (i, 0, strnum); } For (i = 1; i { Cstring strnum; INT nnum = i; Strnum.format ("% d", i); SetTextMatrix (0, I, Strnum); } // Populate the original content in GRID For (i = 1; i { For (int J = 1; j { SetTextMatrix (i, j, "1"); } } // Create a control M_PEDIT = New CEDIT (); M_Pedit-> Create (WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_NUMBER, CRECT (0, 0, 0), This, ID_CTRL_EDIT); m_pspinbuttonctrl = new cspinbuttonctrl (); m_pspinbuttonctrl-> create (uds_arrowkeys | uds_setbuddyint | uds_alignright | ws_border, CRECT (0, 0, 0, 0), this, ID_CTRL_SPIN); Here to explain that the unit in the msflexGrid is the mite (1 = = 1/1440IN), so when we want to specify the length width or the like, the unit is converted to 缇. Row_height_pixel * 1440.0 / pdc-> getDeviceCaps (LogPixelsy). Where row_height_pixel is a macro representing a pixel unit, PDC-> getDeviceCaps (LogPixelsy) gets the pixel value of the Y-axis per INCH. The value calculated by the formula is the value of the corresponding equally. 4, let the form you can edit The above three points are just the preparation stage. To make the table edit, we also have to respond to the user's click single-handed event and leave the unit's incident, so that when the user clicks on a cell, the current cell is in an editing state and is in the time. Non-editing state. The onClick and the OnleAvecell event provided by the MSFlexGrid control is exactly what we need. Since cctrleditGrid is not an MFC class, the event cannot be used to add events. I have to add it by manual. First add AFX_MSG Void OnleAvell (); AFX_MSG Void OnClick (); add event mapping table in the CPP file Begin_Eventsink_map (CCTRLITGRID, CMSFLEXGRID) // {{AFX_Eventsink_map (CEDITGRID) ON_EVENT_REFLECT (CCTRLEDITGRID, 72 / * Leavecell * /, OnleAvecell, VTS_NONE) ON_EVENT_REFLECT (CCTRLETGRID, -600 / * Click * /, OnClick, VTS_NONE) //}} AFX_EVENTSINK_MAP END_EVENTSINK_MAP () (If the user feels that the manual add time mapping table is difficult, you can add a virtual dialog box in the application. Then insert the MSFlexGrid control in the dialog. Then use ClassWizard to write the event handler to the dialog box, then you can refer Write an event mapping table with the dialog. Remember to finally delete the virtual dialog.) Then add ONLEAVECELL and ONCLICK's function. Onleavecell function: If M_PEDIT is now displayed, the cell is in editing state, so you want to read data from the m_pedit box to the table, and hide m_pedit and m_pspinbuttonctrl. Void cctrleditgrid :: OnleAvecell () { IF (M_Pedit-> iswindowVisible ()) { Int ncol; int NROW; CSTRING STRCONTENT; Ncol = getcol (); nrow = getrow (); m_pedit-> getWindowText (strContent); SetTextMatrix (ncol, strcontent); m_pedit-> showwindow (sw_hide); m_pspinbuttonctrl-> showwindow (sw_hide); } } ONCLICK function: To display m_pedit and m_pspinbuttonctrl in the clicked cell, and make the input focus in m_pedit, the point to explain here is that if the position to be displayed, if the FlexGrid control has a border, it should consider the border. The impact of the width on the location, in this case we set it to boundless box in InitGrid, so it is not considered. Void cctrleditgrid :: onclick () { CDC * PDC = Getdc (); Long x = (getcellleft () * pdc -> getDevicecaps (logpixelsx) / 1440; Long y = (getcelltop () * PDC -> getDeviceCaps (LogPixelsy) / 1440; Long cx = (getcellwidth () * pdc -> getDeviceCaps (LogPixelsx) / 1440; LONG CY = (GetcellHeight () * PDC -> getDeviceCaps (LogPixelsy) / 1440; ReleaseDC (PDC); CSTRING STRCONTENT; StrContent = getText (); m_pedit-> setWindowText (strContent); M_Pedit-> MoveWindow (X, Y, CX, CY, FALSE); M_Pedit-> showwindow (SW_SHOW); M_Pedit-> setfocus (); m_pspinbuttonctrl-> setBuddy (m_pedit); m_pspinbuttonctrl-> setRANGE32 (0, 100); M_PspinButtonCtrl-> MoveWindow (x CX - 16, Y, 16, CY, FALSE); m_pspinbuttonctrl-> showwindow; } Perhaps OneNTercell event can replace OnClick, but the author finds that there will be a problem with OneNtercell: Must quickly click, otherwise it will disappear immediately after the edit box appears. So the author uses the onclick event, which is only responding at the mouse Up. Third, the emergence of several problems and the solution Through the above operation, we can click on a cell in the form to edit, and it seems that we have implemented an editable table. But in the subsequent testing process, the following annoying issues: A At the current cell, it is in an editable state and we attempt to change the column width, and the size of the editing control on the cell is not changed. as follows b When a certain cell is editable and we tried to move the scroll bar, it was found that the cursor of the editing control on the cell was moved to other cells. And more serious is if the front cell section is displayed, click the scroll bar after clicking, it is not just that the cursor moves and the control itself is also moved to other cells. as follows c Trigger the movement of the vertical roller when you click the upper and lower controls, and indirectly lead to the occurrence of B issues. 1. Solution of a problem The first thing I think is that the response event for the column width change of MSFLEXGRID is very disappointed. However, it is found that the following measures can be taken: In the PretranslateMessage message response function in the CEDITGRIDVIEW, the left mouse button is pressed and the message moves, and if the editing control is displayed, the CCTRLITGRID is called in this state. Open is public). Thus, although the original editing state is changed in order to be non-editing, it avoids the problem of displaying the size of the display on the display. Bool CeditGridview :: PretranslateMessage (MSG * PMSG) { IF ((PMSG-> Message == WM_Mousemove) && (PMSG-> WPARAM & MK_LB /TTON)) { CWND * PWND = fromHandle (PMSG-> HWND); IF (PWND-> getRuntimeClass () -> isderivedFrom (runtime_class (cmsflexgrid))) { IF (m_pctrleditgrid-> m_pedit-> iswindowvisible ()) m_pctrleditgrid-> OnleAvecell (); } } Return CView :: PretranslateMessage (PMSG); } 2, the solution to the problem The first thing I thought is still looking for a response event for the column width change of MSFlexGrid in MSDN. It is fortunate to find it. Add AFX_MSG void onscroll () in the header file of CCTRLITGRID; Add ON_EVENT_REFLECT (CTASKEDITGRID, 73 / * SCROLL * /, OSCROLL, VTS_NONE) in CCTRLITGRID's CPP file. Write an onscroll function: If the cell is in editing status calling the ONLEVE function, the editing control is not visible. Void cctrleditGrid :: Onse () { IF (! m_pedit-> iswindowvisible ()) return; Else { OnleAvecell (); } } 3, the solution to the problem The key to the problem is that the VScroll event of the upper and lower controls interferes with the Rolling event response of the FlexGrid, as long as the VScroll message of the upper and lower controls is not. We only need to block the generation of vscroll if the response function of the left mouse button of the CSPINBUTTONCTRL. First inherit the CSPinButtonCtrl to generate new class CMYSPINBUTTONCTRL, change the type of member variable m_pspinbuttonctrl in CCTRLITGRID to CMYSPINBUTTONCTRL, which is also changed to the CMYSPINBUTTONCTRL type when dynamic allocation. Then add CMYSPINBUTTONCTRL message response function ONLBUTTONDOWN, comment out of the default row code cspinbuttonctrl :: ONLBUTTONDOWN (NFLAGS, POINT) in this function, so that the passage of the vscroll message is blocked. Then it is determined that if you click on the upper half of the SPIN control, the value of the EDIT control is added 1. If you click in the lower half, the value of the EDIT control is reduced by 1. This simulates the fine-tuning function of the original Spin control. Void CMYSPINBUTTONCTRL :: ONLBUTTONDOWN (UINT NFLAGS, CPOINT) { Cstring strnum; Int nnum; CMYSPINBUTTONCTRL :: getBuddy () -> getWindowText (Strnum); SSCANF (Strnum, "% D", & nnum); CRECT RECT; CMYSPINBUTTONCTRL :: getWindowRect (& Re); Int nlow, nupper; CMYSPINBUTTONCTRL :: GetRange (nlow, nupper); IF (Point.Y <(Rect.Bottom-Rect.top) / 2)) { Nnum ; IF (nnum> nupper) nnum = Nupper; } Else { Nnum -; IF (nnum nnum = nlow; } Strnum.format ("% d", nnum); CMYSPINBUTTONCTRL :: getBuddy () -> setWindowText (Strnum); } Fourth, summary After the above steps, we basically completed an editable form. The reader can try to add different controls such as CCOMBOBOX, CDATETIMECTRL in the form with the methods of this article. The reader can also add functions. If you are in an editable state in an editable state, double-click the unit to pop up an attribute table about the information about the Bank. To implement the function, you can refer to the solution of the A problem, in CCTRLITGRID Double-click the event in the PretranslateMedView of the parent window, identifies whether it is double-clicked in the cell, then pops up a dialog, and finally remember to return True, indicating that the message has been handled without going down.