Поиск:

Ответ в темуСоздание новой темы Создание опроса
> CListBox и связанные с ним данные 
:(
    Опции темы
mrgloom
Дата 9.11.2012, 10:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



допустим у меня в программе есть CListBox и вектор который содержит экземпляры классов с именами для  CListBox, так вот когда мне надо удалить из CListBox элемент, я прохожусь по вектору и удаляю нужный элемент по имени, потом очищаю листбокс и заполняю оставшимися значениями из вектора.
но этот подход не будет работать, если у нас одинаковые имена в листбоксе, возможно можно как то проставить ссылки? как это делают?

Это сообщение отредактировал(а) mrgloom - 9.11.2012, 10:27
PM MAIL   Вверх
mrgloom
Дата 9.11.2012, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



всмысле вопрос сводится к тому как связать строчку выбранную в листбоксе с данными которые на листбокс выводятся, т.е. можно просто искать по строчке, но тогда нельзя использовать одинаковые названия. можно просто удалят ьпо номеру, но тогда надо следить, чтобы порядок на листбоксе и в векторе данных был один и тот же.
PM MAIL   Вверх
Albor
Дата 9.11.2012, 13:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



У списков есть функция, с помощью которой можно связать элемент списка с данными (SetItemData()). Она принимает DWORD параметр, в который можно поместить либо число (индекс в массиве, например), либо указатель на данные. Но есть вещь покруче - это виртуальный список. Смысл в чём - данные находятся в контейнере, а контрол их отображает и вы фактически работаете только с контейнером. Контролу передаётся только количество отображаемых данных. Примера под рукой нет, но можно погуглить.

Это сообщение отредактировал(а) Albor - 9.11.2012, 15:29
PM MAIL ICQ   Вверх
Albor
Дата 9.11.2012, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



пример с использованием CListCtrl:
1. В свойствах CListCtrl ставим Owner Data в True;
2. Реагируем на уведомление LVN_GETDISPINFO - это список запрашивает данные для отображения;
Код

void CKeListPane::OnLvnGetdispinfoListke(NMHDR *pNMHDR, LRESULT *pResult)
{
    NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    if(m_pData!=NULL)// m_pData - указатель на контейнер с данными
    {
        LV_ITEM* pItem = &(pDispInfo)->item;  // получим указатель на LV_ITEM 
        const CKe * pKe=m_pData->GetKe(pItem->iItem); // вынимаем данные из контейнера по индексу pItem->iItem
        if(pKe)
        {
        if(pItem->mask & LVIF_TEXT)// нужен текст? 
        {
            if(pItem->iSubItem==0)
                lstrcpyn(pItem->pszText, pKe->m_sKeName, pItem->cchTextMax);

        }
        if(pItem->mask & LVIF_IMAGE)// нужна иконка?
        {
            pItem->iImage=pKe->m_nIcon;
        }
        }
    }
    *pResult = 0;
}

В примере используется контейнер CArray содержащий некие объекты класса CKe, данные которого и должны отображаться в списке.
3. Сообщаем списку количество данных для отображения:
Код

CListCtrl * pList=(CListCtrl *)GetDlgItem(IDC_LISTKE);
    pList->SetItemCount(m_pData->GetItemCount());
 
Всё. Теперь работаем с контейнером - добавляем, удаляем и не забываем вызывать SetItemCount(), чтобы список знал сколько ему отображать
PM MAIL ICQ   Вверх
Earnest
Дата 9.11.2012, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



С одной стороны, все правильно, с другой - это решение из серии "зачем просто, когда можно сложно".
mrgloom говорил о ListBox, а не о ListCtrl, а это не одно и то же.
Конечно, у ListCtrl возможностей намного больше, но и интерфейс сложнее. Засунуть строку в ListBox - одна строка кода и есть, и не нужно никакой предварительной подготовки. А виртуальный список тоже требует поддержки кодом, и это оправданно только когда это оправданно (например - много данных)

Что касается использования DATA для каждого элемента списка, совет совершенно правильный. Либо в DATA записывается индекс в векторе строк (или более сложных структур). Но тогда придется обновлять DATA при удалении и вставке элементов в список. Либо можно хранить в DATA указатели на данные. Достаточно просто заменить вектор на список (std::list): в отличие от вектора список гарантирует валидность указателей при удалении и вставке элементов (кроме удаленных, конечно). Можно искать нужный элемент просто по указателю на данные на DATA. А можно вместо указателя на элемент данных хранить указатель на узел списка, из которого легко получается итератор. Но это не очень переносимо, и работает только в том случае, когда итератор списка простой (содержит только указатель на узел; в VC это означает, что отключена отладка итераторов).
А можно, как написано в первом посте, просто перезаполнять список, что как-то неэкономно, но если список маленький, то почему бы и нет...


--------------------
...
PM   Вверх
Albor
Дата 9.11.2012, 16:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Цитата(Earnest @  9.11.2012,  15:07 Найти цитируемый пост)
С одной стороны, все правильно, с другой - это решение из серии "зачем просто, когда можно сложно".

так-то оно так, но лично мне не очень нравится вариант с "синхронизацией" 2х контейнеров. Я бы избавился от вектора и размещал данные в куче, сохраняя указатель на них в списке. 
PM MAIL ICQ   Вверх
mrgloom
Дата 22.11.2012, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



ну вообщем я опять вернулся к этому вопросу, теперь мне нужен список с чекбоксами.

я заменил CListBox на CCheckListBox.

допустим у меня список графиков

класс графика состоит из 
name -имя 
points -точки
is_show-показывать или нет


список небольшой и можно впринципе и перезаполнять его.
но я так и не понял как связать конкретную ячейку с конкретным графиком в списке. 
что такое m_pData- CArray от моего класса? что если я хочу использовать std vector?

опять же еще вопрос
я отлавливаю нажатие на чекбокс
Код

ON_CLBN_CHKCHANGE(IDC_PROFILE_LIST,&CMainWindowDlg::OnCheckChangeProfileList)


во-первых похоже порядок отображаемый списке и порядок в спике в памяти разный, т.е. по номеру обращатся нельзя.
во-вторых похоже что при нажатии на чекбокс, срабатывает только само событие нажатия и когда я пытаюсь опросить листбокс на предмет проставленных галочек в OnCheckChangeProfileList() то само состояние чекбокса еще не проставленно, не понятно как тут быть ,возможно надо оправшивать листбокс прямо перед отрисовкой(или например перед сохранением)?
Код

void CMainWindowDlg::OnCheckChangeProfileList()
{
    int nCount= m_ProfileListBox.GetCount();
    for(int i=0;i<nCount;++i)
    {
        if(m_ProfileListBox.GetCheck(i))
            m_vec_profile[i].is_show==true;
        else
            m_vec_profile[i].is_show= false;
    }

    UpdateForm();
}


Код

void CMainWindowDlg::UpdateForm()
{
    m_ProfileListBox.ResetContent();
    for(int i=0;i<m_vec_profile.size();++i)
    {
        m_ProfileListBox.AddString(m_vec_profile[i].profile_name);

        if (m_vec_profile[i].is_show==true)
            m_ProfileListBox.SetCheck( i, 1 );
        else
            m_ProfileListBox.SetCheck( i, 0 );
    }
}


Это сообщение отредактировал(а) mrgloom - 22.11.2012, 12:03
PM MAIL   Вверх
Albor
Дата 22.11.2012, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Цитата(mrgloom @  22.11.2012,  11:00 Найти цитируемый пост)
список небольшой и можно впринципе и перезаполнять его.
но я так и не понял как связать конкретную ячейку с конкретным графиком в списке. 
что такое m_pData- CArray от моего класса? что если я хочу использовать std vector?


Немного подправлю
Код

void CMainWindowDlg::UpdateForm()
{
    m_ProfileListBox.ResetContent();
    for(int i=0;i<m_vec_profile.size();++i)
    {
       int iItem = m_ProfileListBox.AddString(m_vec_profile[i].profile_name); // добавляем строку и получаем индекс добавленного элемента
        m_ProfileListBox.SetItemData(iItem,i); // привязали индекс данных в векторе к элементу списка
        if (m_vec_profile[i].is_show==true)
            m_ProfileListBox.SetCheck( iItem, 1 );
        else
            m_ProfileListBox.SetCheck( iItem, 0 );
    }
}

чтобы  теперь получить индекс данных в векторе соответствующих выделенному в списке элементу,  например, можно сделать так:
Код

 int i=m_ProfileListBox.GetItemData(m_ProfileListBox.GetCurSel());
 // используем m_vec_profile[i]...

как уже писалось, использование в качестве DATA итераторов или указателей применительно к вектору не очень хорошо. Вектор может перераспределить память и все сохранённые итераторы (указатели) окажутся недействительными.

Это сообщение отредактировал(а) Albor - 22.11.2012, 15:09
PM MAIL ICQ   Вверх
Earnest
Дата 26.11.2012, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Немного добавлю
Цитата(mrgloom @  22.11.2012,  13:00 Найти цитируемый пост)
во-первых похоже порядок отображаемый списке и порядок в спике в памяти разный, т.е. по номеру обращатся нельзя.

Список может быть сортированный или нет. Это выставляется в свойствах. По-умолчанию, кажется, студия ставит сортировку.
Удобнее всего с несортированным списком - вообще мудрить не надо, ибо порядок в списке совпадает с порядком добавления - если ты, конечно, в конец добавляешь: номер в списке == индекс в векторе. Удаляй, добавляй - главное, синхроннно. А вот если нужна сортировка, тогда пригодится data: записывай туда индекс соответствующего элемента, как показал Albor: AddString возвращает позицию, в которую реально попал новый элемент. Но еще раз, она не совпадает с индексом в векторе (в приведенном коде) только для сортированного списка.


--------------------
...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0890 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.