简体   繁体   中英

drag and drop a Tab from a QtabBar to other QtabBar in a splitted Widget PyQt Qt

How could I archive this: - I need to drag and drop a tab from its tabBar to other tabBar in a splitted widget? I already subclass the QtabBar and implement the drag and drop events, i already can drag it with the right pixmap and etc, and also i can drop it into the same tabBar, but not in the other one .. got this error in the output telling me that im not providing the right arguments, here is the code, that i simplified for make it and example, and plus a .JPG of the window.

class EsceneTest(qg.QMainWindow):
    def __init__(self,parent=getMayaWindow()):
        super(EsceneTest,self).__init__(parent)
        #---------------------------------------------------------#        
        #check for open Window first
        winName = windowTitle
        if cmds.window(winName, exists =1):
            cmds.deleteUI(winName, wnd=True)

        self.setAttribute(qc.Qt.WA_DeleteOnClose) 
        self._initUI()      

    def _initUI(self):                     
        self.setObjectName(windowObject)
        self.setWindowTitle(windowTitle)
        self.setMinimumWidth(450)
        self.setMinimumHeight(500)
        self.resize(1080, 800) # re-size the window
        centralWidget = qg.QWidget()
        centralWidget.setObjectName('centralWidget')
        self.setCentralWidget(centralWidget)
        central_layout = qg.QVBoxLayout(centralWidget)

        ######################
        # tab container
        #
        self.tabWidget = qg.QTabWidget()
        self.tabWidget.setAcceptDrops(True)
        self.tab_layout = qg.QVBoxLayout(self.tabWidget)
        central_layout.addWidget(self.tabWidget)

        #######################
        # TabBar
        #                 
        custom_tabbar = ColtabBar()
        self.tabWidget.setTabBar(custom_tabbar)        

        #######################
        # ViewportTab
        #         
        tabCentral_wdg = qg.QWidget()
        self.top_lyt = qg.QVBoxLayout(tabCentral_wdg)
        self.tab_layout.addLayout(self.top_lyt)       

        fixedHBox_lyt = qg.QHBoxLayout()
        self.top_lyt.addLayout(fixedHBox_lyt)   
        self.tabWidget.addTab(tabCentral_wdg,'- Viewport')

        #######################
        # Example ExtraTab
        #        
        tabTwo_wdg = qg.QWidget()
        tabTwo_wdg_lyt = qg.QHBoxLayout(tabTwo_wdg)
        self.tab_layout.addLayout(tabTwo_wdg_lyt)        
        label = qg.QLabel(' -- This is an example -- ')
        label.setStyleSheet("""
                            background : qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgb(53, 57, 60), stop:1 rgb(33, 34, 36));
                            border-style : none;
                            font-size: 40px;
                            font-family: Calibri;
                            color : rgb(200,200,100);
                        """)
        label.setAlignment(qc.Qt.AlignVCenter | qc.Qt.AlignHCenter )
        tabTwo_wdg_lyt.addWidget(label)       
        tab_panel_lyt = qg.QVBoxLayout(label)    
        self.tabWidget.addTab(tabTwo_wdg,'- ExtraExample') 

        ############################
        #   Q Splitter Widget to insert the dragged Tabs
        #
        split = qg.QSplitter(qc.Qt.Orientation.Vertical, self)
        central_layout.addWidget(split)
        tab_splitted = qg.QTabWidget()
        split.setLayout(qg.QVBoxLayout())
        split.insertWidget(0,tab_splitted)
        tabBar_2 = ColtabBar()
        tab_splitted.setTabBar(tabBar_2)
        tabBar_2.addTab('- Insert-Here')
#---------------------------------------------------------------------------------------------#

