相对于彼此定位2个QDialog形式

时间:2017-02-03 08:35:00

标签: qt

我创建了2个QDialogs表单,D1和D2。如何使D1和D2彼此保持恒定距离(如果我移动D1,D2也会移动,反之亦然)?

2 个答案:

答案 0 :(得分:1)

我认为它最终会有点单调乏味,但您可能尝试的一件事就是使用窗口掩码让极简主义容器成为两个对话框。所以......就像......

class minimalist_container: public QWidget {
  using super = QWidget;
public:
  explicit minimalist_container (QWidget *parent = nullptr)
    : super(parent)
    {}
protected:
  virtual void resizeEvent (QResizeEvent *event) override
    {

      /*
       * Start with an empty mask.
       */
      QRegion mask;

      /*
       * Now loop though the children and add a region to
       * the mask for each child based on its geometry.
       */
      for (const auto *obj: children()) {
        if (const auto *child = dynamic_cast<const QWidget *>(obj)) {
          mask += child->geometry();
        }
      }
      setMask(mask);
      super::resizeEvent(event);
    }
};

然后你可以用通常的方式添加布局和子项,但父本身应该基本上是不可见的......

minimalist_container minimalist_container;
auto *minimalist_container_layout = new QHBoxLayout;
minimalist_container_layout->addWidget(new QColorDialog);
minimalist_container_layout->addStretch(1);
minimalist_container_layout->addWidget(new QFontDialog);
minimalist_container.setLayout(minimalist_container_layout);
minimalist_container.show();

上面的代码链接蒙版的父窗口小部件中的所有子项,以便它们在视觉上看起来不同但在移动父项时一起移动。

然而,有几个小问题。默认情况下,父级的标题栏是唯一可见的,而我认为您真正想要的是父级标题栏是唯一一个不可见的人。它当然可以通过设置窗口标志和/或配置窗口管理器来隐藏,但是您可能必须编写代码来处理通常的移动,调整大小等功能。

所以,正如我所说的那样......乏味,但它确实可行。

答案 1 :(得分:0)

您可以安装事件过滤器来监视源窗口的移动/调整大小,并将更改传播到目标窗口。在OS X上,您还需要按下非客户区按钮,因为在窗口移动时不会发送窗口移动事件,但只有在它停止一小段时间后才会发送。

我将传播方向作为练习留给读者:)

// https://github.com/KubaO/stackoverflown/tree/master/questions/win-move-track-42019943
#include <QtWidgets>

class WindowOffset : public QObject {
   Q_OBJECT
   QPoint m_offset, m_ref;
   QPointer<QWidget> m_src, m_dst;
   void adjust(QEvent * event, const QPoint & delta = QPoint{}) {
      qDebug() << "ADJUST" << delta << event;
      m_dst->move(m_src->geometry().topRight() + m_offset + delta);
   }
protected:
   bool eventFilter(QObject *watched, QEvent *event) override {
#ifdef Q_OS_OSX
      if (watched == m_src.data()) {
         if (event->type() == QEvent::NonClientAreaMouseButtonPress) {
            m_ref = QCursor::pos();
            qDebug() << "ACQ" << m_ref << event;
         }
         else if (event->type() == QEvent::NonClientAreaMouseMove &&
                  static_cast<QMouseEvent*>(event)->buttons() == Qt::LeftButton) {
            auto delta = QCursor::pos() - m_ref;
            adjust(event, delta);
         }
      }
#endif
      if ((watched == m_src.data() &&
                (event->type() == QEvent::Move || event->type() == QEvent::Resize)) ||
               (watched == m_dst.data() && event->type() == QEvent::Show)) {
         if (event->type() == QEvent::Move)
            m_ref = QCursor::pos();
         adjust(event);
      }
      return false;
   }
public:
   WindowOffset(const QPoint & offset, QObject * parent = nullptr) :
      QObject{parent},
      m_offset{offset}
   {}
   WindowOffset(QWidget * src, QWidget * dst, const QPoint & offset, QObject * parent = nullptr) :
      WindowOffset{offset, parent}
   {
      src->installEventFilter(this);
      dst->installEventFilter(this);
      m_src = src;
      m_dst = dst;
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QLabel d1{"Source"}, d2{"Target"};
   WindowOffset offset{&d1, &d2, {200, 50}};
   for (auto d : {&d1, &d2}) {
      d->setMinimumSize(300,100);
      d->show();
   }
   return app.exec();
}

#include "main.moc"