Russian Qt Forum

Qt => Model-View (MV) => Тема начата: AlphaGh0St от Июнь 27, 2011, 21:10



Название: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 27, 2011, 21:10
Всем привет!
В образовательных и практических целях пишу (точнее пытаюсь) программку, работающую по технологии Модель-представление через сеть.

Но столкнулся с рядом проблем. С начала даже не знал, от чего отталкиваться. Потом подсказали...

Написал простенький сервер, который в хранит список строк. Строки в список можно добавлять и удалять. Если клиент отсылает серверу строку "3. ", то сервер возвращает весь список.

Задумка следующая: клиентская программа должна работать по технологии Модель-представление и отображать текущее состояние списка на сервере.

Как это реализовать?
Нужно переопределить метод data() в своём классе так, чтобы он запрашивал данные у сервера... но, сколько с ним просидел, ничего не получилось.

Благодарю за внимание.


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 28, 2011, 20:21
Судя по количеству просмотров, тема интересна не для меня одного.
Если у кого-нибудь есть опыт в написании таких программ, пожалуйста, поделитесь.


Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июнь 28, 2011, 23:17
Судя по количеству просмотров, тема интересна не для меня одного.
Если у кого-нибудь есть опыт в написании таких программ, пожалуйста, поделитесь.
да ничего особо интеренсного/сложного нет.
есть класс модели, если класс подгружения данных по сети в модель (сетевик).
на какие события сетевик подгружает данные - дело индивидуальное.
как только появляются обновления в данных - он сообщает об этом модели.
всё.


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 30, 2011, 16:52
В теории, действительно, особо сложного ничего нет, но давайте перейдём к практике.
Почитав документацию и провозившись целый день, некоторые моменты стали понятны, но я снова зашёл в тупик.

Понял, что сервер написан не правильно, переписал так, как посоветовали: если серверу отправить строку "length", он вернёт общее количество хранимых у себя строк. Если отправить номер строки, сервер вернёт строку по этому номеру.
Сервер работает правильно, 100%.

Переписал модель: метод rowCount() отсылает серверу строку "length" и возвращает общее количество строк. Метод data() по идее должен отсылать серверу число, а по этому числу, сервер вернёт указанную строку.
Но, если метод rowCount() вызывается и не однократно, то data() не вызывается вовсе.

Сейчас приведу код. Прошу сильно не сердиться за кривой код. На данный момент, мне... "лишь бы заработало".
Вот код метода rowCount()
Код:
int NetworkModelRO::rowCount(const QModelIndex &parent) const {
    slotSendToServer("length"); // посылаем серверу запрос на общее кол-во строк

// ответ считывается в переменную stringNetworkMessage
// (она определена в классе) из слота получения ответа от сервера
    int n = stringNetworkMessage.toInt(); 

    qDebug() << "stringNetworkMessage.toInt() => " << n;

    return n;
}
Этот метод работает.


Метод data(), вот с ним проблема
Код:
QVariant NetworkModelRO::data(const QModelIndex &index, int role) const {
    qDebug() << "data(): index.row() => " << index.row();

    if (!index.isValid())
        return QVariant();

    if (index.row() >= rowCount())
        return QVariant();

    if (role == Qt::DisplayRole){
        QString tmp = QString("%1").arg(index.row()); // переводим указанный индекс в строку
        slotSendToServer(tmp); // отправляем его серверу

        qDebug() << "data(): stringNetworkMessage => " << stringNetworkMessage;

        return stringNetworkMessage; // получаем ответ в этой переменной (строка по указанному индексу)
        }
    else
        return QVariant();
}

В чём проблема? Где я допустил ошибку?


Название: Re: Модель-представление, работа через сеть
Отправлено: BRE от Июнь 30, 2011, 16:56
А что возвращает columnCount?
Ноль?


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 30, 2011, 17:21
columnCount() ?
Я его не переопределял. Согласно документации, по скольку у меня список, переопределять метод columnCount() нет необходимости, нужен лишь метод rowCount().
А...не ужели метод columnCount тоже нужен?


