Элемент управления CFListCtrl 2.0
От: Денис Солоненков  
Дата: 10.09.02 10:53
Оценка: 106 (6)
Статья:
Элемент управления CFListCtrl 2.0
Автор(ы): Денис Солоненков
Дата: 27.08.2002


Авторы:
Денис Солоненков

Аннотация:
Класс CFListCtrl — это элемент управления типа дерево-список для MFC.
трабл FList в MDI app
От: Yuri Россия http://spbdetails.ru
Дата: 25.02.03 14:34
Оценка:
Привет всем!
Элемент отличный, но при работе в MDI приложении я заметил одну неприятную особенность: при переключении между MDI окнами FList прокручивается на начало списка (в самый верх), хотя должен бы помнить позицию, на которой стоял курсор ранее
Take it easy.
Баг в пустом листе
От: kondrik  
Дата: 24.02.03 15:28
Оценка:
Когда ListCtrl пустой появляются проблемы с перерисовкой.
Может это только у меня проблема?
.
Сохранение данных в классе FListCtrl
От: Хирург Россия http://www.surgeonclub.narod.ru
Дата: 05.12.02 10:05
Оценка:
Помогите пожалуйста!!!
Надо написать рекурсию по всему дереву в листе.
Короче, данные надо сохранить на диск и считать с него.

