从QTabWidget拖放标签 [英] Drag and drop tab from QTabWidget

查看:512
本文介绍了从QTabWidget拖放标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从标签小部件拖动一个标签,并拆分观察区域(如eclipse那样,您可以将标签标题拖到编辑区域中,类似于PyCharm中选项卡上的split vertical功能) 。

I am trying to drag a tab from a tab widget and split the viewing area (- like eclipse does then you drag a tab heading into the edit area - and similar to the 'split vertically' functionality on a tab in PyCharm).

我尝试使用拖放功能,但无法获取标签主区域(例如文本区域)来注册来自QTabBar的拖动。然后,我尝试只是跟随鼠标移动,进一步,但分裂器代码不是很有效,它是相当丑陋的代码。

I tried using drag and drop but can't get the tab main area (eg text area) to register a drag coming from the QTabBar. I then tried just following the mouse movements and got further but the splitter code is not quite working and it's pretty ugly code.

NB我不使用可停靠的小部件,因为此代码将用于应用程序的中央部件。我喜欢使用拖放来做到这一点 - 任何人都有任何想法?

NB I'm not using dockable widgets as this code will be used for the central widget of an app. I'd prefer to use drag and drop to do this - anyone have any ideas?

from PyQt4.QtGui import QWidget, QDrag, QTabBar, QTabWidget, QPainter, QPalette,\
QBrush, QColor, QPen, QVBoxLayout, QHBoxLayout, QTextEdit, QCheckBox
from PyQt4.QtCore import QByteArray, QMimeData, QPoint
from PyQt4 import QtCore, QtGui

class CentralTabWidget(QTabWidget):

    def __init__(self, parent=None):
        QTabWidget.__init__(self, parent)
        self.parent = parent

        tabBar = CentralTabBar(self)
        self.setTabBar(tabBar)
        self.addWidgets()

    def addWidgets(self):
        tab1 = QWidget()
        self.addTab(tab1, "Tab1")
        textArea = QTextEdit()
        textArea.setText("Text area 1")
        vBox = QVBoxLayout()
        vBox.addWidget(textArea)
        tab1.setLayout(vBox)
        tab2 = QWidget()
        self.addTab(tab2, "Tab2")
        textArea2 = QTextEdit()
        textArea2.setText("Text area 2")
        vBox2 = QVBoxLayout()
        vBox2.addWidget(textArea2)
        tab2.setLayout(vBox2)
        self.setAcceptDrops(True)
        self.verticalLineOverlay = Overlay(parent = self)
        self.verticalLineOverlay.hide()

    def dragEnterEvent(self, event):
        mimeData = event.mimeData()
        event.accept()

    def dragMoveEvent(self, event):
        print(">>dragMoveEvent()")

    def dropEvent(self, event):
        mimeData = event.mimeData()
        event.setDropAction(QtCore.Qt.MoveAction)
        event.accept()

    def resizeEvent(self, event):    
        self.verticalLineOverlay.resize(event.size())
        event.accept()