class ColtabBar(qg.QTabBar):
    def __init__(self):
        super(ColtabBar, self).__init__()
        self.indexTab = None        
        self.setAcceptDrops(True)   

    ##################################
    # Events
    def mouseMoveEvent(self, e):
        if e.buttons() != qc.Qt.MiddleButton:
            return

        globalPos = self.mapToGlobal(e.pos())
        posInTab = self.mapFromGlobal(globalPos)
        self.indexTab = self.tabAt(e.pos())
        tabRect = self.tabRect(self.indexTab)


        pixmap = qg.QPixmap(tabRect.size())
        self.render(pixmap,qc.QPoint(),qg.QRegion(tabRect))
        mimeData = qc.QMimeData()
        drag = qg.QDrag(self)
        drag.setMimeData(mimeData)
        drag.setPixmap(pixmap)

        cursor = qg.QCursor(qc.Qt.OpenHandCursor)    
        drag.setHotSpot(e.pos() - posInTab)
        drag.setDragCursor(cursor.pixmap(),qc.Qt.MoveAction)       
        dropAction = drag.exec_(qc.Qt.MoveAction)


    def mousePressEvent(self, e):
        #super(qg.QWidget).mousePressEvent(e)
        if e.button() == qc.Qt.RightButton:
            print('press')

        if e.button() == qc.Qt.LeftButton:            
            globalPos = self.mapToGlobal(e.pos())
            posInTab = self.mapFromGlobal(globalPos)
            self.indexTab = self.tabAt(e.pos())
            self.setCurrentIndex(self.indexTab)

    def dragEnterEvent(self, e):
        e.accept()


    def dropEvent(self, e):
        e.setDropAction(qc.Qt.MoveAction)
        e.accept()        
        self.insertTab(self.indexTab, self.tabText(self.indexTab)) 
        self.removeTab(self.indexTab)

the ColtabBar is the subclass where im doing the drag and drop events.

IMAGE - > 例子

After many hours and have eaten many manyyyy pages of Qt today over the web, I did it in my way, now I can drag and drop tabs from one tabBar to the other and vice-versa and not just from selection the current tab, i could select every tab that I want in my tab bar and will show me the pixmap of the little tab while dragging...

Here is the code:

** EDITED **

I made it more bullet proof, I had a bug when I was using more than 2 tabs with the index, now is working better, and when I drop it in the same widget it return the event and not execute the code, plus the hovering tabs select with the right mouse button as well .. I hope this can help anybody in the future.

TABINDEX = int()

def getTabIndex(index):
    global TABINDEX
    if index == -1 or index == TABINDEX:
        return
    TABINDEX = index
    print (TABINDEX)
    return TABINDEX


class ColtTab(qg.QTabWidget):
    def __init__(self):
        super(ColtTab,self).__init__()
        self.setAcceptDrops(True)
        self.tabBar = self.tabBar()
        self.tabBar.setMouseTracking(True)
        self.setDocumentMode(True)
        self.indexTab = int()
        self.setMovable(True)
        self.setStyleSheet(style_sheet_file)


    # test for hovering and selecting tabs automatic while mouser over then - not working for now...
    def eventFilter(self, obj, event):
        if obj == self.tabBar:
            if event.type() == qc.QEvent.MouseMove:
                index=self.tabBar.tabAt(event.pos())
                self.tabBar.setCurrentIndex (index)
                return True
            else:
                return
        else:
            return

    ##################################
    # Events
    #
    def mouseMoveEvent(self, e):
        if e.buttons() != qc.Qt.MiddleButton:
            return

        globalPos = self.mapToGlobal(e.pos())
        #print(globalPos)
        tabBar = self.tabBar
        #print(tabBar)
        posInTab = tabBar.mapFromGlobal(globalPos)
        #print(posInTab)
        self.indexTab = tabBar.tabAt(e.pos())
        #print(self.indexTab)
        tabRect = tabBar.tabRect(self.indexTab)
        #print(tabRect)
        #print(tabRect.size())

        pixmap = qg.QPixmap(tabRect.size())
        tabBar.render(pixmap,qc.QPoint(),qg.QRegion(tabRect))
        mimeData = qc.QMimeData()
        drag = qg.QDrag(tabBar)
        drag.setMimeData(mimeData)
        drag.setPixmap(pixmap)
        cursor = qg.QCursor(qc.Qt.OpenHandCursor)
        drag.setHotSpot(e.pos() - posInTab)
        drag.setDragCursor(cursor.pixmap(),qc.Qt.MoveAction)
        dropAction = drag.exec_(qc.Qt.MoveAction)


    def mousePressEvent(self, e):
        if e.button() == qc.Qt.RightButton:
            self.tabBar.installEventFilter(self)
            print('Right button pressed')

        super(ColtTab, self).mousePressEvent(e)


    def dragEnterEvent(self, e):
        e.accept()
        if e.source().parentWidget() != self:
            return

        # Helper function for retrieving the Tab index into a global Var
        getTabIndex(self.indexOf(self.widget(self.indexTab)))


    def dragLeaveEvent(self,e):
        e.accept()


    def dropEvent(self, e):
        if e.source().parentWidget() == self:
            return

        e.setDropAction(qc.Qt.MoveAction)
        e.accept()
        counter = self.count()

        if counter == 0:
            self.addTab(e.source().parentWidget().widget(TABINDEX),e.source().tabText(TABINDEX))
        else:
            self.insertTab(counter + 1 ,e.source().parentWidget().widget(TABINDEX),e.source().tabText(TABINDEX))

        print ('Tab dropped')

    def mouseReleaseEvent(self, e):
        if e.button() == qc.Qt.RightButton:
            print('Right button released')
            self.tabBar.removeEventFilter(self)

        super(ColtTab, self).mouseReleaseEvent(e)


    #---------------------------------------------------------------------------------#

Pic ->

示例:

Found this thread useful. Used your solution to create a self contained generic example in PyQt5. May help someone in the future.

