C++ изменяет размер пристыкованного Qt QDockWidget программно?

Я только начал работать над новым проектом C++/Qt. Это будет основанная на MDI IDE с закрепленными виджетами для таких вещей, как дерево файлов, браузер объектов, вывод компилятора и т. Д. Пока что меня беспокоит одна вещь: я не могу понять, как программно сделать QDockWidget меньше. Например, этот фрагмент создает мое нижнее окно дока "Информация о сборке":

m_compilerOutput = new QTextEdit;
m_compilerOutput->setReadOnly(true);
dock = new QDockWidget(tr("Build Information"), this);
dock->setWidget(m_compilerOutput);
addDockWidget(Qt::BottomDockWidgetArea, dock);

При запуске моя программа выглядит следующим образом (имейте в виду, на ранней стадии разработки):

фактический

Тем не менее, я хочу, чтобы это выглядело так:

ожидаемый

Я не могу этого добиться. Справочник Qt на QDockWidget говорит это:

Настраиваемые подсказки размеров, минимальные и максимальные размеры и политики размеров должны быть реализованы в дочернем виджете. QDockWidget будет уважать их, настраивая свои собственные ограничения, чтобы включить фрейм и заголовок. Ограничения размера не должны быть установлены на самом QDockWidget, потому что они изменяются в зависимости от того, закреплен ли он

Теперь это говорит о том, что один из способов сделать это будет подкласс QTextEdit и переопределить sizeHint() метод. Тем не менее, я бы предпочел не делать это только для этой цели, и я не пытался найти это, чтобы быть рабочим решением.

Я пробовал звонить dock->resize(m_compilerOutput->width(), m_compilerOutput->minimumHeight())звонит m_compilerOutput->setSizePolicy() с каждым из его вариантов... Ничто до сих пор не повлияло на размер. Как я уже сказал, я бы предпочел простое решение в несколько строк кода, а не создание подкласса просто для изменения sizeHint(), Все предложения приветствуются.

9 ответов

Решение

Я только что прошел этот же процесс. После попытки слишком много перестановок resize(), adjustSize() и друзья на виджетах док-станции и содержащихся в них виджетах, ни один из которых не работал, в итоге я получил подклассы QListView и добавив, что sizeHint() метод.

Теперь это работает как шарм.

Я сделал это легко: HEADER:

private void setDockSize(QDockWidget *dock, int, int);
  public slots:
  void returnToOldMaxMinSizes();

ИСТОЧНИК:

QSize oldMaxSize, oldMinSize;

void MainWindow::setDockSize(QDockWidget* dock, int setWidth,int setHeight)
{

    oldMaxSize=dock->maximumSize();
    oldMinSize=dock->minimumSize();

  if (setWidth>=0)
    if (dock->width()<setWidth)
        dock->setMinimumWidth(setWidth);
    else dock->setMaximumWidth(setWidth);
  if (setHeight>=0)
    if (dock->height()<setHeight)
        dock->setMinimumHeight(setHeight);
    else dock->setMaximumHeight(setHeight);

    QTimer::singleShot(1, this, SLOT(returnToOldMaxMinSizes()));
}

void MainWindow::returnToOldMaxMinSizes()
{
    ui->dockWidget->setMinimumSize(oldMinSize);
    ui->dockWidget->setMaximumSize(oldMaxSize);
}

Это старый вопрос, но я хотел бы упомянуть, что Qt 5.6 представил функцию QMainWindow::resizeDocks, чтобы справиться с этим.

К сожалению, это не работает для моего варианта использования (перемещение разделителя между двумя QDockWidget, которые были разделены с помощью QMainWindows::splitDockWidget)

Похоже, виджет-док изменяет свой размер до нужного размера, учитывая его дочерний виджет. Из документации QDockWidget (выделено мое):

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

Чтобы изменить размер, необходимо изменить размер дочернего виджета.

РЕДАКТИРОВАТЬ: документация Qt может иногда вводить в заблуждение, когда обсуждаются подсказки размера. Часто это относится к любому виду изменения размера, выполняется ли оно автоматически виджетом или программно.

Вы пробовали звонить resize() на QTextEdit внутри вашего док-виджета? Вы можете также попытаться временно установить максимальный и минимальный размеры виджета до того размера, который вы хотите, а затем восстановить исходные значения.

Вы могли бы сделать это:

