7

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

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

使用 Qt::Popup 创建一个窗口(小部件)| Qt::Window flags 正是我想要的,除了我不想要它提供的 3D 阴影边框效果。我想要一个无边框的窗口。请注意,Qt::FramelessWindowHint 标志不能实现这一点。

有人有任何线索吗?

进一步说明:下面是一个简单的测试应用程序的片段,它创建了一个带有按钮的窗口。按下按钮时,会显示一个弹出窗口,用户可以在 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()
{

}
4

3 回答 3

6

我为我之前发布的问题制定了一个解决方案。

QWidget首先,可以通过从with flags派生来创建弹出窗口小部件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捕获适当的消息后生成所需的 WindowsWM_NCACTIVATE消息。

从这里开始,有一些细节需要处理以确保它是健壮的(WM_ACTIVATEAPP想到拦截),然后将它包装成一些好的和可重用的东西。

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

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

于 2009-07-02T10:25:42.477 回答
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 
    //----------------------
}

我还没有测试,但我认为它必须工作。

于 2013-07-18T12:36:49.740 回答
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 的关注。

于 2009-06-30T01:10:35.873 回答