Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: xintrea от Ноябрь 12, 2008, 22:25



Название: Буфер обмена и самодельные типы данных
Отправлено: xintrea от Ноябрь 12, 2008, 22:25
Здравствуйте!


Не могу осилить тему передачи собственного типа данных через буфер обмена. Сделал себе тестовый примерчик, но пока заставить работать не могу.

В чем у меня непонятки?

Начнем с постановки задачи - надо заставить передаваться через буфер обмена какой-нибудь объект определенного типа. В данный момент пытаюсь разобраться с типом QMap<QString,QString>. Если хотябы такой объект смогу передать, дальше уже будет прощще. В перспективе, конечно, буду не QMap<QString,QString> передавать, а что-то более сложное, но пока хотябы это сделать.

Сразу скажу, что конвертить данный хеш в текст и форматировать с использованием символов Tab и Enter - это не вариант. Должны передаваться любые данные, не только текст.

Теперь выдержки из книжек:

"...может понадобиться перетаскивать и принимать свои собственные типы данных, например звуковые данные. Как поступать в подобных ситуациях? Для этих случаев, в классе QMimeData определен метод setData(), в который первым параметром нужно передать строку, характеризующую тип данных, а вторым сами данные в объекте класса QByteArray. Но можно поступить и иначе - унаследовать класс QMimeData и перезаписать методы formats() и retrieveData() ..."

"...если мы хотим перетаскивать пользовательские данные, необходимо сделать выбор между следующими альтернативами:
1. Мы можем обеспечить произвольные данные в виде массива QByteArray, используя функцию QMimeDada::setData(), и извлекать их пожже, используя функцию QMimeDada::data().
2. Мы можем создать подкласс QMimeData и переопределить функции formats() и retrieveData() для обработки наших пользовательских типов данных.
3. Для выполнения операций drag and ndrop в рамках одного приложения мы можем создать подкласс QMimeData и хранить данные в любых структурах данных. ..."

(Чем отличается пункт 2 от пункта 3 не совсем ясно, ну да ладно)

Для помещения данных в clipboard в любом случае надо пользоваться методом setMimeData() объекта QClipboard. А этот метод принимает данные типа QMimeData. Производный класс от QMimeData мы можем скормить в setMimeData(). Вот пример (clipbrecords - это производный от QMimeData класс)

Код:
 // Создается объект, который будет помещен в буфер обмена
 clipbrecords *rcd=new clipbrecords();
 rcd->set_field("name","Article about scintific");
 rcd->set_field("author","Aristotel");
 rcd->set_field("text","Scintific is paradox area of mind");
 rcd->print();

 // Создается буфер обмена
 QClipboard *cbuf=QApplication::clipboard();

 // Объект с данными помещается в буфер обмена
 cbuf->setMimeData(rcd);

Проблемы возникают, когда мы пытаемся извлечь данные.

Код:
 // Создается объект для приема данных
 clipbrecords *rcd2=new clipbrecords();

 // Данные из буфера вставляются в принимающий объект
 rcd2=cbuf->mimeData(); // <- Ошибка здесь

 rcd2->print();

Этот код не можем скомпилировать, потому что cbuf->mimeData() возвращает объект типа QMimeData, который не может быть преобразован в clipbrecords.

Код:
ошибка: некорректное преобразование из 'const QMimeData*' в 'clipbrecords*'

А если попробуем сделать приведение типов, как это сделано в примере в книге

Код:
rcd2=qobject_cast<clipbrecords *>(cbuf->mimeData());

то получим уже другие ошибки

Код:
/usr/local/Trolltech/Qt-4.4.1/include/QtCore/qobject.h: In function 'T qobject_cast(const QObject*) [with T = clipbrecords*]':
src/main.cpp:156:   instantiated from here
/usr/local/Trolltech/Qt-4.4.1/include/QtCore/qobject.h:451: ошибка: reinterpret_cast from type 'const QObject*' to type 'clipbrecords*' casts away constness
src/main.cpp:156:   instantiated from here
/usr/local/Trolltech/Qt-4.4.1/include/QtCore/qobject.h:453: ошибка: static_cast from type 'const QObject*' to type 'clipbrecords*' casts away constness

Что свидетельствует от том, что вроде как нужно иметь объект, в который возвращается начение с модификатором const. Но тогда мы не сможем этому объекту ничего присвоить. Поэтому пробую конструкцию присвоения в момент инициализаии

Код:
const clipbrecords *rcd2=qobject_cast<const clipbrecords *>(cbuf->mimeData());