Установите максимальную высоту для вашего QTextEdit:

m_compilerOutput = new QTextEdit;
m_compilerOutput->setMaximumHeight(100);

А затем в событии show вашего главного окна установите его обратно в старый размер или что-то высокое:

void MainWindow::showEvent(QShowEvent *)
{
   m_compilerOutput->setMaximumHeight(10000);
}

Это все, что вам нужно.

Тесты с использованием изменения размера на QDockWidget::widget() (т.е. виджет, который QDockWidget управляет) не работает должным образом.

С QDockWidget подкласс (DW), в котором QWidget с QHBoxLayout к которому добавлены два виджета (левая панель и правая панель), для каждого из которых установлена ​​политика размера QSizePolicy::MinimumУ DW обычно видны оба виджета панели. Когда DW расположен в боковой док-станции приложения (QMainWindow) слот для обработки DW dockLocationChanged сигнал скрывает левую панель и изменяет размеры DW->widget() по размеру правой панели. Когда DW программно перемещается в нижнюю область дока, leftPanel становится видимым, и DW заполняет всю ширину главного окна (конечно). Когда DW затем программно перемещается в боковую область дока, левая панель скрывается, а DW изменяет размеры вниз. Это работает как задумано. Однако, если DW перетаскивается из нижней области дока в боковую область дока, хотя левая панель скрыта, а изменение размера применяется, как и раньше, размер DW не изменяется, как это происходит, когда изменение положения выполняется программно. Размер DW можно вручную изменить, перетаскивая ручку сплиттера между DW и центральной областью главного окна. Обратите внимание, что центральная область главного окна QWidget иметь QHBoxLayout с размерами полиции QSizePolicy::Expanding,

призвание adjustSize на главное окно после изменения размера DW не влияет. Это несмотря на то, что ДН переиздан sizeHint вернуть минимальный размер в зависимости от того, видна ли левая панель или нет.

Либо я что-то упускаю в том, как контролировать размер QDockWidget (что, учитывая трудности, которые я имел, понимая все взаимодействия между частями системы управления компоновкой, вполне вероятно), или QMainWindow игнорирует или отменяет инструкции макета, которые ему дают. Внимательное изучение потока событий во время QDockWidget Операции репозиции предполагают последнее: после обработки слота dockLocationChanged Сигнал выполнил свою работу по изменению размера и вернулся в цикл обработки событий. Я вижу, что QMainWindowпосле изменения положения пользователя применяет дополнительные операции изменения размера QDockWidget тем самым уничтожая логику приложения, которая пытается контролировать размер дока. Что-то не так в QMainWindow....

Если dockWidgets закреплены, размеры контролируются их родителем. В таких случаях вы можете использовать QMainWindow::resizeDocks функция.

Если плавающий, размеры определяются их детей.Изменение размера детей для достижения вашей цели.

Проблема изменения размера док-виджетов, когда MainWindow развернута, описана в QTBUG-16252 ( https://bugreports.qt.io/browse/QTBUG-16252)

Я нашел другой обходной путь. У меня работает на QT 5.4.1 minGW на Windows7. Похоже, что некоторые операции восстановления состояния виджета тесно связаны с циклом событий QApplication.

Размеры DockWidget восстанавливаются корректно ТОЛЬКО при соблюдении следующих условий:

  1. restoreGeometry () вызывается ДО входа в QApplication::exec() (например, в конструкторе вашего класса MainWindow)

  2. restoreState () вызывается ПОСЛЕ exec () (например, через QTimer)

Вот мой код:

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

    //...

    MainWindow mainWindow;
    mainWindow.show();

    return application.exec();
}

MainWindow::MainWindow(...) 
{
    ui->setupUi(this);

    //...
    QTimer* nt = new QTimer(this);

    nt->setSingleShot(true);
    nt->setInterval( 100 );

    connect(nt, SIGNAL(timeout()), SLOT(restoreWidgetSettings()));
    nt->connect(nt, SIGNAL(timeout()), SLOT(deleteLater()));

    nt->start();

    restoreWidgetSettings(true);
}

void MainWindow::restoreWidgetSettings(bool geometryOnly) {

    //...
    QByteArray geometry = getSettings();

    restoreGeometry(geometry);

    if(geometryOnly)
        return;

    //... //create dock widgets here

    restoreState(mainWindowState);

}
Другие вопросы по тегам