Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Mindtraveller от Июнь 19, 2007, 19:00



Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Mindtraveller от Июнь 19, 2007, 19:00
Приветствую.

В простой ситуации, почему-то, не могу разобраться с созданием/удалением элементов в QTableWidget.

Ситуация следующая: есть QTableWidget, в нём два столбца. При клике на один из элементов другого контрола, в QTableWidget отображаются соответствующие ему свойства.
Казалось бы, всё элементарно: удалить предыдущие ячейки, создать новые. Вот код:
Код:
void ObjUI::EnlistObjectProperties(const Properties &props, QTableWidget *widget)
{
while (widget->rowCount())
widget->removeRow(widget->rowCount()-1);

for (int i=0; i<props.size(); ++i)
{
widget->insertRow(i);

const Property &p = props[i];

QTableWidgetItem *newItem = new QTableWidgetItem (QString::fromLocal8Bit(p.name.c_str()));
newItem->setFlags(Qt::ItemIsEnabled);
widget->setItem(i, 0, newItem);

newItem = new QTableWidgetItem (QString::fromLocal8Bit(p.Value2String().c_str()));
newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
widget->setItem(i, 1, newItem);
}
}


Так вот, на первой же попытке удалить существующие строки, в строке
      widget->removeRow(widget->rowCount()-1);
выбрасывается исключение.

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


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Emc от Июнь 19, 2007, 20:17
Код:

widget->clear();

несколько проще


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Mindtraveller от Июнь 19, 2007, 23:43
Всё равно исключение... не помогло...


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Racheengel от Июнь 20, 2007, 00:50
widget у тебя инициализирован нормально?


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Mindtraveller от Июнь 20, 2007, 01:11
Да, он создаётся автоматом QT-Дизайнером, после чего uic генерит хедэр, где всё это инициализируется.

Кстати, забавно, на VCL затыков на таких простых вещах не было.
А здесь, простейшие вещи не работают...  :?

Кто работал с QTableWidget, подскажите всё-таки, что я делаю не так?


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: pastor от Июнь 20, 2007, 10:07
Я использовал (и спользую) QTableWidget::clear () и QTableWidget::clearContents(), никаких исключений небыло. имхо, что-то не так у тебя в логике работы программы. Приведи код вызова  clear(), что пишет после падения  и стек вызавов после падения.


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Mindtraveller от Июнь 20, 2007, 11:46
Да, что-то действительно не так... Выдаёт исключение даже вот такой вот простой код:
Код:

dialog->objProps->setRowCount(100);
//в одном из методов идёт вызов
EnlistObjectProperties(..., dialog->objProps);
//...
void ObjUI::EnlistObjectProperties(const Properties &props, QTableWidget *widget)
{
widget->clearContents();
QTableWidgetItem *newItem = new QTableWidgetItem (QString::fromLocal8Bit("***"));
widget->setItem(0, 0, newItem);
}


Так вот, при первом вызове EnlistObjectProperties всё нормально.
При втором вызове, исключение выбрасывается из строки
widget->clearContents();

В режиме отладки сообщение об исключение такое:
Цитировать
User breakpoint called from code at ******

P.S. Версия QT 4.2.2, линковка динамическая; компилятор Intel 8.04; сборка Win32 Debug
P.P.S. При выходе из приложения появляется такое же исключение (user breakpoint) откуда-то изнутри QT. Но это уже другая история, тут бы с этим для начала разобраться.


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Emc от Июнь 20, 2007, 11:54
поставь после widget->clearContents();
проверку rowCount();
похоже чистится всё и ты добавляешь item в пустую таблицу (без строк/столбцов)


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: Mindtraveller от Июнь 20, 2007, 12:43
проверка показала rowCount() == 100

добавлено спустя 42 минуты:

 Я тут подумал над ситуацией, и нашёл некую странность. Поясню.

Есть правило, касающееся разработки программ, состоящих из основного модуля и DLL. Оно состоит в том, что класс должен удаляться в том же модуле, в котором и был создан. Т.е. пары new/delete должны принадлежать либо основному модулю, либо DLL.

А QT мы подключаем как раз при помощи DLL. То есть, получается что QT из своего DLL пытается при очистке таблицы удалить класс элемента таблицы, который я создал в основном коде.
Такое поведение действительно вызывает исключения.
Решается данная проблема путём введения абстрактных классов, как вы знаете.

Я посмотрел исходники реализации QTableWidget. И абстрактные классы там для работы с ячейками не используются:
Код:
class QTableWidget { ... QVector<QTableWidgetItem*> tableItems; ...}
...
void QTableModel::clearContents()
{
    for (int i = 0; i < tableItems.count(); ++i) {
        if (tableItems.at(i)) {
            tableItems.at(i)->model = 0;
            delete tableItems.at(i);
            tableItems[i] = 0;
        }
    }
    reset();
}


Как видите, всё делается напрямую.
Теперь я удивляюсь почему оно вообще работает :)

Вот, например, у меня стоит Win32 Debug и соответствующий memory manager, а QT скомпилирован в Release, да ещё и, например, VC++6 компилятором, а не моим Интеловским.
Значит, когда я у себя делаю new QTableWidgetItem (...) - он регистрируется в одном менеджере памяти (CRT), а внутри кода QT они делают delete его же, но своим менеджером. И всё. Всё грохнулось.
Наверное здесь не поможет даже если выставить Multithreaded Runtime Library


Название: [4.2.*] Проблема при работе с QTableWidget
Отправлено: pastor от Июнь 20, 2007, 14:50
Наваял тестовый примерчик. Все работает. Ничего не падает. Вот основной код:

Код:
Test::Test(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
tableWidget->setColumnCount(2);

connect(pushButton, SIGNAL(clicked()), this, SLOT(slot_1()));
}

void Test::slot_1()
{
tableWidget->clearContents();
tableWidget->setRowCount(0);

for (int i=0; i<100; ++i)
   {
      tableWidget->insertRow(i);

 QTableWidgetItem *newItem = new QTableWidgetItem (QString("Cell (%1:0)").arg(i));
      newItem->setFlags(Qt::ItemIsEnabled);
      tableWidget->setItem(i, 0, newItem);

 newItem = new QTableWidgetItem (QString("Cell (%1:1)").arg(i));
      newItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
      tableWidget->setItem(i, 1, newItem);
   }
}


При нажатии на кнопку pushButton вызываеться слот slot_1. При неоднократном нажатии на эту кнопку, все работает корректно.
Qt 4.2.3, VS2005

ЗЫ: имхо, что-то не так в логике работы программы.