Но в этом случае имею такую ошибку

Код:
ошибка: passing 'const clipbrecords' as 'this' argument of 'void clipbrecords::print()' discards qualifiers

то есть по каким-то причинам, вызов метода print() у принимаемого объекта  становится невозможным...


В общем, чую что я вообще не понял как работать с буфером обмена. Тем более, что если закомментировать выдов метода print() для принимаемого объекта, то далее будет ошибка компиляции в объекте clipbrecords перегружаемого для QMimeData метода retrieveData(). Как его писать вообще не понял. Он должен возвращать тип QVariant. А мои данные представлены в виде QMap<QString,QString>, и QVariant такой тип не может передать без плясок с бубном. Но даже если я и соображу как передавать производный тип данных через QVariant, остается непонятным, почему невозможно вызов метода print() у объекта rcd2 скомпилировать. И как тогда дальше преобразовывать полученные данные методами объекта clipbrecords? Их тоже не вызовешь.

В рунете толковых объяснялок нет. Надеюсь, гуру скажут что делаю не так?


Название: Re: Буфер омена и самодельные тепы данных
Отправлено: spirit от Ноябрь 12, 2008, 22:36
в QVariant можно запихнуть любой тип, как это сделать см. в описалове Q_DECLARE_METATYPE.


Название: Re: Буфер омена и самодельные тепы данных
Отправлено: BRE от Ноябрь 12, 2008, 22:38
Объяви функцию print так
void print() const;


Название: Re: Буфер омена и самодельные типы данных
Отправлено: ритт от Ноябрь 12, 2008, 23:41
Цитировать
const QMimeData * QClipboard::mimeData ( Mode mode = Clipboard ) const
Returns a reference to a QMimeData representation of the current clipboard data.

а посему:

Код:
// Создается объект для приема данных
// Данные из буфера вставляются в принимающий объект
const clipbrecords *rcd2 = cbuf->mimeData();
rcd2->print(); // <- Ошибка здесь: немодифицирующий метод должен быть статическим или иметь правый const


Название: Re: Буфер омена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 13, 2008, 05:50
ну или избавится от конст, да... ты не за был про макрос Q_OBJECT в производном классе?

Код:
//передача мапа
typedef QMap<QString, QString> Fields;
Fields fields;

f1["name"]="Article about scintific";
//...
QMimeData md;
QBuffer b1(&QByteArray());
b1.open(QIODevice::ReadWrite);
QDataStream s1(&b1);
s1 << f1;
b1.seek(0);

md.setData("Fields", b1.data());

QApplication::clipboard()->setMimeData(&md);

//прием мапа
QBuffer b2(&QApplication::clipboard()->mimeData()->data("Fields"));
b2.open(QIODevice::ReadOnly);
QDataStream s2(&b2);
Fields f2;
in >> f2;

qDebug() << f2;



Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 13, 2008, 13:51
Все, парни, получилось. Спасибо всем кто помогал.

Подводных камней было конечно много, но в конце концов заработало.

Подумываю сделать урок (текст объяснялки + пример проекта), ибо про передачу самодельных данных через буфер обмена инфы в рунете практически нет. А так лишний вопрос будет иметь готовое решение.

Кстати, что думают модераторы про создание ветки "Уроки", в которых можно будет создавать только темы с первым постом в виде урока. На flasher.ru так раньше было, очень помогало и начинающим, и тем кто разбирался с какой-нить новой темой во flash.

Вот примерно какие уроки планирую сделать

- Работа с буфером обмена. Передача нестандартных данных.
- Работа с ini файлами (борьба с затыками месторазмещения ini файлов)
- Работа с QDir (особенности логики работы QDir c с абсолютными и относительными путями)
- Как сделать самодельный виджет (рабочая заготовка)
- Преобразование QIndexModel в порядковый номер и обратно
- Как понять, от какого объекта пришел сигнал
- Отладочный вывод XML данных
- Отладочный вывод дерева объектов, если неработают функции dumpObjectInfo() и dumpObjectTree()


Название: Re: Буфер омена и самодельные типы данных
Отправлено: spirit от Ноябрь 13, 2008, 14:20
Цитировать
Преобразование QIndexModel в порядковый номер и обратно
QModelIndex  ;)


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 13, 2008, 14:43
Цитировать
Преобразование QIndexModel в порядковый номер и обратно
QModelIndex  ;)

Ну это я по памяти писал.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: ритт от Ноябрь 13, 2008, 14:48
для того завели вику. если готов потратить какое-то время на написание статьи/статей, свяжись с пантером.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 13, 2008, 15:18
для того завели вику. если готов потратить какое-то время на написание статьи/статей, свяжись с пантером.

