WxPython select item - python-3.6

I want get value from selected item in list when I click a button, and post it in another list.
self.list_ctrl = wx.ListCtrl(panel, size=(30,100), pos=(20,30),
style=wx.LC_REPORT
|wx.BORDER_SUNKEN
)
self.list_ctrl2 = wx.ListCtrl(panel, size=(200,300),pos=(60,200), style=wx.LC_REPORT|wx.BORDER_SUNKEN)
btn = wx.Button(panel, label="Add Line")
btn2 = wx.Button(panel, label="Get Column 0")
btn3 = wx.Button(panel, label="select")
btn.Bind(wx.EVT_BUTTON, self.add_line)
btn2.Bind(wx.EVT_BUTTON, self.getColumn)
btn3.Bind(wx.EVT_BUTTON, self.getSelection)
def add_line(self, event):
line = "Line %s" % self.index
self.list_ctrl.InsertItem(self.index, line)
self.list_ctrl.SetItem(self.index, 1, "01/19/2010")
self.list_ctrl.SetItem(self.index, 2, "USA")
self.index += 1
def getColumn(self, event):
item = self.list_ctrl.GetItem(itemIdx=0, col=0)
print (item.GetText())
self.list_ctrl2.InsertItem(item)
def getSelection (self, event):
item2=self.list_ctrl.GetNextSelected()
self.list_ctrl2.InsertItem(item2)
I have try with GetItem, GetNextSelected. I have search on https://docs.wxpython.org/wx.ListCtrl.html#wx.ListCtrl.GetNextSelected
But I think I have a syntaxic problem and I didn't find

I have found my answer
define list :
self.userList = wx.ListCtrl(self.panel,pos=(50,200), size=(-1,500),style=wx.LC_REPORT)
Bind event :
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.addSendList, self.userList)
define event :
def AddSendList(self, evt):
choice= self.userList.GetFirstSelected()
item = self.userList.GetItem(itemIdx=choice, col=0)
textItem=item.GetText()
print(choice)
print(textItem)
self.sendList.InsertItem(0,textItem)
With this Function I can have the selected value in a ListCtrl, and put value in a other ListCtrl.

Related

Wxpython grid AppendRows

The following code is used to generate a table that an row can be added by a button, but only the data of the last row is eliminated after running.
import wx, wx.grid
class GridData(wx.grid.PyGridTableBase):
_cols = "a b c".split()
_data = [
"1 2 3".split(),
"4 5 6".split(),
"7 8 9".split()
]
_highlighted = set()
def GetColLabelValue(self, col):
return self._cols[col]
def GetNumberRows(self):
return len(self._data)
def GetNumberCols(self):
return len(self._cols)
def GetValue(self, row, col):
return self._data[row][col]
def SetValue(self, row, col, val):
self._data[row][col] = val
def AppendRows(self, *args):
msg = wx.grid.GridTableMessage(self,
wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED,
)
self.GetView().ProcessTableMessage(msg)
return True
# self.GetView().EndBatch()
# msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
# self.GetView().ProcessTableMessage(msg)
def GetAttr(self, row, col, kind):
attr = wx.grid.GridCellAttr()
attr.SetBackgroundColour(wx.GREEN if row in self._highlighted else wx.WHITE)
return attr
def set_value(self, row, col, val):
self._highlighted.add(row)
self.SetValue(row, col, val)
class Test(wx.Frame):#main frame
def __init__(self):
wx.Frame.__init__(self, None)
self.data = GridData()
self.grid = wx.grid.Grid(self)
self.grid.SetTable(self.data)
btn = wx.Button(self, label="set a2 to x")
btn.Bind(wx.EVT_BUTTON, self.OnTest)
self.Sizer = wx.BoxSizer(wx.VERTICAL)
self.Sizer.Add(self.grid, 1, wx.EXPAND)
self.Sizer.Add(btn, 0, wx.EXPAND)
def OnTest(self, event):
self.grid.AppendRows(numRows=3)
#self.data.set_value(1, 0, "x")
self.grid.Refresh()
app = wx.PySimpleApp()
app.TopWindow = Test()
app.TopWindow.Show()
app.MainLoop()
There is no error report,and the expectation can't be reached.
The following code is used to generate a table that can be added by a button, but only the data of the last row can be eliminated after running.

How do I connect WindowContextHelpButtonHint to a widget click?

I can add self.setWindowFlags(Qt.Window | Qt.WindowContextHelpButtonHint | Qt.WindowCloseButtonHint) to the constructor of my QMainWindow which adds the '?' button. Now I want to add contextual help information to virtually all UI components. How do I connect a click on the '?' button and then a click on some ui element (say a qlistview) such that a help message pops up?
Below is part of my program stripped to make it easy. How do I make it such that when the user clicks the '?' and then either a QDoubleSpinBox or the QListView or any of the QPushButtons that a help message displays?
I have searched for this but it seems the vast amount of questions and answers are about how to remove the '?' button or how to add it. None actually deal with how to alter the button's behaviour.
I've also tried using setInputMethodHints() to assign hints to ui components but this method doesn't accept custom strings as I assumed it would.
Btw: I also would like the '?' button to not replace the minimization button. I have yet to figure out how to achieve this either.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
APPNAME = 'Mesoscale Brain Explorer'
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle(APPNAME)
self.sidebar = Sidebar()
self.setWindowFlags(Qt.Window | Qt.WindowContextHelpButtonHint | Qt.WindowCloseButtonHint)
self.setup_ui()
def setup_ui(self):
self.pl_frame = QFrame()
splitter = QSplitter(self)
self.enable = lambda yes: splitter.setEnabled(yes)
splitter.setHandleWidth(3)
splitter.setStyleSheet('QSplitter::handle {background: #cccccc;}')
splitter.addWidget(self.sidebar)
splitter.addWidget(self.pl_frame)
self.setCentralWidget(splitter)
self.menu = self.menuBar()
m = self.menu.addMenu('&File')
a = QAction('&New project', self)
a.setShortcut('Ctrl+N')
a.setStatusTip('Create new project')
m.addAction(a)
a = QAction('&Open project', self)
a.setShortcut('Ctrl+O')
a.setStatusTip('Open project')
m.addAction(a)
a = QAction("&Quit", self)
a.setShortcut("Ctrl+Q")
a.setStatusTip('Leave The App')
a.setIcon(QIcon('pics/quit.png'))
m.addAction(a)
about_action = QAction('&About ' + APPNAME, self)
about_action.setStatusTip('About ' + APPNAME)
about_action.setShortcut('F1')
m = self.menu.addMenu('&Project')
m.setEnabled(False)
a = QAction("&Close", self)
a.setStatusTip('Close project')
m.addAction(a)
self.project_menu = m
help_menu = self.menu.addMenu('&Help')
help_menu.addAction(about_action)
class Sidebar(QWidget):
open_pipeconf_requested = pyqtSignal()
open_datadialog_requested = pyqtSignal()
automate_pipeline_requested = pyqtSignal()
x_origin_changed = pyqtSignal(float)
y_origin_changed = pyqtSignal(float)
units_per_pixel_changed = pyqtSignal(float)
def __init__(self, parent=None):
super(Sidebar, self).__init__(parent)
self.x_origin = QDoubleSpinBox()
self.y_origin = QDoubleSpinBox()
self.units_per_pixel = QDoubleSpinBox()
self.setup_ui()
def setup_ui(self):
self.setContentsMargins(4, 6, 5, 0)
vbox = QVBoxLayout()
hbox = QHBoxLayout()
hbox.addWidget(QLabel('Origin:'))
hbox.addWidget(QLabel('Units per pixel:'))
vbox.addLayout(hbox)
hbox2 = QHBoxLayout()
hhbox = QHBoxLayout()
hhbox2 = QHBoxLayout()
hhbox.addWidget(QLabel("X:"))
hhbox.addWidget(self.x_origin)
hhbox.addWidget(QLabel("Y:"))
hhbox.addWidget(self.y_origin)
hhbox2.addWidget(self.units_per_pixel)
hbox2.addLayout(hhbox)
hbox2.addLayout(hhbox2)
vbox.addLayout(hbox2)
self.units_per_pixel.setDecimals(5)
self.units_per_pixel.setMaximum(100000)
self.x_origin.setMaximum(100000)
self.y_origin.setMaximum(100000)
self.pl_list = QListView()
self.pl_list.setIconSize(QSize(18, 18))
self.pl_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.pl_list.setEditTriggers(QAbstractItemView.NoEditTriggers)
vbox.addWidget(QLabel('Pipeline:'))
vbox.addWidget(self.pl_list)
pb = QPushButton('&Automation')
pb.clicked.connect(self.automate_pipeline_requested)
vbox.addWidget(pb)
vbox.addSpacerItem(QSpacerItem(0, 1, QSizePolicy.Minimum, QSizePolicy.Expanding))
pb = QPushButton('&Configure Pipeline')
pb.clicked.connect(self.open_pipeconf_requested)
vbox.addWidget(pb)
pb = QPushButton('&Manage Data')
pb.clicked.connect(self.open_datadialog_requested)
vbox.addWidget(pb)
vbox.setStretch(0, 0)
vbox.setStretch(1, 0)
vbox.setStretch(2, 0)
self.setLayout(vbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setApplicationName(APPNAME)
app.setOrganizationName('University of British Columbia')
w = MainWindow()
w.resize(1060, 660)
w.show()
app.exec_()
app.deleteLater()
del w
sys.exit()

wxPython: populate grid from another class using flatenotebook

I am trying to save a text file from the first page of a flatNotebook, write them to an EXTERNALLY defined sqLite database and write the values to a grid on the second page of the flatNotebook. The values are saved to the text file and written to the database successfully but I cannot get the values to populate the grid at the same time. They values show up in the grid after I close the program and restart it. I am having a hard time understanding how to call the function onAddCue(). I have tried so many things that I'm just confusing myself at this point. Please help me understand what I am doing wrong. Here is my entire code:
cue =[4,'NodeA',11,22,33,44,55,66,77,88,99]
class InitialInputs(scrolled.ScrolledPanel):
global cue
def __init__(self, parent, db):
scrolled.ScrolledPanel.__init__(self, parent, -1)
self.db = db
self.cur = self.db.con.cursor()
self.saveBtn = wx.Button(self, -1, "Save Current Values")
self.Bind(wx.EVT_BUTTON, self.onSave, self.saveBtn)
self.dirname = ""
def onSave(self, event):
global cue
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.txt", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if dlg.ShowModal() == wx.ID_OK:
itcontains = cue
self.filename=dlg.GetFilename()
self.dirname=dlg.GetDirectory()
filehandle=open(os.path.join(self.dirname, self.filename),'w')
filehandle.write(str(itcontains))
filehandle.close()
dlg.Destroy()
row = cue[0] - 1
InsertCell ="UPDATE CUES SET 'Send'=?,'RED'=?,'GREEN'=?,'BLUE'=?,'RGB_Alpha'=?,'HUE'=?,'SAT'=?,'BRightness'=?,'HSB_Alpha'=?,'Fade'=? WHERE DTIndex=%i" %row
self.cur.execute(InsertCell, cue[1:])
self.db.con.commit()
GridPanel().grid.onAddCue() #This is the part that's not working
class Grid(gridlib.Grid):
global cue
def __init__(self, parent, db):
gridlib.Grid.__init__(self, parent, -1)
self.CreateGrid(20,10)
for row in range(20):
rowNum = row + 1
self.SetRowLabelValue(row, "cue %s" %rowNum)
self.db = db
self.cur = self.db.con.cursor()
meta = self.cur.execute("SELECT * from CUES")
labels = []
for i in meta.description:
labels.append(i[0])
labels = labels[1:]
for i in range(len(labels)):
self.SetColLabelValue(i, labels[i])
all = self.cur.execute("SELECT * from CUES ORDER by DTindex")
for row in all:
row_num = row[0]
cells = row[1:]
for i in range(len(cells)):
if cells[i] != None and cells[i] != "null":
self.SetCellValue(row_num, i, str(cells[i]))
self.Bind(gridlib.EVT_GRID_CELL_CHANGED, self.CellContentsChanged)
def CellContentsChanged(self, event):
x = event.GetCol()
y = event.GetRow()
val = self.GetCellValue(y,x)
if val == "":
val = "null"
ColLabel = self.GetColLabelValue(x)
InsertCell = "UPDATE CUES SET %s = ? WHERE DTindex = %d"%(ColLabel,y)
self.cur.execute(InsertCell, [(val),])
self.db.con.commit()
self.SetCellValue(y, x, val)
class GridPanel(wx.Panel):
def __init__(self, parent, db):
wx.Panel.__init__(self, parent, -1)
self.db = db
self.cur = self.db.con.cursor()
grid = Grid(self, db)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(grid)
self.SetSizer(sizer)
self.Fit()
def onAddCue():
global cue
row = cue[0] - 1
col=0
while col < 10:
for i in cue[1:]:
grid.SetCellValue(row, col, str(i))
col = col+1
class GetDatabase():
def __init__(self, f):
# check db file exists
try:
file = open(f)
file.close()
except IOError:
# database doesn't exist - create file & populate it
self.exists = 0
else:
# database already exists - need integrity check here
self.exists = 1
self.con = sqlite.connect(f)
class Frame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1,"Stage Lighting", size=(800,600))
panel = wx.Panel(self)
notebook = wx.Notebook(panel)
page1 = InitialInputs(notebook, db)
page2 = GridPanel(notebook, db)
notebook.AddPage(page1, "Initial Inputs")
notebook.AddPage(page2, "Grid")
sizer = wx.BoxSizer()
sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
panel.SetSizer(sizer)
self.Layout()
if __name__ == "__main__":
db = GetDatabase("data.db")
app = wx.App()
logging.basicConfig(level=logging.DEBUG)
Frame().Show()
app.MainLoop()
Apparently, the question is about python syntax errors!
onAddCue is a method belonging to the class GridPanel. The class is instantiated in the variable page2.
So, you need to call the method something like this:
page2.OnAddCue()

