crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

explorer85
  опции профиля:
сообщение 3.8.2011, 19:12
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


ЗАДАДЧА.
Исходные данные:

Есть две сущности
1. Задача
struct Task
{
    int TaskID;
    int ProjectID;
    QString Name;
    QString Notes;
    int Importance;
.......
};


2. Проект

struct Project
{
    int ProjectID;
    QString Name;
    QString Notes;
........
};


Эти сущности можно добавлять в списки

QVector <Task> tasks;
QVector <Project> projects;

Причем
при добавлении Задачи в tasks мы указываем ей ProjectID что указывает
на ее принадлежность к проекту с таким же ProjectID

при добавлении Проекта в projects мы указываем ему ProjectID.

Таким образом получается иерархическая связь на верхнем уровне проекты
на нижнем уровне задачи.
У одного проекта может быть несколько задач.
Задача одновременно может находится только в одном проекте.
НУ вобщем я думаю понятно двухуровневое дерево получается
проекты родители, задачи дети.
-----------------------------------------------------------
Необходимо реализовать GUI для работы со списками этих сущностей.
-----------------------------------------------------------
Реализовать интерфейс ввода необходимо следующим образом, в двух видах:
1. Двухуровневое дерево проектов и задач.
Проект1
Задача 1
Задача 2
Проект2
Задача 3
Без проекта
Задача 4

Здесь можно добавить проект, удалить проект, отредактировать проект
Здесь можно добавить задачу к проекту, удалить задачу из проекта, отредактировать задачу.
Проект "Без проекта" отредактировать и удалить нельзя (он создается приложением автоматически
чтобы было куда добавлять задачи во втором виде)


2. Список задач.
Задача 1
Задача 2
Задача 3
Задача 4

Здесь можно добавить задачу, отредактировать задачу, удалить задачу
При создании задачи в этом виде она попадает в проект "Без проекта"


Вопрос как это сделать с помощью mvc фреймворка qt??????

PS: Сразу скажу я эту проблему решил но на свой взгляд криво, и не уверен в правильности решения, и некоторые вещи у меня не работают.
PPS: Если кому интересно выложу здесь свои свои решения у меня их 2 одно реализовано криво другое не реализовано есь только идея.
PPPS: Очень надеюсь на помощь людей которые считают себя реально прокаченными в MVC ...и вообще всех homosapiens))
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
2 страниц V   1 2 >  
Начать новую тему
Ответов (1 - 12)
explorer85
  опции профиля:
сообщение 3.8.2011, 20:04
Сообщение #2


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


И так мое первое решение реализованное.

//класс хранилище данных берет данные из базы данных и предоставляет их моделям
class Storage : public QObject
{
    Q_OBJECT
public:
    Storage();
    //добавить задачу
    void addTask(Task tsk);
    //удалить задачу
    void removeTask();
    //вернуть все задачи с id проекта
    QVector <Task> tasksAtProject(int id);
    //вернуть все задачи с принадлежащие группе
    QVector <Task> tasksAtGroup(int n);
    //заменить задачу в списке задач
    void replaceTask(Task tsk);
    //заменить проект в списке проектов
    void replaceProject(Project prj);
private:
   QVector <Task> tasks;
    QVector <Project> projects;
};


Создается экземпляр данного класса.

После этого создаютя две модели производные от QAbstractItemModel, в эти модели передается указатель
на экземпляр Storage
Модель #1: строится по правилам модели списка (использует только tasks) и отображает их на QListView
Модель #2: строится по правилам модели дерева (использует projects - верхний уровень родители, tasks - нижний уровень дети) и отображает их на QTreeView)
В кажой модели по одному столбцу все данные из структур Task и Project передаются юзерролями, и обрабатываются кастомными делегатами.

Пользователь может пользоваться одновременно только дним из представлений (добавлять, удалять, редактировать) строки(задачи и проекты)

ПРОБЛЕМА!!!
Данные в моделях и представлениях не синхронизируются между собой!!!
НАПРИМЕР!!!
Добавляем в виде №2 (дерево) строку(задачу) : делаем в модели №2

begininsertrows()
storage_ptr->addTask(Task tsk);
endinsertrows()


данные добавляются в QVector <Task> tasks;
модель №2 уведомляется о том что данные добавились

а вот модель и представление №1 НИЧЕГО ОБ ЭТОМ НЕ ЗНАЮТ
ПОЭТОМУ ПРИ ПЕРЕХОДЕ К ВИДУ №2 мне приходится делать reset() что неправильно я думаю но другого выхода не вижу