Парни, толку от вашей вики никакого, потому что о ней мало кто знает. Основная страница данного ресурса - FORUM (http://www.prog.org.ru/index.php?action=forum (http://www.prog.org.ru/index.php?action=forum)), а не НАЧАЛО (http://www.prog.org.ru/index.php (http://www.prog.org.ru/index.php)). Поймите, у вас нету "сайта по QT", у вас есть форум по QT. И его главная страница - http://www.prog.org.ru/index.php?action=forum (http://www.prog.org.ru/index.php?action=forum).

Чтобы вики начали читать, и люди вообще знали о том что она есть в природе, нужно в заголовке форума прописать что-то в стиле "Так же загляните в нашу базу знаний Qt - уроки, готовые решения". И эта надпись должна мозолить глаза на каждой станице.

Я вот например зарегистрировался здесь полгода назад, а про вики только сегодня узнал. И то не сам узнал, а когда сказали. А на flasher.ru раздел Уроки читал в первый же день. Почуствуйте разницу. Не хотим делать уроки на форуме - хорошо, но давайте тогда четко и явно укажем где у нас копятся "неизменяемые" данные.

Но и этого мало. По-хорошему, надо всунуть поиск по вики в результаты поиска по форуму. Вот тогда вики начнут пользоваться и читать. Конечно, никто такого делать не будет, а это на самом деле очень важно. Поэтому раздел Уроки очень форуму нужен. Ведь решения будут как минимум видны в поиске.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 13, 2008, 15:24
Щас посмотрел - да, ребята, эта вики http://prog.org.ru/qt_wiki/ (http://prog.org.ru/qt_wiki/) - унылое Г. И из этого Г надо долго и упорно выбираться. Не стоит тратить на такую вики время, сделайте раздел на форуме, будьте человечнее, и люди к вам потянутся.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: Karl-Philipp от Ноябрь 13, 2008, 17:56
xintrea, ну и что же в Вики не так? Что-то я не наблюдал там "унылого Г" :)


Название: Re: Буфер омена и самодельные типы данных
Отправлено: pastor от Ноябрь 13, 2008, 18:04
Щас посмотрел - да, ребята, эта вики http://prog.org.ru/qt_wiki/ (http://prog.org.ru/qt_wiki/) - унылое Г. И из этого Г надо долго и упорно выбираться. Не стоит тратить на такую вики время, сделайте раздел на форуме, будьте человечнее, и люди к вам потянутся.

Ну если каждый будет тока обсырать и ничего не делать, то она такой и останеться. Вики только подняли. Взял бы да и написал пару статеек.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: Rcus от Ноябрь 13, 2008, 18:12
Ну если каждый будет тока обсырать и ничего не делать, то она такой и останеться. Вики только подняли. Взял бы да и написал пару статеек.

Идея и сила вики в свободе редактирования. Надо хотя бы сквозную регистрацию/вход с форумом.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: pastor от Ноябрь 13, 2008, 18:16
Надо хотя бы сквозную регистрацию/вход с форумом.

Это уже предложено Admin'у. Ждем ответа


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 13, 2008, 19:00
Надо чтоб в результатох поиска по форуму отображались и результаты поиска в вики. Это админ может сделать? Без такого поиска никуда не уедем.


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 02:20
А вот и обещаный урок.

Как передавать через буфер обмена произвольные типы данных

Рано или поздно при разработке более-менее крупного проекта, возникает задача передачи через буфер обмена самодельных данных. В литературе и документации по Qt этот вопрос освещен слабо, и данный урок должен восполнить этот пробел.

Давайте посмотрим, что написано по вопросу передачи собственных типов данных в книге М.Шлее "Qt4. Профессиональное программирование на C++".

Цитировать
"...может понадобиться перетаскивать и принимать свои собственные типы данных, например звуковые данные. Как поступать в подобных ситуациях? Для этих случаев, в классе QMimeData определен метод setData(), в который первым параметром нужно передать строку, характеризующую тип данных, а вторым сами данные в объекте класса QByteArray. Но можно поступить и иначе - унаследовать класс QMimeData и перезаписать методы formats() и retrieveData() ..."

Городить огород с методом setData() и с преобразованием наших данных в QByteArray (и обратно) мы не будем. А сделам более правильно, а именно разберемся, что скрывается за фразой "унаследовать класс QMimeData и перезаписать методы formats() и retrieveData()".
 