Stop the error when trying to manipulate the items of a Listbox, but no item is selected?

I am a beginner in tkinter. I am making a list of names. You can delete, select and edit it, but if I don't select anything in the list and click these buttons, it says:
Exception in Tkinter callback Traceback (most recent call last): File
"C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__ return
self.func(*args) File "C:\Users\user\Desktop\HOW_TOUGH - NEW\Change_user.py",
line 60, in Edit (idx, ) = d ValueError: need more than 0 values to unpack'''
I am planning to disable the buttons if the user doesn't click anything but I am not expert enough. Here's my code (it's a child window)
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class Nick:
def __init__(self, master ):
self.master = master
self.window = Toplevel(master)
self.window.title('Change User')
self.window.geometry('300x300')
self.window.minsize(300, 300)
self.window.maxsize(300, 300)
self.nickname = StringVar()
self.lb = Listbox(self.window, selectmode = 'SINGLE')
f= open('users.txt','r')
rec = f.readlines()
f.close()
for i in rec:
p = i.find('|')
nickname = i[:p]
self.lb.insert(END, nickname)
self.lb.pack()
self.Ed = ttk.Button(self.window, text = 'Edit', command = self.Edit).pack()
self.Del = ttk.Button(self.window, text = 'Delete', command = self.Delete).pack()
self.Bac = ttk.Button(self.window, text = 'Back', command = self.Back).pack()
self.Okay = ttk.Button(self.window, text = 'Ok', command = self.Ok).pack()
def Back(self):
self.window.destroy()
def Delete(self):
d = self.lb.curselection()
(idx, ) = d
self.lb.delete(idx)
f = open('users.txt','r')
r = f.readlines()
f.close()
rec = r[idx]
r.remove(rec)
f = open('users.txt','w')
new = ''.join(r)
r = f.write(new)
f.close()
messagebox.showinfo(title='Success', message = 'Delete successful')
def Edit(self):
d = self.lb.curselection()
(idx, ) = d
import Edit as Edet
Edet.Edit(self.master, idx)
def Ok(self):
d = self.lb.curselection()
(idx, ) = d
get = self.lb.get(idx)
self.window.destroy()
print (get)
print (d)
The method curselection() returns an empty tuple when nothing is selected. You can skip those methods just by adding a
if not d:
return
If you want to gray out your buttons, you can do this:
button["state"] = DISABLED
Note that this won't work currently with your code as you did this:
self.button = ttk.Button(...).pack()
The problem lies in the call of pack() which returns None, effectively binding self.button to None. Just assign the button object to the variable first and then pack it. Furthermore, it's not recommended to import * from Tkinter because you're dropping ~190 names in your namespace. Just use
import tkinter as tk

qt: pyqt: QTreeView internal drag and drop almost working... dragged item disappears

I almost have a completely working drag and drop re-order within a QTreeView. Everything seems to be ok except the dropped object never appears (though I can reference it numerous different ways that proves to me that it actually exists where it should be). If anyone has a moment and could run the following code and let me know what I am doing wrong I would really appreciate it. I have been banging my head against this process for over a week now:
You should be able to just copy and run the following code (I have a bunch of print statements in it that seem to indicate that everything is working correctly but obviously something is off):
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
################################################################################
class Branch(object):
"""
Basic branch/leaf node.
"""
#---------------------------------------------------------------------------
def __init__(self, name, value, parent=None):
"""
Constructor.
"""
super(Branch, self).__init__()
#name and parent are both to be stored directly as variables
self.name = name
self.parent = parent
self.value = value
#store sub-objects (usually other branches)
self.objD = dict()
self.nameL = list()
#---------------------------------------------------------------------------
def get_name(self):
"""
Getter.
"""
return self.name
#---------------------------------------------------------------------------
def get_parent(self):
"""
Returns the parent of this object.
"""
return self.parent
#---------------------------------------------------------------------------
def set_value(self, value):
"""
Generic setter for all settings.
"""
self.value = value
#---------------------------------------------------------------------------
def get_value(self):
"""
Generic getter for all settings. Returns the display value
"""
return self.value
#---------------------------------------------------------------------------
def add_child_obj(self, obj, row=None):
"""
Adds the param object to the dict and list.
"""
self.objD[obj.get_name()] = obj
if row == None:
self.nameL.append(obj.get_name())
else:
self.nameL.insert(row, obj.get_name())
print "JUST ADDED CHILD AT ROW:", self.nameL.index(obj.get_name())
#---------------------------------------------------------------------------
def remove_child_at_row(self, row):
"""
Removes the param object from the dict and list.
"""
childName = self.nameL[row]
del(self.nameL[row])
del(self.objD[childName])
#---------------------------------------------------------------------------
def get_child_count(self):
"""
Returns the number of children in this branch.
"""
return len(self.nameL)
#---------------------------------------------------------------------------
def get_child_list(self):
"""
Returns a list of the visible children names.
"""
return self.nameL
#---------------------------------------------------------------------------
def get_child_at_row(self, row):
"""
Returns a specific child object based on its ordinal (only consider
visible children).
"""
childName = self.nameL[row]
return self.objD[childName]
#---------------------------------------------------------------------------
def get_child_by_name(self, childName):
"""
Returns a specific child object based on its name.
"""
return self.objD[childName]
#---------------------------------------------------------------------------
def get_index(self):
"""
Returns this object's index position with regard to its siblings.
"""
siblingsL = self.parent.get_child_list()
return siblingsL.index(self.get_name())
################################################################################
class MyTreeView(QtGui.QTreeView):
"""
Overrides the QTreeView to handle keypress events.
"""
#---------------------------------------------------------------------------
def __init__(self, model, parent=None):
"""
Constructor for the TreeView class.
"""
super(MyTreeView, self).__init__(parent)
self.setModel(model)
################################################################################
class MyTreeModel(QtCore.QAbstractItemModel):
"""
My tree view data model
"""
#---------------------------------------------------------------------------
def __init__(self, root):
"""
Constructor for the TreeModel class
"""
super(MyTreeModel, self).__init__()
self.root = root
self.fontSize = 8
self.selection = None
#---------------------------------------------------------------------------
def columnCount(self, index=QtCore.QModelIndex()):
"""
Returns the number of columns in the treeview.
"""
return 1
#---------------------------------------------------------------------------
def rowCount(self, index=QtCore.QModelIndex()):
"""
Returns the number of children of the current index obj.
"""
if index.column() > 0:
return 0
if not index.isValid():
item = self.root
else:
item = index.internalPointer()
if item:
return item.get_child_count()
return 0
#---------------------------------------------------------------------------
def index(self, row, column, parent):
"""
Returns a QModelIndex item for the current row, column, and parent.
"""
if not self.hasIndex(row, column, parent):
return QtCore.QModelIndex()
if not parent.isValid():
parentItem = self.root
else:
parentItem = parent.internalPointer()
childItem = parentItem.get_child_at_row(row)
if childItem:
return self.createIndex(row, column, childItem)
else:
return QtCore.QModelIndex()
#---------------------------------------------------------------------------
def parent(self, index):
"""
Returns a QModelIndex item for the parent of the given index.
"""
if not index.isValid():
return QtCore.QModelIndex()
childItem = index.internalPointer()
if not childItem:
return QtCore.QModelIndex()
parentItem = childItem.get_parent()
if parentItem == self.root:
return QtCore.QModelIndex()
return self.createIndex(parentItem.get_index(), 0, parentItem)
#---------------------------------------------------------------------------
def data(self, index, role=QtCore.Qt.DisplayRole):
"""
Returns the text or formatting for a particular cell, depending on the
role supplied.
"""
#invalid indexes return invalid results
if not index.isValid():
return QtCore.QVariant()
#access the underlying referenced object
item = index.internalPointer()
#edit role displays the raw values
if role == QtCore.Qt.EditRole:
return item.get_value()
#return the data to display
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
return item.get_value()
return QtCore.QVariant()
#---------------------------------------------------------------------------
def headerData(self, index, orientation, role=QtCore.Qt.DisplayRole):
"""
Returns the text for the horizontal headers (parameter names)
"""
if role == QtCore.Qt.TextAlignmentRole:
if orientation == QtCore.Qt.Horizontal:
alignment = int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
return QtCore.QVariant(alignment)
alignment = int(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
return QtCore.QVariant(alignment)
if role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
if orientation == QtCore.Qt.Horizontal:
if int(index) == 0:
return "Name"
#---------------------------------------------------------------------------
def supportedDropActions(self):
"""
We allow re-ordering.
"""
return QtCore.Qt.MoveAction
#---------------------------------------------------------------------------
def flags(self, index):
"""
Returns whether or not the current item is editable/selectable/etc.
"""
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
#by default, you can't do anything
enabled = QtCore.Qt.ItemIsEnabled
selectable = QtCore.Qt.ItemIsSelectable
editable = QtCore.Qt.ItemIsEditable
draggable = QtCore.Qt.ItemIsDragEnabled
droppable = QtCore.Qt.ItemIsDropEnabled
#return our flags.
return enabled | selectable| editable| draggable| droppable
#---------------------------------------------------------------------------
def setData(self, index, value, role=QtCore.Qt.EditRole):
"""
Sets the data.
"""
#convert the value into a string
if value:
item = index.internalPointer()
item.set_value(value)
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
index, index)
return True
#---------------------------------------------------------------------------
def supportedDropActions(self):
"""
Only allow moves
"""
return QtCore.Qt.MoveAction
#---------------------------------------------------------------------------
def mimeTypes(self):
"""
Only accept the internal custom drop type which is plain text
"""
types = QtCore.QStringList()
types.append('text/plain')
return types
#---------------------------------------------------------------------------
def mimeData(self, index):
"""
Wrap the index up as a list of rows and columns of each
parent/grandparent/etc
"""
rc = ""
theIndex = index[0] #<- for testing purposes we only deal with 1st item
while theIndex.isValid():
rc = rc + str(theIndex.row()) + ";" + str(theIndex.column())
theIndex = self.parent(theIndex)
if theIndex.isValid():
rc = rc + ","
mimeData = QtCore.QMimeData()
mimeData.setText(rc)
return mimeData
#---------------------------------------------------------------------------
def dropMimeData(self, data, action, row, column, parentIndex):
"""
Extract the whole ancestor list of rows and columns and rebuild the
index item that was originally dragged
"""
if action == QtCore.Qt.IgnoreAction:
return True
if data.hasText():
ancestorL = str(data.text()).split(",")
ancestorL.reverse() #<- stored from the child up, we read from ancestor down
pIndex = QtCore.QModelIndex()
for ancestor in ancestorL:
srcRow = int(ancestor.split(";")[0])
srcCol = int(ancestor.split(";")[1])
itemIndex = self.index(srcRow, srcCol, pIndex)
pIndex = itemIndex
item = itemIndex.internalPointer()
parent = parentIndex.internalPointer()
#modify the row if it is -1 (we want to append to the end of the list)
if row == -1:
row = parent.get_child_count()
self.beginInsertRows(parentIndex, row-1, row)
print "------------------"
parentIndex.internalPointer().add_child_obj(item)
print "------------------"
self.endInsertRows()
print "sanity check:"
print "dragged Node", item.get_name()
print "parent Node", parent.get_name()
print "inserted at row",row
print "inserted Node:",parent.get_child_at_row(row).get_name()
print row, column
print "from index():",self.index(row, 0, parentIndex).internalPointer().get_name()
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"),
self.index(row, 0, parentIndex),
self.index(row, 0, parentIndex))
return True
#---------------------------------------------------------------------------
def insertRow(self, row, parent):
print "insertRow"
return self.insertRows(row, 1, parent)
#---------------------------------------------------------------------------
def insertRows(self, row, count, parent):
print "insertRows"
self.beginInsertRows(parent, row, (row + (count - 1)))
self.endInsertRows()
return True
#---------------------------------------------------------------------------
def removeRow(self, row, parentIndex):
print "removeRow"
return self.removeRows(row, 1, parentIndex)
#---------------------------------------------------------------------------
def removeRows(self, row, count, parentIndex):
self.beginRemoveRows(parentIndex, row, row)
print "about to remove child at row:",row
print "which is under the parent named:",parentIndex.internalPointer().get_name()
print "and whose own name is:",parentIndex.internalPointer().get_child_at_row(row).get_name()
parentIndex.internalPointer().remove_child_at_row(row)
self.endRemoveRows()
return True
class Ui_MainWindow(object):
def printChildren(self, item):
print item.name
for child in item.get_child_list():
self.printChildren(item.get_child_by_name(child))
def printit(self):
self.printChildren(self.root)
def setupUi(self, MainWindow):
root = Branch("root", "root", QtCore.QVariant)
item1 = Branch("ITEM1","ITEM1",root)
item2 = Branch("ITEM2","ITEM2",root)
item3 = Branch("ITEM3","ITEM3",root)
root.add_child_obj(item1)
root.add_child_obj(item2)
root.add_child_obj(item3)
item1a = Branch("thinga","thinga",item1)
item1b = Branch("thingb","thingb",item1)
item1.add_child_obj(item1a)
item1.add_child_obj(item1b)
item2a = Branch("thingc","thingc",item2)
item2b = Branch("thingd","thingd",item2)
item2.add_child_obj(item2a)
item2.add_child_obj(item2b)
item3a = Branch("thinge","thinge",item3)
item3b = Branch("thingf","thingf",item3)
item3.add_child_obj(item3a)
item3.add_child_obj(item3b)
item1a1 = Branch("___A","___A",item1a)
item1a2 = Branch("___B","___B",item1a)
item1a.add_child_obj(item1a1)
item1a.add_child_obj(item1a2)
item1b1 = Branch("___C","___C",item1b)
item1b2 = Branch("___D","___D",item1b)
item1b.add_child_obj(item1b1)
item1b.add_child_obj(item1b2)
item2a1 = Branch("___E","___E",item2a)
item2a2 = Branch("___F","___F",item2a)
item2a.add_child_obj(item2a1)
item2a.add_child_obj(item2a2)
item2b1 = Branch("___G","___G",item2b)
item2b2 = Branch("___H","___H",item2b)
item2b.add_child_obj(item2b1)
item2b.add_child_obj(item2b2)
item3a1 = Branch("___J","___J",item3a)
item3a2 = Branch("___K","___K",item3a)
item3a.add_child_obj(item3a1)
item3a.add_child_obj(item3a2)
item3b1 = Branch("___L","___L",item3b)
item3b2 = Branch("___M","___M",item3b)
item3b.add_child_obj(item3b1)
item3b.add_child_obj(item3b2)
self.root = root
MainWindow.setObjectName("MainWindow")
MainWindow.resize(600, 400)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.myModel = MyTreeModel(root)
self.treeView = MyTreeView(self.myModel, self.centralwidget)
self.treeView.setObjectName("treeView")
self.treeView.dragEnabled()
self.treeView.acceptDrops()
self.treeView.showDropIndicator()
self.treeView.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
self.treeView.expandAll()
self.horizontalLayout.addWidget(self.treeView)
self.btn = QtGui.QPushButton('print', MainWindow)
MainWindow.connect(self.btn, QtCore.SIGNAL("clicked()"), self.printit)
self.horizontalLayout.addWidget(self.btn)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 600, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
This doesn't solve all the problems, but changing dropMimeData() to the following will at least allow moving leaf items.
self.beginInsertRows(parentIndex, row, row)
parentIndex.internalPointer().add_child_obj(Branch(item.get_name(), item.get_value(), parent), row)
self.endInsertRows()
A drag-drop operation is effectively two steps, an insert (done in dropMimeData) and a remove (done automatically by the Move drag operation). The changes above insert a new item rather than trying to insert an item which is already in the model and which will be removed from the old location after the insert occurs.

Resources