Qt

Динамическое создание виджетов Qt. QGridLayout

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

Задача такая же: Есть объект QGroupBox groupBox, в него надо запихнуть виджеты (labels & lineEdits) в QGridLayout лэйауте. Данные берутся из запроса (он представлен в сообщении по ссылке выше).

Более универсальный способ будет выглядеть так:

if(ui->groupBox->layout()) {
	QLayoutItem *child;
    while ((child = ui->groupBox->layout()->takeAt(0)) != 0) {
    	delete child->widget();
        delete child;
    }
    delete ui->groupBox->layout();
}
QGridLayout *layout = new QGridLayout(ui->groupBox);
ui->groupBox->setLayout(layout);
int pos = 0; //устанавливаем позицию расположения виджетов в 0
int colsCount = 2; //Количество колонок в лэйауте
while (query.next()) { //берем результаты запроса
	QLabel *newLabel = new QLabel(this);
    newLabel->setText(query.value("caption").toString()+":");
    newLabel->setObjectName("label_"+query.value("name_").toString());
    layout->addWidget(newLabel,pos/colsCount,pos%colsCount);
    pos++; //сдвигаемся

    QLineEdit *newEdit = new QLineEdit(this);
    newEdit->setObjectName(query.value("name_").toString());
    layout->addWidget(newEdit,pos/colsCount,pos%colsCount);
    lineEdits.push_back(newEdit);
    pos++;
}

В данном случае мне необходимо было разместить объекты в бокс с двумя колонками. Поэтому colsCount = 2. Если их должно быть больше, то значение переменной нужно поменять. Очищение лэйаута позволяет при изменении результатов запроса все очистить и нарисовать все в соответствии с актуальными данными.

Qt, Базы данных

Qt. Динамическое создание виджетов на форме

Динамическое создание виджетов на форме может помочь, когда расположение и/или видимость виджетов подпадает под какие-то условия. Приведу пример. Допустим, в базе данных есть некая таблица, в которой хранятся настройки видимости, подписи, id наименований колонок основных таблиц базы, где хранятся важные данные:

CREATE TABLE table_settings
(
id serial NOT NULL,
table_id integer NOT NULL,
column_id integer,
visible boolean NOT NULL DEFAULT true,
caption character varying(50),
name_ character varying(50),
CONSTRAINT table_settings_pkey PRIMARY KEY (id),
CONSTRAINT table_settings_table_id_fkey FOREIGN KEY (table_id)
REFERENCES table_names (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)

где

  • id — ID записи п/п
  • table_id — id таблицы, о колонках которой хранится информация
  • visible — должна ли быть данная колонка видна
  • caption — название колонки, которое задается пользователем
  • name_ — наименование колонки, которое задается при создании таблицы
CREATE TABLE table_names
(
id serial NOT NULL,
name_ character varying NOT NULL,
CONSTRAINT table_names_pkey PRIMARY KEY (id),
CONSTRAINT table_names_name__key UNIQUE (name_)
)

А это, собственно, та таблица, где хранятся наименования таблиц, для которых нам надо выставить некие настройки.

Для динамического создания виджетов (пусть в нашем примере это будут виджеты классов QLabel и QLineEdit — подпись и поле ввода) на форме разместим объект QGridLayout, куда мы будем «пихать» виджеты. Я еще делаю такой трюк: помещаю в layout объекты в ряд в таком количестве, как хочу видеть результат:

Динамическое создание виджетов на форме в Qt

Далее эти два виджета делаю невидимыми:

ui->label->setVisible(false);
ui->lineEdit->setVisible(false);

Для того, чтобы не просто разместить виджеты на форме, но и потом брать из них информацию для наших нужд, объявим в отделе private класса формы объект класса QVector<QLineEdit*> lineEdits.

Теперь приступим непосредственно к динамическому созданию виджетов.

QSqlQuery query;
//произведем выборку необходимых значений из базы данных
if (!query.exec(QString("select column_id, caption, name_, visible from table_settings "
"where "
"table_id = (select id from table_names where "
"name_ = 'products') "
"order by column_id")))
qDebug() << query.lastError().text(); 
while (query.next()) { 
	QLabel *newLabel = new QLabel(this); //пользовательское наименование колонки newLabel->setText(query.value(1).toString()+":");
	newLabel->setObjectName("label"+query.value(2).toString());
	//видимый в зависимости от значения visible в результатах запроса
	newLabel->setVisible(query.value(3).toBool());
	//размещаем в layout
	ui->widgetsLayout->addWidget(newLabel); //QGridLayout
	QLineEdit *newEdit = new QLineEdit(this);
	newEdit->setObjectName(query.value(2).toString());
	newEdit->setVisible(query.value(3).toBool());
	ui->widgetsLayout->addWidget(newEdit);
	//добавляем в вектор
	lineEdits.push_back(newEdit);
}
//подстройка размера формы в зависимости от расположенных на ней виджетов
this->resize(this->sizeHint());

Динамическое создание виджетов на форме в Qt

Чтобы обратится к отдельному объекту в векторе, достаточно указать его индекс:

for (int i = 0; i < lineEdits.size(); ++i)
	qDebug() << lineEdits[i]->objectName() << " - " << lineEdits[i]->text();

Более элегантная и универсальная версия этого метода представлена здесь: Динамическое создание виджетов Qt. QGridLayout