Не могу с GetNextFRow нормально разбраться...глючит чето
Много строк...
От: Tigger  
Дата: 29.11.02 07:02
Оценка:
Если добавить много строк, например, 9000, и закрыть программу, то она закрывается, но продолжает висеть в памяти.
Сначала думал в моеу проге глюк,потом проверил и в демо-программе:
в функции CFListDemoDlg::Init() изменил цикл на for(int i=0; i<9000; i++),
результат аналогичный.
Множественный выбор
От: _Kostya_  
Дата: 31.10.02 08:45
Оценка:
Элемент управления классный, но очень хотелось бы иметь возможность выделять сразу несколько элементов. Кроме этого я хочу вывести по нажатию правой кнопки мыши контекстное меню, которое меняется в зависимости от строки, на котором находится мышь. Как это сделать?
m_treeList.SetReadOnly(FALSE); трабл?
От: DuШes  
Дата: 11.09.02 10:53
Оценка:
после того, как устанавливаю значение TRUE — те только для чтения, как в DEBUG-версии, так и в RELEASE-версии вываливается ексершен после того, как окно с данным контролом активизировано и нажимаю клавишу ESCAPE //// Не очень приятно, буду искать блох, но может быть автор сам быстрее найдет?
Re: трабл FList в MDI app
От: 2Los  
Дата: 19.03.03 22:30
Оценка:
Возможно у тебя при переключении между MDI окнами происходит вызов функции SetTextLineCount, которая приводит к вызову MeasureItem. Последняя функции вычисляет высоту строки.
Eсли FList прокручен вниз, то его последующая перерисовка приводит приводит к необъяснимым багам в изображении. Поэтому, чтобы не было лишних проблем, в функции MeasureItem FList прокручивается вверх до упора.
Re: Баг в пустом листе
От: 2Los  
Дата: 19.03.03 22:12
Оценка:
Не, это реальный баг, скоро исправлю
Re: Много строк...
От: Tigger  
Дата: 29.11.02 07:15
Оценка: :)
Ой, изините. Оболгал элемент :-((((
Выходит всё-таки. На Athlon XP 1500+ при 9000 строк примерно через 40 секунд память освобождает.
Извините.
Re: Множественный выбор
От: 2Los  
Дата: 20.11.02 22:56
Оценка:
Что касаемо контекстного меню, то в прилагаемом к статье примере показано, как его вызвать (собственно, это делается "как обычно"). При этом, если контекстное меню вызывает правой кнопкой мыши, то строчка, над которой находится указатель, выделяется и её можно заполучить вызовом GetSelectedFRow(), а затем, в зависимости от строки и сформировать контекстное меню.


Если же контекстное меню вызвано нажатием спец. клавиши на клавиатуре, то для определения строки, над которой находится мышь, потребуется небольшое хирургическое вмешательство:)

Для этого в CFListCtrl присутствует функция HitTestMouseClick, но она является protected member, поэтому нужно залезть в исходиники исправить атрибут доступа на public. Кроме того, в этой функции есть небольшой баг и для нормальной работы нужно еще исправить следующий код внутри функции:

row+= (point.y-rect.top)/rect.Height();
if(row>=bottom)
return FALSE;

на такой:

int addrow=(point.y-rect.top)/rect.Height();
row+=addrow;
if(row>=bottom || addrow<0)
return FALSE;

После чего можно использовать функцию HitTestMouseClick для определения строки, над которой находится курсор, например так. В этом примере опеределяется ячейка таблицы, над которой находится мышь, из нее "вынимается" текст и помещается в контекстное меню, как новый пункт:

void CFListDemoDlg::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
HFROW hFRow=NULL;
int iFColumn=-1;
GetCursorPos(&point);
m_treeList.ScreenToClient(&point);
if(m_treeList.HitTestMouseClick(point, hFRow, iFColumn))
{
CMenu menu;
menu.CreatePopupMenu();
menu.InsertMenu(0, MF_BYPOSITION, 1001, m_treeList.GetFItemText(hFRow, iFColumn));

GetCursorPos(&point);
menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
return;
}
}

И напоследок одно замечание. Функция HitTestMouseClick возвращает TRUE только если мышь находится над существующей строкой и столбцом одновременно. Если же нужно определить только строку и, при этом не важно, какой столбец, то после вызова HitTestMouseClick проверять следует не ее возвращаемое значение, а значение параметра hFRow. Если перед вызовом функции обнулить hFRow, то после вызова эта переменная будет иметь значение NULL, если курсор не находится не над одной из строк.
Следующий пример аналогичен предыдущему, за тем исключением, что текст для пункта меню всегда берется из первой колонки:

void CFListDemoDlg::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
HFROW hFRow;
int iFColumn;
GetCursorPos(&point);
m_treeList.ScreenToClient(&point);
m_treeList.HitTestMouseClick(point, hFRow, iFColumn);
if(hFRow!=NULL)
{
CMenu menu;
menu.CreatePopupMenu();
menu.InsertMenu(0, MF_BYPOSITION, 1001, m_treeList.GetFItemText(hFRow, 0));

GetCursorPos(&point);
menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
return;
}
}
Re: m_treeList.SetReadOnly(FALSE); трабл?
От: 2Los  
Дата: 07.10.02 20:44
Оценка:
Пробовал устанавливать и TRUE и FALSE, а потом нажимать ESCAPE, но
так ничего и не вывалилось. Не мог бы ты выслать свой проект и
пояснения, что в какой последовательности нажимать, а я посмотрю
Re: Custom controls
От: mikadi Россия  
Дата: 10.12.03 10:57
Оценка:
Хочется вставить в FListCtrl собственный контрол для редактирования элементов (на базе CEdit).
Не подскажете наиболее "красивый" способ?
Пока что мне приходит в голову только порождение наследника от CFListCtrl.
Re: Элемент управления CFListCtrl 2.0
От: Krotow Латвия  
Дата: 01.02.04 11:43
Оценка:
Здравствуйте, Денис Солоненков, Вы писали:

ДС>Класс CFListCtrl — это элемент управления типа дерево-список для MFC.


Очень хорошо. Но хотелось то же самое под WTL для VC++ 6.0. С комбинацией CListViewCtrl, CTreeViewCtrl (это, как в сабже) и вдобавок — с CProgressBarCtrl.
Пока стараюсь переделать сам, но как то не очень получается
Re: CFListCtrl 2.0 вывод на печать
От: Ringin  
Дата: 05.10.04 14:07
Оценка:
С использованием MFC я почти ничего не делал, подскажите как вывести на печать то что содержится в таблице, ведь если я просто нажимаю предпросмотр там пусто.

Спасибо!
Re: Элемент управления CFListCtrl 2.0
От: bobik_ Украина http://farnetstat.narod.ru/
Дата: 09.12.04 00:42
Оценка:
Привет.
Очень хороший класс, много функциональный, но в нем отсутсвует одна замечательная особеность, которая мне была ужастно необходима, поетому мне пришлось модифицировать класс самому. А особенность проста, что бы editbox мог иметь свойство password, то есть рисовать звездочки вместо текста. Если кому интерестно то привожу что и куда надо вкрутить что бы такая замечательная особенность появилась.

Во первых в хедернике надо обьявить вот такой дефайн
#define FL_PASSWORD //звездочки в поле ввода

цифирку я такую выбрал так как она не была занята слава богу

теперь надо модифицировать метод в исходнике
BOOL CFListCtrl::DrawElement(int nType, CDC *pDC, HFROW hFRow, int iFColumn, CRect *prcElement)

а точнее секцию которая выглядит теперь вот так

case FLDR_FITEM_TEXT:
{
if(!GetFRect(hFRow, iFColumn, FLRC_FITEM_TEXT, rcElement, TRUE))
return FALSE;
rcElement.DeflateRect(FL_BORDER_SPACE, 1, FL_BORDER_SPACE, 2);

CString text=GetFItem(hFRow, iFColumn).m_strText;
int nFormat=GetFColumn(iFColumn).m_nFormat| DT_EXTERNALLEADING | DT_NOPREFIX | DT_EXTERNALLEADING;
nFormat|= GetOptions().m_nTextLineCount>1 ? DT_WORDBREAK : 0;
if(GetFRow(hFRow)->m_bBoldText){
CFont* pFont=pDC->GetCurrentFont();
CFont font;
LOGFONT logFont;
pFont->GetLogFont(&logFont);
logFont.lfWeight=FW_BOLD;
font.CreateFontIndirect(&logFont);
pFont=(CFont*)pDC->SelectObject(&font);

int cntrl_type = 0;
int ctrl = GetFItem(hFRow, iFColumn).m_iControlProfile;
if (ctrl != -1)
cntrl_type = GetControlType(ctrl);
if ((cntrl_type & FL_PASSWORD) == FL_PASSWORD)
{
CString tmp;
int tmp_i = text.GetLength();
for (int i =0; i < tmp_i; i++)
{
tmp += "*";
}
pDC->DrawText(tmp, -1, rcElement, nFormat);
}
else
pDC->DrawText(text, -1, rcElement, nFormat);
pDC->SelectObject(pFont)->DeleteObject();
}
else
{
int cntrl_type = 0;
int ctrl = GetFItem(hFRow, iFColumn).m_iControlProfile;
if (ctrl != -1)
cntrl_type = GetControlType(ctrl);
if ((cntrl_type & FL_PASSWORD) == FL_PASSWORD)
{
CString tmp;
int tmp_i = text.GetLength();
for (int i =0; i < tmp_i; i++)
{
tmp += "*";
}
pDC->DrawText(tmp, -1, rcElement, nFormat);
}
else
pDC->DrawText(text, -1, rcElement, nFormat);
}
}
break;


и последний штрих
в методе

LRESULT CFListCtrl::InplaceControl(UINT code, UINT nChar, FL_INPLACE_NOTIFY* pInplaceNotify)

надо изменить секцию

case FL_EDIT:
case FL_EDIT|FL_BUTTON:
{
BOOL bShowEdit=FALSE;
CString text;
if(code==WM_CHAR)
{
if(::IsCharAlphaNumeric((TCHAR)nChar))
{
bShowEdit=TRUE;
text=(TCHAR)nChar;
}
}
else if(code==WM_LBUTTONDBLCLK || nChar==VK_RETURN || nChar==VK_F2 || (nChar==VK_TAB && m_nChar==VK_TAB))
{
bShowEdit=TRUE;
text=GetFItemText(m_hFRow, m_iFColumn);
}
if(bShowEdit)
{
FL_NOTIFY notify;
NotifyInit(notify, m_hFRow, m_iFColumn, FLNM_EDIT_BEGIN);
if(FL_ISOK(NotifySend(notify)))
{
CRect rect;
GetFRect(m_hFRow, m_iFColumn, FLRC_FITEM_TEXT, rect);
rect.DeflateRect(0, 1, 0, 0);
CFList_Edit* pEdit = new CFList_Edit(m_hFRow, m_iFColumn);
DWORD dwStyle=(GetOptions().m_nTextLineCount>1 ? ES_AUTOVSCROLL|ES_MULTILINE|ES_WANTRETURN: ES_AUTOHSCROLL);

int cntrl_type = 0;
int ctrl = GetFItem(m_hFRow, m_iFColumn).m_iControlProfile;
if (ctrl != -1)
cntrl_type = GetControlType(ctrl);
if ((cntrl_type & FL_PASSWORD) == FL_PASSWORD)
dwStyle |= ES_PASSWORD;
pEdit->Create(WS_CHILD|WS_VISIBLE|dwStyle, rect, this, IDC_INPLACE_EDIT);
m_pInplaceControl=pEdit;
pEdit->ModifyStyleEx(WS_EX_CLIENTEDGE, 0);
UpdateFRow(m_hFRow);

pEdit->SetWindowText(text);
pEdit->SetSel(text.GetLength(), -1);

pEdit->SetFont(GetFont());
pEdit->SetFocus();
}
}
}
if(FL_ISCONTROL())
break;

единственное остается добавить что данный стиль будет работать только для editbox то есть такой контрол стоит добавлять вот так

m_List.AddControl(FL_EDIT | FL_PASSWORD);

по моему достаточно элегантоя модификация класса в лучшую сторону
Re[2]: Элемент управления CFListCtrl 2.0
От: bobik_ Украина http://farnetstat.narod.ru/
Дата: 09.12.04 00:45
Оценка:
Одна поправка

#define FL_PASSWORD 1
Re[2]: Множественный выбор
От: kondrik  
Дата: 18.01.05 14:02
Оценка:
Здравствуйте!

То кто-нибудь решил вопросы множественного выбора в листе с помощью мыши (выбор выделением мыши)?
.
Re: Нотификация при выборе в комбике
От: BlackHeretic Израиль  
Дата: 15.03.05 17:36
Оценка:
Здравствуйте, Денис Солоненков, Вы писали:

Собственно тема. Есть комбик — очень нужно отловить момент когда произвели выбор и он захлопнулся.
Кто нить имеет готовое решение или копать и править сорцы?
ICQ 156156278
Re: Элемент управления CFListCtrl 2.0
От: nen777w  
Дата: 06.04.07 14:26
Оценка:
Баг есть: В сортированом комбобоксе неправильно приходит итем дата. (пока не устранял)

Также хочу поделиться как сделать нормальные кнопки (с текстом) в контроле :
Итак в h файле:

добавим метод
void SetFItemButtonText(HFROW hFRow, int iFColumn, CString text);


в класс XFList_ControlProfile, член:
CString m_strButtonText;


в cpp файл:

void CFListCtrl::SetFItemButtonText(HFROW hFRow, int iFColumn, CString text)
{
    ASSERT((GetCP(hFRow, iFColumn)->m_nControlType&FL_BUTTON)==FL_BUTTON);
    GetCP(hFRow, iFColumn)->m_strButtonText = text;
    UpdateFRow(hFRow);
}


в методе CFListCtrl::GetFRect

изменим кейс расчитывающий ширину и высоту кнопки

    case FLRC_FITEM_BUTTON:
        {                    
            if( !(GetCP(hFRow, iFColumn)->m_nControlType&FL_BUTTON)
                || !(GetSelectedFRow()==hFRow && GetSelectedFColumn()==iFColumn)                
                || !GetFRect(hFRow, iFColumn, FLRC_FITEM_COMBOBOX, rect, bFItemOrigin))
                return FALSE;        
            int left=rect.left;
            //            
            
            int nControlType = GetCP(hFRow, iFColumn)->m_nControlType;
            
            if( nControlType==FL_BUTTON)
            {
                CPaintDC dc(this);
                CSize sz = dc.GetTextExtent( GetCP(hFRow, iFColumn)->m_strButtonText );
                rect.bottom -= (FL_ISGRID() ? 1 : 0);
                rect.left += rect.Width() - sz.cx - 2;
            }
            else if( nControlType==FL_COMBOBOX )
            {
                rect.left=rect.right-FL_STEP+(FL_ISGRID() ? 1 : 0);                        
                rect.bottom=rect.top+rect.Width();
            }
            //            
            if(rect.left<=left) return FALSE;
        }
        break;


и case отрисовке CFListCtrl::DrawElement :

case FLDR_FITEM_BUTTON:
if( бла бла бла ... ) {...}

            else if(FL_ISBUTTON(GetCP(hFRow, iFColumn)->m_nControlType))
            {
                CBrush brush(GetSysColor(COLOR_BTNFACE));
                pDC->FillRect(rcElement, &brush);
                pDC->Draw3dRect(rcElement, GetSysColor(COLOR_3DHILIGHT), GetSysColor(COLOR_3DSHADOW) );
                
                rcElement.DeflateRect(2, 1, 1, 1);                
                pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
                pDC->SetTextColor(GetSysColor(COLOR_BTNTEXT));                
                pDC->DrawText(GetCP(hFRow, iFColumn)->m_strButtonText /*_T("...")*/, -1, rcElement, DT_CENTER);
            }
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.