Название: Re: Модель-представление, работа через сеть
Отправлено: BRE от Июнь 30, 2011, 17:28
Просто пытаюсь понять, почему не вызывается data().  :)
А rowCount возвращает точно не 0?


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 30, 2011, 17:48
вот отладочные данные от rowCount()
строк на сервере 3.
Код:
stringNetworkMessage.toInt() =>  0 
stringNetworkMessage.toInt() =>  0
stringNetworkMessage.toInt() =>  0
stringNetworkMessage.toInt() =>  0
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3
stringNetworkMessage.toInt() =>  3


Название: Re: Модель-представление, работа через сеть
Отправлено: Kolobok от Июнь 30, 2011, 22:29

Вот код метода rowCount()
Код:
int NetworkModelRO::rowCount(const QModelIndex &parent) const {
    slotSendToServer("length"); // посылаем серверу запрос на общее кол-во строк

// ответ считывается в переменную stringNetworkMessage
// (она определена в классе) из слота получения ответа от сервера
    int n = stringNetworkMessage.toInt(); 

    qDebug() << "stringNetworkMessage.toInt() => " << n;

    return n;
}


покажи код слота получения ответа от сервера


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июнь 30, 2011, 22:46
Вот код слота получения ответа от сервера
Код:
oid NetworkModelRO::slotReadyRead(){
    QDataStream in(socket);
    in.setVersion(QDataStream::Qt_4_7);

    for(;;){
        if(!nextBlockSize){
            if(socket->bytesAvailable() < sizeof(quint16))
                break;

            in >> nextBlockSize;
            }

        if(socket->bytesAvailable() < nextBlockSize)
            break;

        in >> stringNetworkMessage; // <---

        nextBlockSize = 0;
        }
}


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 01, 2011, 14:35
Есть какие-нибудь идеи? ... ???


Название: Re: Модель-представление, работа через сеть
Отправлено: BRE от Июль 01, 2011, 14:41
Попробуй жестко забить в rowCount, что бы он возвращал 3 и посмотри, будет ли вызываться data.


Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июль 01, 2011, 14:45
а я бы не стал так на прямую обращаться в сеть из методов модели.
отдельный класс висит, работает с серваком.. как оттуда обновления-изменения есть - он подкешировал инфу, и отдал модели..
модель тогда работает быстро и чётко.


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 01, 2011, 15:25
Переписал метод rowCount() так, чтобы он возвращал 3. И, действительно, обмен данными пошёл, в представлении отобразились строки.  Но тут, к сожалению, тоже, не всё так гладко...

ieroglif, не могли бы Вы рассказать подробнее, желательно с практической точки зрения или предоставить информацию, для реализации описанного Вами метода ? (или пример).



Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 01, 2011, 15:49
ieroglif, т.е. я правильно Вас понял?
Нужно написать отдельный класс, который возьмёт всё сетевое взаимодействие на себя.
В этом "сетевом" классе должны быть методы для получения общего кол-ва строк и получения строки по номеру.
Все полученные от сервера данные, сетевой класс хранит в своих полях.

А модель лишь запрашивает эти данные через методы rowCount() и data() у сетевого класса.

Тогда у меня ещё вопрос: каким образом подобный подход отразится на быстродействии модели?


Название: Re: Модель-представление, работа через сеть
Отправлено: BRE от Июль 01, 2011, 16:05
По скорости будет тоже самое. Весь код, который был бы в модели переноситься в другой класс "типа модели", который делает все тоже самое.
Кешировать данные на стороне клиента конечно придется, где это будет происходить в классе модели или в специальном отдельном классе псевдомодели не важно.



Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июль 01, 2011, 17:58
Тогда у меня ещё вопрос: каким образом подобный подход отразится на быстродействии модели?
с моей точки зрения это отразится только в лучшую сторону.
если за работу с сетью отвечает сама модель, то тормоза в сети вызовут тормоза в модели и, опасаюсь (исходники не смотрел, так что 100% сказать не могу) что это может вызвать тормоза в гуе.
если же за сетевое взаимодействие отвечает отдельный класс, то можно его вынести в отдельный поток, и даже если сеть будет тормозить - на гуе это никак не скажется.


