2015-08-08 73 views
0

我试图从选项卡窗口小部件中拖动一个选项卡并拆分查看区域( - 就像eclipse那样,然后将选项卡标题拖动到编辑区域 - 类似于“垂直分割”功能在PyCharm的一个标签中)。从QTabWidget拖放选项卡

我尝试了使用拖放操作,但无法获得标签主区域(例如文本区域)注册来自QTabBar的拖动。然后,我尝试了一下鼠标移动,并得到了更多,但分离器代码不工作,它是非常丑陋的代码。

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

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:

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_() 

但我不认为我有另外的小部件的父VS子中央窗口部件是正确的。

回答

2

这是我过去用来做你要找的一个技巧。如果你想对参数进行很多控制,但是它能完成这项工作,那么它可能非常有限。

  1. 将第2个QMainWindow为您QMainWindowcentralWidget
  2. 请勿为此第二QMainWindow设置任何centralWidget
  3. 设置标志:QMainWindow.AllowNestedDocksQMainWindow.AllowTabbedDocks

  4. 加入QDockWidgets添加标签。这些将被自动威胁为QTabWidgets

  5. 使用QMainWindow.tabifyDockWidget(firstWidget,secondWidget)以编程方式堆叠的小部件(可以多次使用超过2个部件)

例子:

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) 
+0

我已经加入你的建议,原来的问题,企图。我没有正确的代码 - 是否在第二个主窗口中添加'firstwidget'和'secondWidget'? - 我尝试过,但有一个空白的对话框。 –

+0

我写了一个例子。我无法测试它,因为我从m'y手机上写下它。它应该工作它接近我做了什么 –

+0

如果我可以在你的手机上写这个 –

相关问题