spraff
11th November 2008, 15: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.
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.