Название: Re: Модель-представление, работа через сеть
Отправлено: Kolobok от Июль 01, 2011, 18:25
Вот код слота получения ответа от сервера
Код:
oid NetworkModelRO::slotReadyRead(){
    QDataStream in(socket);
    in.setVersion(QDataStream::Qt_4_7);

    for(;;){
        if(!nextBlockSize){
            if(socket->bytesAvailable() < sizeof(quint16))
                break;

            in >> nextBlockSize;
            }

        if(socket->bytesAvailable() < nextBlockSize)
            break;

        in >> stringNetworkMessage; // <---

        nextBlockSize = 0;
        }
}

Модель не знает, что число строк изменилось. Посмотри методы
void QAbstractItemModel::beginInsertRows ( const QModelIndex & parent, int first, int last ) [protected]
void QAbstractItemModel::endInsertRows () [protected]


Название: Re: Модель-представление, работа через сеть
Отправлено: BRE от Июль 01, 2011, 20:26
с моей точки зрения это отразится только в лучшую сторону.
если за работу с сетью отвечает сама модель, то тормоза в сети вызовут тормоза в модели и, опасаюсь (исходники не смотрел, так что 100% сказать не могу) что это может вызвать тормоза в гуе.
если же за сетевое взаимодействие отвечает отдельный класс, то можно его вынести в отдельный поток, и даже если сеть будет тормозить - на гуе это никак не скажется.
Если view нужно получить данные, которых нет в кеше модели и их нужно забирать с сервера, то совершенно не важно кто и в каком потоке их будет выкачивать. Модель на этот момент все равно должна быть заморожена, вместе с обслуживающим view ну и со всем gui.
Как вариант, можно вместо требуемых, но отсутствующих данных, возвращать строку "loading..." и грузить строку с сервера, но это все частности реализации.


Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июль 02, 2011, 04:07
Как вариант, можно вместо требуемых, но отсутствующих данных, возвращать строку "loading..." и грузить строку с сервера, но это все частности реализации.
ну лично я бы так и сделал - только возвращал бы пустой QVariant(), а "загрузка" писал бы в статус-баре


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 02, 2011, 19:29
Фуууууух, как я уже задолбался... Вожусь-вожусь с этим делом, а почти ничего не выходит...

Нет, нет, уведомлений о загрузке и всего прочего не надо. Я пишу не на показ, а для себя, из практических соображений. Чем проще, тем лучше...для начала...
Но Ваша идея мне понравилась, возьму на заметку.

Ну так в итоге, стоит ли использовать промежуточный "сетевой" класс?
И, если "да", то сетевой класс должен работать на прямую, запрашивая данные у сервера и тут же передавать модели, или запрашивать данные, сохранять их у себя, а модели предоставлять уже сохранённые данные?


Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июль 03, 2011, 10:06
Фуууууух, как я уже задолбался... Вожусь-вожусь с этим делом, а почти ничего не выходит...

Нет, нет, уведомлений о загрузке и всего прочего не надо. Я пишу не на показ, а для себя, из практических соображений. Чем проще, тем лучше...для начала...
Но Ваша идея мне понравилась, возьму на заметку.

Ну так в итоге, стоит ли использовать промежуточный "сетевой" класс?
И, если "да", то сетевой класс должен работать на прямую, запрашивая данные у сервера и тут же передавать модели, или запрашивать данные, сохранять их у себя, а модели предоставлять уже сохранённые данные?
ну какой-то класс по любому должен заниматься кешированием полученых с сервера данных? =) я бы оставил это на сетевой класс.


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 03, 2011, 13:05
С классом модели более-менее понятно. А вот с сетевым классом трудности.

Пусть сетевой касс содержит поле
Код:
private:
    vector<QString> vecS; // для хранения у себя строк с сервера

и методы
Код:
public: 
    int getRowCount() const;
    QVariant getData(const int index) const;

1) Значит, если модель вызывает метод rowCount(), нужно вызвать метод getRowCount() сетевого класса и вернуть размер вектора, верно?
В самом простом виде, получается так:
Код:
int NetworkModelRO::rowCount(const QModelIndex &parent) const { return networkClass->getRowCount(); }

2) Метод сетевого класса getData() возвращает модели (по вызову метода data()) строку из вектора по указанному индексу.
В самом простом виде, без проверок, получается так:
Код:
QVariant NetworkModelRO::data(const QModelIndex &index, int role) const { return networkClass->getData(index.row()); }

Но как быть с заполнением вектора? И как достичь синхронизации данных на сервере и в векторе?
    Если по каждому вызову метода data(), запрашивать указанную строку с сервера, помещать в вектор и возвращать модели, то в векторе будет полно дубликатов.
    Если по каждому вызову метода data(), полностью обновлять вектор... ну это тоже не дело.

3) Если модель вызывает метод rowCount() в тот момент, когда сетевой класс ещё не получил данные с сервера и вектор пуст, то метод вернёт 0. Чуть выше я написал отладочные данные от rowCount(). Как быть с этим?


Название: Re: Модель-представление, работа через сеть
Отправлено: ieroglif от Июль 03, 2011, 19:57
мда.. действительно..
значит однозначно, кешированные данные с сервера хранит модель.
в таком случае сетевой класс на какие-то события производит запрос данных с сервера, и сигналит новыми данными модели, которая по этим сигналам уже меняет "кэш" и сообщает вьюхе об обновлении данных.


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 14, 2011, 11:30
Извиняюсь за долгое отсутствие.
Возвращаясь к теме обсуждения, хочу сказать, что вызов метода rowCount() в начале несколько раз возвращает 0, а за тем реальный размер. Эта проблема так и не была решена...
Отладочные данные показали, что с начала модель несколько раз вызывает метод rowCount() и метод возвращает 0, а лишь ПОТОМ приходят реальные данные с сервера.

Вот отладочные данные (в сокращённом виде):

Модель вызывает свой метод rowCount(), который вызывает метод getRowCount() сетевого класса.
Этот метод возвращает 0 и модель получает значение 0.
getRowCount() n =>  0
getRowCount() n =>  0

Затем видно, что ПОСЛЕ того, как модель получила значение 0, от сервера пришли реальные данные.
slotReadyRead() stringNetworkMessage =>  "3"
slotReadyRead() stringNetworkMessage =>  "3"

т.е. получается так, что метод rowCount() вызвался (пусть) 4 раза, 4 раза вернул значение 0, а уже после пришли 4 ответа от сервера...

После этого модель делает очередной вызов метода rowCount() и на этот раз получает реальные данные.
getRowCount() n =>  3
getRowCount() n =>  3
slotReadyRead() stringNetworkMessage =>  "3"
slotReadyRead() stringNetworkMessage =>  "3"

Подскажите, что здесь не правильно и как это исправить?


Название: Re: Модель-представление, работа через сеть
Отправлено: AlphaGh0St от Июль 17, 2011, 22:08
Стоооят все темы на одном месте, и народ оффлайн... вымер что-ли форум?... ???
Есть идеи по поводу метода rowCount() ?
Скока вот с ним вожусь, ну ни как не могу понять, в чём дело...


Название: Re: Модель-представление, работа через сеть
Отправлено: Странник от Июль 18, 2011, 11:23
если для учебных целей, советую для начала написать синхронную реализацию. то есть отправили серверу запрос, дождались ответа с помощью waitForReadyRead, прочли данные и вернули результат. когда осмыслите такой вариант и прочувствуете его недостатки, можно подумать уже над асинхронной реализацией.