
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.14.88] |
![]() |
|
![]() |
|
|
Здравствуйте!
Использую для изучения проект Majestio из темы Работа с QTCreator начинающего. Немного изменил проект, использую FormLayout (чтобы при изменении размеров формы не разъезжались поля для ввода). Добавил также кнопку, чтобы потом проверять логин и пароль (пока с сигналами и слотами не разобрался). Возник следующий вопрос: как только я добавляю третий HLayout - форма почему-то не появляется, а как только убираю - появляется (в проекте строки с 3 лайоутом закоментированы). Это связано со свойствами FormLayout? Проект прикрепил. У меня пока вопросы очень простые, можно будет их задавать в одной теме, чтобы не засорять ветку форума? Прикреплённый файл ![]() |
Сообщ.
#2
,
|
|
|
Да, для такой формы, для красивого выравнивания - можно использовать лайяуты QGridLayout или QFormLayout. Так как на форме у нас вырисовываются две колонки контролов, то QFormLayout - лучший выбор, ибо QGridLayout тут будет избыточен. Честно говоря мне бы не хотелось комментировать твой код, я лучше покажу как правильно делается. Код немного подчистил и добавил реализацию размещений на базе QFormLayout, а заодно и подключил слот для примера:
dialog.h ![]() ![]() #ifndef DIALOG_H #define DIALOG_H #include <QtWidgets> class Dialog : public QDialog { Q_OBJECT QLineEdit* nameInput; QLineEdit* surnameInput; QLineEdit* passwordInput; QPushButton* authButton; public: Dialog(QWidget* parent = nullptr); ~Dialog(); void SetupWidgetsForm(); public slots: void checkLabels(const QString &text); }; #endif // DIALOG_H dialog.cpp ![]() ![]() #include "dialog.h" Dialog::Dialog(QWidget* parent) : QDialog(parent) { SetupWidgetsForm(); connect(nameInput, &QLineEdit::textChanged, this, &Dialog::checkLabels); connect(surnameInput, &QLineEdit::textChanged, this, &Dialog::checkLabels); connect(passwordInput, &QLineEdit::textChanged, this, &Dialog::checkLabels); } Dialog::~Dialog() { } void Dialog::SetupWidgetsForm() { // Создание QFormLayout QFormLayout* layout = new QFormLayout(); // Поля ввода nameInput = new QLineEdit(); surnameInput = new QLineEdit(); passwordInput = new QLineEdit(); passwordInput->setEchoMode(QLineEdit::Password); // Добавление полей на форму, вернее в макет сперва layout->addRow("Имя:", nameInput); layout->addRow("Фамилия:", surnameInput); layout->addRow("Пароль:", passwordInput); // Установка выравнивания меток по правому краю layout->setLabelAlignment(Qt::AlignRight); // Кнопка Авторизации authButton = new QPushButton(" Авторизация "); authButton->setEnabled(false); // Создание горизонтального макета для кнопки для выравнивания по правому краю QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->addStretch(); // Добавляем растяжение слева buttonLayout->addWidget(authButton); // Добавляем кнопку // Добавление горизонтального макета с кнопкой в основной макет layout->addRow(buttonLayout); setLayout(layout); setWindowTitle("Форма входа"); // Устанавливаем минимальные размеры формы, значение "нуль" означает // "высоту формы взять по минимуму", но чтобы все элементы поместились // Хотя можно было бы вызвать и просто setMinimumWidth(480); setMinimumSize(480,0); } void Dialog::checkLabels([[maybe_unused]] const QString& text) { bool checkEmpty = nameInput->text().isEmpty() || surnameInput->text().isEmpty() || passwordInput->text().isEmpty(); authButton->setEnabled(!checkEmpty); } Изначально кнопка [Авторизация] имеет состояние "не разрешена". В процессе ввода данных в поля ввода вызывается слот Dialog::checkLabels. В нем проверяется заполнение всех полей ввода. И если все заполнены, тогда кнопке авторизации устанавливается состояние "разрешена". |
Сообщ.
#3
,
|
|
|
Спасибо большое за код! Конечно, лучше показывать, как надо, чтобы я мог учиться. Разбирать мой код бессмысленно, пока ничего толкового я изобразить не могу.
|
Сообщ.
#4
,
|
|
|
Здравствуйте!
Хочу попытаться реализовать на QT без дизайнера программу на C#, внешний вид который прикрепил. Иинтерфейс сделан убого, много недостатков, но основные элементы (группу чекбоксов, спинера и др.) хотелось бы иметь в программе на QT). Для начала я хотел бы реализовать первую вкладку на QTabWidget. Правильно ли я понял следующее: 1. На основной форме нужно создать Layout формы. Предполагаю использовать QVBox, поскольку основным элементом интерфейса будет являться QTabWidget. Расширение функциональности программы будет идти путем добавления вкладок. 2. В какой-то из Layout (предполагаю использовать Grid) включить все элементы этой вкладки. 3. Создать QTabWidget с нужными параметрами (размеры и др.). 4. Затем методом addTab(ссылка на Layout с элементами, "Имя ярлыка вкладки") добавить вкладку. 5. Затем добавить в Layout формы созданный QTabWidget. Помогите, пожалуйста, советом и критикой. Прикреплённая картинка
|
Сообщ.
#5
,
|
|
|
Ну в принципе более менее верно. Будет код - покажи.
|
Сообщ.
#6
,
|
|
|
Спасибо за ответ. Как только сделаю - обязательно покажу.
|
Сообщ.
#7
,
|
|
|
Решил сначала попробовать сделать QGroupBox:
![]() ![]() void Dialog::SetupWidgetsForm() { QHBoxLayout *main_layout = new QHBoxLayout(); QGroupBox *grb_chennels = new QGroupBox("Каналы"); QVBoxLayout *grb_chennels_layout = new QVBoxLayout(); for(int i=0; i < 8; i++) { grb_chennels_layout -> addWidget(new QCheckBox(QString::number(i+1))); } grb_chennels -> setLayout(grb_chennels_layout); main_layout -> addWidget(grb_chennels); setLayout(main_layout); setMinimumSize(480,0); } ![]() ![]() QCheckBox *arr_checkbox = new QCheckBox[16]; for(int i=0; i < 16; i++) { arr_checkbox[i] = QCheckBox(QString::number(i+1)); } ![]() ![]() "N:\MyProgramming\qtTestLayout\dialog.cpp:22: error: use of deleted function 'QCheckBox& QCheckBox::operator=(const QCheckBox&)' ..\..\dialog.cpp: In member function 'void Dialog::SetupWidgetsForm()': ..\..\dialog.cpp:22:53: error: use of deleted function 'QCheckBox& QCheckBox::operator=(const QCheckBox&)' 22 | arr_checkbox[i] = QCheckBox(QString::number(i+1)); |
Сообщ.
#8
,
|
|
|
Ну вот смотри, я набросал тебе макет твоей программы.
Прикреплённая картинка
dialog.h ![]() ![]() #ifndef DIALOG_H #define DIALOG_H #include <QtWidgets> class Dialog : public QDialog { Q_OBJECT QTabWidget *TabWidget; QVector<QWidget*> Tabs; QVector<QCheckBox*> Checks; public: Dialog(QWidget* parent = nullptr); ~Dialog(); void SetupWidgetsForm(); }; #endif // DIALOG_H dialog.cpp ![]() ![]() #include "dialog.h" Dialog::Dialog(QWidget* parent) : QDialog(parent) { SetupWidgetsForm(); } Dialog::~Dialog() { } void Dialog::SetupWidgetsForm() { setWindowTitle("Такая программка"); // Создание макета самой формы и сразу его установка QVBoxLayout* layout = new QVBoxLayout; setLayout(layout); setMinimumSize(640,480); // Инициализирование табов и помещение в макет TabWidget = new QTabWidget; for (auto i=0; i<3; i++) Tabs.push_back(new QWidget); TabWidget->addTab(Tabs[0],"Настройка программы"); TabWidget->addTab(Tabs[1],"Графики"); TabWidget->addTab(Tabs[2],"Вывод результатов"); layout->addWidget(TabWidget); // Заполнение таба "Настройка программы" QVBoxLayout *outerLayout = new QVBoxLayout; Tabs[0]->setLayout(outerLayout); QHBoxLayout *upperLayout = new QHBoxLayout; outerLayout->addLayout(upperLayout); QGroupBox *channels = new QGroupBox("Каналы"); upperLayout->addWidget(channels); for (auto i = 0; i < 16; ++i) Checks.push_back(new QCheckBox(QString::number(i+1))); QGridLayout *checkLayout = new QGridLayout; channels->setLayout(checkLayout); for (auto i = 0; i < 16; ++i) checkLayout->addWidget(Checks[i], i % 8, i / 8); QPushButton *filler1 = new QPushButton("Потом"); QPushButton *filler2 = new QPushButton("Потом"); filler1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); filler2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); upperLayout->addWidget(filler1); upperLayout->addWidget(filler2); QPushButton *filler3 = new QPushButton("Потом будет заполняться"); filler3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); outerLayout->addWidget(filler3); } Ну и сразу замечания. Места в макете, которые планируется дальше заполнять, я временно занял кнопками, растянутыми на всю доступную площадь. Когда до этих областей доберешься - вместо вставки кнопки вставляй нужный тебе лайяут, и в него уже добавляй контролы. Что касается чекбоксов - я их поместил в два ряда в QGridLayout. И обрати внимание, что все контролы, которые как-то будут взаимодействовать с пользователем или между собою - нужно объявлять полями класса. Иначе в других методах класса к ним доступа не будет, хотя они будут отображаться и висеть в памяти. Локальные объявки допустимы только для лайяутов. И то, если ты не собираешься в динамике добавлять или удалять контролы. Кстати. Посмотри важное преимущество "ручной" сборки формы. Я однотипные элементы, для удобства, могу собирать в контейнеры (вектора, мапы) и удобно к ним обращаться. В случае же использования дизайнера - каждое поле будет отдельной переменной. Во первых, это загромождает сам класс. А во вторых - если понадобится динамическая перекомпоновка, то используя дизайнер форм, про нее можно смело забыть. |
Сообщ.
#9
,
|
|
|
Спасибо огромное! Я только сейчас стал понимать, почему не следует использовать дизайнер. Все больше нравится QT. Буду дальше разбираться.
|
Сообщ.
#10
,
|
|
|
При создании интерфейса функция SetupWidgetsForm очень сильно разрастается. А можно ли в QT сделать следующее:
- создать в каком-то методе (классе) один элемент интерфейса, например комбобокс; - создать в другом методе (классе) другой элементы интерфейса, например набор спиннеров; - создать набор кнопок для сохранения, загрузки, очистки настроек и т.д. А затем прикрепить их к нужным лайаутам и разместить на форме? Или это мои фантазии и так делать QT не умеет (или это не нужно)? Как сложный интерфейс делают специалисты по QT без использования дизайнера? |
Сообщ.
#11
,
|
|
|
tumanovalex, "сетап" можно конечно разнести на n-методов. Но я бы не советовал такое делать. Лучше будет делать в одном методе - НО код комментировать. Т.е. просто комментариями визуально разделять "шаги". Это конечно дело вкуса. Если такое не нравится - безусловно можно сделать набор методов, а-ля setupCombo, setupSpin, setupButtons и вызывать их последовательно в конструкторе. Но в этом лично я какого-то профита не вижу.
|
Сообщ.
#12
,
|
|
|
Спасибо за ответ. Понятно.
|
Сообщ.
#13
,
|
|
|
tumanovalex, я обычно разделяю "сетап" контроллов и потом сетап коннектов. Как это делать - дело "вкусовщины"!. Можно просто тупо в конструкторе, можно разносить в методы, это дело - предпочтений. Мой подход "Не плодить сущностей без необходимости". По ссылке выше - "математическая часть" =)
|
Сообщ.
#14
,
|
|
|
Понятно. Интерфейс закончу на следующей неделе. Очень понравилось делать интерфейс без редактора. Большое спасибо за совет делать его без дизайнера!
|
Сообщ.
#15
,
|
|
|
В первом приближении сделал интерфейс вкладки "Настройки программы". Также попробовал получить параметры из этой вкладки. Не смог понять, как получить состояние всех чекбоксов в групбоксе "Каналы". Также хотел посоветоваться по поводу сохранения, загрузки и сбросу настроек. В старой программе на C# я сохранял и загружал файлы в виде сsv файлов, чтобы их можно было редактировать в текстовом редакторе. Очень нужны критика, замечания и предложения по интерфейсу программы, поскольку это мой первый опыт проекта на QT. Проект прикрепил.
Прикреплённый файл ![]() |
Сообщ.
#16
,
|
|
|
Ну тут не посмотрел - немного напряг со временем. Чуть позже, если разгребусь. Но сразу советы-аксиомы:
1) Любой вид контрола/виджета - мы всегда добавляем в лайаут родителя 2) В лайаут родителя мы можем добавлять не только контролы, но и дочерние лайауты (это если необходимо создать сложную структуру размещений) 3) Если мы хотим контрол сделать чьи-то родителем, мы должны создать новый лаяут, и установить его в этот контрол. Тогда, добавляя прочие контролы в созданный лайаут, мы фактически добавляем их "в контрол". Это обычно бывает с группирующими контролами. Цитата tumanovalex @ В старой программе на C# я сохранял и загружал файлы в виде сsv файлов CSV - очень древнее, и сейчас не самое хорошее решение. Мои варианты следующие: Оба вышеуказанных формата, и JSON, и SQLite3 - хорошо поддерживаются Qt. |
Сообщ.
#17
,
|
|
|
Цитата Majestio @ Да мне не к спеху, еще много чего нужно освоить. Спасибо за ответ. По-моему мнению, у меня конфигурация очень простая и не объемная. Наверное, пока сгодится QSettings. А дальше будет видно. Ну тут не посмотрел |
Сообщ.
#18
,
|
|
|
Здравствуйте!
Немного изменил проект Dialog Majestio - сделал несколько файлов (архив qtTestLayout.zip). Все нормально работает, элементы управления на форме появляются. Поскольку в программе на C# форма имеет кнопки изменения размеров окна, решил заменить Dialog на MainWindow. Программа компилируется, но элементы управления не создаются, появляется просто пустая форма с заголовком. Отладчик показывает, что при выполнении программы метод SetupWidgets вызывается и операторы в нем выполняются. Помогите, пожалуйста, разобраться, почему так происходит. Проект прикрепил. Прикреплённый файл ![]() Прикреплённый файл ![]() |
Сообщ.
#19
,
|
|
|
tumanovalex, есть два варианта:
1) Ты возвращаешь тип формы как QDialog, и добавляешь необходимые системные иконки путём вызова в конструкторе: ![]() ![]() setWindowFlags(windowFlags() | Qt::WindowMinMaxButtonsHint); Не тестировал, написал навскидку. Лучше все же ознакомится с темой Window Flags 2) Твой вариант с QMainWindow. Тут немного по-другому. Сперва создаётся QWidget самого верхнего уровня. В него собирается всё содержимое окна. Потом этот виджет устанавливается в качестве центрального с помощью setCentralWidget(QWidget *widget) (ссылка). Добавлено Да, еще ... есть разница в показе формы как диалога из main.cpp: ![]() ![]() dialog.exec(); // Модальный режим //или dialog.show(); // Немодальный режим |
Сообщ.
#20
,
|
|
|
А вообще в QtCreator сейчас дизайнером пользоваться можно? Как оно?
ЗЫ Переделывал в 2008г. программы на Дельфи в QTcreator на С++ (перешел на линукс). С дизайнером не получилось справиться. Рисовал окна и контролы, вроде нормально было, а когда что-то изменить надо было, получалось криво. Плюнул и сделал все в рантайме - все стало хорошо. Кстати, часть программ скомпилил в Lazarus - без проблем. |
Сообщ.
#21
,
|
|
|
SergeyIT, в принципе примитивные статические формы в QtCreator'е делать можно. Как говорят на "вкус и цвет" ... Но я по опыту просто не советую. Со временем и простые формы кодировать получается не сильно медленнее, чем "рисовать" в дизайнере. Повторяться не буду, тут уже было обширное обсуждение.
|
Сообщ.
#22
,
|
|
|
Majestio, спасибо, не видел этого обсуждения.
|
![]() |
|
|
Решил использовать для первой вкладки QGridLayout:
![]() ![]() void MainWindow::SetupWidgets() { setWindowTitle("Такая программка"); setMinimumSize(640,480); // Инициализирование табов и помещение в макет TabWidget = new QTabWidget; for (auto i=0; i<3; i++) Tabs.push_back(new QWidget); TabWidget->addTab(Tabs[0],"Настройка программы"); TabWidget->addTab(Tabs[1],"Графики"); TabWidget->addTab(Tabs[2],"Вывод результатов"); setCentralWidget(TabWidget); // Создание лайаута для таба 0 QGridLayout *layTab0 = new QGridLayout; Tabs[0]->setLayout(layTab0); // Создание групбокса "Каналы" QGroupBox *grbChannels = new QGroupBox("Каналы"); for (auto i = 0; i < 16; i++) Checks.push_back(new QCheckBox(QString::number(i+1))); QGridLayout *layCheck = new QGridLayout; grbChannels->setLayout(layCheck); for (int i = 0; i < 16; ++i) layCheck->addWidget (Checks[i], i % 8, i / 8); grbChannels->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); layTab0->addWidget(grbChannels, 0, 0, Qt::AlignLeft); } Прикреплённая картинка
Прикреплённый файл ![]() |
Сообщ.
#24
,
|
|
|
tumanovalex, как мы договаривались ранее - я тебе код не пишу. Но даю наводку ...
Если хочешь элементы управления в твоём гриде "отталкивать" в какую либо сторону (или стороны) - используй addStretch. Читай доки, ищи примеры. |
Сообщ.
#25
,
|
|
|
Получилось с помощью addStretch и setFixedSize:
![]() ![]() grbChannels->setFixedSize(350, 60); ........ grbParamsData->setFixedSize(600, 300); ........ QVBoxLayout *layLower = new QVBoxLayout(); QHBoxLayout *layButtons = new QHBoxLayout(); layButtons->addWidget(grbSettings); layButtons->addWidget(grbAdc); layLower->addLayout(layButtons); layLower->addStretch(0); layTab0->addLayout(layLower, 1, 0, Qt::AlignLeft); Прикреплённый файл ![]() |
Сообщ.
#26
,
|
|
|
tumanovalex, лучше покажи скрин, и на нем стрелками укажи что не нравится, и что куда нужно передвинуть.
|
Сообщ.
#27
,
|
|
|
Цитата tumanovalex @ Не очень понял, почему изменение значений в addStretch не изменяет расположения layLower по отношению к grbParamsData. Дам наводку. Хотя тебе бы было более полезно самому RTFM. Как работает addStretch? Это, считай, "псевдо-виджет", который просто вставляет пустое пространство, которое может раздвигать соседние элементы в лайауте. Простой вариант: есть несколько виджетов, вставленных в лауаут, и один addStretch(1) - он эти элементы раздвинет влево-вправо, или вверх-вниз, в зависимости от типа лайаута Более сложный вариант: есть несколько виджетов, вставленных в лауаут, и есть несколько addStretch, пусть один будет с аргументом 1, а второй 3. Они также будут раздвигать соседние виджеты. Но тут разница в том, что первый addStretch постарается раздвинуть соседние элементы так, чтобы раздвигаемое пространство было примерно равно 1/3 раздвигаемому пространству второго addStretch. Лайфхак! ![]() Для теста таких "вещей" заведи подкаталог с проектами-тестами. Почитал доку, осознал, протестируй в очередном тестовом проекте. Убедись. ...Ну и чтобы закрепить это "действо" - этот каталог назови не Tests, а Testo. В честь моих когда-то таких же "стартов", когда тесты нужно было месить как тесто ![]() |
Сообщ.
#28
,
|
|
|
При запуске программы расстояние между меткой с надписью "Выбран файл для записи результатов" и групбоксами ниже небольшое. При максимизации экрана это расстояние становится большим. Скриншоты и проект без setFixedSize прикрепил. Подскажите, пожалуйста, каким графическим редактором лучше пользоваться для нанесения разноцветных стрелок, овалов и надписей на рисунках. Я пользуюсь XnView, в этой программе мне не удалось сделать стрелки и овалы.
Прикреплённая картинка
Прикреплённая картинка
Прикреплённый файл ![]() Добавлено Хотелось бы также научиться задавать расстояние между групбоксами, например групбоксом "Параметры настройки..." и групбоксами "Сохранение настроек" и "Работа с АЦП". Сейчас они придвинулись вплотную, а хотелось бы установить заданное расстояние. |
Сообщ.
#29
,
|
|
|
Цитата tumanovalex @ Подскажите, пожалуйста, каким графическим редактором лучше пользоваться для нанесения разноцветных стрелок, овалов и надписей на рисунках. Я пользуюсь XnView, в этой программе мне не удалось сделать стрелки и овалы. Для получения скриншотов и быстрого нанесения там же линий, стрелок и прямоугольников лучше всего использовать Lightshot. |
Сообщ.
#30
,
|
|
|
Цитата tumanovalex @ При максимизации экрана это расстояние становится большим. Ну я твой код не буду переписывать. Просто посмотри как работает "расширитель", сделай тестовый пример: ![]() ![]() Dialog::Dialog(QWidget *parent) : QDialog(parent) { QVBoxLayout *L = new QVBoxLayout(); QPushButton *B1 = new QPushButton("111"); QPushButton *B2 = new QPushButton("222"); QPushButton *B3 = new QPushButton("333"); L->addWidget(B1); L->addWidget(B2); L->addWidget(B3); L->addStretch(1); // посмотри как эта строчка влияет - пробуй ее закомментировать и пересобрать, потом сними комменты и опять пересобери setLayout(L); setMinimumSize(640,480); } |
Сообщ.
#31
,
|
|
|
Спасибо, попробую
|