Нам нужно будет создать класс, унаследованный от класса QMimeData. С этим вопросов возникнуть не должно. Метод formats() просто возвращает список строк, содержащий текстовые идентификаторы данных, которые данный класс может обработать. (Мы можем сами себе придумать и использовать такие строки, например "myapplication/sounddata", "myapplication/matrixdata" и.т.д. Это нас оградит хотябы от того, что после копирования данных в буфер и попытки вставки в текстовый редактор, в редактор не будет запихиваться бинарный мусор. Блокировка произойдет потому, что текстовый редактор способен работать с данными "text/plain", а всякие "myapplication/sounddata" ему неизвестны, и поэтому данные с таким идентификатором в буфере обмена будут проигнорированы).

В данном классе можно создать свойство (или несколько свойств), которые будут содержать наши передаваемые данные. Заполнять данные в свойствах можно отдельными методами. То есть, не нужно передавать всю требуемую структуру данных в виде каким-то образом сгенерированного QByteArray. Можно также написать метод, который примет данные в виде определенной пользователем структуры, и запомнит ее (в свойстве класса, которое имеет тип данной структуры). То есть, внесение данных крупной проблемы не представляет.

Но дело осложняется тем, что метод retrieveData() должен возвращать все данные из буфера единовременно, и возвращать данные надо в виде типа QVariant. Вот какой прототип, согласно документации, должен быть у перегружаемого нами метода retrieveData()

Код:
QVariant retrieveData ( const QString & mimeType, QVariant::Type type ) const


Если бы мы возвращали данные в виде QByteArray, то особых проблем бы не возникло - QByteArray прекрасно передается через QVariant. Но тогда нужно будет городить низкоуровневую упаковку и разбор данных из такого массива. А это ничем не отличается от работы с буфером обмена через метод setData().

Поэтому, первая наша задача - разобраться, как передавать через QVariant самодельную структуру данных. Как только мы это поймем, сделать все остальное не составит большого труда.

Не буду отсылать к документации, и объясню на пальцах, как передавать произвольные структуры чере QVariant. Предположим, у нас есть некая структура

Код:
// Структура данных, которая будет передаваться через буфер обмена
struct clipb_struct
{
 int number; // Некое число
 QString stringline; // Некая строка
 QMap<QString, QString> namevaluetable; // Некая таблица вида "имя переменной" "значение"
};

Чтобы передавать через QVariant данные с типом clipb_struct, надо этот тип просто-напросто зарегистрировать в программе. Делается это так

Код:
Q_DECLARE_METATYPE(clipb_struct);

само собой, данный код нужно размещать после описания структуры. После этого действия, структура clipb_struct будет передаваться через QVariant.


Ну а дальше все просто. Пишется класс, унаследованный от QMimeData. В классе делаем переменную (свойство) типа clipb_struct. Пишем методы (или метод), которые будут заполнять поля данной переменной. Переопределяем метод retrieveData(), он как раз и должен возвращать переменную типа clipb_struct. Можем так же написать методы-хелперы, которые будут возвращать значения полей переменной типа clipb_struct.

Работу с буфером обмена можно организовать так.

Внесение информации в буфер обмена

Код:
 // Создается ссылка на буфер обмена
 QClipboard *pastebuf=QApplication::clipboard();

 // Создается объект, который будет помещен в буфер обмена и вносятся в него данные
 clipb *cb=new clipb();
 cb->set_number(100);
 cb->set_stringline("Hello Qt");
 cb->ins_namevalue("name","Article about scintific");
 cb->ins_namevalue("author","Aristotel");
 cb->ins_namevalue("text","Scintific is paradox area of mind");
 cb->print();

 // Объект с данными помещается в буфер обмена
 pastebuf->setMimeData( cb );

Извлечение данных из буфера обмена

Код:
 // Создается ссылка на буфер обмена
 QClipboard *getbuf=QApplication::clipboard();

 // Создается объект для приема данных
 const clipb *cb2;

 // Данные из буфера вставляются в принимающий объект
 cb2=qobject_cast<const clipb *>(getbuf->mimeData());

после таких действий в объекте cb2 в переменной типа clipb_struct будут лежать переданные через буфер данные. И их можно извлекать далее с помощью методов-хелперов, или с помощью одного метода, который просто возращает переменную типа clipb_struct.


Чтобы все стало более понятно,  прикрепляю готовый пример. В примере демонстрируется передача соственного типа данных через буфер обмена. Пример предельно простой, нет никаких кнопочек, только главное окно программы. В примере происходит копирование в буфер, и, сразу, извлечение из буфера. Вся последовательность действий пишется в консоль.

