一,前言
在上一篇blog13. QlistView显示iconfont--Apple的学习笔记中,我用QSS无法修改widget标题栏的颜色。此时突然想到之前看到过QT制作的无窗体工程。若无窗体就解决此问题了。并且我发现比如酷狗音乐等主界面好像都是工具栏标题栏合并的,所以我要尝试下。
二,需求
无标题栏,工具栏设置关闭应用程序的按钮即可。
三,遇到的问题
1. 如何隐藏标题栏?
答:setWindowFlags(Qt::FramelessWindowHint)
2. 无标题栏情况下如下移动主窗口?
答:重写代替标题栏的控件的mouseEvent即可。我用menubar代替了Widget的标题栏。最关键的就是鼠标位置,要获取全局的,而不是相对主控件的位置。API为mapToGlobal。并且初始化的时候要传入主窗体win=parent;
,通过win->setGeometry设置主窗体位置。
void MenuC::mousePressEvent(QMouseEvent *ev)
{
QMenuBar::mousePressEvent(ev);
if(ev->type() == QMouseEvent::MouseButtonPress)
{
m_StartMove= true;
m_curPoint = mapToGlobal(ev->pos());
}
}
void MenuC::mouseMoveEvent(QMouseEvent *ev)
{
QMenuBar::mouseMoveEvent(ev);
if(m_StartMove)
{
QPoint step = mapToGlobal(ev->pos()) - m_curPoint;
QPoint point = step + win->geometry().topLeft();
win->setGeometry(QRect(point, win->size()));
m_curPoint += step;
}
}
void MenuC::mouseReleaseEvent(QMouseEvent *ev)
{
QMenuBar::mouseReleaseEvent(ev);
m_StartMove = false;
}
3. 点击菜单按钮也会移动主窗口,并且无法释放鼠标?
答:这是因为重写鼠标事件没有禁止原来的菜单按下事件功能,所以按钮的时候做些判断若点击到菜单按钮则不触发移动功能即可。
void MenuC::mousePressEvent(QMouseEvent *ev)
{
QMenuBar::mousePressEvent(ev);
if(ev->type() == QMouseEvent::MouseButtonPress)
{
const QList<QAction*>& actions = this->actions();
for (int i = 0; i < actions.size(); ++i)
{
QAction* pAction = actions.at(i);
QRect rect = actionGeometry(pAction);
if (rect.contains(ev->pos()))
{
qDebug()<<ev->pos();
}
else
{
m_StartMove= true;
m_curPoint = mapToGlobal(ev->pos());
}
}
}
}
4. 重写事件的设计方法?
答:由于这个鼠标是全局事件,我上面只能解决一个action问题,若再加几个menu和action依然存在问题。需要找到彻底的解决方法。一般可能想到的就是重写event,把自己需要处理的event单独拿出,其它继续传递。但是如果控件多的时候,就要重写很多event。这就要用到事件过滤器,eventfilter在event事件前做的过滤。可以使用一个事件过滤器,来判断是否需要调用event()函数,所以用eventfilter才是更好的方法。
5. 如何使事件可以传递到top顶层父类?
答:事件接受后就不会再向父类传递了。一般不使用event ->accept();和event->ignore();一般若忽略,则直接调用父类的事件。在closeEvent事件处理函数中,accept是关闭窗口,ignore是不关闭窗口,只有在closeEvent中才是这样。
四,效果
看上去界面效果不错吧~若要自己做最小化最大化按钮,可以用toolbutton或toolbar或pushbutton等。我只是自己做了一个MenuC类,继承了MenuBar类。
五,小结
体验了下自定义标题栏的效果。主要困难就是拖动事件收到影响,纠结了些时间。主要一开始搜索的是标题栏和菜单栏合并,其实搜索QT自定义标题栏,可以找到很多设计案例可以参考的。了解了全局事件处理的关键技术installEventFilter。