PDA

View Full Version : Stacks of transparent widgets and inputs passing through



spraff
11th November 2008, 16:36
Hello. I want to layer widgets in such a way that you can see through them and interact with all layers. The obvious thing seemed to be to subclass QStackedLayout and override the hiding behaviour. So I came up with this:

viewlayout.hpp:
class ViewLayout : public QStackedLayout {
Q_OBJECT
public:
ViewLayout (QWidget * =0);

int addWidget (QWidget *);
int insertWidget (int, QWidget *);

public slots:
void setCurrentIndex (int);
void setCurrentItem (QWidget *);

private:
//! Shows everything in the widget.
void show_all ();
};
viewlayout.cpp:

ViewLayout :: ViewLayout (QWidget * parent) : QStackedLayout(parent) {
}

int ViewLayout :: addWidget (QWidget * w) {
int r = QStackedLayout :: addWidget (w);
show_all ();
return r;
}

int ViewLayout :: insertWidget (int i, QWidget * w) {
int r = QStackedLayout :: insertWidget (i, w);
show_all ();
return r;
}

void ViewLayout :: setCurrentIndex (int) {
// Do nothing. There is no notion of "current" item.
}

void ViewLayout :: setCurrentItem (QWidget *) {
// Do nothing. There is no notion of "current" item.
}

void ViewLayout :: show_all () {
for (int i=0; i<count(); i++) {
itemAt(i)->widget()->raise();
itemAt(i)->widget()->show();
}
}

The widget that uses it:
view.hpp:
class View : public QWidget {
Q_OBJECT
public:
View (QWidget * =0);

//! Remove the window from the view but do not destroy it.
void removeWidget (QWidget *);

//! \see QStackedLayout
int addWidget (QWidget *);

//! \see QStackedLayout
int insertWidget (int, QWidget *);

// \see QStackedLayout
QWidget * widget (int) const;
};

view.cpp:

View :: View (QWidget * parent) : QWidget(parent) {
ViewLayout * l = new ViewLayout ();
setLayout(l);
}

void View :: removeWidget (QWidget * w) {
layout() -> removeWidget (w);
}

int View :: addWidget (QWidget * w) {
ViewLayout * l = dynamic_cast<ViewLayout *>(layout());
return l -> addWidget (w);
}

int View :: insertWidget (int i, QWidget * w) {
ViewLayout * l = dynamic_cast<ViewLayout *>(layout());
return l -> insertWidget (i, w);
}

QWidget * View :: widget (int i) const {
ViewLayout * l = dynamic_cast<ViewLayout *>(layout());
return l -> widget (i);
}

And here's a demo window to put into such a stack.
bouncetest.hpp:
class BounceTest : public QFrame {
Q_OBJECT
public:
BounceTest (QWidget * =0);

private:
QWidget * obj;
int vx;
int vy;

private slots:
void timeOut();
};

bouncetest.cpp:
#include <stdlib.h>

namespace {unsigned int count = 0;}

BounceTest :: BounceTest (QWidget * parent) : QFrame(parent) {
setFrameStyle(QFrame::Panel|QFrame::Plain);
setLineWidth(3);
QString s = "%1 %1 %1 %1\n%1 %1 %1 %1\n%1 %1 %1 %1\n%1 %1 %1 %1\n";
obj = new QPushButton (s.arg(count++),this);
obj->move(rand()%500,rand()%400);
vx = 11;
vy = 7;
QTimer::singleShot(200,this,SLOT(timeOut()));
}

void BounceTest :: timeOut () {
int X = obj->x();
int Y = obj->y();
int W = width();
int H = height();
int Wo= obj->width();
int Ho= obj->height();
if ((X+Wo)>W || X<0)
vx = -vx;
if ((Y+Ho)>H || Y<0)
vy = -vy;
obj->move (X+vx,Y+vy);
QTimer::singleShot(150,this,SLOT(timeOut()));
}

And finally, main.cpp:

View * bt = new View ();
bt->addWidget (new BounceTest());
bt->addWidget (new BounceTest());
bt->addWidget (new BounceTest());
bt->addWidget (new BounceTest());
bt->addWidget (new BounceTest());
bt->resize(800,600);
bt->show ();


At first glance, it seems okay except not all the Views have been resized.

Also, you can press the topmost button but none of the others. How do I rewrite BounceTest such that any click or mouse move not hitting any of its children wil propagate to the lower levels?

Thanks for reading this far.