【问题标题】:QGridLayout issue with inserting widgets插入小部件的 QGridLayout 问题
【发布时间】:2011-10-28 16:46:29
【问题描述】:

(使用 Qt 4.6.3、x64、linux)

我正在测试如何将小部件正确插入到现有的QGridLayout 中,该QGridLayout 充满了各种小部件。一个分解的人为案例如下:

QApplication app(argc,argv);
QWidget      w;
QGridLayout* gl     = new QGridLayout(&w);
QLabel*      label  = new QLabel("Image Size:");
QLineEdit*   wedit  = new QLineEdit("100");
QLabel*      xlabel = new QLabel("x");

wedit->setAlignment(Qt::AlignRight);
gl->addWidget(label);
gl->addWidget(xlabel, 0, 1, 1, 1);
gl->addWidget(wedit,  0, gl->columnCount());

这会创建以下小部件:

.

假设有一个如上所述的现有 QGridLayout,但没有“x”标签,并且我希望将其插入到布局中,切换后两个 addWidget 行可能看起来有效,即:

\\ same as above
gl->addWidget(label);
gl->addWidget(wedit,  0, gl->columnCount());
gl->addWidget(xlabel, 0, 1, 1, 1);

但是,这会创建以下内容:

这之后的gl->columnCount() 仍然是 2,因为 x-label 和 QLineEdit 都在填充同一个单元格。基于这些知识,下面的代码产生了最初的预期结果:

gl->addWidget(label);
gl->addWidget(wedit,  0, 2); // note: specified column 2, columnCount() is now 3
gl->addWidget(xlabel, 0, 1, 1, 1);

虽然这不是特别有用,因为有问题的原始布局在构建时并没有考虑到后来的布局。

由于 addWidget 允许指定单元格位置以及行/列跨度,Qt 不会自动替换布局中的现有小部件似乎很奇怪。有没有人建议我如何克服这个问题?我认为可以重新创建一个 QGridLayout 并将原始的子级复制到其中,注意在正确的位置插入附加的小部件。然而,这很丑陋,并且容易受到 Qt 版本问题的影响(因为我想修改内置小部件)。

编辑

我意识到我正在假设以 QHBoxLayout 的方式思考,其中插入小部件是唯一可以理解的,而在 QGridLayout 中,情况并非如此 (?)。

我可以澄清一下,我最终想修改QFileDialog::getSaveFileName,方法是在下面两行(即“文件和名称:”上方)的正上方插入一个小部件(类似于上面显示的小部件)。

谢谢

【问题讨论】:

  • 如果有办法改变 QGridLayout 中子部件的行和列,也许可以制作一个函数,接收 rowIndex,然后将每个子部件的行移入行 rowIndex 和更高(即进一步向下)。
  • QFileDialog::*,我相信,如果可用,请使用本机文件对话框。所以我认为你不能使用 Qt 修改他们的布局。
  • 我实际上已经找到了解决问题的方法,所以我相信这是可能的。我仍然对最初的重点子小部件有一些小问题。当我整理出这些怪癖并使其可供审查时,我会发布一个解决方案。

标签: c++ qt user-interface layout


【解决方案1】:

切换后两行addWidget 无效。对于以下代码:

gl->addWidget(label);
gl->addWidget(wedit,  0, gl->columnCount());
gl->addWidget(xlabel, 0, 1, 1, 1);

addWidget() 调用的参数在添加小部件之前进行评估。因此,gl->columnCount() 在第二次调用时计算结果为 1 而不是 2,因为仍然必须创建列。您实际上是将两个小部件添加到第一列。

【讨论】:

  • 我给出的例子是一个人为的案例,有点不切实际。事先将小部件放在单元格中不是一种选择。如果我的帖子中没有更清楚地说明这一点,我深表歉意。我想做的是将一个小部件插入一个已经存在的(不是由我创建的)QGridLayout 的单元格中。这将需要在 QGridLayout 中重新分配受影响的子小部件。
  • 编辑:重新定位,而不是重新分配。
【解决方案2】:

一个可能的解决方案是重新添加应该重新定位的小部件。 IE。

QLayoutItem* x01 = gl->itemAtPosition(0,1);
gl->addWidget(x01->widget(), 0, 2);
gl->addWidget(xlabel, 0, 1, 1, 1);

现在,这不是特别漂亮,也不是很容易维护,因为新版本的 Qt 可能会更改原始小部件,并且盲目地挑选和重新定位子部件并不是那么聪明。下面的真实例子(我真正想解决的那个)是改变 Qt 的“另存为”对话框窗口,它使用 QFileDialog::getSaveFileName 显示。

