65.9K
CodeProject is changing. Read more.
Home

Multistring List Control

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.86/5 (6 votes)

Oct 24, 2002

3 min read

viewsIcon

135083

downloadIcon

1426

A list control, that supports multistring text items, drag & drop and item's editing

Sample Image - lpage.jpg

Actuality

The standard CListCtrl is very good instrument for creating lists. It can be present as icon's set, simple list or report, can have many columns. But it can't have text items with many strings per one, i.e. items with different heights; the maximum lenghth of CListCtrl's items is 512 characters (I haven't intend virtual lists). So I decide to create a class, that have over-passed this problem - the CLPPageCtrl. In first, I planed to inherit it from CListCtrl, but it has one unpleasant characteristic: monoheights of items, at that there is no way to set this height as you want (the height depends on selected font of the control). At any case I didn't find it. In addition I wanted to reserve possibility to add non only-text items. Pictures, tables and so on. And I wanted to realize Drag & Drop and editing for items. Of course, the CHTMLView is good decision for it. In this case there is need to write on DHTML, to write scripts and may be to generate HTML pages dynamically. Finally I have wrote CLPageCtrl as child of CWnd.

Properties of control

CLPPageCtrl has these properies:

  • Multistring text items
  • One views - list (not report, icon view)
  • All items of one type have one style
  • Text(CLPPara) items can have mark on the left - radios, one for all (to select)
  • Drag&drop for items
  • Editing for text items with saving user's new lines ('\v' instead of '\n')
  • Text items have aligning: left-, right-, center- and wide-justify
  • Items have const width - screen width
  • The control can be scrolled

Inner struct

CLPPageCtrl is a child of CWnd and CLPPage. CLPPage carry out most work (it suppose possibility to create CLPPageView). As long as items can be various, CLPPage doesn't know many about items. It just know, that they have a placement rectangle and may have mark. Besides CLPPage is a manager, that store statically parameters for items - text color, offset from border, distance between items, font. And items have rectangle, there they do everything, that they want, and state field to store own conditions. They know about CLPPage well. CLPPage communicates with CLPFields using LPFMSG. This is analogue of MSG struct of Microsoft Platform SDK. I tried to make items like as child window of main - CLPPage. In the end, most functions in CLPPage call CLPPage::OnWmMessage(), that call CLPField::WmMessage() for one's part.

Futures of using

Using of CLPPageCtrl is very simple. You can define a variable of CLPPageCtrl type or inherit new class from it. Then setup styles by function SetStyles and structure LPFSTLE with various flags that are described in lpage.h. After creation of window (standard CWnd::Create(...)), add one ore more items as initializing by AddItem with pointer to CLPField. You need not be afraid of memory leak - AddItem() will copy item and destroy at end correctly. After this you will have a list with items, that can be drag & dropped and edited. One AddItem method has a point on input. It's suit to add an item by mouse's click. This way it allow you to insert an item between other items. To get text from a text item, call GetItem(), the text will be placed in CLPField::text. Don't forget about '\v'. This char appears when user press <Enter> key in edit. Selected ("marked") item is determined by GetMarkedItem(), edited by GetFocusedItem(). All of them returns CLPField pointer. You can translate it to index using GetItemIndex(). Also you can change text's font and color and background color by calling SetFont()(this method is absent in CLPPage interface, because I intercept WM_SETFONT window message), SetTextColor() and SetBkColor().

Sample code

To present my work I created an SDI project with MFC-exe wizard. Here I don't use document/view paradigm. The CChildView class is inherited from CLPPageCtrl. The ChildView.cpp is to be of interest of analysis. Here I cite its fragment:

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CLPPageCtrl::OnCreate(lpCreateStruct) == -1) return -1;

    // List's initialization
    CString str;
    for (int i=0; i<15; i++){
        str.Format("Multistring\vitem\v%i", i+1); // item with many strings
        CLPPara para(this, str); 
        AddItem(-1, ¶, 0); // add to end
    }
    return 0;
}

// change color of text
void CChildView::OnViewColors()
{
    CColorDialog dlg(text_color, CC_ANYCOLOR | 
                                 CC_FULLOPEN |
                                 CC_PREVENTFULLOPEN |
                                 CC_ENABLEHOOK, this);
    if (dlg.DoModal()==IDOK){
        SetTextColor(dlg.m_cc.rgbResult);
        InvalidateRect(NULL, 0);
    }
}

// change text's font
void CChildView::OnSetfont() 
{
    CFontDialog dlg(NULL, CF_EFFECTS | CF_SCREENFONTS |
                         CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT |
                         CF_NOOEMFONTS, NULL, this);    
    GetFont()->GetLogFont(&dlg.m_lf);
    if (dlg.DoModal()==IDOK){
        CFont fnt; fnt.CreateFontIndirect(&dlg.m_lf);
        SetFont(&fnt);
    }
}


// display context menu with insert,(delete) items
void CChildView::OnContextMenu(CWnd* pWnd, CPoint ptScreen) 
{
    CPoint ptClient = ptScreen; ScreenToClient(&ptClient);
    CMenu *pmnu = m_mnuContext.GetSubMenu(0); ASSERT(pmnu); 

    if (GetItem(ptClient)) // if on item
      pmnu->EnableMenuItem(ID_CONTEXTMENU_DELETE, MF_ENABLED|MF_BYCOMMAND);
    else 
      pmnu->EnableMenuItem(ID_CONTEXTMENU_DELETE, MF_GRAYED|MF_BYCOMMAND);
    pmnu->TrackPopupMenu(TPM_RIGHTBUTTON, ptScreen.x, ptScreen.y, this);
}

// delete item
void CChildView::OnContextmenuDelete() 
{
        // GetHotItem() returns an item under mouse cursor
    DeleteItem(GetItemIndex(GetHotItem()));
}

// add item
void CChildView::OnContextmenuAdd() 
{
        // don't forget translate point from screen coordinates
    CPoint pt; GetCursorPos(&pt), ScreenToClient(&pt);
        CLPPara para(this, "");
        // place edit on new item
    SetFocusedItem(AddItem(pt, ¶)); 
}