вот схема моего варианта, там еще 2 прокси модели для сортировки данных


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

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 4.8.2011, 7:28
Сообщение #3


фрилансер
******

Группа: Участник
Сообщений: 2943
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


explorer85, привет!

за работу с моделью подсказать ничего не могу, а насчёт организации хранения данных, я бы вот так сделал
Раскрывающийся текст
#include <map>

struct Project
{
    int ProjectID; //ключ

    ........
};

struct Task
{
    int TaskID;     //составной ключ
    int ProjectID;  //
    
    .......
};


//таблица проектов
typedef std::map<int /*ProjectID*/, Project> td_projectList;

//таблица задач
typedef std::map<int /*ProjectID*/, std::map<int /*TaskID*/, Task> > td_taskList;

//библиотека проектов
class CProjectLibrary
{
private:
    td_projectList m_projectList;
    td_taskList m_taskList;

    //счётчик изменений
    int m_ChangeCounter;

public:
    ......

    int GetChangeCounter()const
    {
        return m_ChangeCounter;
    }

};


суть в следующем: у CProjectLibrary должны быть открытые функции, которые позволяют работать с закрытыми списками. При внесении одного или группы изменений каждая такая функция увеличивает счётчик изменений. Теперь, любой отображающий данные виджет может глянуть - не отличается ли значение счётчика от последнего использованного ? Если отличается, то перерисоваться.

Ну и не забывай про синхронизацию внутри CProjectLibrary, если присутствует многопоточнсть

Сообщение отредактировал Алексей1153 - 4.8.2011, 7:29
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
explorer85
  опции профиля:
сообщение 4.8.2011, 9:34
Сообщение #4


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


Алексей1153, спасибо за совет да с мапами пологичней и побыстрей. А насчет счтечика... дело в том что проекты и задачи отображаютя исключительно но через модели на представлениях и я их пробовал уведомлять сигналом , ну по аналогии с вашим счетчиком, но столкнулся с проблемой описанной в конце способа №1.
Эх неужели никто всерьез не работал с моделями??? перечитал эту ветку за год похожие проблемы вроде встречались.... Неужели все в отпусках и на каникулах........
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 4.8.2011, 10:06
Сообщение #5


фрилансер
******

Группа: Участник
Сообщений: 2943
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


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

Если же пресловутая модель (я не сталкивался ещё пока) не позволяет работать с таким классом совместно, то у меня возникают сомнения насчёт нужности этой самой модели в данном случае.


PS нэгодующая модэль : http://i9.photobucket.com/albums/a55/peppe...models/l152.jpg

Сообщение отредактировал Алексей1153 - 4.8.2011, 10:09
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
explorer85
  опции профиля:
сообщение 4.8.2011, 10:24
Сообщение #6


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Алексей1153 @ 4.8.2011, 11:06) *
explorer85, мне тут вот что непонятно: массивы инкапсулированы. Если наружу не выдавать на них ссылок или указателей, то менять содержимое смогут только открытые функции CProjectLibrary. А это означает, что любое изменение можно отследить всегда.


Все правильно, любое изменение можно отследить так как данные в массивах изменяются только с помощью открытых функции CProjectLibrary. Но проблема то не в этом!!!
Еще раз повторюсь есть задача отображать эти данные в двух разных видах указанным способом...(в первом посте я все понятно обьяснил? может просто недопонимание какое то есть)
Я нашел решение которое привел во 2 посте. Проблема в том что я не могу понять правильно ли я сделал применительно к философии mvc в qt или нет, и хочу спросить как бы вы решили эту проблему? :rolleyes:

Я ужасно извиняюсь, ну просто мне кажется что для понимания моей проблемы, нужен человек который имеет опыт написания собствеееных моделей производных от QAbstractItemModel и прокси QAbstractProxyModel

Вот я конечно может быть много прошу но мне нужны как бы два ответа 1 теоретический, о правильности выбранной мной концепции 2 практический применительно этой концепции к конкретным классам QAbstract***Model в Qt

Цитата(Алексей1153 @ 4.8.2011, 11:06) *
Если же пресловутая модель (я не сталкивался ещё пока) не позволяет работать с таким классом совместно, то у меня возникают сомнения насчёт нужности этой самой модели в данном случае.

В том то и дело что я не могу врубиться как организовать правильную работу со этим своим классом MVC фреймворка Qt!!!

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 4.8.2011, 10:27
Сообщение #7


фрилансер
******

Группа: Участник
Сообщений: 2943
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


explorer85, да, видимо я что-то не понимаю. Послежу :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
explorer85
  опции профиля:
сообщение 4.8.2011, 10:32
Сообщение #8


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


В том то и дело что я не могу врубиться как организовать правильную работу между своим классом и стандартными интерфейсами QAbstract**Model MVC фреймворка Qt!!! Не понимаю правильно я их настроил для работы (создал два подкласса QAbstractItemModel в них передал указатели на свой класс с данными итд, ну начинаю повторяться уже)


Алексей1153 Ну вообще проблема ясно сформулирована? чтобы мне знать а то может быть и другие люди не поймут? :mellow:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 4.8.2011, 10:48
Сообщение #9


фрилансер
******

Группа: Участник
Сообщений: 2943
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


проблема описана очень ясно и крупно:

Цитата
ПРОБЛЕМА!!!
Данные в моделях и представлениях не синхронизируются между собой!!!
<...>
данные добавляются в QVector <Task> tasks;
модель №2 уведомляется о том что данные добавились

а вот модель и представление №1 НИЧЕГО ОБ ЭТОМ НЕ ЗНАЮТ



по сути у тебя аналог окна виндового Explorer (дерево папок слева, содержимое папки - справа) только не для файловой системы, а для дерева проектов

Ты упоминаешь, что передаёшь указатель на экземпляр своего класса. При изменениях меняется счётчик. Уведомлений, конечно же, никаких не произойдёт, их надо инициировать. Я бы сделал проверку по таймеру (скажем, раз в секунду) счётчика, и при его изменении обновлял бы представление, которое не в фокусе (тут спорный вопрос - наверное, вместе со счётчиком полезно запоминать инициатора изменений, чтобы его не обновлять)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
explorer85
  опции профиля:
сообщение 4.8.2011, 11:23
Сообщение #10


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(Алексей1153 @ 4.8.2011, 11:48) *
по сути у тебя аналог окна виндового Explorer (дерево папок слева, содержимое папки - справа) только не для файловой системы, а для дерева проектов

Да попал в точку. Щас потыркал проводник та же концепция. Ну только разве что эти два вида у меня доступны не одновременно. А так тоже самое слева проекты, справа задачи)) и если обратил внимание то и модель фильтрации и сортировки для каждого вида тоже своя. Ведь в проводнике если справа в списке сортировать элементы то влевом они остаются в том порядке каком и были. ну это так философия. Хотя интересно как там сделано))

Цитата(Алексей1153 @ 4.8.2011, 11:48) *
Ты упоминаешь, что передаёшь указатель на экземпляр своего класса. При изменениях меняется счётчик. Уведомлений, конечно же, никаких не произойдёт, их надо инициировать. Я бы сделал проверку по таймеру (скажем, раз в секунду) счётчика, и при его изменении обновлял бы представление, которое не в фокусе (тут спорный вопрос - наверное, вместе со счётчиком полезно запоминать инициатора изменений, чтобы его не обновлять)

Да тут все проще зачем таймер если есть сигналы и слоты :rolleyes: Просто я говорил проблема с индексами что нельзя корректно уведомить второе представление об изменениях в первом так как модельные индексы у них разные потому что они связаны с двумя моделями..................

И еще один ньюанс... не хотел пугать просто... Допустим мне захотелось сделать группировку списка задач по каким либо признакам... например по важности (в структуре Task есть такое поле importance) от (0 - 5)
какое я щас вижу решение? делать еще одну связку модель + представление + делегат, передавать модели указатель на Storage с данными .........ну итд. То есть получается некислое дублирование кода, рост сложности кода проекта ну итд со всеми вытекающими.... И я так наверное и сделаю если никто ничего не посоветует выдающегося.... Эх где вы победители школьных олимпиад, эйнштейны, знатоки qt :rolleyes:

Извиняюсь за флуд... но мне почему то кажется что если бы эту тему увидел парень из troolteh котроый писал MVC фреймворк он бы сказал "Не парься брат делай void QAbstractItemModel::reset () для второй модели" :rolleyes:
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Алексей1153
  опции профиля:
сообщение 4.8.2011, 11:30
Сообщение #11


фрилансер
******

Группа: Участник
Сообщений: 2943
Регистрация: 19.6.2010
Из: Обливион
Пользователь №: 1822

Спасибо сказали: 215 раз(а)




Репутация:   34  


Цитата
Хотя интересно как там сделано))

