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:
Q_OBJECT
public:
public slots:
void setCurrentIndex (int);
private:
//! Shows everything in the widget.
void show_all ();
};
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 ();
};
To copy to clipboard, switch view to plain text mode
viewlayout.cpp:
}
int ViewLayout
:: addWidget (QWidget * w
) { show_all ();
return r;
}
int ViewLayout
:: insertWidget (int i,
QWidget * 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();
}
}
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();
}
}
To copy to clipboard, switch view to plain text mode
The widget that uses it:
view.hpp:
Q_OBJECT
public:
//! Remove the window from the view but do not destroy it.
//! \see QStackedLayout
//! \see QStackedLayout
// \see QStackedLayout
};
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;
};
To copy to clipboard, switch view to plain text mode
view.cpp:
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);
}
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);
}
To copy to clipboard, switch view to plain text mode
And here's a demo window to put into such a stack.
bouncetest.hpp:
class BounceTest
: public QFrame { Q_OBJECT
public:
private:
int vx;
int vy;
private slots:
void timeOut();
};
class BounceTest : public QFrame {
Q_OBJECT
public:
BounceTest (QWidget * =0);
private:
QWidget * obj;
int vx;
int vy;
private slots:
void timeOut();
};
To copy to clipboard, switch view to plain text mode
bouncetest.cpp:
#include <stdlib.h>
namespace {unsigned int count = 0;}
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->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
()));
}
#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()));
}
To copy to clipboard, switch view to plain text mode
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 ();
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 ();
To copy to clipboard, switch view to plain text mode
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.
Bookmarks