Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Close Widget Window if mouse clicked outside of it

Tags:

qt

This is sort of a chicken and egg problem. I'd like my widget window to be closed when the mouse clicks outside. As I understand it, there will be no mouse events for my widget for a click occurring outside of it. There is a SetFocus slot, but where is its counterpart or focus loss? "focusOutEvent" doesn't get called for my class.

My widget window is a child window of a widget always shown on my main window and it's a "Qt::ToolTip", so I assume some problems could arise from that fact. Any way around that?

My Goal: I have a custom toolbar widget where buttons on it may have “drop down” widgets. These drop down widgets have no standard windows frame. I don’t want them to “steal” caption focus from the main window and I want them to disappear as soon as the user clicks ANYWHERE on the screen outside of their region. I have having serious difficulties finding a strategy that’s not compromise on Qt to get this done.

Am I missing something? (bet I am).

like image 747
JasonGenX Avatar asked Sep 14 '11 19:09

JasonGenX


3 Answers

I used:

setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);

This seems to work well on OSX and Windows. My window appears correctly, does not steal the focus from my main window's caption, and the focus loss event is called correctly as soon as I click outside of it.

like image 161
JasonGenX Avatar answered Oct 24 '22 00:10

JasonGenX


you can do this by using QDesktopWidget.h like this

void MainWindow::on_actionAbout_triggered()
{
    AboutDialog aboutDialog;
    //Set location of player in center of display
    aboutDialog.move(QApplication::desktop()->screen()->rect().center() -aboutDialog.rect().center());
    // Adding popup flags so that dialog closes when it losses focus
    aboutDialog.setWindowFlags(Qt::Popup);
    //finally opening dialog
    aboutDialog.exec();

}
like image 38
bulldog68 Avatar answered Oct 24 '22 01:10

bulldog68


If your widget could have focus, and 'steal' the caption focus of some of your other widgets, it would have been easier. Something like this could work:

class ToolBarWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ToolBarWidget(QWidget * parent = 0)
    {
        setFocusPolicy(Qt::ClickFocus);
    }

protected:
    void focusOutEvent(QFocusEvent * event)
    {
        close();
    }
}

And when you create any of your widgets you'd do:

ToolBarWidget * pWidget = new ToolBarWidget(this);
pWidget->show();
pWidget->setFocus();

Done! Well, I guess not quiet. first, you don't want the ToolBarWidget to get any focus in the first place. And second, you want for the user to be able to click anywhere and the ToolBarWidget to be hidden. So, you may keep track of every ToolBarWidget that you create. For example, in a 'QList ttWidgets' member variable. Then, whenever you create a new ToolBarWidget, you'd do this:

ToolBarWidget * pWidget = new ToolBarWidget(this);
pWidget->installEventFilter(this);
pWidget->show();

and in your main widget class, implement the eventFilter() function. Something like:

bool MainWidget::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::FocusOut ||
        event->type() == QEvent::KeyPress ||
        event->type() == QEvent::MouseButtonPress)
    {
        while (!ttWidgets.isEmpty()) {
            ToolBarWidget * p = ttWidgets->takeFirst();
            p->close();
            p->deleteLater();
        }
    }
    return MainWidget::eventFilter(obj, event);
}

And that will work. Because this way, even though your ToolTabWidgets aren't getting focus, some other widget in your main widget has focus. And once that changes (whether the user clicked out of your window, or on another control inside it, or in this case, a key or mouse button is pressed, the control will reach that eventFilter() function and close all your tab widgets.

BTW, in order to capture the MouseButtonPress, KeyPress etc. from the other widgets, you would either need to installEventFilter on them too, or just reimplement the QWidget::event(QEvent * event) function in your main widget, and look for those events there.

like image 45
Amy Avatar answered Oct 24 '22 01:10

Amy