Создайте всплывающее окно в Qt без тени - PullRequest
7 голосов
/ 30 июня 2009

Я разрабатываю приложение с использованием Qt 4.5 (под Windows Vista, но хочу, чтобы оно было кроссплатформенным). Я использую C ++

Я хотел бы создать всплывающее окно, которое содержит виджет QLineEdit, с функцией, которая, когда пользователь взаимодействует с виджетом QLineEdit, всплывающее окно не активируется (главное окно приложения остается активным).

Создание окна (виджета) с помощью Qt :: Popup | Флаги Qt :: Window дают мне именно то, что я хочу, за исключением того, что я не хочу, чтобы это обеспечивало эффект 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()
{

}

Ответы [ 3 ]

6 голосов
/ 02 июля 2009

Я разработал решение вопроса, который я разместил ранее.

Сначала можно создать всплывающий виджет, производный от QWidget с флагами Qt::Window | Qt::FramelessWindowHint. Я на самом деле взломал qwidget_win.cpp, чтобы убедиться, что мое окно имеет тот же стиль и расширенный стиль, что и элемент управления Popup, предоставляемый WPF (0x96000000 и 0x08000088 соответственно), как определено с помощью Spy ++, однако я не думаю, что это должно иметь значение.

Установка стиля окна не решает проблему активации окна. Ключ к этому для перехвата сообщений Windows, сообщающих главному окну о том, что это не клиентская область, должен быть обновлен (сообщение WM_NCACTIVATE). Это может быть сделано путем предоставления пользовательской реализации QApplication::winEventFilter(MSG* msg, long* result).

К сожалению, просто есть инактивированные WM_ NCACTIVATE сообщения недостаточно, потому что это, кажется, предотвращает WM_ACTIVATE и другие сообщения, которые в противном случае генерируются, от отправки во всплывающее окно. Чтобы решить эту проблему, у меня есть подтверждение концепции работы, где я генерирую необходимые сообщения Windows в winEventFilter после получения соответствующего сообщения WM_NCACTIVATE.

Отсюда есть некоторые детали, которые нужно проработать, чтобы убедиться, что он надежный (перехват WM_ACTIVATEAPP приходит на ум), а затем обернуть его во что-то приятное и многократно используемое.

Все это, конечно, для Windows, интересно посмотреть, есть ли проблемы в Linux.

Все это немного болезненно. Надеюсь, я не пропустил что-то очевидное ...

4 голосов
/ 18 июля 2013

Попробуйте этот странный код ниже (протестировано на 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 голосов
/ 30 июня 2009

Я думаю, что тень, которую вы видите, связана с темой Windows, которую вы используете. Я использую тему Windows Classic Theme и не вижу теней:)

В любом случае, что если вы подключите textChanged () SIGNAL QLineEdit к пользовательскому действию, которое восстанавливает фокус главного окна? Что-то вроде:

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.

...