Bottom Page

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
 [PyQt] Drag items across tabs
#1
When a dragged item hovers on a tab, I want the view to switch on this tab. The problem is two fold;

1. How to trigger new events once the mouse entered the tagBar
2. How to know which tab is being hovered

I tried subclassing the QTabBar, and catching dragMoveEvent, but the event is never triggered. Then I tried to reset or ignore the dragEnterEvent, so it might be trigered again without leaving the tabBar. What I tried are the commented lines below;

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class TabBar(QtWidgets.QTabBar):
    def __init__(self, parent):
        super().__init__()
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        print("enter", event)
        #event.ignore()
        #QtCore.QCoreApplication.postEvent(self, QtGui.QDragLeaveEvent())
        #QtCore.QCoreApplication.sendEvent(self, QtGui.QDragLeaveEvent())
        #QtCore.QObject.event(self, QtGui.QDragLeaveEvent())
        #self.dragLeaveEvent(QtGui.QDragLeaveEvent())

    # This event is never called
    def dragMoveEvent(self, event):
        print("move", event)


class TabWidget(QtWidgets.QTabWidget):
    def __init__(self, parent):
        super().__init__()
        tab1 = QtWidgets.QTreeWidget()
        self.setTabBar(TabBar(self))
        self.addTab(tab1, "1st tab")
        self.addTab(QtWidgets.QTreeWidget(), "2nd tab")
        self.addTab(QtWidgets.QTreeWidget(), "3rd tab")

        item = QtWidgets.QTreeWidgetItem()
        item.setText(0, "drag me")
        tab1.addTopLevelItem(item)
        tab1.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        super().__init__()
        self.ui = QtWidgets.QWidget(self)
        self.ui.tab = TabWidget(self)
        self.ui.layout = QtWidgets.QVBoxLayout()
        self.ui.layout.addWidget(self.ui.tab)
        self.ui.setLayout(self.ui.layout)
        self.setCentralWidget(self.ui)
        self.show()


if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = Main(app)
    sys.exit(app.exec_())
I wonder if this is possible to do, as the tabBar is seen as a single object containing all the tabs, and I don't know how to access them directly. Any ideas?
Quote
#2
look at this example on github

It shows how to drag/drop/move between TreeWidgets
Quote
#3
Thanks for your reply. Yes I saw this already, but it is not what I am looking for. Accepting a drop in the TreeWidget is easy, but I want the tab to change once it is hovered, just like when something is hovered over tabs in Chrome or Firefox. The problem is that only a single even occur once the drag enter the tagbar, but I couldn't find how todo it for separate tabs.
Quote
#4
to get dragMoveEvent printing add to dragEnterEvent:

event.accept()

I tried it a bit, I can change the tab index with an eventFilter, but it works only after mouse button release.

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
 
 
class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        super().__init__()
        self.tab1 = QtWidgets.QTreeWidget()
        self.tab2 = QtWidgets.QTreeWidget()
        self.tab3 = QtWidgets.QTreeWidget()
        self.tabIndex = 0
        item = QtWidgets.QTreeWidgetItem()
        item.setText(0, "drag me")
        self.tab1.addTopLevelItem(item)
        self.tab1.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
        self.TabBar = QtWidgets.QTabBar()
        self.ui = QtWidgets.QWidget(self)
        self.ui.tab = QtWidgets.QTabWidget(self)
        self.ui.tab.setTabBar(self.TabBar)
        self.ui.tab.addTab(self.tab1, "1st tab")
        self.ui.tab.addTab(self.tab2, "2nd tab")
        self.ui.tab.addTab(self.tab3, "3rd tab")
        self.tab2.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.tab3.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.ui.layout = QtWidgets.QVBoxLayout()
        self.ui.layout.addWidget(self.ui.tab)
        self.ui.setLayout(self.ui.layout)
        self.setCentralWidget(self.ui)

        self.TabBar.setCurrentIndex(self.tabIndex)
        self.mouseHoverOnTabBar()

        self.setAcceptDrops(True)
        self.show()

    def mouseHoverOnTabBar(self):
        self.ui.tab=self.ui.tab.tabBar()
        self.ui.tab.setMouseTracking(True)
        self.ui.tab.installEventFilter(self)

    def eventFilter(self, obj, event):
        if obj == self.ui.tab:
            if event.type() == QtCore.QEvent.Enter:
                pos = event.pos()
                self.tabIndex=self.TabBar.tabAt(pos)
                print("tab index:", self.tabIndex)
#                self.TabBar.setCurrentIndex (self.tabIndex)
#                self.TabBar.setTabEnabled(self.tabIndex, True)
                self.dragEnterEvent(event)
                event.accept()
                return True
        return super().eventFilter(obj, event)

    def dragEnterEvent(self, event):
        print("drag enter")
#        pos = QtGui.QCursor.pos()
#        self.tabIndex=self.TabBar.tabAt(pos)
#        print("tab index:", self.tabIndex, "\npos:", pos)
        self.TabBar.setCurrentIndex (self.tabIndex)
        event.accept()

    def dragMoveEvent(self, event):
        print("drag move enter")
        event.accept()

    def hoverEnter(self, event):
        print ("On Hover")
        event.accept()
 
