在没有阴影的Qt中创建一个弹出窗口

时间:2009-06-29 22:05:58

标签: qt popup popupwindow

我正在使用Qt 4.5开发一个应用程序(在Windows Vista下,但希望它是跨平台的)。我正在使用C ++

我想创建一个包含QLineEdit小部件的弹出窗口,其功能是当用户与QLineEdit小部件交互时,弹出窗口未激活(主应用程序窗口保持活动状态)。

使用Qt :: Popup创建窗口(窗口小部件) Qt :: Window标志给了我我想要的东西,除了我不想要它提供的3D阴影边框效果。我想要一个无边框的窗户。请注意,Qt :: FramelessWindowHint标志不能实现此目的。

有人有任何线索吗?

进一步说明:下面是一个简单的测试应用程序的snippit,它创建一个带有按钮的窗口。按下按钮时,会显示一个弹出窗口,用户可以键入QLineEdit框。当用户执行此操作时,主窗口仍保持激活状态:

http://howlettresearch.com/popup_img_1.png

但是,请注意弹出窗口上的阴影边框(我无法摆脱它)。

相比之下,在注释掉的行中创建窗口允许在没有阴影的情况下创建弹出样式窗口,但是当用户在弹出窗口中单击QLineEdit时,主窗口不再处于活动状态。您可以判断,因为主窗口上的阴影已更改。

http://howlettresearch.com/popup_img_2.png

我真的在一个弹出窗口之后,就好像它是主窗口的一部分。作为旁注,弹出窗口在外面点击时消失了,但这几乎是我想要的行为,我可以使用它和grabMouse等来做我想要的......只要我能摆脱那个阴影!

PopupTest::PopupTest(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    QPushButton* pb = new QPushButton("test button");
    setCentralWidget(pb);
    QObject::connect(pb, SIGNAL(clicked()), this, SLOT(handleClick()));
}

void PopupTest::handleClick()
{
    //QFrame* popup1 = new QFrame(this, Qt::Tool | Qt::Window | Qt::FramelessWindowHint);
    QFrame* popup1 = new QFrame(this, Qt::Popup | Qt::Window );
    popup1->resize(150,100);
    QLineEdit *tmpE = new QLineEdit( popup1 );
    connect( tmpE, SIGNAL( returnPressed() ), popup1, SLOT( hide() ) );
    tmpE->setGeometry(10,10, 130, 30);
    tmpE->setFocus();
    popup1->show();
}

PopupTest::~PopupTest()
{

}

3 个答案:

答案 0 :(得分:6)

我找到了我之前发布的问题的解决方案。

首先,可以通过使用标记QWidgetQt::Window | Qt::FramelessWindowHint派生来创建弹出窗口小部件。我实际上攻击qwidget_win.cpp以确保我的窗口具有与WPF提供的Popup控件相同的样式和扩展样式(分别为0x96000000和0x08000088),这是使用Spy ++确定的,但是我不认为这应该重要。

设置窗口样式不能解决Window激活问题。这样做的关键是拦截通知主窗口它的非客户区域的Windows消息应该更新(WM_NCACTIVATE消息)。这可以通过提供QApplication::winEventFilter(MSG* msg, long* result)的自定义实现来完成。

不幸的是,仅仅吃掉WM_ NCACTIVATE消息是不够的,因为它似乎会阻止WM_ACTIVATE和其他消息被发送到弹出窗口。为了解决这个问题,我有一个概念验证工作,我在winEventFilter捕获了适当的WM_NCACTIVATE消息后生成所需的Windows消息。

从这里开始,有一些细节可以确保它是健壮的(拦截WM_ACTIVATEAPP会浮现在脑海中),然后将其包装成一些好的和可重用的东西。

所有这些都是特定于Windows的,有趣的是看看Linux下是否存在问题。

这一切都有点痛苦。希望我没有错过任何明显的东西......

答案 1 :(得分:4)

尝试下面这个奇怪的代码(在Qt v5。*上测试):

//BasePopup.h
#ifndef BASEPOPUP_H
#define BASEPOPUP_H
#include <QFrame>

class BasePopup : public QFrame
{
    Q_OBJECT
public:
    explicit BasePopup(QWidget* parent = nullptr);
};

#endif // BASEPOPUP_H


//BasePopup.cpp
#include "BasePopup.h"

BasePopup::BasePopup(QWidget *parent)
    : QFrame(parent, Qt::Window | Qt::FramelessWindowHint)
{
    /*setAttribute(Qt::WA_TranslucentBackground);*/ /* if need transparent background; 
    set this attribute in another place create window with black background */
    show();       // must be, if not system shadow occur :) I don't know why
    setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
    show();
    //---------------------- 
    //yours code here 
    //----------------------
}

仅适用于此序列方法调用。如果改变了一些东西,我们就会弹出阴影。 (魔术:))))

修改

我在枚举Qt::NoDropShadowWindowHint中找到了这个标志Qt::WindowFlags(Qt v5.3)。 出现在Qt v5的一个版本中。*。 使用上面的这个标志代码必须看起来像这样。

//BasePopup.cpp
#include "BasePopup.h"

BasePopup::BasePopup(QWidget *parent)
    : QFrame(parent, Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint)
{
    //---------------------- 
    //yours code here 
    //----------------------
}

我还没有测试过,但我认为它必须有效。

答案 2 :(得分:2)

我认为您看到的阴影与您正在使用的Windows主题有关。我在这里使用Windows经典主题,我没有看到任何阴影:)

无论如何,如果将QLineEdit的textChanged()SIGNAL连接到恢复主窗口焦点的自定义操作,该怎么办? 类似的东西:

void PopupTest::handleClick()
{
   QFrame* popup1 = new QFrame(this, Qt::Tool | Qt::Window | Qt::FramelessWindowHint);
   popup1->resize(150,100);
   QLineEdit *tmpE = new QLineEdit( popup1 );
   connect( tmpE, SIGNAL( returnPressed() ), popup1, SLOT( hide() ) );
   connect( tmpE, SIGNAL( textChanged(const QString&)), this, SLOT( setActive() ) );
   tmpE->setGeometry(10,10, 130, 30);
   tmpE->setFocus();
   popup1->show();
}

void MainWindow::setActive()
{
   this->activateWindow();
}

您必须创建一个名为setActive()的插槽,并且还应该将QLineEdit放入类头中,以便从setActive()函数中执行以下操作:

tmpE->setFocus();

还要重点关注QLineEdit。