Проект с исходниками дан в нескольких кодировках.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: Пантер от Ноябрь 16, 2008, 09:59
Вики - унылое Г потому, что занимаюсь только я, а времени не очень много. Предполагалось, что я начну, а люди подтянутся. Вот и подтягивайтесь. Можете мне статьи давать, а я буду их в вику ложить, если не хотите на регистрацию заморачиваться.


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: BRE от Ноябрь 16, 2008, 10:12
Извлечение данных из буфера обмена

Код:
 // Создается ссылка на буфер обмена
 QClipboard *getbuf=QApplication::clipboard();

 // Создается объект для приема данных
 const clipb *cb2=new clipb();

 // Данные из буфера вставляются в принимающий объект
 cb2=qobject_cast<const clipb *>(getbuf->mimeData());


Зачем создавать объект для приема данных, если следом указателю присваивается новое значение?
Может лучше так:
Код:
// Создается ссылка на буфер обмена
QClipboard *getbuf=QApplication::clipboard();

const clipb *cb2=qobject_cast<const clipb *>(getbuf->mimeData());
cb2->print();


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 22:52
Зачем создавать объект для приема данных, если следом указателю присваивается новое значение?
Может лучше так:
Код:
// Создается ссылка на буфер обмена
QClipboard *getbuf=QApplication::clipboard();

const clipb *cb2=qobject_cast<const clipb *>(getbuf->mimeData());
cb2->print();

Чтобы понять зачем, стоит прочитать книжку "Совершенный код". Кратко говоря, логически атомарные операции для улучшения понятности кода человеком, надо делать отдельно, и на валить все в одну кучу.

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

Код:
const clipb *cb2=qobject_cast<const clipb *>(QApplication::clipboard()->mimeData());

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


Название: Re: Буфер омена и самодельные типы данных
Отправлено: Rcus от Ноябрь 16, 2008, 23:05
Но все же на вопрос вы не ответили.
Выделив память в куче вы должны точно знать кто ее освободит и когда, в вашем же примере вызов new clipbrd() гарантированно приведет к утечке памяти.
И кстати однострочный вариант выглядит экспрессивнее :) (именно за цепочки вызовов я люблю C++)


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 23:12
Вики - унылое Г потому, что занимаюсь только я, а времени не очень много. Предполагалось, что я начну, а люди подтянутся. Вот и подтягивайтесь.

Подтянусь только в том случае, если поиск по данному форуму будет индексировать и статьи в вики. А в результатах поиска будут, соответсвенно, видны и и обычные ссылки на темы форума, и ссылки на вики-статьи. Заметьте, не "ссылка на сообщение с сылкой на вики-статью", а прямые ссылки на вики-статью. Лишний клик - меньше знаний с экспоненциальной зависимостью.

Если поиска по вики в пространстве форума это не будет, толку от вики никакого.


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: BRE от Ноябрь 16, 2008, 23:13
Чтобы понять зачем, стоит прочитать книжку "Совершенный код".
Почитай лучше книги ты, посмотри свой код.  ;)


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 23:19
Но все же на вопрос вы не ответили.
Выделив память в куче вы должны точно знать кто ее освободит и когда, в вашем же примере вызов new clipbrd() гарантированно приведет к утечке памяти.
И кстати однострочный вариант выглядит экспрессивнее :) (именно за цепочки вызовов я люблю C++)

Объясняю. Дело в том, что здесь идет работа с буфером обмена. Который может быть заполнен независимо от нас. Поэтому нам лучше сделать копию данных и дальше спокойно работать с копией, а не с сылкой на объект в буфере. Конечно, в таком простом примере с буфером ничего плохого не произойдет. В реальных условиях возможны варианты, особенно если обработка буфера производится в смежных основных циклах Qt программы.

Хотя да, лоханулся, копирования данных у меня не происходит. И действия хоть и работают, но бессмысленно new. Поэтому я и нелюблю C/C++, но приходится прогать на нем, ибо альтернатив нет.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: Rcus от Ноябрь 16, 2008, 23:22
Все понятно, возможно именно таким было ваше намерение, но все же ваш код не копирует объект (и умоляю вас не упоминайте CC всуе).


