简体   繁体   中英

Qt: Force child window to have its own task bar entry

I'm using Qt 5 and C++ and I want to force some of my child windows to have their own task bar entries. Right now, I am able to create parentless QWidgets and use the signal-slot mechanism to close those windows when a main window (QMainWindow) is closed.

However as I add more and more parents and childs this whole signal-slot technique will get tedious (won't it?) and I am sure that Qt already has a feature I can use for this. I've seen this ; Primary and Secondary Windows section talks about what I'm trying to do. It says:

In addition, a QWidget that has a parent can become a window by setting the Qt::Window flag. Depending on the window management system such secondary windows are usually stacked on top of their respective parent window, and not have a task bar entry of their own.

I can see that I need to set my QWidgets as Primary Windows but I don't exactly know how.

So I tried:

// when a QMainWindow's (this) push button is clicked:
QWidget* newWindow = new QWidget(this, Qt::Window);
newWindow->show();

It doesn't give me the behavior I want. How can I set newWindow as a Primary Window while still keeping this as its parent?

I don't now native method to do it in Qt. But you can use for it signal/slot it's definitely not create a serious burden on the processor until you have at least a thousand windows. For it you can implement your own child parent mechanizme.

For example:

class myOwnWidget: public QWidget{
    Q_OBJECT
public:
    myOwnWidget(myOwnWidget* parent = 0):
        QWidget(){
        if(parent){
            connect(parent,SIGNAL(close()), this,SLOT(deleteLater()));
        }
    }

    void closeEvent(QCloseEvent* e){
        emit close();
        QWidget::closeEvent(e);
    }

signals:
    void close();
};

class PrimaryWindow : public myOwnWidget{
    PrimaryWindow(myOwnWidget *parent):
        myOwnWidget(parent)
    {
        //your constructor here
    }

}

using:

PrimaryWindow * rootWindows = new PrimaryWindow();
PrimaryWindow * childWin = new PrimaryWindow(rootWindows);

In code PrimaryWindow create without Qt-parent, but for closing child windows you should inherit all your windows from myOwnWidget .

Hope it help.

Heavily based on posters Konstantin T.'s and Mike's ideas, I have developed two classes, MyWidget and MyMainWindow , which can use themselves and each other in their constructors to create child windows which will have their own task bar entries while still acting as children to their parent windows (ie getting automatically closed and destroyed upon termination of the parent window). MyWidget replaces QWidget and MyMainWindow replaces QMainWindow if such a behavior is desired.

my_widget.h:

#ifndef MY_WIDGET_H
#define MY_WIDGET_H

#include <QWidget>
#include <QMainWindow>

class MyMainWindow;

class MyWidget : public QWidget{

    Q_OBJECT

public:
    MyWidget(MyWidget* parent = 0){
        if(parent){
            connect(parent, SIGNAL(window_closed()),
                    this, SLOT(close()));
            connect(parent, SIGNAL(destroyed(QObject*)),
                    this, SLOT(deleteLater()));
        }
    }

    MyWidget(MyMainWindow* parent);

    void closeEvent(QCloseEvent* event){
        emit window_closed();
        QWidget::closeEvent(event);
    }

signals:
    void window_closed();
};

class MyMainWindow : public QMainWindow{

    Q_OBJECT

public:
    MyMainWindow(MyMainWindow* parent = 0){
        if(parent){
            connect(parent, SIGNAL(window_closed()),
                    this, SLOT(close()));
            connect(parent, SIGNAL(destroyed(QObject*)),
                    this, SLOT(deleteLater()));
        }
    }

    MyMainWindow(MyWidget* parent){
        connect(parent, SIGNAL(window_closed()),
                this, SLOT(close()));
        connect(parent, SIGNAL(destroyed(QObject*)),
                this, SLOT(deleteLater()));
    }

    void closeEvent(QCloseEvent* event){
        emit window_closed();
        QMainWindow::closeEvent(event);
    }

signals:
    void window_closed();
};

#endif // MY_WIDGET_H

my_widget.cpp:

#include "my_widget.h"

MyWidget::MyWidget(MyMainWindow* parent){
    connect(parent, SIGNAL(window_closed()),
            this, SLOT(close()));
    connect(parent, SIGNAL(destroyed(QObject*)),
            this, SLOT(deleteLater()));
}

Example main.cpp:

#include <QApplication>
#include "my_widget.h"

int main(int argc, char* argv){
    QApplication a(argc, argv);

    MyWidget mw1{new MyWidget};
    mw1.setWindowTitle("ctor: MyWidget(MyWidget*)");
    mw1.show();

    MyMainWindow mmw1{&mw1};
    mmw1.setWindowTitle("ctor: MyMainWindow(MyWidget*)");
    mmw1.show();

    MyMainWindow mmw2{&mmw1};
    mmw2.setWindowTitle("ctor: MyMainWindow(MyMainWindow*)");
    mmw2.show();

    MyWidget mw2{&mmw2};
    mw2.setWindowTitle("ctor: MyWidget(MyMainWindow*)");
    mw2.show();
    return a.exec();
}

So the window chain is: mw1 -> mmw1 -> mmw2 -> mw2 where any window that is closed will also destroy all windows to its right and all windows in the chain will have their own task bar entries.

I'm sure there are more elegant ways of defining the constructors in my_widget.h , but as a newbie this worked for me to obtain the exact behavior I needed. I'd appreciate to see better practices on my_widget.h .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM