maya python print state of checkbox? - python

I'm trying to get the state of a checkbox in a maya UI using python. I was wondering if someone would help me. currently when the user hits the Distribute button, it calls a function which should print the true/false state of the 'x' checkbox.
import maya.cmds as cmds
class createMyLayoutCls(object):
def __init__(self, *args):
pass
def show(self):
self.createMyLayout()
def createMyLayout(self):
#check to see if our window exists
if cmds.window('utility', exists = True):
cmds.deleteUI('utility')
# create our window
self.window = cmds.window('utility', widthHeight = (200, 200), title = 'Distribute', resizeToFitChildren=1, sizeable = False)
cmds.setParent(menu=True)
# create a main layout
mainLayout = cmds.columnLayout(w = 200, h = 200, cw = 10, rs = 8, co = ['both',2])
# X Control
self.xAxis = cmds.checkBox('X')
# Distribute Button
btnDistribute = cmds.button(label = 'Distribute', width = 200, height = 40, c = self.GetSelectedNodes)
# show window
cmds.showWindow(self.window)
def GetSelectedNodes(self,*args):
cal = cmds.checkBox(self['X'],q = True, v = True)
print cal
b_cls = createMyLayoutCls()
b_cls.show()

you need to pass the checkbox's name into the call to checkBox in GetSelectedNodes:
def GetSelectedNodes(self,*args):
cal = cmds.checkBox(self.xAxis,q = True, v = True)
print cal

Related

Python self.after() changes running order

I am (still!) writing a Noughts and Crosses program using Tkinter in Python 3.
I wanted to implement a short pause between the player's move and the computer's move, so in the add_move_comp() method implemented self.after() function.
I expected this to pause the program for 1000ms then continue by 'drawing' on the computer's move.
However when I run my code, the program only recognises the computer's move the next move after, causing problems with identifying a 3-in-a-row.
I think this is due to line 62 running after 1000ms while the rest of the program continues running, but I don't know how to stop the whole program and continue running with line 62 after the pause.
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000,lambda i = i, j = j :self.guiGrid[i][j].config(textvariable = self.nought)) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running
This is due to the fact that self.after imeadiately returns and starts the given function after passing trough a queque to prevent the actual Window from beeing unable to responde because there is some code running. A way to work around this is to create a BooleanVariable for validation and using self.wait_variable as follows:
from tkinter import *
from functools import partial
from itertools import *
import random
class Window(Frame):
def __init__(self, master = None): # init Window class
Frame.__init__(self, master) # init Frame class
self.master = master # allows us to refer to root as master
self.rows = 3
self.columns = 3
self.guiGrid = [[None for x in range(self.rows)] for y in range(self.columns)] # use this for the computer's moves
self.noText = StringVar(value = '')
self.cross = StringVar(value = 'X')
self.nought = StringVar(value = 'O')
self.button_ij = None
self.myMove = True
self.validationVar = BooleanVar(self)
self.create_window()
self.add_buttons()
def create_window(self):
self.master.title('Tic Tac Toe')
self.pack(fill = BOTH, expand = 1)
for i in range(0,3): # allows buttons to expand to frame size
self.grid_columnconfigure(i, weight = 1)
self.grid_rowconfigure(i, weight = 1)
def add_buttons(self):
rows = 3
columns = 3
for i in range (rows):
for j in range(columns):
self.button_ij = Button(self, textvariable = self.noText, command = lambda i=i, j=j: self.add_move(i,j))
self.guiGrid[i][j] = self.button_ij
self.button_ij.grid(row = i,column = j, sticky =E+W+S+N)
def add_move(self, i,j):
# player's move
while self.myMove:
pressedButton = self.guiGrid[i][j]
self.guiGrid[i][j].config(textvariable = self.cross)
# computer's turn
self.myMove = False
while (self.myMove == False):
self.add_move_comp()
def add_move_comp(self):
repeat = True
while repeat:
i = random.randint(0,0) # row - only allow O to be drawn on 1st row for testing purposes
j = random.randint(0,2) # column
testText = self.guiGrid[i][j].cget('text')
if testText == '':
self.after(1000, self.validationVar.set, True)
self.wait_variable(self.validationVar)
self.guiGrid[i][j].config(textvariable = self.nought) # search up rules with returning values using lambda
print('Should plot O at row: ',i,' column: ',j)
print('TEXT ACTUALLY PLOTTED IS: ',self.guiGrid[i][j].cget('text'))
self.myMove = True
repeat = False
print(self.guiGrid[0][0].cget('text'), self.guiGrid[0][1].cget('text'), self.guiGrid[0][2].cget('text')+'THIS IS PRINTING')
root = Tk() # creating Tk instance
rootWidth = '500'
rootHeight = '500'
root.geometry(rootWidth+'x'+rootHeight)
ticTacToe = Window(root) # creating Window object with root as master
root.mainloop() # keeps program running

Python tkinter Doubling Checkboxes

I'm currently working on a Synthesizer inside Python for a school project and currently have a really troublesome issue. I have a Stack of Checkboxes which mark when a note is played and on which pitch inside a sequencer. My Problem is that whenever I open two Oscillators inside my synthesizer and put in the Values inside the checkboxes, the checkboxes duplicate their value over the multiple windows, but don't do it for the actual sequence, as in I have two lists with correct values, but the values aren't properly displayed inside the window.
To Replicate the Problem hit "new Oscillator" then click on "Arpeggio", do this a second time and click any Checkbox on the Arppeggio Windows
I know this might be a confusing explanation, but I'm going to link the complete code in the bottom so you can try it out and might know what I'm talking about.
The problem occurs inside the "Arpeggio" Class
import numpy # used for Waveform Calculation
from functools import partial # used for Command Combining
from tkinter import * # used for GUI
from tkinter import ttk # used for GUI
from tkinter import filedialog # used for GUI
np = numpy # Simplifying Libraries
tk = ttk # Simplifying Libraries
fd = filedialog # Simplifying Libraries
root = Tk()
#StartupFunction
def StartUp():
print("")
print("Starting Startup")
app = App(root) # Initializing GUI
print("Finished Startup")
main()
("Exiting Startup")
#Main Program Function
def main():
print("Executing Main")
root.mainloop()
print("Finished Main")
return 0
class Oscillator():
pass
class App(tk.Frame):
OscillatorWindowList = []
OscillatorList = []
SoundInputArrayList = []
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
root.title("PySynth")
root.geometry("984x300")
root.resizable(False, True)
root.maxsize(984,720)
btnNewOscillator = Button(root,text="New Oscillator",command=self.NewOscillator,relief=RIDGE,bg="#2d2d2d",fg="white")
btnNewOscillator.place(x = 8, y = 8+128)
def NewOscillator(self):
print("AddingOscillator")
self.OscillatorList.append(Oscillator())
self.SoundInputArrayList.append(SoundInputArray(root,len(self.OscillatorList)-1,len(self.OscillatorList)-1))
print(self.OscillatorList)
self.OscillatorWindowList.append(OscillatorGUI(root,self.OscillatorList[len(self.OscillatorList)-1],len(self.OscillatorList)))
def EXIT(self):
root.destroy()
#$SoundInputArray
class SoundInputArray():
actv = []
CheckbuttonList = []
CheckButtonFreq = []
i=0
ButtonCount = 32
VolumeSlider = None
btnArpeggio = None
Arpeggio = None
hasArpeggio = False
LFO = None
ArpeggioList = [(0,0)]
def __init__(self,master,oscillatorCount,number):
btnArpeggio = Button(master,text="Arpeggio",command=self.OpenArpeggio,relief=RIDGE,bg="#2d2d2d",fg="white")
btnArpeggio.place(x = 8, y = (1+oscillatorCount)*48 +128 )
def OpenArpeggio(self):
if self.Arpeggio == None:
self.Arpeggio = Arpeggio()
def GetArpeggio(self):
return self.Arpeggio
#$Arpeggio
class Arpeggio():
SoundValueList = None
def __init__(self):
GUI = Toplevel(root)
GUI.title("Arpeggio")
GUI.geometry("480x320")
GUI.resizable(False, False)
GUI.configure(bg="#171717")
self.SoundValueList = np.arange(0,16)
self.DrawUI(GUI)
self.ClearList()
def DrawUI(self,frame):
Button(frame,text="display", command= self.PrintSound, width=11,bg="#171717",).place(x = 4, y = 4)
Button(frame,text="empty", command= self.ClearList).place(x = 96, y = 4)
y = 1
x = 1
checkbuttonList = []
for y in range(1,13):
for x in range(0,16):
updatecommand = partial(self.UpdateList,x,y)
checkbuttonList.append(Checkbutton(frame, variable=self.SoundValueList[x], onvalue=y, offvalue=0,command = updatecommand))
checkbuttonList[len(checkbuttonList)-1].place(x = x*24 + 96, y= y*24 + 8)
def ClearList(self):
for i in range(0,16):
self.SoundValueList[i] = 0
def UpdateList(self,x,value):
if (self.SoundValueList[x] == value):
self.SoundValueList[x] = 0
else:
self.SoundValueList[x] = value
self.PrintSound()
def PrintSound(self):
print(self.SoundValueList)
def GetList(self):
print(self.SoundValueList)
return self.SoundValueList
StartUp() # Initiate Program

Maya Python: OptionMenu Selection With Button

I'm new to python in Maya and I'm trying to build a UI which can generate shapes and transform them. The problem I think lies in the ObjectCreation function but I'm not to sure. So far this what I've got:
import maya.cmds as cmds
#check to see if window exists
if cmds.window("UserInterface", exists = True):
cmds.deleteUI("UserInterface")
#create actual window
UIwindow = cmds.window("UserInterface", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = cmds.columnLayout(w = 300, h =500)
def SceneClear(*args):
cmds.delete(all=True, c=True) #Deletes all objects in scene
cmds.button(label = "Reset", w = 300, command=SceneClear)
polygonSelectMenu = cmds.optionMenu(w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
def ObjectCreation(*args):
if polygonSelectMenu.index == 2: #tried referring to index
ma.polySphere(name = "Sphere")
elif polygonSelectMenu == "Cube":
ma.polyCube(name = "Cube")
elif polygonSelectMenu == "Cylinder":
ma.polyCylinder(name = "Cylinder")
elif polygonSelectMenu == "Cone":
ma.polyCone(name = "Cone")
cmds.button(label = "Create", w = 200, command=ObjectCreation)
def DeleteButton(*args):
cmds.delete()
cmds.button(label = "Delete", w = 200, command=DeleteButton)#Deletes selected object
cmds.showWindow(UIwindow) #shows window
What I'm after is for the user to select one of the options from the option menu then to press the create button to generate that shape. I've tried to refer to it by name and index but I don't know what I'm missing. Like I said I'm new to python so when I tried searching for an answer myself I couldn't find anything and when I did find something similar I couldn't understand it. Plus for some reason the SceneClear function/Reset button doesn't seem to work so if there is answer to that please let me know.
polygonSelectMenu contains the path to your optionMenu UI element. In my case it is: UserInterface|columnLayout7|optionMenu4.
This is just a string and not a reference to a UI element.
To access it's current value you must use this:
currentValue = cmds.optionMenu(polygonSelectMenu, query=True, value=True)
All optionMenu's flags are listed here (Maya 2014 commands doc), queryable ones have a little green Q next to them.
As a result, here is your ObjectCreation(*args) function:
def ObjectCreation(*args):
currentValue = cmds.optionMenu(polygonSelectMenu, query=True, value=True)
if currentValue == "Sphere": #tried referring to index
cmds.polySphere(name = "Sphere")
elif currentValue == "Cube":
cmds.polyCube(name = "Cube")
elif currentValue == "Cylinder":
cmds.polyCylinder(name = "Cylinder")
elif currentValue == "Cone":
cmds.polyCone(name = "Cone")
Off-topic:
Avoid declaring functions between lines of code (in your case, the UI creation code), try instead putting the UI creation code inside a function and call this function at the end of your script.
It is readable as you have only few UI elements right now. But once you start having 20 or more buttons/labels/inputs it can be a mess quickly.
Also, I prefer giving an object name to the UI elements, just like you did with your window ("UserInterface").
To give you a concrete example:
cmds.optionMenu("UI_polygonOptionMenu", w = 250, label = "Polygon Selection:")
This optionMenu can be then accessed anywhere in you code using:
cmds.optionMenu("UI_polygonOptionMenu", query=True, value=True)
Here is the full modified script if you want:
import maya.cmds as cmds
def drawUI(): #Function that will draw the entire window
#check to see if window exists
if cmds.window("UI_MainWindow", exists = True):
cmds.deleteUI("UI_MainWindow")
#create actual window
cmds.window("UI_MainWindow", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
cmds.columnLayout("UI_MainLayout", w = 300, h =500)
cmds.button("UI_ResetButton", label = "Reset", w = 300, command=SceneClear)
cmds.optionMenu("UI_PolygonOptionMenu", w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
cmds.button("UI_CreateButton", label = "Create", w = 200, command=ObjectCreation)
cmds.button("UI_DeleteButton", label = "Delete", w = 200, command=DeleteButton)#Deletes selected object
cmds.showWindow("UI_MainWindow") #shows window
def SceneClear(*args):
cmds.delete(all=True, c=True) #Deletes all objects in scene
def ObjectCreation(*args):
currentValue = cmds.optionMenu("UI_PolygonOptionMenu", query=True, value=True)
if currentValue == "Sphere":
cmds.polySphere(name = "Sphere")
elif currentValue == "Cube":
cmds.polyCube(name = "Cube")
elif currentValue == "Cylinder":
cmds.polyCylinder(name = "Cylinder")
elif currentValue == "Cone":
cmds.polyCone(name = "Cone")
def DeleteButton(*args):
cmds.delete()
drawUI() #Calling drawUI now at the end of the script
Hope this will help you.
as said above the maya.cmds works very much like mel and you have to use the command cmds.optionMenu() with the polygonSelectMenu as the first arg.
Alternatively if you use pymel instead, you could access the class attrs of polygonSelectMenu with the dot operator like:
import pymel.core as pm
if pm.window("UserInterface", exists = True):
pm.deleteUI("UserInterface")
UIwindow = pm.window("UserInterface", title = "User Interface Test", w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = pm.columnLayout(w = 300, h =500)
polygonSelectMenu = pm.optionMenu(w = 250, label = "Polygon Selection:")
pm.menuItem(label = " ")
pm.menuItem(label = "Sphere")
pm.menuItem(label = "Cube")
pm.menuItem(label = "Cylinder")
pm.menuItem(label = "Cone")
pm.button(label = "Create", w = 200, command=ObjectCreation)
UIwindow.show()
def ObjectCreation(*args):
print polygonSelectMenu.getValue()
also you could make the program into a class with a drawUI method, which might make it easy to do things like store all the items you create in ObjectCreation inside of a class attr so that you can just delete them with your reset button (as i noticed you have cmds.delete(all=True) which i think is not supported anymore in maya), or store the UI elements in self.ui_element. That way they can be referenced later as the variable without the possible conflicts from having multiple windows open that all have buttons like "UI_CreateButton" or "okButton" etc...
import maya.cmds as cmds
class UI_Test_thingy():
windowName = 'UserInterface'
version = 'v1.1.1'
debug = True
createdThingys = []
def __init__(self):
self.drawUI()
def drawUI(self):
if UI_Test_thingy.debug: print 'DEBUG - drawUI called'
#check to see if window exists
try:
cmds.deleteUI(UI_Test_thingy.windowName)
except:
pass
#create actual window
UIwindow = cmds.window(UI_Test_thingy.windowName, title = "User Interface Test {}".format(UI_Test_thingy.version), w = 500, h = 700, mnb = False, mxb = False, sizeable = False)
mainLayout = cmds.columnLayout(w = 300, h =500)
cmds.button(label = "Reset", w = 300, command=self.SceneClear)
self.polygonSelectMenu = cmds.optionMenu(w = 250, label = "Polygon Selection:")
cmds.menuItem(label = " ")
cmds.menuItem(label = "Sphere")
cmds.menuItem(label = "Cube")
cmds.menuItem(label = "Cylinder")
cmds.menuItem(label = "Cone")
cmds.button(label = "Create", w = 200, command=self.ObjectCreation)
cmds.button(label = "Delete", w = 200, command=self.DeleteButton)#Deletes selected object
cmds.showWindow(UIwindow) #shows window
def DeleteButton(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - DeleteButton called: args: {}'.format(args)
cmds.delete()
def SceneClear(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - SceneClear called: args: {}'.format(args)
thingsToDel = UI_Test_thingy.createdThingys[:] # copy the list of things created by this script
UI_Test_thingy.createdThingys = [] # reset the list before deleteing the items
print 'deleteing: {}'.format(thingsToDel)
if thingsToDel:
cmds.delete( thingsToDel ) #Deletes all objects created by this script
def ObjectCreation(self, *args):
if UI_Test_thingy.debug: print 'DEBUG - ObjectCreation called: args: {}'.format(args)
menuVal = cmds.optionMenu(self.polygonSelectMenu, q=True, value=True)
if menuVal == "Sphere":
UI_Test_thingy.createdThingys += cmds.polySphere(name = "Sphere") # store the results to the class attr createdThingys
elif menuVal == "Cube":
UI_Test_thingy.createdThingys += cmds.polyCube(name = "Cube") # store the results to the class attr createdThingys
elif menuVal == "Cylinder":
UI_Test_thingy.createdThingys += cmds.polyCylinder(name = "Cylinder") # store the results to the class attr createdThingys
elif menuVal == "Cone":
UI_Test_thingy.createdThingys += cmds.polyCone(name = "Cone") # store the results to the class attr createdThingys
if __name__ == '__main__':
ui = UI_Test_thingy()

maya python + Pass variable on button press

I have a script i wrote in python for maya and there are 3 buttons labeled X Y Z. Depending on which button is pressed I want a variable to pass a specific value to the function. How can I do this?? I've written in the comments for the button in regards to what I'm trying to pass. It seems to just print 'false' im not sure why.
import maya.cmds as cmds
class createMyLayoutCls(object):
def __init__(self):
pass
def show(self):
self.createMyLayout()
def createMyLayout(self):
#check to see if our window exists
if cmds.window('utility', exists = True):
cmds.deleteUI('utility')
# create our window
self.window = cmds.window('utility', widthHeight = (200, 200), title = 'Distribute', resizeToFitChildren=1, sizeable = False)
cmds.setParent(menu=True)
# create a main layout
mainLayout = cmds.gridLayout( numberOfColumns=3, cellWidthHeight=(70, 50) )
# X Y Z BUTTONS
btnAlignX = cmds.button(label = 'X', width = 40, height = 40, c = self.TakeAction) # should pass 'axis='X"
btnAlignY = cmds.button(label = 'Y', width = 40, height = 40, c = self.TakeAction) # should pass 'axis='Y"
btnAlignZ = cmds.button(label = 'Z', width = 40, height = 40, c = self.TakeAction) # should pass 'axis='Z"
# show window
cmds.showWindow(self.window)
def TakeAction(self, axis=''):
print axis
if axis == 'x':
print 'you selected x'
if axis == 'y':
print 'you selected y'
if axis == 'y':
print 'you selected z'
b_cls = createMyLayoutCls()
b_cls.show()
To substitute lambda, you can use partial :
from functools import partial
btnAlignX = cmds.button(label='X', c=partial(self.TakeAction, 'X'))
Both lambda and partial should work.
Hope it helps.
Use a lambda to give each button command its own mini-function:
btnAlignX = cmds.button(label='X', c=lambda *_:self.TakeAction('X'))
btnAlignY = cmds.button(label='Y', c=lambda *_:self.TakeAction('Y'))
btnAlignZ = cmds.button(label='Z', c=lambda *_:self.TakeAction('Z'))

unresponsive drag and drop in pygobject

im trying to get drag and drop working well in pygobject, but it is slow and unresponsive, 90% of the time i have to wave the item i am dragging around before i can drop it successfully, can anyone see if i am doing it incorrectly or is this a bug with pygobject? here is my code
from gi.repository import Gtk, GdkPixbuf, Gdk
import os
def got_data_cb(windowid, context, x, y, data, info, time):
# Got data.
tempArray = data.get_text().splitlines()
for i in tempArray:
i = i.replace('file://','')
print i
windowid.get_model().append([i])
context.finish(True, False, time)
def drop_cb(windowid, context, x, y, time):
# Some data was dropped, get the data
windowid.drag_get_data(context, context.list_targets()[-1], time)
return True
def main():
win = Gtk.Window()
win.connect('destroy', lambda x: Gtk.main_quit())
win.set_default_size(450, 400)
amodel = Gtk.ListStore(str)
column = Gtk.TreeViewColumn()
title = Gtk.CellRendererText()
column.pack_start(title, True)
column.add_attribute(title, "text", 0)
atree = Gtk.TreeView(amodel)
atree.append_column(column)
builder = Gtk.Builder()
filename = os.path.join('', 'treeview.ui')
builder.add_from_file(filename)
abox = builder.get_object('treeview1')
atree.drag_dest_set(0, [], 0)
atree.connect('drag_motion', lambda v,w,x,y,z: True)
atree.connect('drag_drop', drop_cb)
atree.connect('drag_data_received', got_data_cb)
win.add(atree)
win.show_all()
if __name__ == '__main__':
Gtk.main()
main()
Because I haven't "treeview.ui" file, you referenced, I port the drag'n'drop treeview example of pygtk.
This might be also an example on how to convert old pygtk code to pygi. I only test this code with python3.
#!/usr/bin/env python
# example treeviewdnd.py
from gi.repository import Gtk, Gdk, Pango, GObject
class TreeViewDnDExample:
TARGETS = [
('MY_TREE_MODEL_ROW', Gtk.TargetFlags.SAME_WIDGET, 0),
('text/plain', 0, 1),
('TEXT', 0, 2),
('STRING', 0, 3),
]
# close the window and quit
def delete_event(self, widget, event, data=None):
Gtk.main_quit()
return False
def clear_selected(self, button):
selection = self.treeview.get_selection()
model, iter = selection.get_selected()
if iter:
model.remove(iter)
return
def __init__(self):
# Create a new window
self.window = Gtk.Window()
self.window.set_title("URL Cache")
self.window.set_size_request(200, 200)
self.window.connect("delete_event", self.delete_event)
self.scrolledwindow = Gtk.ScrolledWindow()
self.vbox = Gtk.VBox()
self.hbox = Gtk.HButtonBox()
self.vbox.pack_start(self.scrolledwindow, True, True, 0)
self.vbox.pack_start(self.hbox, False, True, 0)
self.b0 = Gtk.Button('Clear All')
self.b1 = Gtk.Button('Clear Selected')
self.hbox.pack_start(self.b0, True, True, 0)
self.hbox.pack_start(self.b1, True, True, 0)
# create a liststore with one string column to use as the model
self.liststore = Gtk.ListStore(str)
# create the TreeView using liststore
self.treeview = Gtk.TreeView(self.liststore)
# create a CellRenderer to render the data
self.cell = Gtk.CellRendererText()
# create the TreeViewColumns to display the data
self.tvcolumn = Gtk.TreeViewColumn('URL', self.cell, text=0)
# add columns to treeview
self.treeview.append_column(self.tvcolumn)
self.b0.connect_object('clicked', Gtk.ListStore.clear, self.liststore)
self.b1.connect('clicked', self.clear_selected)
# make treeview searchable
self.treeview.set_search_column(0)
# Allow sorting on the column
self.tvcolumn.set_sort_column_id(0)
# Allow enable drag and drop of rows including row move
self.treeview.enable_model_drag_source( Gdk.ModifierType.BUTTON1_MASK,
self.TARGETS,
Gdk.DragAction.DEFAULT|
Gdk.DragAction.MOVE)
self.treeview.enable_model_drag_dest(self.TARGETS,
Gdk.DragAction.DEFAULT)
self.treeview.drag_dest_add_text_targets()
self.treeview.drag_source_add_text_targets()
self.treeview.connect("drag_data_get", self.drag_data_get_data)
self.treeview.connect("drag_data_received",
self.drag_data_received_data)
self.scrolledwindow.add(self.treeview)
self.window.add(self.vbox)
self.window.show_all()
def drag_data_get_data(self, treeview, context, selection, target_id,
etime):
treeselection = treeview.get_selection()
model, iter = treeselection.get_selected()
data = bytes(model.get_value(iter, 0), "utf-8")
selection.set(selection.get_target(), 8, data)
def drag_data_received_data(self, treeview, context, x, y, selection,
info, etime):
model = treeview.get_model()
data = selection.get_data().decode("utf-8")
drop_info = treeview.get_dest_row_at_pos(x, y)
if drop_info:
path, position = drop_info
iter = model.get_iter(path)
if (position == Gtk.TreeViewDropPosition.BEFORE
or position == Gtk.TreeViewDropPosition.BEFORE):
model.insert_before(iter, [data])
else:
model.insert_after(iter, [data])
else:
model.append([data])
if context.get_actions() == Gdk.DragAction.MOVE:
context.finish(True, True, etime)
return
def main():
Gtk.main()
if __name__ == "__main__":
treeviewdndex = TreeViewDnDExample()
main()
In order for me to get drag n drop working from another desktop app to my app, I had to add a drag_motion_callback to copy the data into the context:
Class Window(Gtk.Window):
def __init__(self):
#other stuff before here
#Set up dragNdrop to add URIs to open draw
self.connect("drag-motion", self.motion_cb)
self.connect("drag-drop", self.drop_cb)
self.connect("drag-data-received", self.got_data_cb)
self.drag_dest_set(0, [], 0)
def motion_cb(self, wid, context, x, y, time):
Gdk.drag_status(context,Gdk.DragAction.COPY, time)
# Returning True which means "I accept this data".
return True
def drop_cb(self, wid, context, x, y, time):
wid.drag_get_data(context, context.list_targets()[-1], time)
def got_data_cb(self, wid, context, x, y, data, info, time):
#Need to do something here
files=data.get_text().rstrip('\n').split('\n')
for fn in files:
fn= fn.split('file://',1)[-1]
self.add_file(fn)
self.place_items()
print files
context.finish(True, False, time)

Categories