class ImageFileDialog : public QFileDialog {
public:
  ImageFileDialog(QWidget* parent);
  ~ImageFileDialog();
  QString getFileName() const;
  QSize getImageSize() const;
  QDialog::DialogCode exec(); // Overriden

protected:
  void showEvent(QShowEvent* event); // Overriden

private:
  QString    fileName_;
  QSize      imageSize_;
  QLineEdit* widthLineEdit_;
  QLineEdit* heightLineEdit_;
};

在源代码中(仅显示构造函数、焦点处理和执行):

ImageFileDialog::ImageFileDialog(QWidget* parent)
  : fileName_(""),
    imageSize_(0,0),
    widthLineEdit_(0),
    heightLineEdit_(0)
{
  setAcceptMode(QFileDialog::AcceptSave);
  setFileMode(QFileDialog::AnyFile);
  setConfirmOverwrite(true);

  QGridLayout* mainLayout = dynamic_cast<QGridLayout*>(layout());
  assert(mainLayout->columnCount() == 3);
  assert(mainLayout->rowCount()    == 4);

  QWidget*     container      = new QWidget();
  QGridLayout* glayout        = new QGridLayout();
  QLabel*      imageSizeLabel = new QLabel("Image Size:");
  widthLineEdit_              = new QLineEdit("400");
  heightLineEdit_             = new QLineEdit("300");
  widthLineEdit_->setAlignment(Qt::AlignRight);
  heightLineEdit_->setAlignment(Qt::AlignRight);

  container->setLayout(glayout);
  glayout->setAlignment(Qt::AlignLeft);
  glayout->addWidget(widthLineEdit_);
  glayout->addWidget(new QLabel("x"), 0, 1);
  glayout->addWidget(heightLineEdit_, 0, 2);
  glayout->addWidget(new QLabel("[pixels]"), 0, 3);
  glayout->addItem(new QSpacerItem(250, 0), 0, 4);
  glayout->setContentsMargins(0,0,0,0); // Removes unwanted spacing

  // Shifting relevant child widgets one row down.
  int rowCount = mainLayout->rowCount();
  QLayoutItem* x00 = mainLayout->itemAtPosition(mainLayout->rowCount()-2,0);
  QLayoutItem* x10 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,0);
  QLayoutItem* x01 = mainLayout->itemAtPosition(mainLayout->rowCount()-2,1);
  QLayoutItem* x11 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,1);
  QLayoutItem* x02 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,2);
  assert(x00);   assert(x01);   assert(x10);   assert(x11);   assert(x02);

  mainLayout->addWidget(x00->widget(), rowCount-1, 0, 1, 1);
  mainLayout->addWidget(x10->widget(), rowCount,   0, 1, 1);
  mainLayout->addWidget(x01->widget(), rowCount-1, 1, 1, 1);
  mainLayout->addWidget(x11->widget(), rowCount,   1, 1, 1);
  mainLayout->addWidget(x02->widget(), rowCount-1, 2, 2, 1);

  // Adding the widgets in the now empty row.
  rowCount        = mainLayout->rowCount();
  mainLayout->addWidget(imageSizeLabel, rowCount-3, 0, 1, 1 );
  mainLayout->addWidget(container,      rowCount-3, 1, 1, 1);

  // Setting the proper tab-order
  QLayoutItem* tmp  = mainLayout->itemAtPosition(mainLayout->rowCount()-2,1);
  QLayoutItem* tmp2 = mainLayout->itemAtPosition(mainLayout->rowCount()-1,1);
  assert(tmp); assert(tmp2);
  QWidget::setTabOrder(heightLineEdit_      , tmp->widget());
  QWidget::setTabOrder(tmp->widget(), tmp2->widget());
}

// Makes sure the right widget is in focus
void ImageFileDialog::showEvent(QShowEvent* event)
{
  widthLineEdit_->setFocus(Qt::OtherFocusReason);
}

// Called to create the widget
QDialog::DialogCode ImageFileDialog::exec()
{
  if (QFileDialog::exec() == QDialog::Rejected)
    return QDialog::Rejected;
  // The code that processes the widget form and stores results for later calls to
  // getImageSize()
  return QDialog:Accepted;
}

其中,例如使用

ImageFileDialog* dialog = new ImageFileDialog(&w);
dialog->exec();

创建以下小部件:


欢迎评论和更好地做到这一点,或者为什么这是完全错误的:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 2020-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多