import sys

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class Tabs(QTabWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
        self.setAcceptDrops(True)
        self.tabBar = self.tabBar()
        self.tabBar.setMouseTracking(True)
        self.indexTab = None
        self.setMovable(True)

        self.addTab(QWidget(self), 'Tab One')
        self.addTab(QWidget(self), 'Tab Two')

    def mouseMoveEvent(self, e):
        if e.buttons() != Qt.RightButton:
            return

        globalPos = self.mapToGlobal(e.pos())
        tabBar = self.tabBar
        posInTab = tabBar.mapFromGlobal(globalPos)
        self.indexTab = tabBar.tabAt(e.pos())
        tabRect = tabBar.tabRect(self.indexTab)

        pixmap = QPixmap(tabRect.size())
        tabBar.render(pixmap,QPoint(),QRegion(tabRect))
        mimeData = QMimeData()
        drag = QDrag(tabBar)
        drag.setMimeData(mimeData)
        drag.setPixmap(pixmap)
        cursor = QCursor(Qt.OpenHandCursor)
        drag.setHotSpot(e.pos() - posInTab)
        drag.setDragCursor(cursor.pixmap(),Qt.MoveAction)
        dropAction = drag.exec_(Qt.MoveAction)


    def dragEnterEvent(self, e):
        e.accept()
        if e.source().parentWidget() != self:
            return

        print(self.indexOf(self.widget(self.indexTab)))
        self.parent.TABINDEX = self.indexOf(self.widget(self.indexTab))


    def dragLeaveEvent(self,e):
        e.accept()


    def dropEvent(self, e):
        print(self.parent.TABINDEX)
        if e.source().parentWidget() == self:
            return

        e.setDropAction(Qt.MoveAction)
        e.accept()
        counter = self.count()

        if counter == 0:
            self.addTab(e.source().parentWidget().widget(self.parent.TABINDEX),e.source().tabText(self.parent.TABINDEX))
        else:
            self.insertTab(counter + 1 ,e.source().parentWidget().widget(self.parent.TABINDEX),e.source().tabText(self.parent.TABINDEX))


class Window(QWidget):
    def __init__(self):

        super().__init__()

        self.TABINDEX = 0
        tabWidgetOne = Tabs(self)
        tabWidgetTwo = Tabs(self)

        layout = QHBoxLayout()

        self.moveWidget = None

        layout.addWidget(tabWidgetOne)
        layout.addWidget(tabWidgetTwo)

        self.setLayout(layout)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

This is modified from someone elses code, perhaps one of the examples above.

Anyhow, it's a minimal code for tab-to-tab or tab-to-window drag / droping of tab's contents.

from PyQt5.QtWidgets import QTabWidget
from PyQt5.QtCore import Qt, QPoint, QMimeData
from PyQt5.QtGui import QPixmap, QRegion, QDrag, QCursor

class TabWidget(QTabWidget):
   def __init__(self, parent=None, new=None):
      super().__init__(parent)
      self.setAcceptDrops(True)
      self.tabBar().setMouseTracking(True)
      self.setMovable(True)
      if new:
         TabWidget.setup(self)

   def __setstate__(self, data):
      self.__init__(new=False)
      self.setParent(data['parent'])
      for widget, tabname in data['tabs']:
         self.addTab(widget, tabname)
      TabWidget.setup(self)

   def __getstate__(self):
      data = {
         'parent' : self.parent(),
         'tabs' : [],
      }
      tab_list = data['tabs']
      for k in range(self.count()):
         tab_name = self.tabText(k)
         widget = self.widget(k)
         tab_list.append((widget, tab_name))
      return data

   def setup(self):
      pass

   def mouseMoveEvent(self, e):
      if e.buttons() != Qt.RightButton:
         return

      globalPos = self.mapToGlobal(e.pos())
      tabBar = self.tabBar()
      posInTab = tabBar.mapFromGlobal(globalPos)
      index = tabBar.tabAt(e.pos())
      tabBar.dragged_content = self.widget(index)
      tabBar.dragged_tabname = self.tabText(index)
      tabRect = tabBar.tabRect(index)

      pixmap = QPixmap(tabRect.size())
      tabBar.render(pixmap,QPoint(),QRegion(tabRect))
      mimeData = QMimeData()

      drag = QDrag(tabBar)
      drag.setMimeData(mimeData)
      drag.setPixmap(pixmap)

      cursor = QCursor(Qt.OpenHandCursor)

      drag.setHotSpot(e.pos() - posInTab)
      drag.setDragCursor(cursor.pixmap(),Qt.MoveAction)
      drag.exec_(Qt.MoveAction)

   def dragEnterEvent(self, e):
      e.accept()
      #self.parent().dragged_index = self.indexOf(self.widget(self.dragged_index))

   def dragLeaveEvent(self,e):
      e.accept()

   def dropEvent(self, e):
      if e.source().parentWidget() == self:
         return

      e.setDropAction(Qt.MoveAction)
      e.accept()
      tabBar = e.source()
      self.addTab(tabBar.dragged_content, tabBar.dragged_tabname)


if __name__ == '__main__':
   from PyQt5.QtWidgets import QWidget, QApplication, QHBoxLayout
   import sys

   class Window(QWidget):
      def __init__(self):

         super().__init__()

         self.dragged_index = None
         tabWidgetOne = TabWidget(self)
         tabWidgetTwo = TabWidget(self)
         tabWidgetOne.addTab(QWidget(), "tab1")
         tabWidgetTwo.addTab(QWidget(), "tab2")

         layout = QHBoxLayout()

         self.moveWidget = None

         layout.addWidget(tabWidgetOne)
         layout.addWidget(tabWidgetTwo)

         self.setLayout(layout)

   app = QApplication(sys.argv)
   window = Window()
   window1 = Window()
   window.show()
   window1.show()
   sys.exit(app.exec_())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM