1. 程式人生 > >QT實現拖拽TabWidget選項卡形成單獨的視窗,雙擊標題欄可還原的功能【dock功能】

QT實現拖拽TabWidget選項卡形成單獨的視窗,雙擊標題欄可還原的功能【dock功能】

近期做QT,我也是新手,這個主要是用重構父類事件實現的,即子類化。

此文章是在http://blog.csdn.net/zmm19861210/article/details/9036779上看到的,但是我做了一定的修改[備註:下方的程式碼上未體現,還是老程式碼],我做了解構函式的修改,就是將堆上那些new出來的私有變數給delete掉,由於程式碼是在主機上除錯的,公司使用遠端桌面方式上網,所以沒有許可權上傳到遠端桌面來整個demo真是遺憾。

這個功能看似簡單,實現起來確實有點兒難度。
在程式碼裡詳細說明吧。
//CTabWidget.h
#ifndef CTABWIDGET_H
#define CTABWIDGET_H
#include <QTabWidget>
#include <QtGui>
#include "CTabBar.h"

class CTabWidget :public QTabWidget
{
    Q_OBJECT
public:
    CTabWidget(QWidget* =0);
	virtual ~CTabWidget(){};
public:
	CTabBar *tabBar;
};
#endif // CTABWIDGET_H

//CTabWidget.cpp
#include "CTabWidget.h"

CTabWidget::CTabWidget(QWidget *parent):QTabWidget(parent)
{
	tabBar = new CTabBar;
	setTabBar(tabBar);     //這裡是關鍵,這樣用我們自定義的CTabBar替換原來的QTabBar
}

//CTabBar.h
#ifndef CTABBAR_H
#define CTABBAR_H
#include <QTabBar>
#include <QtGui>

class CTabBar :public QTabBar
{
	Q_OBJECT
public:
	CTabBar(QWidget* =0);
	virtual ~CTabBar(){};
protected:
	void mousePressEvent(QMouseEvent *);
	void mouseReleaseEvent(QMouseEvent *);   //通過兩個事件模擬出tab被拖動的動作
private:
	bool pressFlag;
signals:
	void sig_tabDrag(int,QPoint);
};
#endif

//CTabBar.cpp
#include "CTabBar.h"
#include <QtGui>
 
CTabBar::CTabBar(QWidget *parent):QTabBar(parent),pressFlag(false)
{
 
}
 
void CTabBar::mousePressEvent(QMouseEvent *event)
{    
    if (event->button()==Qt::LeftButton)
    {
        pressFlag = true;
    }
    QTabBar::mousePressEvent(event);
}
 
void CTabBar::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton &&pressFlag )
    {
        pressFlag = false;     
        if(tabRect(currentIndex()).contains( event->pos()))
            return;
        emit sig_tabDrag(currentIndex(),event->pos());
    }    
}

現在實現視窗標題欄被雙擊動作
//CWidget.h
#ifndef CWIDGET_H
#define CWIDGET_H
#include <QtGui/QWidget>

class CWidget:public QWidget
{
	Q_OBJECT
public:
	CWidget(QWidget* = 0);
	~CWidget();
protected:
	bool event(QEvent *);
signals:
	void sig_doubleClickedTitleBar();  //被雙擊時發射的訊號
};
#endif

//CWidget.cpp
#include "CWidget.h"
#include <QtGui>
CWidget::CWidget(QWidget *parent):QWidget(parent)
{

}

CWidget::~CWidget()
{

}

bool CWidget::event(QEvent *event)
{
#ifdef unix
    if(event->type() == QEvent::MouseButtonDblClick){   //標題欄單擊沒反應,就單擊視窗邊緣替代吧
        emit sig_doubleClickedTitleBar();
        return true;
    }
#endif   
	if (event->type() == QEvent::NonClientAreaMouseButtonDblClick)  //這個事件在Linux下沒有觸發,應該算是Qt的一個Bug吧
    {
		emit sig_doubleClickedTitleBar();
		return true;
	}
    return QWidget::event(event);
}

//CMainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
#include "CTabWidget.h"
#include "CTabBar.h"

class CMainWindow:public QMainWindow
{
	Q_OBJECT
public:
	CMainWindow(QWidget* = 0);  
private:
	CTabWidget *tabWidget;
private slots:
    void slot_tabBarDoubleClicked();            //響應雙擊彈回的槽函式
    void slot_tabDrag(int index,QPoint point);  //響應拖動動作的槽函式
    void slot_closeTab(int);                    //關閉tab的槽函式
};

#endif // MAINWINDOW_H

//CMainWindow.cpp
#include "CMainWindow.h"
#include "CTabWidget.h"
#include "CWidget.h"
#include <QtGui>

CMainWindow::CMainWindow(QWidget *parent):QMainWindow(parent)
{
    tabWidget = new CTabWidget(this);
    tabWidget->setMovable(true);
    tabWidget->setTabsClosable(true);
    tabWidget->setTabShape(QTabWidget::Triangular);
    //新增4個tab頁
    tabWidget->addTab(new QTextEdit,"eidt 1");
    tabWidget->addTab(new QTextEdit,"eidt 2");
    tabWidget->addTab(new QTextEdit,"eidt 3");
    tabWidget->addTab(new QTextEdit,"eidt 4");
    setCentralWidget(tabWidget);

    connect(tabWidget->tabBar,SIGNAL(sig_tabDrag(int,QPoint)),this,SLOT(slot_tabDrag(int,QPoint)));
    connect(tabWidget,SIGNAL(tabCloseRequested(int)),this,SLOT(slot_closeTab(int)));
    connect(tabWidget,SIGNAL(currentChanged(int)),tabWidget,SLOT(setCurrentIndex(int)));

    resize(800,600);
}

void CMainWindow::slot_tabDrag(int index,QPoint point)
{
    CWidget *widget = new CWidget;
    QWidget *draged = tabWidget->widget(index);
    QString windowName = tabWidget->tabText(index);
    tabWidget->removeTab(index);
    connect(widget,SIGNAL(sig_doubleClickedTitleBar()),this,SLOT(slot_tabBarDoubleClicked()));

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(draged);
    widget->setLayout(layout);
    widget->resize(600,400);
    widget->move(point+pos()+tabWidget->pos());
    widget->setWindowTitle(windowName);
    widget->show();
    draged->show();
}

void CMainWindow::slot_tabBarDoubleClicked()
{
    CWidget *widget = qobject_cast<CWidget*>(sender());
    QObjectList list = widget->children();
    QTextEdit *edit = NULL;
    
    for(int i = 0;i<list.count();++i)
    {
        if(list[i]->inherits("QTextEdit"))
        {
            edit = qobject_cast<QTextEdit*>(list[i]);
            break;
        }
    }
    if(edit == NULL)
    {
        return ;
    }

    edit->setParent(tabWidget);
    tabWidget->addTab(edit,widget->windowTitle());
    delete widget;
}

void CMainWindow::slot_closeTab(int index)
{
    QWidget *draged = tabWidget->widget(index);
    tabWidget->removeTab(index);
    delete draged;
}

//main.cpp
#include "CMainWindow.h"
#include <QApplication>
#include <QCleanlooksStyle>

int main(int argc,char **argv)
{
    QApplication app(argc,argv);
    QApplication::setStyle(new QCleanlooksStyle);
    QTextCodec::setCodecForTr(QTextCodec::codecForName("gb2312"));
    CMainWindow mainwindow;
	mainwindow.show();
    return app.exec();
}