PyQt5: Drag and drop between item peers in a QTreeWidget - python

Nodes of the same level can be dragged and prevented from entering each other, not other parent nodes.
I overwrote the dragMoveEvent and dropEvent methods in the QTreeWidget.I only have the second layer effect correct, which can drag each other and prevent entry into each other. But the first and third levels have different errors. For example, node1-1-1 and Node1-2-2 cannot be dragged to each other. Node1 can be dragged inside Node2, which is not in accordance with my finished requirements.
class TreeWidget(QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if current_item and current_item.type() == 0:
super().dragMoveEvent(event)
elif item and item.type() == 1 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
elif item and item.type() == 2 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if current_item and current_item.type() == 0:
super(TreeWidget, self).dropEvent(event)
elif item and item.type() == 1 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
elif item and item.type() == 2 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
else:
event.ignore()
class BasicTreeTest1(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTreeWidget')
self.tree = TreeWidget()
root1 = QTreeWidgetItem(self.tree,type=0)
root1.setText(0, 'node1')
child1_1 = QTreeWidgetItem(root1,type=1)
child1_1.setText(0, 'node1-1')
child1_1.setFlags(child1_1.flags() & ~Qt.ItemIsDropEnabled)
child1_2 = QTreeWidgetItem(root1, type=1)
child1_2.setText(0, 'node1-2')
child1_2.setFlags(child1_2.flags() & ~Qt.ItemIsDropEnabled)
child1_1_1 = QTreeWidgetItem(child1_1, type=2)
child1_1_1.setText(0, 'node1-1-1')
child1_1_1.setFlags(child1_1_1.flags() & ~Qt.ItemIsDropEnabled)
child1_2_1 = QTreeWidgetItem(child1_1, type=2)
child1_2_1.setText(0, 'node1-2-1')
child1_2_1.setFlags(child1_2_1.flags() & ~Qt.ItemIsDropEnabled)
root2 = QTreeWidgetItem(self.tree,type=0)
root2.setText(0, 'node2')
child2_1 = QTreeWidgetItem(root2, type=1)
child2_1.setText(0, 'node2-1')
child2_1.setFlags(child2_1.flags() & ~Qt.ItemIsDropEnabled)
child2_2 = QTreeWidgetItem(root2, type=1)
child2_2.setText(0, 'node2-2')
child2_2.setFlags(child2_2.flags() & ~Qt.ItemIsDropEnabled)
root3 = QTreeWidgetItem(self.tree, type=0)
root3.setText(0, 'node3')
child3_1 = QTreeWidgetItem(root3, type=1)
child3_1.setText(0, 'node3_1')
child3_1.setFlags(child3_1.flags() & ~Qt.ItemIsDropEnabled)
child3_2 = QTreeWidgetItem(root3, type=1)
child3_2.setText(0, 'node3_2')
child3_2.setFlags(child3_2.flags() & ~Qt.ItemIsDropEnabled)
child3_2_1 = QTreeWidgetItem(child3_2, type=2)
child3_2_1.setText(0, 'node3-2-1')
child3_2_1.setFlags(child3_2_1.flags() & ~Qt.ItemIsDropEnabled)
child3_2_2 = QTreeWidgetItem(child3_2, type=2)
child3_2_2.setText(0, 'node3-2-2')
child3_2_2.setFlags(child3_2_2.flags() & ~Qt.ItemIsDropEnabled)
# root1.setFlags(root1.flags() & ~Qt.ItemIsDropEnabled)
# root2.setFlags(root2.flags() & ~Qt.ItemIsDropEnabled)
# root3.setFlags(root3.flags() & ~Qt.ItemIsDropEnabled)
# child22.setFlags(child22.flags() & ~Qt.ItemIsDropEnabled)
self.setCentralWidget(self.tree)
self.tree.expandAll()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = BasicTreeTest1()
w.show()
sys.exit(app.exec_())
This site is my reference: https://blog.csdn.net/this_is_id/article/details/125258736

UPDATE:
Since your latest edits change the requirements, a different approach is needed. At the moment, the only solution I can see is to get the current drop-indicator, which then makes it possible to know if the drop-target is above or below an item. Qt uses a private method for this, which must be ported to PyQt to access the same functionality. I have implemented this in the demo script below, which only allows sibling items (at any level) to be re-ordered within their own parent:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class TreeWidget(QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
if self.canDrop(event):
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
if self.canDrop(event):
super().dropEvent(event)
else:
event.ignore()
def canDrop(self, event):
target = self.itemAt(event.pos())
current = self.currentItem()
if target is not None and target.parent() is current.parent():
index = self.indexFromItem(target)
indicator = self.dragIndicator(
event.pos(), self.visualItemRect(target), index)
return (indicator == QAbstractItemView.AboveItem or
indicator == QAbstractItemView.BelowItem)
return False
def dragIndicator(self, pos, rect, index):
indicator = QAbstractItemView.OnViewport
if not self.dragDropOverwriteMode():
margin = int(max(2, min(rect.height() / 5.5, 12)))
if pos.y() - rect.top() < margin:
indicator = QAbstractItemView.AboveItem
elif rect.bottom() - pos.y() < margin:
indicator = QAbstractItemView.BelowItem
elif rect.contains(pos, True):
indicator = QAbstractItemView.OnItem
else:
touching = rect.adjust(-1, -1, 1, 1)
if touching.contains(pos, False):
indicator = QAbstractItemView.OnItem
if (indicator == QAbstractItemView.OnItem and
not self.model().flags(index) & Qt.ItemIsDropEnabled):
if pos.y() < rect.center().y():
indicator = QAbstractItemView.AboveItem
else:
indicator = QAbstractItemView.BelowItem
return indicator
class BasicTreeTest1(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTreeWidget')
self.tree = TreeWidget()
root1 = QTreeWidgetItem(self.tree,type=0)
root1.setText(0, 'node1')
child1_1 = QTreeWidgetItem(root1,type=1)
child1_1.setText(0, 'node1-1')
child1_2 = QTreeWidgetItem(root1, type=1)
child1_2.setText(0, 'node1-2')
child1_1_1 = QTreeWidgetItem(child1_1, type=2)
child1_1_1.setText(0, 'node1-1-1')
child1_2_1 = QTreeWidgetItem(child1_1, type=2)
child1_2_1.setText(0, 'node1-2-1')
root2 = QTreeWidgetItem(self.tree,type=0)
root2.setText(0, 'node2')
child2_1 = QTreeWidgetItem(root2, type=1)
child2_1.setText(0, 'node2-1')
child2_2 = QTreeWidgetItem(root2, type=1)
child2_2.setText(0, 'node2-2')
root3 = QTreeWidgetItem(self.tree, type=0)
root3.setText(0, 'node3')
child3_1 = QTreeWidgetItem(root3, type=1)
child3_1.setText(0, 'node3_1')
child3_2 = QTreeWidgetItem(root3, type=1)
child3_2.setText(0, 'node3_2')
child3_2_1 = QTreeWidgetItem(child3_2, type=2)
child3_2_1.setText(0, 'node3-2-1')
child3_2_2 = QTreeWidgetItem(child3_2, type=2)
child3_2_2.setText(0, 'node3-2-2')
self.setCentralWidget(self.tree)
self.tree.expandAll()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = BasicTreeTest1()
w.setGeometry(600, 100, 500, 400)
w.show()
sys.exit(app.exec_())
PREVIOUS SOLUTION:
To prevent child items dropping onto each other you can change their item-flags. The default flags include Qt.ItemIsDropEnabled, so you just need to remove that:
child111 = QTreeWidgetItem(root1, type=1)
child111.setFlags(child111.flags() & ~Qt.ItemIsDropEnabled)
Of course, this won't stop items being dragged and dropped between parents, but your current code already prevents that by reimplementing dragMoveEvent and dropEvent, so it looks like the above changes are all that's needed.
Here is a complete working example based on your code:
from PyQt5 import QtCore, QtWidgets
class TreeWidget(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setDragDropMode(QtWidgets.QTreeWidget.InternalMove)
def dragMoveEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if item and item.type() == 1 and current_item.parent() == item.parent():
super().dragMoveEvent(event)
else:
event.ignore()
def dropEvent(self, event):
current_item = self.currentItem()
item = self.itemAt(event.pos())
if item and item.type() == 1 and current_item.parent() == item.parent():
super(TreeWidget, self).dropEvent(event)
else:
event.ignore()
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.tree = TreeWidget()
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tree)
root1 = QtWidgets.QTreeWidgetItem(self.tree,type=0)
root1.setText(0, '1')
child111 = QtWidgets.QTreeWidgetItem(root1,type=1)
child111.setFlags(child111.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child111.setText(0, '11')
child12 = QtWidgets.QTreeWidgetItem(root1, type=1)
child12.setFlags(child12.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child12.setText(0, '12')
root2 = QtWidgets.QTreeWidgetItem(self.tree,type=0)
root2.setText(0, '2')
child121 = QtWidgets.QTreeWidgetItem(root2, type=1)
child121.setFlags(child121.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child121.setText(0, '21')
child122 = QtWidgets.QTreeWidgetItem(root2, type=1)
child122.setFlags(child122.flags() & ~QtCore.Qt.ItemIsDropEnabled)
child122.setText(0, '22')
self.tree.expandAll()
if __name__ == '__main__':
app = QtWidgets.QApplication(['Test'])
window = Window()
window.setWindowTitle('Test')
window.setGeometry(600, 100, 300, 200)
window.show()
app.exec_()

Related

Use rich module in curses panel

It's my first time with curses module and I want make menu with this.
I have found example on internet for make this.
import curses
from curses import panel
class Menu(object):
def __init__(self, items, stdscreen):
self.window = stdscreen.subwin(0, 0)
self.window.keypad(1)
self.panel = panel.new_panel(self.window)
self.panel.hide()
panel.update_panels()
self.position = 0
self.items = items
self.items.append(("exit", "exit"))
def navigate(self, n):
self.position += n
if self.position < 0:
self.position = 0
elif self.position >= len(self.items):
self.position = len(self.items) - 1
def display(self):
self.panel.top()
self.panel.show()
self.window.clear()
while True:
self.window.refresh()
curses.doupdate()
for index, item in enumerate(self.items):
if index == self.position:
mode = curses.A_REVERSE
else:
mode = curses.A_NORMAL
msg = "%d. %s" % (index, item[0])
self.window.addstr(10 + index, 1, msg, mode)
key = self.window.getch()
if key in [curses.KEY_ENTER, ord("\n")]:
if self.position == len(self.items) - 1:
break
else:
self.items[self.position][1]()
elif key == curses.KEY_UP:
self.navigate(-1)
elif key == curses.KEY_DOWN:
self.navigate(1)
self.window.clear()
self.panel.hide()
panel.update_panels()
curses.doupdate()
class MyApp(object):
def __init__(self, stdscreen):
self.screen = stdscreen
curses.curs_set(0)
submenu_items = [("beep", curses.beep), ("flash", curses.flash)]
submenu = Menu(submenu_items, self.screen)
main_menu_items = [
("beep", curses.beep),
("flash", curses.flash),
("submenu", submenu.display),
]
main_menu = Menu(main_menu_items, self.screen)
main_menu.display()
if __name__ == "__main__":
curses.wrapper(MyApp)
It's work pretty good, but I want show a Banner for my title. For this I use rich module and pyfiglet like this :
from rich import print
from rich.text import Text
from rich.panel import Panel
banner = Text(pyfiglet.figlet_format("Title Test", font="bulbhead"), style="bold magenta")
bannerPanel = Panel(Text(pyfiglet.figlet_format("Title Test", font="bulbhead"), style="bold magenta").plain)
I can't add Text object or Panel object with self.window.addstr() because he want a string object.
Is it possible to show bannerPanel or banner above my menu?
Thanks in advance
The only thing I managed to do is add Text().plain.

How can I check or uncheck QStandrdItem's check box in "PySide2 QStandardItemModel" with mouse click and drag?

what I need in this case is "uncheck or check" the items in QListView with mouse hold and press
I've added Items with check boxes , I need to change the state of the items (check or uncheck) for multi items with just press and hold , like making multi selection .
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class items_List(QListView):
clicked = pyqtSignal()
def __init__(self,items):
QListView.__init__(self)
#self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.model = QStandardItemModel()
self.setModel(self.model)
self.model.itemChanged.connect(self.on_itemChanged)
self.items = items
self.add_items_(self.items)
self.show()
def add_items_(self,all_items=None):
self.active_items = []
if all_items == None:
return
for item in all_items:
#self.model.appendRow(str(i))
self.item = QStandardItem(str(item))
self.item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable)
self.item.setData(QVariant(Qt.Checked), Qt.CheckStateRole)
self.model.appendRow(self.item)
self.active_items.append(str(item))
def selected_item(self):
print "Selected "
#pyqtSlot(QStandardItem)
def on_itemChanged(self, item):
state = ['UNCHECKED', 'TRISTATE', 'CHECKED'][item.checkState()]
if state == 'UNCHECKED':
self.active_items.remove(item.text())
else:
if item.text() not in self.active_items:
self.active_items.append(str(item.text()))
print self.active_items
def main():
app = QApplication(sys.argv)
items = [1001,1002,1003,1004,1005]
win = items_List(items)
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Derive and set color to the index of newly-added children

I have created subclass of QTreeWidget and QTreeWidgetItem where I am trying to highlight the new added items (where the text will be colored red).
The tree hierarchy that I have adopted is as follows:
|-- parent
|--|-- child
|--|-- child
The tree widget is initially populated from a dictionary.
To get the difference, I did it by converting the current hierarchy in the tree widget into a dictionary and have it compared against the initial dictionary that it was populated with.
However if I add in a new child to an existing parent in which the name of the new child already existed in another parent, the same method as mentioned above does not works, as it will colored the first result that it find.
To replicate:
select menuB
right mouse click > add new sub item
input name: a101
hit "Highlight Diff." button
a101 child item under menuA is highlighted instead of the one in menuB
What would be the best way to go in getting the index of newly added child(ren)?
Thank you for any replies.
P.S: If anyone has better suggestion for the parent highlighting, please feel free to chip in.
class CustomTreeWidgetItem(QtGui.QTreeWidgetItem):
def __init__(self, widget=None, text=None, is_tristate=False):
super(CustomTreeWidgetItem, self).__init__(widget)
self.setText(0, text)
if is_tristate:
# Solely for the Parent item
self.setFlags(
self.flags()
| QtCore.Qt.ItemIsTristate
| QtCore.Qt.ItemIsEditable
| QtCore.Qt.ItemIsUserCheckable
)
else:
self.setFlags(
self.flags()
| QtCore.Qt.ItemIsEditable
| QtCore.Qt.ItemIsUserCheckable
)
self.setCheckState(0, QtCore.Qt.Unchecked)
def setData(self, column, role, value):
state = self.checkState(column)
QtGui.QTreeWidgetItem.setData(self, column, role, value)
if (role == QtCore.Qt.CheckStateRole and
state != self.checkState(column)):
tree_widget = CustomTreeWidget()
if tree_widget is not None:
tree_widget.itemToggled.emit(self, column)
class CustomTreeWidget(QtGui.QTreeWidget):
def __init__(self, widget=None):
super(CustomTreeWidget, self).__init__(widget)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.show_custom_menu)
def show_custom_menu(self):
base_node = self.selectedItems()[0]
qmenu = QtGui.QMenu(self)
remove_action = QtGui.QAction("Remove item", self)
remove_action.triggered.connect(self.remove_selected_item)
qmenu.addAction(remove_action)
# The following options are only effected for top-level items
# top-level items do not have `parent()`
if not base_node.parent():
add_new_child_action = QtGui.QAction("Add new sub item", self)
add_new_child_action.triggered.connect(
partial(self.adds_new_child_item, base_node)
)
# qmenu.addAction(add_new_child_action)
qmenu.insertAction(remove_action, add_new_child_action)
qmenu.exec_(QtGui.QCursor.pos())
def add_item_dialog(self, title):
text, ok = QtGui.QInputDialog.getText(
self,
"Add {0} Item".format(title),
"Enter name for {0}-Item:".format(title)
)
if ok and text != "":
return text
def add_new_parent_item(self):
input_text = self.add_item_dialog("Parent")
if input_text:
CustomTreeWidgetItem(self, input_text, is_tristate=True)
def adds_new_child_item(self, base_node):
input_text = self.add_item_dialog("Sub")
if input_text:
CustomTreeWidgetItem(base_node, input_text)
self.setItemExpanded(base_node, True)
def remove_selected_item(self):
root = self.invisibleRootItem()
for item in self.selectedItems():
(item.parent() or root).removeChild(item)
def derive_tree_items(self, mode="all"):
all_items = defaultdict(list)
root_item = self.invisibleRootItem()
top_level_count = root_item.childCount()
for i in range(top_level_count):
top_level_item = root_item.child(i)
top_level_item_name = str(top_level_item.text(0))
child_num = top_level_item.childCount()
all_items[top_level_item_name] = []
for n in range(child_num):
child_item = top_level_item.child(n)
child_item_name = str(child_item.text(0)) or ""
if mode == "all":
all_items[top_level_item_name].append(child_item_name)
elif mode == "checked":
if child_item.checkState(0) == QtCore.Qt.Checked:
all_items[top_level_item_name].append(child_item_name)
elif mode == "unchecked":
if child_item.checkState(0) == QtCore.Qt.Unchecked:
all_items[top_level_item_name].append(child_item_name)
return all_items
class MainApp(QtGui.QWidget):
def __init__(self):
super(MainApp, self).__init__()
# initial dictionary that is populated into the tree widget
test_dict = {
"menuA": ["a101", "a102"],
"menuC": ["c101", "c102", "c103"],
"menuB": ["b101"],
}
self._tree = CustomTreeWidget()
self._tree.header().hide()
for pk, pv in sorted(test_dict.items()):
parent = CustomTreeWidgetItem(self._tree, pk, is_tristate=True)
for c in pv:
child = CustomTreeWidgetItem(parent, c)
self.orig_dict = self._tree.derive_tree_items()
# Expand the hierarchy by default
self._tree.expandAll()
tree_layout = QtGui.QVBoxLayout()
self.btn1 = QtGui.QPushButton("Add new item")
self.btn2 = QtGui.QPushButton("Highlight Diff.")
tree_layout.addWidget(self._tree)
tree_layout.addWidget(self.btn1)
tree_layout.addWidget(self.btn2)
main_layout = QtGui.QHBoxLayout()
main_layout.addLayout(tree_layout)
self.setLayout(main_layout)
self.setup_connections()
def setup_connections(self):
self.btn1.clicked.connect(self.add_parent_item)
self.btn2.clicked.connect(self.highlight_diff)
def add_parent_item(self):
# Get current selected in list widget
# CustomTreeWidgetItem(self._tree, "test", is_tristate=True)
self._tree.add_new_parent_item()
def highlight_diff(self):
self.current_dict = self._tree.derive_tree_items()
if self.orig_dict != self.current_dict:
# check for key difference
diff = [k for k in self.current_dict if k not in self.orig_dict]
if diff:
# get the difference of top-level items
for d in diff:
top_item = self._tree.findItems(d, QtCore.Qt.MatchExactly|QtCore.Qt.MatchRecursive)
#print aaa[0].childCount()
top_item[0].setTextColor(0, QtGui.QColor(255, 0, 0))
if top_item[0].childCount():
for n in range(top_item[0].childCount()):
top_item[0].child(n).setTextColor(0, QtGui.QColor(255, 0, 0))
# to highlight the child diff. of existing top-items
# issue with this portion if the new added item name already existed
for k, v in self.current_dict.items():
if k in self.orig_dict:
diff = set(v).difference(self.orig_dict.get(k), [])
for d in diff:
child_item = self._tree.findItems(d, QtCore.Qt.MatchExactly|QtCore.Qt.MatchRecursive)
child_item[0].setTextColor(0, QtGui.QColor(255, 0, 0))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MainApp()
w.show()
sys.exit(app.exec_())
You can save in a role a flag indicating if it is a new item or not and change the color using a delegate:
import sys
from functools import partial
from PyQt4 import QtCore, QtGui
from collections import defaultdict
IsNewItemRole = QtCore.Qt.UserRole + 1000
class CustomTreeDelegate(QtGui.QStyledItemDelegate):
#property
def text_color(self):
if not hasattr(self, "_text_color"):
self._text_color = QtGui.QColor()
return self._text_color
#text_color.setter
def text_color(self, color):
self._text_color = color
def initStyleOption(self, option, index):
super(CustomTreeDelegate, self).initStyleOption(option, index)
if self.text_color.isValid() and index.data(IsNewItemRole):
option.palette.setBrush(QtGui.QPalette.Text, self.text_color)
class CustomTreeWidgetItem(QtGui.QTreeWidgetItem):
def __init__(self, parent=None, text="", is_tristate=False, is_new_item=False):
super(CustomTreeWidgetItem, self).__init__(parent)
self.setText(0, text)
flags = QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsUserCheckable
if is_tristate:
flags |= QtCore.Qt.ItemIsTristate
else:
self.setCheckState(0, QtCore.Qt.Unchecked)
self.setFlags(self.flags() | flags)
self.setData(0, IsNewItemRole, is_new_item)
def setData(self, column, role, value):
state = self.checkState(column)
QtGui.QTreeWidgetItem.setData(self, column, role, value)
if role == QtCore.Qt.CheckStateRole and state != self.checkState(column):
tree_widget = self.treeWidget()
if isinstance(tree_widget, CustomTreeWidget):
tree_widget.itemToggled.emit(self, column)
class CustomTreeWidget(QtGui.QTreeWidget):
itemToggled = QtCore.pyqtSignal(QtGui.QTreeWidgetItem, int)
def __init__(self, widget=None):
super(CustomTreeWidget, self).__init__(widget)
self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.show_custom_menu)
def show_custom_menu(self, pos):
base_node = self.itemAt(pos)
if base_node is None:
return
qmenu = QtGui.QMenu(self)
remove_action = QtGui.QAction("Remove item", self)
remove_action.triggered.connect(self.remove_selected_item)
qmenu.addAction(remove_action)
# The following options are only effected for top-level items
# top-level items do not have `parent()`
if base_node.parent() is None:
add_new_child_action = QtGui.QAction("Add new sub item", self)
add_new_child_action.triggered.connect(
partial(self.adds_new_child_item, base_node)
)
# qmenu.addAction(add_new_child_action)
qmenu.insertAction(remove_action, add_new_child_action)
qmenu.exec_(self.mapToGlobal(pos))
def add_item_dialog(self, title):
text, ok = QtGui.QInputDialog.getText(
self, "Add {0} Item".format(title), "Enter name for {0}-Item:".format(title)
)
if ok:
return text
def add_new_parent_item(self):
input_text = self.add_item_dialog("Parent")
if input_text:
it = CustomTreeWidgetItem(
self, input_text, is_tristate=True, is_new_item=True
)
def adds_new_child_item(self, base_node):
input_text = self.add_item_dialog("Sub")
if input_text:
it = CustomTreeWidgetItem(base_node, input_text, is_new_item=True)
self.setItemExpanded(base_node, True)
it.setData(0, IsNewItemRole, True)
def remove_selected_item(self):
root = self.invisibleRootItem()
for item in self.selectedItems():
(item.parent() or root).removeChild(item)
class MainApp(QtGui.QWidget):
def __init__(self, parent=None):
super(MainApp, self).__init__(parent)
# initial dictionary that is populated into the tree widget
test_dict = {
"menuA": ["a101", "a102"],
"menuC": ["c101", "c102", "c103"],
"menuB": ["b101"],
}
self._tree = CustomTreeWidget()
self._tree.header().hide()
self._tree_delegate = CustomTreeDelegate(self._tree)
self._tree.setItemDelegate(self._tree_delegate)
for pk, pv in sorted(test_dict.items()):
parent = CustomTreeWidgetItem(self._tree, pk, is_tristate=True)
for c in pv:
child = CustomTreeWidgetItem(parent, c)
# Expand the hierarchy by default
self._tree.expandAll()
tree_layout = QtGui.QVBoxLayout()
self.btn1 = QtGui.QPushButton("Add new item")
self.btn2 = QtGui.QPushButton("Highlight Diff.")
tree_layout.addWidget(self._tree)
tree_layout.addWidget(self.btn1)
tree_layout.addWidget(self.btn2)
main_layout = QtGui.QHBoxLayout(self)
main_layout.addLayout(tree_layout)
self.setup_connections()
def setup_connections(self):
self.btn1.clicked.connect(self.add_parent_item)
self.btn2.clicked.connect(self.highlight_diff)
def add_parent_item(self):
# Get current selected in list widget
# CustomTreeWidgetItem(self._tree, "test", is_tristate=True)
self._tree.add_new_parent_item()
def highlight_diff(self):
self._tree_delegate.text_color = QtGui.QColor(255, 0, 0)
self._tree.viewport().update()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MainApp()
w.show()
sys.exit(app.exec_())

How to filter the access to path with gtk.fileselection (python)?

I working with gtk.fileselection and it works perfectly. But how can I block the access to a given path with fileselection widget.
If I do not block access to a certain path, the user can see sensitive information inside my system.
class FileSelection:
# Get the selected filename and print it to the console
def file_ok_sel(self, w):
print "%s" % self.filew.get_filename()
def destroy(self, widget):
gtk.main_quit()
def __init__(self):
#Create a new file selection widget
self.filew = gtk.FileSelection("File selection")
self.filew.hide_fileop_buttons()
self.filew.get_focus()
self.filew.connect("destroy", self.destroy)
# Connect the ok_button to file_ok_sel method
self.filew.ok_button.connect("clicked", self.file_ok_sel)
# Connect the cancel_button to destroy the widget
self.filew.cancel_button.connect("clicked",lambda w: self.filew.destroy())
# Lets set the filename, as if this were a save dialog,
# and we are giving a default filename
self.filew.set_filename("penguin.png")
self.filew.show()
def main(self):
gtk.main()
print "selection"*10
return 0
In fact I would like to allow access only to the paths that hang from "mnt/tnc/" and not allow access to any more.
archivosTNC = os.listdir("/mnt/tnc")
lista = []
for a in archivosTNC:
if a[-2:] == ".H":
lista.append(a)
elif a[-4:] == ".txt":
lista.append(a)
elif a[-4:] == ".png":
lista.append(a)
elif a[-4:] == ".jpg":
lista.append(a)
ventana = gtk.Window()
ventana.set_default_size(-1, 300)
scrolledWindow = gtk.ScrolledWindow()
scrolledWindow.set_policy (hscrollbar_policy=gtk.POLICY_NEVER, vscrollbar_policy=gtk.POLICY_AUTOMATIC)
ventana.add(scrolledWindow)
tabla=table()
vbox = gtk.VBox()
tabla.attachToCell(vbox, col=1, row=1)
scrolledWindow.add_with_viewport(tabla)
#ventana.add(vbox)
for item in lista:
boton = gtk.Button(str(item))
boton.connect('clicked', self.devolverNombreArchivo)
vbox.pack_start(boton)

qtreewidget unwanted white space (additional unremovable rows)

I am creating a custom qtreewidget class that autoresizes its window to fit exactly the currently visible elements (I don't want to have to scroll). To do this, I run a count function to find the number of open qtreewidgetitems and their children and set a fixed height from there. However, when I expand a child widget (click the expand arrow on one of my items) the whole view suddenly needs to scroll because there is extra white space at the bottom, despite my count function accurately calculating the needed height. How do I get rid of it?
Below is a working class that can be run directly as is.
import sys
from PyQt4 import QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class TreeWidget(QTreeWidget):
def __init__(self, parent=None):
super(TreeWidget, self).__init__()
self.installEventFilter(self)
self.setStyleSheet('''
background: None;
border: None;
outline: None;
outline-width: 0px;
selection-background-color: blue;
''')
header = QtGui.QTreeWidgetItem(["Tree", "First"])
self.setAutoScroll(False)
self.setHeaderItem(header)
self.header().close()
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def fill_item(self, item, value):
item.setExpanded(False)
if type(value) is dict:
for key, val in sorted(value.iteritems()):
child = QTreeWidgetItem()
child.setText(0, unicode(key))
# child.doubleClicked.connect(lambda: self.doubleClicked1(child))
item.addChild(child)
self.fill_item(child, val)
elif type(value) is list:
last = None
for val in value:
child = QTreeWidgetItem()
if type(val) is dict:
item.addChild(child)
child.setText(0, '[dict]')
# child.doubleClicked.connect(lambda: self.doubleClicked1(child))
self.fill_item(child, val)
last = child
elif type(val) is list:
self.fill_item(last, val)
else:
item.addChild(child)
child.setText(0, unicode(val))
child.setText(1, 'test')
# child.doubleClicked.connect(lambda: self.doubleClicked1(child))
child.setExpanded(False)
last = child
else:
child = QTreeWidgetItem()
child.setText(0, unicode(val))
child.setText(1, 'test')
# child.doubleClicked.connect(lambda: self.doubleClicked1(child))
item.addChild(child)
def fill_widget(self, value):
self.clear()
self.fill_item(self.invisibleRootItem(), value)
def resizeEvent(self, event):
self.resize()
def resize(self):
width = 50
self.header().resizeSection(1, width)
self.header().resizeSection(0, self.width()-width)
height = self.visibleCount()
print height/15
self.setFixedHeight(height+0)
def eventFilter(self, source, event):
if source is self:
if event.type() == 1:
self.resize()
elif event.type() == QEvent.Leave:
self.clearSelection()
return QtGui.QTreeWidget.eventFilter(self, source, event)
def visibleCount(self, parent=0):
height = 0
if parent == 0:
topHeight = 0
for a in xrange(self.topLevelItemCount()):
item = self.topLevelItem(a)
topHeight += self.visualItemRect(item).height()
if item.isExpanded():
height += self.visibleCount(item)
height += topHeight
else:
childHeight = 0
for a in xrange(parent.childCount()):
item = parent.child(a)
childHeight += self.visualItemRect(item).height()
if item.isExpanded():
height += self.visibleCount(item)
height += childHeight
return height
def editClicked(self, parent=0):
# print 'edit 2'
if parent == 0:
for a in xrange(self.topLevelItemCount()):
item = self.topLevelItem(a)
print type(item)
item.setExpanded(True)
self.editClicked(item)
else:
for a in xrange(parent.childCount()):
item = parent.child(a)
print type(item)
item.setText(1, '+')
item.setExpanded(True)
self.editClicked(item)
def doubleClicked1(self, widget):
print widget
def main():
app = QtGui.QApplication(sys.argv)
ex = TreeWidget()
data = [
'Make sure ZMQ remote button gets honored',
'Fill in plot',
'Remove cycle',
'Remove current control or make it working',
'Handle possible startup errors with dialogs',
'Get improved current read-out (requires hardware changes)',
['1','2','3'],
'Email quench notification'
]
ex.fill_widget(data)
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You can remove the event filter entirely. You need to resize the widget when the items are expanded or collapsed. Both actions trigger signals, so you can simply connect those signals to resize:
class TreeWidget(QTreeWidget):
def __init__(self, parent=None):
super(TreeWidget, self).__init__(parent)
self.expanded.connect(self.resize)
self.collapsed.connect(self.resize)

Categories

Resources