4

I'd appreciate help creating a top-level window in Qt with the following characteristics. The window must be:

  1. Borderless, titleless and lie on top of all other windows on the desktop (easy)
  2. Draggable by clicking and dragging anywhere inside it (this what I need help with)
  3. Constrained to the top border of the desktop while dragging (relatively easy)

Basically, I'm trying to collapse our QT application to a top-level icon on the top border of the desktop.

Olumide
  • 5,397
  • 10
  • 55
  • 104

1 Answers1

6

You'll find the answer to the first part in: Making a borderless window with for Qt, and the answer to the second part in Select & moving Qwidget in the screen.

Combining the two, and adding the last part is straightforward.

Here's how you could do it:

#include <QtGui>

class W: public QWidget
{
    Q_OBJECT

Set up a borderless widget with a few buttons to lock/unlock and quit:

    public:
        W(QWidget *parent=0)
            : QWidget(parent, Qt::FramelessWindowHint), locked(false)
        {
            QPushButton *lock   = new QPushButton("Lock");
            QPushButton *unlock = new QPushButton("Unlock");
            QPushButton *quit   = new QPushButton("&Quit");

            connect(lock,   SIGNAL(clicked()), this, SLOT(lock()));
            connect(unlock, SIGNAL(clicked()), this, SLOT(unlock()));
            connect(quit, SIGNAL(clicked()),
                    QApplication::instance(), SLOT(quit()));

            QHBoxLayout *l = new QHBoxLayout;
            l->addWidget(lock);
            l->addWidget(unlock);
            l->addWidget(quit);
            setLayout(l);
        }

    public slots:
        void lock() {
          locked = true;
          move(x(), 0); // move window to the top of the screen
        }
        void unlock() { locked = false; }

Do the mouse handling:

    protected:
        void mousePressEvent(QMouseEvent *evt)
        {
            oldPos = evt->globalPos();
        }

        void mouseMoveEvent(QMouseEvent *evt)
        {
            const QPoint delta = evt->globalPos() - oldPos;
            if (locked)
                // if locked, ignore delta on y axis, stay at the top
                move(x()+delta.x(), y()); 
            else
                move(x()+delta.x(), y()+delta.y());
            oldPos = evt->globalPos();
        }

    private:
        bool locked;
        QPoint oldPos;
};
Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
  • It mostly works. Unfortunately the borderless widget still has a frame, which I suspect is property of Window 7. The top of this "frame" is still draggable. The other edges of the frame aren't. – Olumide Sep 12 '13 at 16:39
  • Just ran that on Windows 7 (Qt 5), I'm not seeing a border with the code above (with the includes reworked for Qt5) – Mat Sep 12 '13 at 16:58
  • Frame I meant. I'm still on Qt 4. See http://nicug.blogspot.co.uk/2011/03/qt-windows-7-extend-frame-into-client.html for suggested workaround. – Olumide Sep 12 '13 at 17:10
  • I guess it could be a Qt5/Qt4 thing, but that sounds a bit strange. I'm not seeing any sort of border or frame with the code above, even if I derive from QMainWindow or QDialog instead of a plain QWidget. Strange. – Mat Sep 13 '13 at 09:05
  • On Windows this works fine. But on Linux Mint, if the widget is on the second screen, the move() is not obeyed and the widget is constrained to remain within the boundary of the second screen. [Other QWidgets created in the app don't have this problem and can move between the screen, however, the dragging is done by clicking on the top bar of the widget] – David Casper Mar 24 '19 at 00:00