QTabWidget自定义,拖入拖出Tab页的简易实现

QTabWidget自定义,拖入拖出Tab页的简易实现0 实现效果 声明 这只是个测试 不是很满意 放着也没用就分享下 实现效果 GIF 完整代码链接 https github com gongjianbo MyTestCode tree master Qt MyTabWidget 相关参考 https www cnblogs com findumars p 5175984 html 相关参考 https github com MRXY001 Qt DragableTabW 实现过程 QTabWidget 的 Tab

0.实现效果

(声明:这只是个测试,不是很满意,放着也没用就分享下)

实现效果GIF:

QTabWidget自定义,拖入拖出Tab页的简易实现

完整代码链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/MyTabWidget

相关参考:https://www.cnblogs.com/findumars/p/5175984.html

相关参考:https://github.com/MRXY001/Qt-DragableTabWidget

1.实现过程

QTabWidget的Tab页签只能拖拽交换顺序,没有把Tab页拖入拖出的功能,我们可以通过继承QTabBar重新实现部分接口来实现这个功能。

首先是Tab页的拖出,主要通过QTabBar的鼠标事件来处理,如果拖出了QTabBar的区域就生成一个QDrag,用于显示Tab页的快照跟随鼠标。

当鼠标释放的时候,如果在QTabBar外部,则从QTabBar移除该页面,作为一个独立的窗口显示。

然后是Tab页的拖回,也是判断鼠标释放时的位置,如果在QTabBar范围,就添加到QTabBar中。

(1.目前这种方式效果不理想,太生硬了,没有浏览器Tab拖拽那种流畅的感觉,后期修改的话可能需要实时判断位置,而不是鼠标释放时才去处理;2.没有很好的利用Qt的drag drop事件接口,后期可以尝试下;3.QTabWidget很多默认的效果不大好,比如TabBar占据宽度居然是根据页签总宽而不是TabWidget占的宽度,这样判断区域也不方便,还有Tab页过多时的左右按钮也不好用,如果时间足够的话,最好重写)

主要代码片段:

void MyTabBar::mousePressEvent(QMouseEvent *event) { QTabBar::mousePressEvent(event); if(event->button()==Qt::LeftButton&¤tIndex()>=0) { //保存状态 //pressPos=event->pos(); theDragPress=true; } } void MyTabBar::mouseMoveEvent(QMouseEvent *event) { QTabBar::mouseMoveEvent(event); //move的时候button为NoButton,但是button's里有 if(theDragPress&&event->buttons()) { //是否脱离了tabbar的范围 if(!theDragOut&&!contentsRect().contains(event->pos())){ theDragOut=true; emit beginDragOut(this->currentIndex()); //QDrag.exec后就不会触发release了,自己手动触发 //不过他好像还是在鼠标弹起之后才会进行动画,待解决 QMouseEvent *e=new QMouseEvent(QEvent::MouseButtonRelease, this->mapFromGlobal(QCursor::pos()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); //mouseReleaseEvent(event); QApplication::postEvent(this,e); } } } void MyTabBar::mouseReleaseEvent(QMouseEvent *event) { QTabBar::mouseReleaseEvent(event); theDragPress=false; theDragOut=false; }
void MyTabWidget::initTabBar() { MyTabBar *bar=new MyTabBar(this); //setTabBar是protected成员函数,要使用就得继承 setTabBar(bar); //点击页签上的关闭按钮时,触发信号 connect(bar,&QTabBar::tabCloseRequested,this,&MyTabWidget::removeNormalIndex); //拖拽到外部-还未释放鼠标 connect(bar,&MyTabBar::beginDragOut,this,[this,bar](int index){ if(!indexValid(index)) return; QWidget *drag_tab=this->widget(index); //固定tab就不让拖出 if(!drag_tab||fixedPage.contains(drag_tab)) return; //把当前页作为快照拖拽 //尺寸加了标题栏和边框 QPixmap pixmap(drag_tab->size()+QSize(2,31)); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); if(painter.isActive()) { //这里想做标题栏贴在内容之上 //但是没法获取默认标题栏的图像啊,就随便画一个矩形框 //如果设置了外部主题颜色,需要改下 QRect title_rect{0,0,pixmap.width(),30}; painter.fillRect(title_rect,Qt::white); painter.drawText(title_rect,Qt::AlignLeft|Qt::AlignVCenter," "+drag_tab->windowTitle()); painter.drawRect(pixmap.rect().adjusted(0,0,-1,-1)); } painter.end(); drag_tab->render(&pixmap,QPoint(1,30)); QMimeData *mime=new QMimeData; QDrag *drag=new QDrag(bar); drag->setMimeData(mime); drag->setPixmap(pixmap); drag->setHotSpot(QPoint(10,0)); //鼠标弹起后drag就释放了,这时候去判断是否拖拽到了外部 connect(drag,&QDrag::destroyed,this,[=]{ QPoint bar_point=bar->mapFromGlobal(QCursor::pos()); //不在范围,拖出 if(!bar->contentsRect().contains(bar_point)){ popPage(drag_tab); } }); drag->exec(Qt::MoveAction); }); } void MyTabWidget::popPage(QWidget *page) { takeNormalPage(page); //这里套一个自定义标题栏的窗口给page MyTabPopup *pop=new MyTabPopup(this); pop->setAttribute(Qt::WA_DeleteOnClose); pop->setContentWidget(page); pop->setWindowTitle(page->windowTitle()); pop->resize(page->size()); //拖出来的位置有点偏移 pop->move(QCursor::pos()-QPoint(10,10)); //判断独立窗口是否拖回tab connect(pop,&MyTabPopup::dragRelease,this,[=](const QPoint &pos){ const QPoint bar_pos=tabBar()->mapFromGlobal(pos); //如果又拖回了tabbar范围内,就把widget取出来放回tab if(tabBar()->contentsRect().contains(bar_pos)) { QWidget *content=pop->getContentWidget(); this->appendNormalPage(content); pop->disconnect(); //关闭的时候会在原来的位置闪一下? pop->close(); //this->activateWindow(); } }); pop->show(); page->show(); pop->activateWindow(); pop->setFocus(); } 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/218477.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 上午7:09
下一篇 2026年3月18日 上午7:10


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号