一、效果展示
二、实现思路
写一个继承QTabWidget的类TabWidget,通过eventFilter函数对QTabBar的QEvent::MouseButtonPress、QEvent::MouseMove、QEvent::MouseButtonRelease、QEvent::HoverLeave进行处理和对拖出窗口的QEvent::Move事件进行处理达到拖出拆分窗口,拖入合并窗口,固定标签的效果。通过设置QTabBar的右键菜单实现关闭左侧标签、右侧标签、其他标签、固定标签、取消标签等功能,以上功能均在类TabWidget中实现。
三、代码
TabWidget.h
#ifndef TABWIDGET_H
#define TABWIDGET_H
#include <QTabWidget>
#include <QSet>
#include <QMenu>
class TabWidget : public QTabWidget
{
Q_OBJECT
public:
TabWidget(QWidget *parent = nullptr);
void setTabCanMove(int index,bool canMove);
void setTabsClosable(bool closeable);
bool tabsClosable() const;
int addTab(QWidget *page, const QString &label);
int addTab(QWidget *page, const QIcon &icon, const QString &label);
int insertTab(int index, QWidget *page, const QString &label);
int insertTab(int index, QWidget *page, const QIcon &icon, const QString &label);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
bool eventFilter(QObject *watched, QEvent *event);
signals:
public slots:
private:
bool m_tabClosable;
bool m_isDrag;
int m_dragIndex;
int m_xOffset;
int m_offset;
bool m_tabBarPress;
QSet<QWidget*> m_unDragWidgets;
QPoint m_mousePressPoint;
QMenu* m_menu;
QAction* m_closeLeftTabAct;
QAction* m_closeRightTabAct;
QAction* m_closeOtherTabAct;
QAction* m_fixedTabAct;
QAction* m_unFixedTabAct;
void startDrag(int index);
void createContextMenu();
void setTabCloseBtn(int index,QWidget* widget);
signals:
private slots:
void tabBarCustomContextMenuRequested(const QPoint &pos);
void onCloseLeftTabAct();
void onCloseRightTabAct();
void onCloseOtherTabAct();
void onFixedTabAct();
void onUnFixedTabAct();
void onCurrentChanged(int index);
};
#endif // TABWIDGET_H
TabWidget.cpp部分代码,详细代码请下载
bool TabWidget::eventFilter(QObject *watched, QEvent *event)
{
QTabBar* tabBar=this->tabBar();
if(watched==tabBar)
{
if(event->type()==QEvent::MouseButtonPress)
{
m_tabBarPress=true;
QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
if(mouseEvent)
{
int index=tabBar->tabAt(mouseEvent->pos());
if(index>-1)
{
if(index<m_unDragWidgets.count())
{
m_isDrag=false;
}
else
{
QRect rect=tabBar->tabRect(index);
m_xOffset=rect.left()-mouseEvent->pos().x();
m_mousePressPoint=mouseEvent->pos();
m_dragIndex=index;
m_isDrag=true;
}
}
}
}
else if(event->type()==QEvent::MouseMove)
{
QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
if(mouseEvent)
{
if(!m_tabBarPress)
{
int index=tabBar->tabAt(mouseEvent->pos());
for(int i=m_unDragWidgets.count();i<count();i++)
{
QWidget* widget=tabBar->tabButton(i,QTabBar::RightSide);
if(widget)
{
if(i!=currentIndex())
{
widget->setVisible(i==index);
}
}
}
}
if(m_isDrag)
{
QPoint point=mouseEvent->pos();
if(m_dragIndex==m_unDragWidgets.count()&&mouseEvent->x()<m_mousePressPoint.x())
{
return true;
}
if(qAbs(m_mousePressPoint.y()-point.y())>tabBar->height())
{
startDrag(m_dragIndex);
}
}
else
{
return true;
}
int index=tabBar->tabAt(QPoint(mouseEvent->pos().x()+m_xOffset,mouseEvent->pos().y()));
if(m_unDragWidgets.count()>index)
{
return true;
}
}
}
else if(event->type()==QEvent::MouseButtonRelease)
{
m_tabBarPress=false;
QMouseEvent* mouseEvent=static_cast<QMouseEvent*>(event);
if(mouseEvent)
{
int index=tabBar->tabAt(mouseEvent->pos());
if(index!=-1)
{
QWidget* widget1=this->widget(index);
QSet<QWidget*>::iterator iter=m_unDragWidgets.find(widget1);
if(iter!=m_unDragWidgets.end())
{
return true;
}
}
}
}
else if(event->type()==QEvent::HoverLeave)
{
QHoverEvent* hEvent=static_cast<QHoverEvent*>(event);
if(hEvent)
{
int index=tabBar->tabAt(hEvent->oldPos());
if(index>=m_unDragWidgets.count()&&index!=currentIndex())
{
QWidget* widget=tabBar->tabButton(index,QTabBar::RightSide);
if(widget){
widget->hide();
}
}
}
}
}
QWidget* dragOutWidget=qobject_cast<QWidget*>(watched);
if(dragOutWidget&&dragOutWidget!=tabBar&&dragOutWidget->parentWidget()==nullptr)
{
if(event->type()==QEvent::Move)
{
QPoint pos=dragOutWidget->pos();;
QRect tabRect(tabBar->mapToGlobal(QPoint(0,0)),QSize(this->width(),tabBar->height()));
if (tabRect.contains(pos))
{
int index = tabBar->tabAt(tabBar->mapFromGlobal(pos));
int newIndex;
if(index>=0)
{
QWidget* widget=this->widget(index);
if (m_unDragWidgets.find(widget) != m_unDragWidgets.end())
{
return true;
}
newIndex = this->insertTab(index, dragOutWidget, dragOutWidget->windowIcon(), dragOutWidget->windowTitle());
}
else
{
newIndex = this->addTab(dragOutWidget, dragOutWidget->windowIcon(), dragOutWidget->windowTitle());
}
dragOutWidget->setAttribute(Qt::WA_DeleteOnClose, false);
setCurrentIndex(newIndex);
}
}
}
return QTabWidget::eventFilter(watched, event);
}
四、源码下载
源码下载,觉得文章还可以的请加关注点赞。