Posts: 164
Threads: 22
Joined: Feb 2017
Sep-01-2019, 01:10 AM
(This post was last modified: Sep-02-2019, 12:06 AM by Alfalfa.)
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?
Posts: 1,028
Threads: 16
Joined: Dec 2016
Sep-01-2019, 01:00 PM
(This post was last modified: Sep-01-2019, 01:00 PM by Axel_Erfurt.)
look at this example on github
It shows how to drag/drop/move between TreeWidgets
Posts: 164
Threads: 22
Joined: Feb 2017
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.
Posts: 1,028
Threads: 16
Joined: Dec 2016
Sep-01-2019, 04:06 PM
(This post was last modified: Sep-01-2019, 04:31 PM by Axel_Erfurt.)
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_())
Posts: 1,028
Threads: 16
Joined: Dec 2016
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_())
Posts: 164
Threads: 22
Joined: Feb 2017
Sep-01-2019, 11:58 PM
(This post was last modified: Sep-02-2019, 12:02 AM by Alfalfa.)
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
|