Версия для печати темы
Форум на CrossPlatform.RU _ Qt GUI _ QTableWidget, Как програмно реализовать перетаскивание?
Автор: Danila_Bagrofff 16.4.2009, 12:07
Есть проблемка: есть 3 виджета:
QTableWidget *tbl = new QTableWidget(10,10,this);
QFrame *frm = new QFrame(this);
QWidget *wdg = new QWidget(frm);
QHBoxLayout *hbl = new QHBoxLayout(frame);
hbl->insertWidget(wdg);
//затем в процессе программы
hbl->removeWidget(wdg);
wdg->setParent(tbl);
tbl->setCellWidget(0,0, wdg);
в процессе программы wdg должен перемещаться между двумя виджетами. Соответственно менять родителя. Лэаут сам тоже устанавливает виджету родителя. То есть у wgt становится родителем frm после команды insertWidget().
есть команда setParent(). Но при смене родителя она ругается.
Если мы перемещаем wdg возникает ошибка:
Цитата
X Error: BadWindow (invalid Window parameter) 3
Major opcode: 25 (X_SendEvent)
Resourse id: .....
Как тогда правильно перемещать виджет между другими?
-----------
Отделено от темы: http://www.forum.crossplatform.ru/index.php?showtopic=2577
Автор: igor_bogomolov 16.4.2009, 13:44
Тут проблема на самом деле в другом.
Дело в том, что один и тот же виджет перемещается между фреймом и ячейкой таблицы. В таблицу виджет устанавливается через setCellWidget.
Если заглянуть в исходники данной функции, докопаемся до следущего кода.
void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget)
{
Q_D(QAbstractItemView);
if (!d->isIndexValid(index))
return;
if (QWidget *oldWidget = indexWidget(index)) {
d->removeEditor(oldWidget);
oldWidget->deleteLater();
}
if (widget) {
widget->setParent(viewport());
d->persistent.insert(widget);
d->addEditor(index, widget, true);
widget->show();
if (!d->delayedPendingLayout)
widget->setGeometry(visualRect(index));
dataChanged(index, index); // update the geometry
}
}
Обратите внимание на код. Когда вставляется виджет, сначало происходит удаление старого. При этом не происходит никакой проверки.
Т.о. образом при повторном вставлении виджета в ячейку, модель ее просто удаляет.
Вобщемто недоработка на мой взгляд.
Обойти проблему можно, если только каждый раз создавать новый виджет. Что не есть хорошо. ИМХО.
Автор: igor_bogomolov 16.4.2009, 14:11
Цитата(Litkevich Yuriy @ 16.4.2009, 15:02)
Если нужно вставлять в ячейку, то устанавливать родителя не надо
Можно и не устанавливать самому. Родидель установтся автоматически.
Цитата
widget->setParent(viewport());
Смотри мое сообщение выше
Автор: Litkevich Yuriy 16.4.2009, 14:53
igor_bogomolov, тут похоже человеку нужно не простая смена родителя, помоему речь о Перетаскивании, соответственно тему нужно разделять.
Автор: igor_bogomolov 16.4.2009, 14:56
Судя по его коду, он делает именно смену родителя. Логику нужно менять, таким образом добиться нужного эфекта не получится.
Но тему разделить наверно стОит
Автор: Danila_Bagrofff 17.4.2009, 7:19
Да, я хочу перенести виджет, чтобы не дублировать.
Сделал очень простой пример:
DMainDialog::DMainDialog(QWidget *parent) : QDialog(parent)
{
vbl = new QVBoxLayout(this);
tbl = new QTableWidget(4,4,this);
tbl->setMinimumSize(100,100);
tbl2 = new QTableWidget(4,4,this);
tbl2->setMinimumSize(100,100);
pb = new QPushButton("push", this);
vbl->addWidget(tbl);
vbl->addWidget(tbl2);
vbl->addWidget(pb);
lbl = new QLabel("label", this);
vbl->addWidget(lbl);
connect(pb, SIGNAL(clicked()), SLOT(clickPB()));
i =0;
}
void DMainDialog::clickPB()
{
i++;
if(i%2)
tbl->setCellWidget(0,0,lbl);
else
tbl2->setCellWidget(0,0,lbl);
}
Если надо, могу скомпиленный вариант дать.
Смысл в том, что после пары перемещений лэйбл вообще пропадает!!!
И происходит ошибка сегментирования.
Это бага Qt? Нужно перед новым размещением создавать дубликат обязательно?
Автор: igor_bogomolov 17.4.2009, 8:20
Да елы палы. Ты вообще читаешь что тебе отвечают. Я тебе вчера сразу ответил что происходит в данной ситуации.
Цитата(igor_bogomolov @ 16.4.2009, 14:44)
Обратите внимание на код. Когда вставляется виджет, сначало происходит удаление старого. При этом не происходит никакой проверки.
Т.о. образом при повторном вставлении виджета в ячейку, модель ее просто удаляет.
Вобщемто недоработка на мой взгляд.
Читай мое сообщение выше.
Автор: Litkevich Yuriy 17.4.2009, 9:40
Цитата(Danila_Bagrofff @ 17.4.2009, 11:19)
Это бага Qt? Нужно перед новым размещением создавать дубликат обязательно?
дело в том, что QTableWidget, предназанчен для довольно примитивных операций над ним. Поэтому он сам удаляет свои элементы (Игорь уже и исходник класса показал)
Автор: igor_bogomolov 17.4.2009, 10:38
Цитата(Litkevich Yuriy @ 17.4.2009, 10:40)
QTableWidget, предназанчен для довольно примитивных операций над ним. Поэтому он сам удаляет свои элементы
Вставка виджета происходит на уровне QAbstractItemView методом setIndexWidget. При этом, данный метод не является виртуальным, и переопределить его не получится.
На мой взгляд имеем недоработку(а возможно и баг), т.к. не происходит проверки вставляемого виджета с предыдущим. Предыдущий виджет просто удаляется. Видимо так сделанно из-за того, что копирование виджетов
запрещено. Хотя, на мой взгляд, они должны были предусмотреть такую возможность, что бы защититься от лишних ошибок, в результаве повторного вставления одного и того же виджета в ячейку. Это с одной стороны ошибка программиста, но и недоработка библиотеки, в крайнем случае описания данного метода.
Так что можно и отрапортовать о баге, посмотрим что ответят. Как считаете, стОит?
ИМХО.
Автор: Danila_Bagrofff 17.4.2009, 12:32
igor_bogomolov, вы уж извините =) Просто я искал разные пути решения =) И игрался по-всякому, стараясь как-нить обойти =) не получилось.
В итоге, создаю копию нужного мне виджета и уже его размещаю. Увы, видимо, иначе пока сделать нельзя.
Спасибо =)
И не ругайтесь сильно =) не каждый раз натыкаешься на бажки кутэ =)
Автор: igor_bogomolov 22.4.2009, 20:51
По этой теме тоже баг репорт написал. Походу не приняли. Видимо из-за моего английского, не поняли что я имею ввиду
Автор: igor_bogomolov 25.4.2009, 0:07
Привет всем.
Сообщением выше я писал, ято отправлял баг репорт по данной теме. Во какой ответ я получил.
Цитата
Hi Igor,
Thanks for reporting this issue.
The code seems to show that this particular case has been omitted, which I agree, could lead to a weird behaviour, even though it is definitely not critical.
However, I tried with no luck reproducing the issue, I attached the test I tried with.
If you either get a FAIL! with this test case, or can provide me with a little compilable example that reproduces the problem, I could file a bug report for that problem.
Моих знаний английского не хватает, что бы до конца понять ответ.
Пробовал перевести Google-ом. Они просят что ли написать небольшой тестовый пример воспроизводящий баг?
Заранее спасибо за помощь
Автор: Litkevich Yuriy 25.4.2009, 0:54
Перевод:
Цитата
Привет Игорь,
Спсибо за сообщение об этой проблеме.
Код, как (мне) кажется, показывает, что этот особый случай был опущен (не принят во внимание), с которым я согласен, может привести к неожиданному поведению, даже несмотря на то, что это некритично.
Тем не мение, я пытался безуспешно воспроизвести проблему, я прикрепил тест, который я проводил.
Если выполучите FAIL! во время этого теста, или сможете предоставить мне маленький компилируемый пример, который воспроизводит проблему, я могу подать сообщение об ошибке для этой проблемы.
Автор: igor_bogomolov 25.4.2009, 1:01
Спасибо, Юрий.
Можно еще совет спросить. Я может сейчас, может за выходные, накидаю тестовый примерчик. Как дальше поступить, создать новый баг репорт или ответить на полученное письмо, и там прикрепить тест?
Автор: Litkevich Yuriy 25.4.2009, 2:12
Цитата(igor_bogomolov @ 25.4.2009, 5:01)
или ответить на полученное письмо, и там прикрепить тест?
или, тебя так и просят.
Автор: igor_bogomolov 27.4.2009, 17:02
Вот ответ который я получил
Цитата
Hi Igor,
Thanks for the test. I am not sure yet why I can't reproduce it with my testcase but yours worked. I've created a task for the development team who will look into fixing
this for a future release.
You can track the status of this entry in the Task Tracker with ID 252253.
See:
http://www.qtsoftware.com/developer/task-tracker/index_html?method=entry&id=252253
Из переписки встал следущий вопрос. В первом письме от тех поддержки я получил следущий код для проверки бага
#include <QtTest/QtTest>
#include <QTreeView>
#include <QStandardItemModel>
#include <QLineEdit>
#include <QApplication>
class Test : public QObject{
Q_OBJECT
private slots:
void testSetIndexWidget(){
QLineEdit *lineEdit = new QLineEdit();
QTreeView itemView;
QStandardItemModel model;
itemView.show();
model.appendRow(new QStandardItem("an item"));
itemView.setModel(&model);
itemView.setIndexWidget(model.index(0,0),lineEdit);
QApplication::processEvents();
QVERIFY(itemView.indexWidget(model.index(0,0)));
QCOMPARE(itemView.indexWidget(model.index(0,0)),lineEdit );
itemView.setIndexWidget(model.index(0,0),lineEdit);
QApplication::processEvents();
QVERIFY(itemView.indexWidget(model.index(0,0)));
QCOMPARE(itemView.indexWidget(model.index(0,0)),lineEdit );
}
};
QTEST_MAIN(Test)
#include "test.moc"
CONFIG+=teambuilder
TEMPLATE = app
TARGET = testcase
DEPENDPATH += .
INCLUDEPATH += .
# Input
SOURCES += test.cpp
CONFIG += qt warn_on debug create_prl link_prl
QT += testlib
Внутри
setIndexWidget для
lineEdit у нас вызывается
deleteLater. Далее делается
QApplication::processEvents() для того чтобы deleteLater отработал. Тем не менее удаления не происходит. Я пробовал делать разные тесты, но положительного результата так и не добился. Кто знает в чем проблема? Почему в данном случае deleteLater у нас не отробатывается?
P.S.
Если кому интересно, вот код который я отправил, что бы баг репорт приняли.
#include <QtGui/QApplication>
#include <QtGui/QDialog>
#include <QtGui/QTableWidget>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
#include <QtCore/QTimer>
class MyClass : public QDialog {
Q_OBJECT
private:
QLineEdit *le;
QTableWidget *tw;
public:
MyClass(QWidget *parent = 0) : QDialog(parent) {
tw = new QTableWidget(5, 5);
le = new QLineEdit;
le->setText("lineEdit");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(tw);
setLayout(layout);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), SLOT(test()));
timer->start(1000);
}
public slots:
void test() {
tw->setCellWidget(0,0,le);
}
};
#include "debug/main.moc"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyClass myClass;
myClass.show();
return app.exec();
}
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)