Qt中的topLevelWidgets()到底是哪些widgets?

先看QT文档对topLevelWidgets()的描述:

[static] QWidgetList QApplication::topLevelWidgets()
Returns a list of the top-level widgets (windows) in the application.
Note: Some of the top-level widgets may be hidden, for example a tooltip if no tooltip is currently shown.
Example:

  void showAllHiddenTopLevelWidgets()
  {
      foreach (QWidget *widget, QApplication::topLevelWidgets()) {
          if (widget->isHidden())
              widget->show();
      }
  }

See also allWidgets(), QWidget::isWindow(), and QWidget::isHidden().

该方法返回应用程序中所有的top-level控件(窗口).

那么,究竟哪些控件才是top-level控件?

看代码:

QWidgetList QApplication::topLevelWidgets()
{
    QWidgetList list;
    QWidgetList all = allWidgets();

    for (QWidgetList::ConstIterator it = all.constBegin(), cend = all.constEnd(); it != cend; ++it) {
        QWidget *w = *it;
        if (w->isWindow() && w->windowType() != Qt::Desktop)
            list.append(w);
    }
    return list;
}

typedef QSet<QWidget *> QWidgetSet;
static QWidgetSet *allWidgets;
QWidgetList QApplication::allWidgets()
{
    if (QWidgetPrivate::allWidgets)
        return QWidgetPrivate::allWidgets->toList();
    return QWidgetList();
}

显然,所谓的top-level控件,返回的就是类QWidgetPrivate的静态成员变量allWidgets中那些 “有自己的窗口而且不是桌面窗口" 的控件。

静态成员变量allWidgets里面又有哪些控件?看QWidget的构造函数:

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
    : QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
    QT_TRY {
        d_func()->init(parent, f);
    } QT_CATCH(...) {
        QWidgetExceptionCleaner::cleanup(this, d_func());
        QT_RETHROW;
    }
}

每一个QWidget的构造都会创建一个QWidgetPrivate对象,然后调用QWidgetPrivate的init()方法:


void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
{
    Q_Q(QWidget);
    if (Q_UNLIKELY(!qobject_cast<QApplication *>(QCoreApplication::instance())))
        qFatal("QWidget: Cannot create a QWidget without QApplication");

    Q_ASSERT(allWidgets);
    if (allWidgets)
        allWidgets->insert(q);
        
    .......
}

QWidgetPrivate直接把绑定的QWidget对象(通过Q_Q(QWidget)获取)插入到了allWidgets中。

所以,分析结果就是:

任何QWidget在创建后都会放到allWidgets,而QApplication::topLevelWidgets()返回的就是除了桌面以外所有带窗口的QWidget!!!!

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的示例,展示如何使用C++和Qt实现类似Multisim软件器件的拖拽和连接。注意,这只是一个基本示例,可能需要进行更多的细节调整和优化,以适应您的具体需求。 首先,我们需要创建两个自定义QWidget,一个代表器件,另一个代表连接线。我们将称它们为ComponentWidget和ConnectionWidget。 ```c++ class ComponentWidget : public QWidget { Q_OBJECT public: explicit ComponentWidget(QWidget *parent = nullptr); signals: void componentMoved(ComponentWidget *component, const QPoint &newPosition); protected: void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; private: QPoint m_dragStartPosition; }; class ConnectionWidget : public QWidget { Q_OBJECT public: explicit ConnectionWidget(QWidget *parent = nullptr); void setStartPoint(const QPoint &point); void setEndPoint(const QPoint &point); protected: void paintEvent(QPaintEvent *event) override; private: QPoint m_startPoint; QPoint m_endPoint; }; ``` ComponentWidget实现了拖拽功能,当用户按下鼠标左键时,将记录下鼠标相对于组件窗口左上角的位置。当用户移动鼠标时,将计算出鼠标的新位置并发出componentMoved信号。 ```c++ ComponentWidget::ComponentWidget(QWidget *parent) : QWidget(parent) { setFixedSize(50, 50); setStyleSheet("background-color: beige; border-radius: 10px;"); } void ComponentWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { m_dragStartPosition = event->pos(); } } void ComponentWidget::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { QPoint newPos = mapToParent(event->pos() - m_dragStartPosition); emit componentMoved(this, newPos); } } ``` ConnectionWidget将显示两个端点之间的连接线。我们将使用QPainter来绘制直线。 ```c++ ConnectionWidget::ConnectionWidget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_TransparentForMouseEvents); } void ConnectionWidget::setStartPoint(const QPoint &point) { m_startPoint = point; update(); } void ConnectionWidget::setEndPoint(const QPoint &point) { m_endPoint = point; update(); } void ConnectionWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.drawLine(m_startPoint, m_endPoint); } ``` 现在,我们需要一个主窗口来包含这些自定义QWidget,并实现器件拖拽和连接的逻辑。 ```c++ class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); protected: void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; private slots: void onComponentMoved(ComponentWidget *component, const QPoint &newPosition); private: ComponentWidget *m_component; ConnectionWidget *m_connection; bool m_isConnecting; QPoint m_startPoint; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_isConnecting(false) { m_component = new ComponentWidget(this); m_component->move(50, 50); m_connection = new ConnectionWidget(this); m_connection->setStartPoint(m_component->mapToParent(m_component->rect().center())); connect(m_component, &ComponentWidget::componentMoved, this, &MainWindow::onComponentMoved); } void MainWindow::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { if (m_component->geometry().contains(event->pos())) { m_isConnecting = true; m_startPoint = m_component->mapToParent(m_component->rect().center()); } } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if (m_isConnecting) { m_connection->setEndPoint(event->pos()); } } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if (m_isConnecting) { m_isConnecting = false; for (QWidget *widget : QApplication::topLevelWidgets()) { if (widget == this) { continue; } if (widget->geometry().contains(event->globalPos())) { QPoint endPoint = widget->mapFromGlobal(event->globalPos()); endPoint = widget->mapToParent(endPoint); endPoint = m_connection->parentWidget()->mapFrom(widget, endPoint); m_connection->setEndPoint(endPoint); break; } } m_connection = new ConnectionWidget(this); m_connection->setStartPoint(m_component->mapToParent(m_component->rect().center())); } } void MainWindow::onComponentMoved(ComponentWidget *component, const QPoint &newPosition) { if (m_isConnecting && component == m_component) { m_connection->setStartPoint(newPosition); } } ``` 在这个主窗口,我们创建了一个ComponentWidget和一个ConnectionWidget。我们还添加了3个事件处理程序:鼠标按下,鼠标移动和鼠标释放。当用户按下鼠标左键时,我们检查是否需要开始连接器件。当用户移动鼠标时,我们更新连接器件的终点。当用户释放鼠标左键时,我们检查鼠标在哪个QWidget上,并将连接线的终点设置为该QWidget上的点。我们还在onComponentMoved槽处理组件移动事件,以便在连接器件时更新连接线的起点。 这只是一个简单的示例,您可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值