Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > [QT4]: Layout Manager


Автор: Mal Hack 27.7.2007, 20:20
Есть QMainWindow. На нем в Designer'e положены QPushButton & QLineEdit.
Так вот. В Form->Layout поставид "Layout to Grid"
Запускаю приложение. Ничего не меняется. Кнопка висит на прямоугольнике 0,0,600,500 (последние две координаты - приблизительно).
Помогает только setGeometry. Как это через Manager сделать и как правильно, с точки зрения оптимальности и рациональности?

Пробовал создаю свою раскладку (в конструкторе QMainWidget, имплиментацию сам делаю):
Код
    QGridLayout *layout = new QGridLayout; 

    this.layout->addWidget(lineEdit, 0, 0);
    this.layout->addWidget(pushButton, 1, 0);

    this->setLayout(layout);

Ругается, мол у укна уже есть раскладка... Глянул ман. Сказано, мол удалите старую, а вот как - не нашел ;(

Автор: Любитель 27.7.2007, 21:34
Во-первых, что значит точка после this!!!

Во-вторых, как ты ui-файл юзаешь? И в дизаёнере после лейоута ты должен увидеть - как всё будет выглядет smile Ещё для удобства есть пункт превью.

В-третьих, удаление лейоута - тупо по ассистенту: delete myWidget->layout(). Деструктор сделает своё дело smile

Автор: Mal Hack 27.7.2007, 22:52
Точка... Как в примере написано было так и писал smile
А может потом сглючило.

В Десигнере я ворму вижу так, как мне надо и в превью тоже.
Вот деструктур такой попробую.

Автор: Любитель 27.7.2007, 22:56
Цитата(Любитель @  27.7.2007,  21:34 Найти цитируемый пост)
как ты ui-файл юзаешь?


Автор: Mal Hack 28.7.2007, 11:47
Я же вроде написал. В Qt Designer. Перетаскиваю на форму элементы и сохраняю.

Автор: brom 28.7.2007, 12:29
Цитата(Любитель @  27.7.2007,  22:56 Найти цитируемый пост)
Цитата(Любитель @  27.7.2007,  21:34 Найти цитируемый пост)
как ты ui-файл юзаешь?


ui файл перегоняешь в сишный код или икпользуешь "как есть" ?
Покажи как ui подключаешь. Я это сделал так:
Код

 QUiLoader loader;
 QFile file("filtr.ui");
 file.open(QFile::ReadOnly);
 QWidget *formFWidget = loader.load(&file, this);
 file.close();
 QVBoxLayout *Flayout = new QVBoxLayout;
 Flayout->addWidget(formFWidget);
 setLayout(Flayout);

и он взял layuot тот который я формировал в Designer

Автор: powerfox 28.7.2007, 14:20
Цитата(Mal Hack @  27.7.2007,  21:20 Найти цитируемый пост)
    QGridLayout *layout = new QGridLayout; 
    this.layout->addWidget(lineEdit, 0, 0);
    this.layout->addWidget(pushButton, 1, 0);
    this->setLayout(layout);

Так надо делать для QDialog и его производных. Кстати, не должно быть ни "this->", ни "this." просто layout->************.

Цитата(Mal Hack @  27.7.2007,  21:20 Найти цитируемый пост)
Сказано, мол удалите старую, а вот как - не нашел ;( 

Удалять не надо - извращение.

Для MainWindow надо делать так:
Код

QWidget *mainWidget = new QWidget;
QGridLayout *mainLayout = new QGridLayout; 
mainLayout->addWidget(lineEdit, 0, 0);
mainLayout->addWidget(pushButton, 1, 0);
mainWidget->setLayout(mainLayout);
setCentralWidget(mainWidget);
   

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

Автор: Mal Hack 28.7.2007, 21:52
Кажется мне, что косяк в месте работы...
Главный файл программы:
Код
#include <QApplication> 
#include "impl/mainWindow.h"

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    ImplMainWindow *mainWindow = new ImplMainWindow;

    mainWindow->show();
    

    app.exec();
}

Заголовочный файл класса окна приложения. Я создаю свой класс (тут будут все слоты организованы), наследник от QMainWindow и наследник от Ui_mainWindow - класс, создаваемый qmake'ом из .ui файла.
Код
#ifndef MAINWINDOW_H 
#define MAINWINDOW_H
#include <QtGui>
#include "../ui_mainWindow.h"

class QLineEdit;
class QPushButton;

class ImplMainWindow: public QMainWindow,public Ui_mainWindow
{

    Q_OBJECT
    public: 
        ImplMainWindow(QMainWindow *parent = 0);
    private:
        QLineEdit *lineEdit;
        QPushButton *pushButton;
        
};

#endif

Файл реализации (пока только конструктор):
Код
#include <QtGui>
#include "mainWindow.h"

ImplMainWindow::ImplMainWindow(QMainWindow *parent): QMainWindow(parent)
{
    lineEdit = new QLineEdit;
    pushButton = new QPushButton;
    
    lineEdit->setParent(this);
    pushButton->setParent(this);

    pushButton->setGeometry(10,10,50,50);
    
    QGridLayout *layout = new QGridLayout; 

    layout->addWidget(lineEdit, 0, 0);
    layout->addWidget(pushButton, 1, 0);

    this->setLayout(layout);
}


Мне кажется, что я не до конца понимаю, как бы сказать, как правильно в Qt сделать соединение формы и программного кода.
На всякий случай, приведу вывод консоли:
Код
malhack@mh-pc-s5:~/CODING/C++QT/test4$ qmake -project
malhack@mh-pc-s5:~/CODING/C++QT/test4$ qmake test4.pro
malhack@mh-pc-s5:~/CODING/C++QT/test4$ make
g++ -c -pipe -O2 -Wall -W -D_REENTRANT  -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Iimpl -I. -I. -o main.o main.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT  -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Iimpl -I. -I. -o mainWindow.o impl/mainWindow.cpp
/usr/bin/moc-qt4 -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Iimpl -I. -I. impl/mainWindow.h -o moc_mainWindow.cpp
g++ -c -pipe -O2 -Wall -W -D_REENTRANT  -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Iimpl -I. -I. -o moc_mainWindow.o moc_mainWindow.cpp
g++  -o test4 main.o mainWindow.o moc_mainWindow.o    -L/usr/lib -lQtGui -lQtCore -lpthread
malhack@mh-pc-s5:~/CODING/C++QT/test4$ ./test4
QWidget::setLayout: Attempting to add QLayout "" to ImplMainWindow "", which already has a layout

Автор: Любитель 28.7.2007, 22:01
Цитата(powerfox @  28.7.2007,  14:20 Найти цитируемый пост)
Кстати, не должно быть ни "this->", ни "this."

Ну this-> допустимо (здесь в плюсах дело, а не в куте). Но обычно зачем (исключение, скажем, иногда в шаблонах)? 

Цитата(powerfox @  28.7.2007,  14:20 Найти цитируемый пост)
Для MainWindow надо делать так

Цитата(Mal Hack @  27.7.2007,  20:20 Найти цитируемый пост)
в конструкторе QMainWidget, имплиментацию сам делаю

Я так понимаю речь про то, что централ виджет он сам реализовывал.

Цитата(powerfox @  28.7.2007,  14:20 Найти цитируемый пост)
Удалять не надо - извращение.

Цитата(Qt Assistant)

If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

То есть для смены лэйоута - надо удалять. Вопрос в том - зачем его менять здесь. Или вручную ставим, или в дизайнере...

Mal Hack, как я понимаю приложение небольшое - может весь код выложишь?

Автор: Mal Hack 28.7.2007, 22:07
Цитата(Любитель @  28.7.2007,  22:01 Найти цитируемый пост)
Ну this-> допустимо (здесь в плюсах дело, а не в куте). Но обычно зачем (исключение, скажем, иногда в шаблонах)? 

Честное пионерское с this'ами разберусь... Стыдно :( Но плохо я пока знаю когда их можно НЕ писать... НЕ совсем понятна структура программ с Qt.

Цитата(Любитель @  28.7.2007,  22:01 Найти цитируемый пост)
Я так понимаю речь про то, что централ виджет он сам реализовывал.

Если под "централ виджет" ты понимаешь главное окно приложения, то да.

Цитата(Любитель @  28.7.2007,  22:01 Найти цитируемый пост)
Mal Hack, как я понимаю приложение небольшое - может весь код выложишь? 

В предыдущем посте полностью выложил код.

Автор: powerfox 28.7.2007, 22:15
Mal Hack:
1. В ImplMainWindow::ImplMainWindow(QMainWindow *parent) нужно
Код

setupUi(this);


2. Замени код
Цитата(Mal Hack @  28.7.2007,  22:52 Найти цитируемый пост)
    QGridLayout *layout = new QGridLayout; 
    layout->addWidget(lineEdit, 0, 0);
    layout->addWidget(pushButton, 1, 0);
    this->setLayout(layout);

На это
Цитата(powerfox @  28.7.2007,  15:20 Найти цитируемый пост)
QWidget *mainWidget = new QWidget;
QGridLayout *mainLayout = new QGridLayout; 
mainLayout->addWidget(lineEdit, 0, 0);
mainLayout->addWidget(pushButton, 1, 0);
mainWidget->setLayout(mainLayout);
setCentralWidget(mainWidget);

Либо сначала удали существующий Layout и устанавливай свой (тебе выше написали, как).
Код

delete this->layout();  // можно и без this, но в данном случае код будет читабельнее.
// Далее твой код
    QGridLayout *layout = new QGridLayout; 
    layout->addWidget(lineEdit, 0, 0);
    layout->addWidget(pushButton, 1, 0);
    this->setLayout(layout);[/quote]



Цитата(Любитель @  28.7.2007,  23:01 Найти цитируемый пост)
То есть для смены лэйоута - надо удалять.

Я сказал, что:

Цитата(Любитель @  28.7.2007,  23:01 Найти цитируемый пост)
То есть для смены лэйоута - надо удалять.

Зачем так резко с выделением? Я ничего противоречащего этому не писал. Просто это извращение, и в данном случае это соовсем не требуется.

Добавлено через 1 минуту и 26 секунд
Цитата(Mal Hack @  28.7.2007,  23:07 Найти цитируемый пост)
Честное пионерское с this'ами разберусь... Стыдно :( Но плохо я пока знаю когда их можно НЕ писать... НЕ совсем понятна структура программ с Qt.

Тут ничего стыдного нет. Они подчиняются правилам С++. Просто в некоторых местах код читабельнее с ними и следует тогда так и писать (придерживаться стиля, принятого в книге по Qt).

Добавлено через 7 минут и 1 секунду
Цитата(Любитель @  28.7.2007,  23:01 Найти цитируемый пост)
Ну this-> допустимо (здесь в плюсах дело, а не в куте). Но обычно зачем (исключение, скажем, иногда в шаблонах)? 

Исключение не только в шаблонах. this используется, когда функция должна выполнить действие именно над вызвавшим объектом (все действия с/над "статикой". Тут чистый С++, не будем вдаваться в рассуждения. Я выразился резкова-то по поводу this, но у нас не политика, где нужно следить за оттенком, подбирая нужный синоним.

Автор: Любитель 28.7.2007, 22:28
Цитата(powerfox @  28.7.2007,  22:15 Найти цитируемый пост)
Зачем так резко с выделением? Я ничего противоречащего этому не писал. Просто это извращение, и в данном случае это соовсем не требуется.

Ну, блин, надо было подчеркнуть в той же строке во втором предложение вторую часть smile Я не говорил, что ты не прав, я говорил, что как таковое сие не извращение smile

Цитата(powerfox @  28.7.2007,  22:15 Найти цитируемый пост)
1. В ImplMainWindow::ImplMainWindow(QMainWindow *parent) нужно

Больше вообще ничего не нужно, если юзаем дизайнер.

Цитата

lineEdit->setParent(this);
pushButton->setParent(this);

Зачем (даже без дизайнера)? При добавлении в лэйоут парент виджетов поменяется.

Автор: powerfox 28.7.2007, 22:36
Цитата(Любитель @  28.7.2007,  23:28 Найти цитируемый пост)
Зачем (даже без дизайнера)? При добавлении в лэйоут парент виджетов поменяется. 

А если не бобавлять, то можно в конструкторе указать родителя:
Код

lineEdit = new QLineEdit (this);



Цитата(Любитель @  28.7.2007,  23:28 Найти цитируемый пост)
Я не говорил, что ты не прав, я говорил, что как таковое сие не извращение smile

Не пробовал, но вполне можно получить указатель на существующий и туда пихать все кнопки. А извращение потому, что в приложениях, где QMainWindow обычно используют как раз центральный виджет. А setLayout - в небольших формах (на базе QWidget).

Автор: Любитель 28.7.2007, 22:37
Сорри - браузер глюкнуло smile

Добавлено через 3 минуты и 18 секунд
Цитата(powerfox @  28.7.2007,  22:36 Найти цитируемый пост)
Не пробовал, но вполне можно получить указатель на существующий и туда пихать все кнопки.

Речь идёт просто про смену лейоута, а не изменение. Для этого нужно удаление согласно ассистенту.

Цитата(powerfox @  28.7.2007,  22:36 Найти цитируемый пост)
 А извращение потому, что в приложениях, где QMainWindow обычно используют как раз центральный виджет. А setLayout - в небольших формах (на базе QWidget).

Повторюсь, я думал, что сие в коде реализации класса виджета, используемого как централа. И в приципе не только в формах - а также в любых собственных виджетах smile Впрочем всё сие мелочи и не есть суть.

Автор: Mal Hack 28.7.2007, 22:44
Цитата(Любитель @  28.7.2007,  22:28 Найти цитируемый пост)
Зачем (даже без дизайнера)? При добавлении в лэйоут парент виджетов поменяется. 

Если этого не написать, то два элемента открываются в двух разных окнах: test <2>, test <3>.

Я так понимаю, создаваемый виджет, который предложил powerfox "ляжет" на окно QMaonWindow, как основной, а мои виджеты лягут на него. Так? По сути это получается как панель (GroupBox безе legend) в Delphi?

В данном случае не очень хочу создавать дополнительный виджет. Это, имхо, обход проблемы, а не ее решение.
Попробовал так:
Код
#include <QtGui>
#include "mainWindow.h"

ImplMainWindow::ImplMainWindow(QMainWindow *parent): QMainWindow(parent)
{
//    setupUi(this);

    lineEdit = new QLineEdit;
    pushButton = new QPushButton;
    
    lineEdit->setParent(this);
    pushButton->setParent(this);
    
    delete this->layout();

    QGridLayout *layout = new QGridLayout; 

    layout->addWidget(lineEdit, 0, 0);
    layout->addWidget(pushButton, 1, 0);

    this->setLayout(layout);
}

В результате, что с раскомментированным SetupUI что с закомментированным, получаю при запуске: Segmentation fault


При таком варианте, позиционирование не таблице, чтоб красиво - не производится, но по крайней мере элементы уже нормально видны на форме, но все идут из точки 0-0.
Код
#include <QtGui>
#include "mainWindow.h"

ImplMainWindow::ImplMainWindow(QMainWindow *parent): QMainWindow(parent)
{
    lineEdit = new QLineEdit;
    pushButton = new QPushButton;
    
    QGridLayout *layout = new QGridLayout; 

    layout->addWidget(lineEdit, 0, 0);
    layout->addWidget(pushButton, 2, 1);

    this->setLayout(layout);

    lineEdit->show();
    lineEdit->setParent(this);
    
    pushButton->show();
    pushButton->setParent(this);
}


Автор: powerfox 28.7.2007, 23:06
Цитата(Mal Hack @  27.7.2007,  21:20 Найти цитируемый пост)
Так вот. В Form->Layout поставид "Layout to Grid"
Запускаю приложение. Ничего не меняется.

Попробуй просто их выделить, правая кнопка мыши, lay uou, **in a freed.

Кстати, я не вчитался (на код это не влияет), но 
Цитата(Mal Hack @  27.7.2007,  21:20 Найти цитируемый пост)
На нем в Designer'e положены QPushButton & QLineEdit.


Цитата(Mal Hack @  28.7.2007,  22:52 Найти цитируемый пост)
 private:
        QLineEdit *lineEdit;
        QPushButton *pushButton;

Выходит, что ты наследуешь кнопки с дизайнерского классса + создаёшь свои.

Добавлено через 2 минуты и 56 секунд
Цитата(Mal Hack @  28.7.2007,  23:44 Найти цитируемый пост)
    lineEdit = new QLineEdit;
    pushButton = new QPushButton;
    
    lineEdit->setParent(this);
    pushButton->setParent(this);


Цитата(Mal Hack @  28.7.2007,  23:44 Найти цитируемый пост)
В результате, что с раскомментированным SetupUI что с закомментированным, получаю при запуске: Segmentation fault

Ты же определяешь lineEdit и pushButton статическими переменными, а работаешь с ними, как с указателями.
У тебя в описании класса они указатели.
Цитата(Mal Hack @  28.7.2007,  22:52 Найти цитируемый пост)
        QLineEdit *lineEdit;
        QPushButton *pushButton;



Цитата(Mal Hack @  28.7.2007,  23:44 Найти цитируемый пост)
При таком варианте, позиционирование не таблице, чтоб красиво - не производится, но по крайней мере элементы уже нормально видны на форме, но все идут из точки 0-0.


Цитата(Mal Hack @  28.7.2007,  23:44 Найти цитируемый пост)
this->setLayout(layout);

СТранно, что собралось.

Автор: Любитель 28.7.2007, 23:49
Только setupUi - и всё! При пользовании дизайнером.

Цитата(Mal Hack @  28.7.2007,  22:44 Найти цитируемый пост)
Я так понимаю, создаваемый виджет, который предложил powerfox "ляжет" на окно QMaonWindow, как основной, а мои виджеты лягут на него. Так? По сути это получается как панель (GroupBox безе legend) в Delphi?

Почитай концепции мэйн-виндоу в куте. Она состоит из:
1. Меню
2. Тулбары
3. Централ-виджет
4. Докеры

Автор: powerfox 28.7.2007, 23:50
Цитата(Любитель @  29.7.2007,  00:49 Найти цитируемый пост)
Только setupUi - и всё! При пользовании дизайнером.

Я сегодня придирчивый. Ещё можно использовать динамическую загрузку smile

Автор: Любитель 29.7.2007, 00:55
Можно, конечно. Я просто пытаюсь минимальной кровью исправить этот код smile

Автор: powerfox 29.7.2007, 01:37
Цитата(Любитель @  29.7.2007,  01:55 Найти цитируемый пост)
Можно, конечно. Я просто пытаюсь минимальной кровью исправить этот код smile 

Дык, я уже своей кровью всё поправил smile И ты тоже. Автору осталось собрать.

Автор: Mal Hack 29.7.2007, 18:59
Все оказалось даже проще...
Qt начинает радовать меня все больше и бельше.
Итак, результаты:
Файл импдлементации:
Код
#include <QtGui>
#include "mainWindow.h"

ImplMainWindow::ImplMainWindow(QMainWindow *parent): QMainWindow(parent)
{
    setupUi(this);

    

}

Файл заголовка имплементации:
Код
#ifndef MAINWINDOW_H 
#define MAINWINDOW_H
#include <QtGui>
#include "../ui_mainWindow.h"

class QLineEdit;
class QPushButton;

class ImplMainWindow: public QMainWindow,public Ui_mainWindow
{

    Q_OBJECT
    public: 
        ImplMainWindow(QMainWindow *parent = 0);
};

#endif


Помогшим - огромное спасибо.

Автор: powerfox 29.7.2007, 19:55
Цитата(Mal Hack @  29.7.2007,  19:59 Найти цитируемый пост)
class QLineEdit;
class QPushButton;

Лишнее, так как ты не вставляешь эти штуки в свой класс.

Цитата(Mal Hack @  29.7.2007,  19:59 Найти цитируемый пост)
  Q_OBJECT

Лишнее. Так как я не вижу в твоём классе слотов/сигналов.

Автор: Mal Hack 29.7.2007, 21:03
1. Уже удалил.
2. Это пока их нет smile Для простоты smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)