class CentralTabBar(QTabBar):   
    def __init__(self, parent=None):
        QTabBar.__init__(self, parent)
        self.parent = parent
        self.__drag_start_pos = QPoint()
        self.setAcceptDrops(True)

    def mousePressEvent(self, event):
        self.__mousePressPos = None
        self.__mouseMovePos = None
        if event.button() == QtCore.Qt.LeftButton:
            self.__mousePressPos = event.globalPos()
            self.__mouseMovePos = event.globalPos()
            if self.parent.parent.dndCheckBox.isChecked():
                self.startDrag()
        super(CentralTabBar, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        self.parent.verticalLineOverlay.setVisible(False)
        currPos = self.mapToGlobal(self.pos())
        ax, ay, aw, ah = self.geometry().getRect()
        if currPos.x() > ax + aw/4:
            self.parent.parent.createSplitter()
        super(CentralTabBar, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() == QtCore.Qt.LeftButton:
            currPos = self.mapToGlobal(self.pos())
            globalPos = event.globalPos()
            diff = globalPos - self.__mouseMovePos
            newPos = self.mapFromGlobal(currPos + diff)
            xp1, yp1, xp2, yp2 = self.geometry().getCoords()
            ax, ay, aw, ah = self.geometry().getRect()
            parentx, parenty, parentw, parenth = self.parent.geometry().getCoords()
            if parenth > 10:
                if (newPos.y() > yp2) and (newPos.y() < (parenth)):
                    self.parent.verticalLineOverlay.setVisible(True)
        super(CentralTabBar, self).mouseMoveEvent(event)

    def startDrag(self):
        data = QByteArray()
        mimeData = QMimeData()
        mimeData.setData("application/x-icon-and-text", data)
        print("Using DnD")
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.exec_()

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

    def dragMoveEvent(self, event):
        print("--dragMoveEvent()")

    def dropEvent(self, event):
        event.setDropAction(QtCore.Qt.MoveAction)
        event.accept()

class Overlay(QWidget):    
    def __init__(self, parent=None):        
        super(Overlay, self).__init__(parent)
        print("--__init__() parent type:{0}".format(type(parent))) 
        self.parent = parent
        palette = QPalette(self.palette())
        palette.setColor(palette.Background, QtCore.Qt.transparent)
        self.setPalette(palette)

    def paintEvent(self, event):  
        self.painter = QPainter()
        self.painter.setPen(QPen(QtCore.Qt.NoPen))
        self.painter.begin(self)
        self.painter.setRenderHint(QPainter.Antialiasing)
        self.painter.fillRect(self.parent.currentWidget().geometry(), QBrush(QColor(255, 255, 255, 10)))
        parentx, parenty, parentw, parenth = self.parent.geometry().getCoords()
        self.painter.drawRect( parentx, parenty, (parentw/2)-10, parenth)   
        self.painter.drawRect( (parentw/2)+10, parenty, parentw, parenth)        
        self.painter.setPen(QPen(QtCore.Qt.NoPen)) 

    def setUpPainter(self):
        self.painter = QPainter()
        self.painter.setPen(QPen(QtCore.Qt.NoPen))
        self.painter.begin(self)
        self.painter.setRenderHint(QPainter.Antialiasing)
        self.painter.fillRect(self.parent.currentWidget().geometry(), QBrush(QColor(255, 255, 255, 10)))
        parentx, parenty, parentw, parenth = self.parent.geometry().getCoords()

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.layout = QHBoxLayout()
        self.dndCheckBox = QCheckBox("Use DnD")
        self.dndCheckBox.setChecked(True)
        self.ctw = CentralTabWidget(self)
        self.layout.addWidget(self.ctw)
        self.layout.addWidget(self.dndCheckBox)
        self.setLayout(self.layout)

    def createSplitter(self):
        #not sure why widgets are not redrawn inside the splitter
        splitter1 = QtGui.QSplitter(QtCore.Qt.Horizontal)
        self.removeWidgets(self.layout)
        splitter1.addWidget(self.ctw)
        self.layout.addWidget(splitter1)
        self.layout.addWidget(self.dndCheckBox)

    def removeWidgets(self, layout):
        for cnt in reversed(range(layout.count())):
            widget = layout.takeAt(cnt).widget()
            if widget is not None: 
                widget.deleteLater()

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.resize(350, 300)
    window.show()
    sys.exit(app.exec_())

在QMainMaindow内使用QMainWindow我尝试过:

Using a QMainWindow inside a QMainMaindow I tried:

from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QMainWindow, QTextEdit, QDockWidget

_DOCK_OPTS = QtGui.QMainWindow.AllowNestedDocks
_DOCK_OPTS |= QtGui.QMainWindow.AllowTabbedDocks

class Window(QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        secondQMainWindow = QMainWindow()
        self.central = secondQMainWindow
        self.setDockOptions(_DOCK_OPTS)
        dw1 = QDockWidget("One")
        textArea = QTextEdit()
        textArea.setText("Text area 1")
        dw1.setWidget(textArea)

        dw2 = QDockWidget("Two")
        textArea2 = QTextEdit()
        textArea2.setText("Text area 2")
        dw2.setWidget(textArea2)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw1)
        self.addDockWidget(QtCore.Qt.RightDockWidgetArea, dw2)
        self.tabifyDockWidget(dw1, dw2)
        dw3 = QDockWidget("Three")
        textArea3 = QTextEdit()
        textArea3.setText("Text area 3")
        dw3.setWidget(textArea3)
        self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dw3)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    app.exec_()

但是我不认为我有添加的小部件到父对象和子中心小部件正确。

But I don't think I have the addition of widgets to the parent vs child central widget correct.

推荐答案

这是一个技巧我过去曾经用过你所寻找的东西。如果您想对参数进行很多控制,那么可能会有很大的限制。

Here is a trick I've used in the past to do what you are looking for. It may be quite limited if you want to have a lot of control on the parameters but it does the job.


  1. 将第二个 QMainWindow 作为 centralWidget QMainWindow

  2. 不要为此第二个 QMainWindow 设置任何 centralWidget

  3. 设置标志: QMainWindow.AllowNestedDocks QMainWindow.AllowTabbedDocks

  1. Put a 2nd QMainWindow as the centralWidget of you QMainWindow.
  2. Don't set any centralWidget for this 2nd QMainWindow.
  3. Set flags : QMainWindow.AllowNestedDocks and QMainWindow.AllowTabbedDocks

添加标签页添加 QDockWidgets 。这些将自动处理为 QTabWidgets

Add tabs by adding QDockWidgets. These will be automatically threated as QTabWidgets.

示例:

window=QtGui.QMainWindow()
    window.centralContent=QtGui.QMainWindow()

window.setCentralWidget(window.centralContent)

window.centralContent.firstTabWidget=QtGui.QWidget()
window.centralContent.firstTabDock=QtGui.QDockWidget("first")
window.centralContent.firstTabDock.setWidget(window.centralContent.firstTabWidget)
window.centralContent.addDockWidget(window.centralContent.firstTabDock)
 window.centralContent.secondTabWidget=QtGui.QWidget()
window.centralContent.secondTabDock=QtGui.QDockWidget("second")
window.centralContent.secondTabDock.setWidget(window.centralContent.secondTabWidget)
window.centralContent.addDockWidget(window.centralContent.secondTabDock)

window.centralContent.tabifyDockWidget( window.centralContent.firstTabDock, window.centralContent.secondTabDock)

这篇关于从QTabWidget拖放标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