Название: Re: Буфер омена и самодельные типы данных
Отправлено: BRE от Ноябрь 16, 2008, 23:24
Объясняю. Дело в том, что здесь идет работа с буфером обмена. Который может быть заполнен независимо от нас. Поэтому нам лучше сделать копию данных и дальше спокойно работать с копией, а не с сылкой на объект в буфере. Конечно, в таком простом примере с буфером ничего плохого не произойдет. В реальных условиях возможны варианты, особенно если обработка буфера производится в смежных основных циклах Qt программы.
Спасибо за объяснения.  :)
Код:
 const clipb *cb2=new clipb();
 cb2=qobject_cast<const clipb *>(getbuf->mimeData());
В первой строке ты выделяешь память, на которую ссылается указатель cb2, во второй строке ты теряешь ту память на которую указывал этот указатель, и она остается не освобожденной.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 23:38
Все понятно, возможно именно таким было ваше намерение, но все же ваш код не копирует объект (и умоляю вас не упоминайте CC всуе).

Исправил.

А что есть CC? Я не знаю такого.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: BRE от Ноябрь 16, 2008, 23:44
Хотя да, лоханулся, копирования данных у меня не происходит. И действия хоть и работают, но бессмысленно new. Поэтому я и нелюблю C/C++, но приходится прогать на нем, ибо альтернатив нет.
1. new был не бессмысленен, а вреден. Ты терял бы память на каждом извлечении из clipa.
2. Нет такого языка С/С++. Это два абсолютно разных языка, с разной идеологией. А вот когда ты это прочувствуешь, тебе понравится и С и С++.  ;)


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 16, 2008, 23:54
2. Нет такого языка С/С++. Это два абсолютно разных языка, с разной идеологией.

А мужики-то не знают. Срочно бегу на форумы по JavaScript объяснять, что "JavaScript -это не Java".


Название: Re: Буфер омена и самодельные типы данных
Отправлено: BRE от Ноябрь 16, 2008, 23:58
2. Нет такого языка С/С++. Это два абсолютно разных языка, с разной идеологией.

А мужики-то не знают. Срочно бегу на форумы по JavaScript объяснять, что "JavaScript -это не Java".

Зря прикалываешься. С++ использует синтаксис С. Но на С++ нельзя писать как на С, иначе теряется его смысл. Это два языка с абсолютно разными подходами к программированию.
Лениво сейчас все расписывать. И я так понимаю, что С++ тебе не очень то интересен. Глянь эту ссылку http://www.insidecpp.ru/art/1/.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: xintrea от Ноябрь 17, 2008, 00:18
Лениво сейчас все расписывать. И я так понимаю, что С++ тебе не очень то интересен.

Неправильно понимаешь. http://www.gamedev.ru/community/experimentalgameplay/forum/?id=75236 (http://www.gamedev.ru/community/experimentalgameplay/forum/?id=75236), раздел "Производные цели", четвертый пункт.


Название: Re: Буфер омена и самодельные типы данных
Отправлено: BRE от Ноябрь 17, 2008, 00:30
Лениво сейчас все расписывать. И я так понимаю, что С++ тебе не очень то интересен.

Неправильно понимаешь. http://www.gamedev.ru/community/experimentalgameplay/forum/?id=75236 (http://www.gamedev.ru/community/experimentalgameplay/forum/?id=75236), раздел "Производные цели", четвертый пункт.
Это я после это твоей фразы
Цитировать
Поэтому я и нелюблю C/C++, но приходится прогать на нем, ибо альтернатив нет.

Qt != С++.
Скажу даже больше, Qt навязывает определенные правила программирования. Как бы стереотипы. Попробуй решить задачу на C++ без использования Qt. Но решить не просто так, что мне нужен вектор объектов, поэтому нужно написать класс Vector. А самому определить сущности, заставить их взаимодействовать...
В это весь кайф.  ;)


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Ноябрь 20, 2008, 08:59
От всё бы вам холиварить, горячие эстонские парни! :)

По поводу Урока (http://www.prog.org.ru/index.php?topic=8041.msg42788#msg42788) есть небольшое дополнение:
Передача данных через QByteArray и setData() отличается от передачи через QByteArray и retrieveData().
Различие заключается в том, что в первом случае придётся перегонять данные в QByteArray и отдавать сразу, а во втором, только тогда, когда пользователь их запросил - тогда и вызывается retrieveData().
Это может быть критично, например, для очень больших объектов или для случаев, когда данные часто изменяются, и ты хочешь скопировать 1 раз, а вставлять всегда наиболее свежее состояние. :)

Случаи 2 и 3 из первого поста, отличаются тем, что если передача данных идёт гарантировано в рамках одного процесса, то ты можешь после получения QMimeDada из клипборда просто привести его к реальному типу и дальше работать с ним через дополнительно определённые методы и свойства, совсем не связываясь с QVariant-ом и прочими QByteArray-ями, а работая просто через указатели и ссылки. :)
Но если передача идёт между разными экземплярами, то данные придётся передавать между процессами. К тому же в принимающем процессе Qt создаст экземпляр стандартного QMimeDada а не твоего наследника.


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 20, 2008, 13:24
Различие заключается в том, что в первом случае придётся перегонять данные в QByteArray и отдавать сразу, а во втором, только тогда, когда пользователь их запросил - тогда и вызывается retrieveData()
как они могут отдаваться сразу... потом, если они копируются в системный буфер, предварительно принимая определенный вид... мне не понятно ???
по поводу больших передаче больших объектов через буфер обмена... так это вообще глупо ::)


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Ноябрь 24, 2008, 22:55
В системный буфер отдаётся список форматов и калбек. По крайней мере в WinApi такое есть, думаю и в Х-ах тоже.
Насчёт больших объёмов - а какие считать большими? И что делать если таки больше?

Например страница сайта - это много или мало? Или отчётик екселевский?
И что делать простому юзеру ежели ему это в свой документ какой вставить нужно?
Сможешь всем объяснить? :)


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 25, 2008, 03:55
знаю что в кде3-4 твои калбеки здорово работают при закрытии проги теряешь буфер. если конечно у тебе не загружен кклипбоард в винде проще там есть оле-объекты.

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


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Ноябрь 26, 2008, 09:02
Оле объекты тут не при чём.
Если используешь этот механизм, то при закрытии программы или всё потеряется, или нужно перегнать в нужные форматы и скормить их клипборду.
Тот же мсворд, если выделить и скопировать много данных, при закрытии спрашивает что с ними делать.

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


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 26, 2008, 12:41
какой механизм? я же написал... смотрел исходники кутэ... ничего подобного не увидел о чем ты тут рассказывал... мне просто интересно где ты эти знания взял (в контексте кутэ)
а именно:
Цитата: Tonal
а во втором, только тогда, когда пользователь их запросил - тогда и вызывается retrieveData()


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Ноябрь 27, 2008, 14:54
Ну, я как бы и не сомнивался в этом механизме. :)
Сделал, когда потребовалось, полагаясь на него, и оно работает.
Код
Python
# -*- coding: cp1251 -*-
#file aaa.py
 
import sys
from PyQt4 import QtCore, QtGui
 
class _MimeData(QtCore.QMimeData):
 u"Класс поддержки клипбоарда"
 format_templ = u'application/x-python-mime;value="%s"'
 obj = None
 format_name = ''
 def __init__(self, obj):
   super(_MimeData, self).__init__()
   self.obj = obj
   self.format_name = self.format_templ % obj.__class__.__name__
 
 def hasFormat(self, mimetype):
   if mimetype in (self.format_name, u'text/plain'):
     return True
   return QtCore.QMimeData.hasFormat(self, mimetype)
 
 def formats(self):
   base_formats = QtCore.QMimeData.formats(self)
   return list(set(list(base_formats) + [self.format_name, u'text/plain']))
 
 def retrieveData(self, mimetype, preferredType):
   print 'retrieveData(%s, %s)' %(mimetype, preferredType)
   if mimetype == self.format_name:
     return QtCore.QVariant(self.obj)
   if mimetype == u'text/plain':
     return QtCore.QVariant(u'%s' % self.obj)
   return QtCore.QMimeData.retrieveData(self, mimetype, preferredType)
 
def main():
 app = QtGui.QApplication(sys.argv)
 print 'copy data to clipboard'
 data1 = _MimeData(['aaa', 'bbb', 'ccc'])
 QtGui.QApplication.clipboard().setMimeData(data1)
 print 'paste data from clipboard'
 data2 = QtGui.QApplication.clipboard().mimeData()
 text = data2.text()
 print text
 
if __name__ == '__main__':
 main()
 
Протокол запуска под виндой:
Код:
C:\Lang>aaa.py
copy data to clipboard
paste data from clipboard
retrieveData(text/plain, 10)
['aaa', 'bbb', 'ccc']
Как видишь, вызовы происходят именно в описываемом мною порядке.
Хотя на linux-е не проверял - приду домой - проверю. :)

Ну и в ассистенте про retrieveData написано:
Цитировать
This function is called by the general data() getter and by the convenience getters (text(), html(), urls(), imageData(), and colorData()).
Т.е. пока не вызвана одна из перечисленных функций, retrieveData не дёрнется.
При вызове QClipboard::setMimeData в винде таковые не вызываются.

