在不使用阴影的情况下在Qt中创建一个弹出窗口

7
我正在使用Qt 4.5(在Windows Vista下,但希望它是跨平台的)开发一个应用程序。我正在使用C ++。
我想创建一个弹出窗口,其中包含一个QLineEdit小部件,当用户与QLineEdit小部件交互时,弹出窗口不会被激活(主应用程序窗口保持活动状态)。
使用Qt :: Popup | Qt :: Window标志创建具有所需效果的窗口(小部件),但我不想要提供的3D阴影边框效果。我想要一个无边框的窗口。请注意,Qt :: FramelessWindowHint标志不能实现此目的。
有人有什么线索吗?
进一步说明:下面是一个简单的测试应用程序中的代码片段,它创建了一个带有按钮的窗口。当按下按钮时,将显示一个弹出窗口,用户可以在其中键入内容。当用户这样做时,主窗口保持激活状态:

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()
{

}

提供您所拥有和所需的截图将会很有帮助。 - shoosh
1
顶层窗口小部件的阴影是Windows根据主题绘制的,与Qt无关。 - Ariya Hidayat
3个回答

6
我解决了我之前发布的问题。
首先,可以通过从QWidget派生并使用标志Qt::Window | Qt::FramelessWindowHint来创建一个弹出窗口小部件。我实际上是通过修改qwidget_win.cpp来确保我的窗口具有与WPF提供的Popup控件相同的样式和扩展样式(分别为0x96000000和0x08000088),这是使用Spy ++确定的,但我认为这不应该有关系。
设置窗口样式无法解决窗口激活问题。解决此问题的关键在于拦截通知主窗口其非客户端区域应更新的Windows消息(WM_NCACTIVATE消息)。这可以通过提供QApplication::winEventFilter(MSG* msg,long* result)的自定义实现来完成。
不幸的是,简单地吃掉非活动的WM_ NCACTIVATE消息是不够的,因为它似乎会阻止发送WM_ACTIVATE和其他生成的消息到弹出窗口。为了解决这个问题,我有一个概念验证正在工作,在winEventFilter中捕获适当的WM_NCACTIVATE消息后,我生成所需的Windows消息。
从这里开始,还有一些细节需要解决,以确保它的稳健性(拦截WM_ACTIVATEAPP),然后将其包装成漂亮且可重用的东西。
当然,所有这些都是针对Windows的,有趣的是看看在Linux下是否存在问题。
所有这些都有点麻烦。希望我没有错过什么明显的东西...

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 v5.3的枚举Qt::WindowFlags中找到了这个标志Qt::NoDropShadowWindowHint,它出现在Qt v5.*的某个版本中。 使用此标志后,上面的代码应该看起来像这样。

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

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

我还没有进行测试,但我认为它一定能够正常工作。


2
我认为你看到的阴影与你使用的Windows主题有关。我在这里使用的是Windows经典主题,没有看到任何阴影 :)
无论如何,如果将QLineEdit的textChanged()信号连接到恢复主窗口焦点的自定义操作中会怎样呢? 类似于:
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的焦点。


这个问题的困扰在于文本框失去了焦点,所以用户不能再输入更多的文字而不重新激活弹出窗口。我认为你对阴影是窗口主题的一部分的想法是正确的。 - Matt Howlett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接