if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = Main(app)
    sys.exit(app.exec_())
Alfalfa likes this post
Quote
#5
forget the last post. It's so easy

setChangeCurrentOnDrag

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
 
 
class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        super().__init__()

        self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
        self.tab1 = QtWidgets.QTreeWidget()
        self.tab2 = QtWidgets.QTreeWidget()
        self.tab3 = QtWidgets.QTreeWidget()
        self.tabIndex = 0
        item = QtWidgets.QTreeWidgetItem()
        item.setText(0, "drag me")
        self.tab1.addTopLevelItem(item)
        self.tab1.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)
        self.TabBar = QtWidgets.QTabBar()

        self.ui = QtWidgets.QWidget(self)
        self.ui.tab = QtWidgets.QTabWidget(self)
        self.ui.tab.setTabBar(self.TabBar)
        self.ui.tab.addTab(self.tab1, "1st tab")
        self.ui.tab.addTab(self.tab2, "2nd tab")
        self.ui.tab.addTab(self.tab3, "3rd tab")
        self.tab2.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.tab3.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
        self.ui.layout = QtWidgets.QVBoxLayout()
        self.ui.layout.addWidget(self.ui.tab)
        self.ui.setLayout(self.ui.layout)
        self.setCentralWidget(self.ui)

        self.TabBar.setCurrentIndex(self.tabIndex)
        self.TabBar.setChangeCurrentOnDrag(True)
        self.TabBar.setAcceptDrops(True)

        self.setAcceptDrops(True)
        self.show()

 
if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = Main(app)
    sys.exit(app.exec_())
Alfalfa likes this post
Quote
#6
dragMoveEvent required that event.acceptProposedAction() is called in dragEnterEvent. So by using tabAt(pos) as you suggested, this work:

#!/usr/bin/python3
import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class TabBar(QtWidgets.QTabBar):
    def __init__(self, parent):
        super().__init__()
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        event.acceptProposedAction()
        QtWidgets.QTabBar.dragEnterEvent(self, event)

    def dragMoveEvent(self, event):
        pos = event.pos()
        index = self.tabAt(pos)
        self.setCurrentIndex(index)


class TabWidget(QtWidgets.QTabWidget):
    def __init__(self, parent):
        super().__init__()
        tab1 = QtWidgets.QTreeWidget()
        self.setTabBar(TabBar(self))
        self.addTab(tab1, "1st tab")
        self.addTab(QtWidgets.QTreeWidget(), "2nd tab")
        self.addTab(QtWidgets.QTreeWidget(), "3rd tab")

        item = QtWidgets.QTreeWidgetItem()
        item.setText(0, "drag me")
        tab1.addTopLevelItem(item)
        tab1.setDragDropMode(QtWidgets.QAbstractItemView.DragOnly)


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent):
        super().__init__()
        self.ui = QtWidgets.QWidget(self)
        self.ui.tab = TabWidget(self)
        self.ui.layout = QtWidgets.QVBoxLayout()
        self.ui.layout.addWidget(self.ui.tab)
        self.ui.setLayout(self.ui.layout)
        self.setCentralWidget(self.ui)
        self.show()


if __name__== '__main__':
    app = QtWidgets.QApplication(sys.argv)
    gui = Main(app)
    sys.exit(app.exec_())

(Sep-01-2019, 06:08 PM)Axel_Erfurt Wrote: forget the last post. It's so easy setChangeCurrentOnDrag

Thanks for the tip, I did not see this in the docs.. Sometimes the solutions are simpler than expected Doh
Quote

Top Page

Possibly Related Threads...
Thread Author Replies Views Last Post
  GUI with drag and drop functionality sayyedkamran 7 2,255 May-26-2020, 10:20 PM
Last Post: jefsummers
  Looking for Python IDE With Drag and Drop GUI Dan_PanMan 0 291 May-23-2020, 04:39 PM
Last Post: Dan_PanMan
  [PyQt] Drag and Move window from menubar WBPYTHON 3 207 Apr-03-2020, 06:15 PM
Last Post: deanhystad
  click drag olivers 1 965 Jan-30-2020, 01:44 AM
Last Post: Larz60+
  [Tkinter] Need help please properly putting tabs within a PanedWindow JackMack118 2 423 Dec-08-2019, 03:02 PM
Last Post: balenaucigasa
  [Tkinter] Adding space between Notebook tabs Columbo 4 1,001 Jul-10-2019, 10:46 PM
Last Post: Columbo
  [Tkinter] How to get a tabs works exactly same as google chrome sarthak260 0 894 Mar-07-2019, 10:45 AM
Last Post: sarthak260
  [Tkinter] How to create multilple tabs in tkinter from different classes Rishav 5 11,324 Jul-11-2018, 11:59 AM
Last Post: CCChris91
  [PyQt] Drag and drop converter Raures 0 2,151 Oct-01-2017, 07:44 PM
Last Post: Raures
  How to create mutiple tabs in tkinter using oops Rishav 2 3,367 Jul-12-2017, 04:43 PM
Last Post: Rishav

Forum Jump:


Users browsing this thread: 1 Guest(s)