П.С. Действительно, виндовская реализация работает через COM (хотя это и не обязательно).


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 27, 2008, 15:28
не ну это не интересно... а ты пробовал получать свои данные в контексте другой программы?  :o


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Ноябрь 28, 2008, 18:38
Да, на винде вполне работает.
Под *nux ещё не проверял, но если верить документации, то должно. :)


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: vaprele07 от Ноябрь 29, 2008, 03:44
блин ты не догнал %) сделай небольшое изменение примеру
после последнего print text
Код
Python
widget = QtGui.QTextEdit()
widget.show()
app.exec_()
 

да здорово в едитор можно вставить твои 'aaa', 'bbb', 'ccc'
а теперь открой, не закрывая окна своей проги, любую другую прогу и попробуй получить данные из буфера...  ;D  т.е. данных твоих в буффере нет!... не понимаю как может одна функция retrievData работать одновременно и на прием и на передачу...

а еще наглядней запусти две копии твоей проги с моим изменением, исправив во второй 'aaa', 'bbb', 'ccc' на 'xxx', 'yyy', 'zzz'

проверял под убунту%)


Название: Re: Буфер обмена и самодельные типы данных
Отправлено: Tonal от Декабрь 01, 2008, 11:17
У меня данные в буфере есть, и любая прога ожидающая text/plain их видит пока тест запущен.

Судя по тому, к чему приводят твои эксперименты, для linux-а этот механизм просто не работает.
Это либо баг/недоделка, либо кривость документации, т.к. там ничего подобного не упомянуто.

Подкорректировал и разделил на 2 проги.
Вот вывод первой:
Код:
C:\Lang\test\python\qtClipb>aaa.py
2008-12-01 14:04:22.971000 copy data to clipboard
!>2008-12-01 14:04:29.148000 retrieveData(text/plain, 10)

2008-12-01 14:04:34.668000 paste data from clipboard
2008-12-01 14:04:34.668000 retrieveData(text/plain, 10)
['aaa', 'bbb', 'ccc']
Вот вывод второй:
Код:
C:\Lang\test\python\qtClipb>bbb.py
2008-12-01 14:04:29.123000 paste data from clipboard
2008-12-01 14:04:29.150000 ['aaa', 'bbb', 'ccc']
Обрати внимание на время.

Вот полный код обоих частей:
Код
Python
# -*- coding: cp1251 -*-
#file aaa.py
import sys
from datetime import datetime
from PyQt4 import QtCore, QtGui
 
#Работа с клипбоардом.
class _MimeData(QtCore.QMimeData):
 u"Класс поддержки клипбоарда"
 format_templ = u'application/x-python-mime;value="%s"'
 obj = None
 format_name = ''
 def __init__(self, obj):
   super(_MimeData, self).__init__()
   self.obj = obj
   self.format_name = self.format_templ % obj.__class__.__name__
 
 def hasFormat(self, mimetype):
   if mimetype in (self.format_name, u'text/plain'):
     return True
   return QtCore.QMimeData.hasFormat(self, mimetype)
 
 def formats(self):
   base_formats = QtCore.QMimeData.formats(self)
   return list(set(list(base_formats) + [self.format_name, u'text/plain']))
 
 def retrieveData(self, mimetype, preferredType):
   print '%s retrieveData(%s, %s)' %(datetime.now(), mimetype, preferredType)
   if mimetype == self.format_name:
     return QtCore.QVariant(self.obj)
   if mimetype == u'text/plain':
     return QtCore.QVariant(u'%s' % self.obj)
   return QtCore.QMimeData.retrieveData(self, mimetype, preferredType)
 
def main():
 app = QtGui.QApplication(sys.argv)
 print datetime.now(), 'copy data to clipboard'
 data1 = _MimeData(['aaa', 'bbb', 'ccc'])
 QtGui.QApplication.clipboard().setMimeData(data1)
 raw_input('!>')
 print datetime.now(), 'paste data from clipboard'
 data2 = QtGui.QApplication.clipboard().mimeData()
 text = data2.text()
 print text
 
if __name__ == '__main__':
 main()
 

Код
Python
# -*- coding: cp1251 -*-
#file bbb.py
import sys
from datetime import datetime
from PyQt4 import QtCore, QtGui
 
def main():
 app = QtGui.QApplication(sys.argv)
 print datetime.now(), 'paste data from clipboard'
 data2 = QtGui.QApplication.clipboard().mimeData()
 text = data2.text()
 print datetime.now(), text
 
if __name__ == '__main__':
 main()