我想制作一个类似于OSX“Dock”功能的滑动“侧边栏”(例如鼠标通过屏幕边缘和Dock滑出)。我一直在玩QDockWidget
,但由于它嵌入在窗口布局中,因此当它变得可见时,它会导致一切都移动。
有人可以提出一种实现方法吗?
我是Qt的新手,因此不想过度思考。这只是一个自定义小部件的问题,还是我应该看一个无边框窗口?自定义小部件方法似乎是正确的,但我不知道如何指定它覆盖其他窗口内容,并且如果窗口缩放也可以缩放。
答案 0 :(得分:2)
QDockWidget
与你想要的东西无关 - 行为。仅仅因为它被称为Dock小部件并不意味着它与OS X中的“Dock”概念相同。它仅仅意味着它停靠在某个地方。 QDockWidget
的文档非常明确地解释了对接行为的含义。
下面的代码实现了您似乎想要的行为。无论是否优秀的设计都是有争议的。代码“复杂”的原因似乎暗示没有人会想出这样的UI设计。实际点击按钮某处显示滑块窗口有什么问题?
代码在Qt 4.8和5.1下工作。
注意:这需要在Qt Quick 2中实现。这就是它的设计目的:)当然Qt 4.6+改进了QWidget移动动画的行为,Qt 5做了进一步的调整,但真的这个代码闻起来它有一个很好的理由:QWidget API虽然功能强大,但最终封装了一组API,这些API可以追溯到原始Macintosh发布时的1984年。当你必须从一堆堆积的画家合成结果时,你才能做到这么多。在Qt Quick中,渲染由GPU完成。动画相当于将几个新的浮点数传递给GPU以更新单个转换矩阵。就是这样。
#include <QApplication>
#include <QWidget>
#include <QGridLayout>
#include <QLabel>
#include <QPainter>
#include <QGradient>
#include <QMouseEvent>
#include <QPropertyAnimation>
class Slider : public QWidget {
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE {
QPainter p(this);
QLinearGradient g(QPointF(0,0), QPointF(rect().bottomRight()));
g.setColorAt(0, Qt::blue);
g.setColorAt(1, Qt::gray);
p.setBackground(g);
p.eraseRect(rect());
p.setPen(Qt::yellow);
p.setFont(QFont("Helvetica", 48));
p.drawText(rect(), "Click Me To Hide");
}
void mousePressEvent(QMouseEvent *) Q_DECL_OVERRIDE {
hide();
}
public:
explicit Slider(QWidget *parent = 0) : QWidget(parent) {
setAttribute(Qt::WA_OpaquePaintEvent);
}
};
class Window : public QWidget {
QGridLayout m_layout;
Slider m_slider;
QLabel m_label;
QPropertyAnimation m_animation;
public:
explicit Window(QWidget *parent = 0, Qt::WindowFlags f = 0) :
QWidget(parent, f),
m_layout(this),
m_slider(this),
m_animation(&m_slider, "pos")
{
setMouseTracking(true);
m_layout.addWidget(&m_label);
m_slider.hide();
m_slider.setMouseTracking(false);
m_animation.setStartValue(QPoint(-width(), 0));
m_animation.setEndValue(QPoint(0, 0));
m_animation.setDuration(500);
m_animation.setEasingCurve(QEasingCurve::InCubic);
}
void leaveEvent(QEvent *) {
if (window() && QCursor::pos().x() <= window()->geometry().topLeft().x()) {
showSlider();
}
}
void childEvent(QChildEvent * ev) {
if (ev->added() && ev->child()->isWidgetType()) {
ev->child()->installEventFilter(this);
static_cast<QWidget*>(ev->child())->setMouseTracking(true);
}
}
bool event(QEvent * ev) {
eventFilter(this, ev);
return QWidget::event(ev);
}
bool eventFilter(QObject *, QEvent * ev) {
if (ev->type() == QEvent::MouseMove) {
auto pos = QCursor::pos();
if (window() && window()->isFullScreen()) {
if (pos.x() <= window()->geometry().topLeft().x()) {
showSlider();
}
}
m_label.setText(QString("%1, %2").arg(pos.x()).arg(pos.y()));
}
return false;
}
void resizeEvent(QResizeEvent *) {
m_slider.resize(size());
m_animation.setStartValue(QPoint(-width(), 0));
}
Q_SLOT void showSlider() {
if (m_slider.isVisible() || (window() && qApp->activeWindow() != window())) return;
m_slider.raise();
m_slider.show();
m_animation.start();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}