да очень просто всё сделано (кхм, если работу с АПИшными Tree View и List View можно вообще назвать простыми. Это ад! Но ад программистский, а не
логический) - я делал такую вещь для одной из программ (не на Qt). Главное: отделить GUI от логики и от данных. Окно лишь показывает текущее
состояние данных, а также позволяет ввести новые данные (для создания нового элемента либо для замены содержимого существующего). После
изменения данных окно должно перерисоваться, чтобы показать текущее содержимое данных. Под перерисовкой понимается не принудительная
перерисовка всего, а, возможно, перерисовка только необходимой части окна для отображения изменений. Но само окно понятия не имеет, что поменялось!
Даже несмотря на то, что именно окно помогло ввести данные. Хранилищем окно не управляет - оно передало введённую информацию и забыло.
Перерисовалось. Типа - "я сделало всё, что могло, сотрите, что теперь в данных".
Оба окна не зависят друг от друга. Они зависят от данных. А то, как сортировать, это уже просто - выводят содержимое данных в том виде, в каком
пользователь попросил.

Цитата
зачем таймер если есть сигналы и слоты

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

Цитата
какое я щас вижу решение? делать еще одну связку модель + представление + делегат, передавать модели указатель на Storage с данными
.........ну итд. То есть получается некислое дублирование кода, рост сложности кода проекта ну итд со всеми вытекающими.... И

таймер вновь спешит на помощь :) Сменишь счётчик вхолостую и всё готово.
Кстати говоря, таймер то таймером, он обновит раз в секунду, что нормально для обновления вида других окон (не в фокусе), но не очень то для текущего
окна (сказали сортировать - а оно отреагировало через секунду...) . Тут делаем так: то, что вызывается в обработчике таймера для обновления окон, надо
иметь возможность вызвать в любой момент. Увеличили счётчик вхолостую, вызвали процедуру. Дальше всё по накатанной

Сообщение отредактировал Алексей1153 - 4.8.2011, 11:31
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
explorer85
  опции профиля:
сообщение 4.8.2011, 12:14
Сообщение #12


Студент
*

Группа: Новичок
Сообщений: 12
Регистрация: 18.3.2011
Пользователь №: 2517

Спасибо сказали: 0 раз(а)




Репутация:   0  


Спасибо за ответы, но просто для всего что вы описали в mvc qt есть стандартные вещи: dataChanged, Begin..EndInsertRows итд. Просто оно как бы все уже есть но вот правильно ли я этим пользуюсь в своей ситуации я не знаю.
Вообще по жизни стараюсь придерживаться правила не изобретать велосипеды и если есть что то готовое пользоваться этим. Но за соблюдение этого правила, приходиться расплачиваться необходимостью подстраиваться под чужие уже написанные решения.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
PAFOS
  опции профиля:
сообщение 5.8.2011, 13:53
Сообщение #13


Активный участник
***

Группа: Участник
Сообщений: 258
Регистрация: 27.12.2010
Из: Дмитров
Пользователь №: 2309

Спасибо сказали: 29 раз(а)




Репутация:   8  


Для начала я бы сделал одну модель и два представления. Как ни крути делать две модели для одних и тех же данных неправильно.
Модель будет иметь иерархическую структуру

Проект1
Задача 1
Задача 2
Проект2
Задача 3
Без проекта
Задача 4

Реализация такой модели - дело практики.

Идем далее...

struct Task
{
    int TaskID;
    int ProjectID;
    QString Name;
    QString Notes;
    int Importance;
.......
};

struct Project
{
    int ProjectID;
    QString Name;
    QString Notes;
........
};


заменяем на

struct Task
{
    int TaskID;
    int ProjectID;
    QString Name;
    QString Notes;
    int Importance;

    Project *project  // <- имея на руках экземпляр Task, можем получить доступ к проекту вообще без гемора
.......
};

struct Project
{
    int ProjectID;
    QVector<Task> tasks // <- ну это как бы понятно)
    QString Name;
    QString Notes;
........
};


Такая структура существенно сократит реализацию модели
Однако надо быть внимательным с указателями и т.п.

И напоследок:

Если посмотреть внимательно на класс QAbstractItemView, то можно найти классный метод setRootIndex( QModelIndex )
Для древовидного представления setRootIndex() должен быть QModelIndex::invalid() (т.е. корень модели)
А для списка - выделенный в древовидном представлении QModelIndex типа "Проект".

Сообщение отредактировал PAFOS - 5.8.2011, 13:55
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 7.6.2025, 6:37