Getting this error when pressing the "Close Window" button in my UI. This button should delete the UI window but isn't. Full traceback:
Error: deleteUI: Object 'Animation_Copy_Tool' not found.
Traceback (most recent call last):
File "", line 36, in closeBtnCmd
RuntimeError: deleteUI: Object 'Animation_Copy_Tool' not found. #
# Animation Copy Tool
# Bakari Holmes 5/7/2015
# This is designed to copy and existing animation
# from one rig to another and make the process easier
# with a simple UI
import maya.cmds as mc
import functools
import maya.mel as mm
import pprint
class AnimCopyWindow(object):
##classmethod
def showUI(cls):
win = cls()
win.create()
return win
def __init__(self):
self.window = "Animation Copy Tool"
self.title = "Animation Copier"
self.size = (546,350)
def pasteTheseKeys(self, *args):
self.offsetVal = mc.intFieldGrp(self.int_offset, q=True, value1=True)
self.selObj_pasteKeys = mc.ls(sl=True)
for objectQuant in self.selObj_pasteKeys:
print objectQuant
self.ct = mc.currentTime(query = True)
self.t = self.ct + self.offsetVal
mc.currentTime(self.t)
# mc.selectKey(selObj_pasteKeys[objectQuant])
mc.pasteKey(time=(self.t,self.t), f=(1.0,1.0), option="merge", copies=1, to=0, fo=0, vo=0)
def closeBtnCmd(self,*args):
mc.deleteUI(self.window,window=True)
def create(self):
# check to see if window exists already
if mc.window(self.window,exists=True):
mc.deleteUI(self.window,window=True)
self.window = mc.window(self.window, title=self.title,widthHeight=self.size,menuBar=True)
self.copyAnim = mc.window(title="Transfer Animation Tool", backgroundColor=[0.3,0.3,0.3],sizeable=False,resizeToFitChildren=True)
#set the layout for UI
mc.columnLayout(adjustableColumn=True)
self.tx_src = mc.textFieldGrp(label="Source Object", editable=False, text=sel[0])
self.int_offset = mc.intFieldGrp(label="Frame Offset Amount", value1=0)
#add paste animation button
self.btn1 = mc.button(label="PASTE ANIMATION", command=self.pasteTheseKeys, bgc=[0.1,0.1,0.5])
#add close button window
self.btn2 = mc.button(label="CLOSE WINDOW", command=self.closeBtnCmd, bgc=[0.2,0.2,0.2])
mc.showWindow()
#################################
#####end of class definition#####
#################################
def keys_as_dictionary(channel):
"""return a dictionay of times:values for <channel>"""
keys = mc.keyframe(channel, q=True, tc=True) or []
values = mc.keyframe(channel, q=True, vc=True) or []
return dict(zip(keys, values))
def channels():
"""return a dictionary of <plug>:<channel_dict> for each animated plug selected"""
keys = mc.keyframe(sl=True, n=True, q=True)
result = {}
for k in keys:
plugs = mc.listConnections(k, p=True)[0]
result[plugs]= keys_as_dictionary(k)
return result
#store selected object info
sel = mc.ls(selection=True)
if (len(sel) != 1):
mm.eval("warning Must select one animated object;")
else:
mc.copyKey()
win = AnimCopyWindow()
win.create()
pprint.pprint(channels())
This error almost always means your UI element is not named what you think it is: Maya will automatically rename the items to make sure that no two siblings have the same name -- you can ask for "my_window" and get back "my_window123" . So you need to capture the actual name that is returned from cmds.window() or whatever ui command you use and delete that. Hard coded names are never reliable
Related
I am trying to make an input widget for a module i have made (see this SO question).
The input widget should have a title bar and a variable number of input lines below. I had in mind to have an delete button at the end of each input line.
The delete button should ideally delete the container widget and all the children widgets, but hiding the container widget and children would also be acceptable.
I have not been able to find a useful recipe to this problem.
Currently i got this code, but i have no clue less as how to solve the problem.
import ipywidgets as w
def add_btn_clicked(b):
input_box.children = (input_box.children[0], line()) + input_box.children[1:]
def delete_btn_clicked(b):
# ???
with output:
print(b.keys)
return None
add = w.Button(icon="plus-circle")
add.on_click(add_btn_clicked)
title = w.HBox([w.Label(value=str(i)) for i in range(3)]+[add])
def line():
delete = w.Button(icon="trash")
delete.on_click(delete_btn_clicked)
return w.HBox([w.FloatText(value=i) for i in range(3)]+[delete])
input_box = w.VBox([title,line()])
output = w.Output()
display(input_box)
display(output)
Is there a way to tell what the parent element is from the button click or another way to achieve what I am attempting?
You can create the widgets and container separately, then define the .parent attribute on the children as the container, before assembling together. That way you can effectively hide the container when the button is clicked (with .parent.layout.display = 'none').
import ipywidgets as w
def add_btn_clicked(b):
input_box.children = (input_box.children[0], line()) + input_box.children[1:]
def delete_btn_clicked(b):
b.parent.layout.display = 'none'
add = w.Button(icon="plus-circle")
add.on_click(add_btn_clicked)
title = w.HBox([w.Label(value=str(i)) for i in range(3)]+[add])
def line():
delete = w.Button(icon="trash")
delete.on_click(delete_btn_clicked)
val_widgets = [w.FloatText(value=i) for i in range(3)]
container = w.HBox()
delete.parent = container
for widg in val_widgets:
widg.parent = container
children = val_widgets + [delete]
container.children = children
return container
input_box = w.VBox([title,line()])
output = w.Output()
display(input_box)
display(output)
I really don't now why I can't call the method setTRSKey from inside my for loop. Am I missing something? This makes no sense to me at all. Pycharm declares it as an unsolved reference
Here is the code:
import math
import nuke
originNode = nuke.selectedNode()
world_matrix = originNode['world_matrix'] # this is an iArray Knob with 16 fields
mResult = nuke.math.Matrix4() # Matrix to copy iArray to
# Ask user for Frame Range operation
ret = nuke.getFramesAndViews('Frame range', '%s-%s' % (nuke.root().firstFrame(), nuke.root().lastFrame()))
if ret != None:
nuke.nodeCopy("%clipboard%") # creating node duplicate
originNode.setSelected(False)
newNode = nuke.nodePaste("%clipboard%") # creating origin node duplicate
newNode['translate'].clearAnimated()
newNode['translate'].setValue(0)
newNode['translate'].setAnimated()
newNode['rotate'].clearAnimated()
newNode['rotate'].setValue(0)
newNode['rotate'].setAnimated()
newNode['scaling'].clearAnimated()
newNode['scaling'].setValue(0)
newNode['scaling'].setAnimated()
frange = nuke.FrameRange(ret[0]) # convert to frange object
for frame in frange:
for i in xrange(0, 16):
mResult[i] = world_matrix.valueAt(frame)[i]
mResult.transpose() # row become columns and vice versa
mTranslate = nuke.math.Matrix4(mResult)
mTranslate.translationOnly()
mRotate = nuke.math.Matrix4(mResult)
mRotate.rotationOnly()
mScale = nuke.math.Matrix4(mResult)
mScale.scaleOnly()
translate = (mTranslate[12], mTranslate[13], mTranslate[14])
rotateRad = mRotate.rotationsZXY()
rotate = (math.degrees(rotateRad[0]), math.degrees(rotateRad[1]),
math.degrees(rotateRad[2])) # convert from radiants to defrees
scale = (mScale.xAxis().x, mScale.yAxis().y, mScale.zAxis().z)
setTRSKey(frame, translate, rotate, scale)
else:
print "User canceled the operation"
def setTRSKey(frame, translate, rotate, scale):
print type(translate(0))
newNode['translate'].setValueAt(translate(0), frame, 0)
newNode['translate'].setValueAt(translate(1), frame, 1)
newNode['translate'].setValueAt(translate(2), frame, 2)
edit: Example with classes where loadDataFromScript is called before defining
class Connecthor(QtWidgets.QDialog, Ui_Dialog):
#
allowedNodes = ["Read", "Write", "Merge", "Keymix", "ChannelMerge", "Roto", "RotoPaint", "Copy", "Shuffle", "PostageStamp", "Camera", "Camera2", "ScanlineRender", "Connector", "ReadGeo", "ReadGeo2", "BackdropNode"]
script_path = os.path.dirname(os.path.realpath(__file__))
#constructor
def __init__(self, parent=None):
super(Connecthor, self).__init__(parent)
self.setupUi(self)
self.setFixedSize(self.size())
#self.setWindowOpacity(0.95)
popupmenu = QtWidgets.QMenu(self.btn_settings)
#popupmenu.addAction("save links for script", self.writeListDictToJson)
#popupmenu.addAction("import links from json", self.readJsonToDict)
popupmenu.addAction("save links for script (manual)", self.saveDatatoScript)
popupmenu.addAction("settings", self.opensetting)
self.btn_settings.setMenu(popupmenu)
self.btn_settings.setIcon(QtGui.QIcon(os.path.join(iconpath, "settings.png")))
self.btn_addSelectedNodes.setIcon(QtGui.QIcon(os.path.join(iconpath, "add.png")))
self.btn_addSelectedNodes.clicked.connect(self.addSelectedNodes)
# #Loading test Json
#self.readJsonToDict()
self.loadDataFromScript()
In Python you must define functions before they are called. Move your setTRSKey definition above the for loop. Generally speaking, function definitions are one of the very first things in the file after imports, though this is not always the case.
I'm trying to create a GUI with QT Designer. I've converted my .ui designer file to a .py.
Here is my code:
from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication
from PyQt4.QtGui import QAction, QIcon
from qgis.core import *
import resources
from delete_feature_dialog import DeleteFeatureDialog
import os.path
class DeleteFeature:
def __init__(self, iface):
# Save reference to the QGIS interface
self.iface = iface
# Declare instance attributes
self.actions = []
self.menu = self.tr(u'&DeleteFeature')
self.toolbar = self.iface.addToolBar(u'DeleteFeature')
self.toolbar.setObjectName(u'DeleteFeature')
def add_action(
self,
icon_path,
text,
callback,
enabled_flag=True,
add_to_menu=True,
add_to_toolbar=True,
status_tip=None,
whats_this=None,
parent=None):
# Create the dialog (after translation) and keep reference
self.dlg = DeleteFeatureDialog()
....
return action
def initGui(self):
icon_path = ':/plugins/DeleteFeature/icon.png'
self.add_action(
icon_path,
text=self.tr(u''),
callback=self.run,
parent=self.iface.mainWindow())
def run(self):
#this code will populate the combo box with all vector layer
self.dlg.layerListCombo.clear()
layers = self.iface.legendInterface().layers()
layer_list = []
for layer in layers:
layerType = layer.type()
if layerType == QgsMapLayer.VectorLayer:
layer_list.append(layer.name())
self.dlg.layerListCombo.addItems(layer_list)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
selectedLayer = layers [selectedLayerIndex]
.....
Then when I open the plugin, I get the following error:
'DeleteFeatureDialog' objectObject has no attribute
'layerlistcombo'in QGIS Plugin
Any suggestion for this.
Seems that you wrote:
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
but you should have written:
selectedLayerIndex = self.dlg.layerListCombo.currentIndex()
Like you did previously in your code (notice the Camel Notation when writing, not just lower-case letters), which is probably causing the No Attribute error you get.
I was wondering if there is any way to find the name of the last window created in Maya, knowing that I can't add any information to the window itself before that... I checked in both the cmds and API but couldn't find anything. Maybe in PyQt but I don't know much about it.
I'm looking for any solution. Thanks
you can work with something like a close callback, save the needed information and restore it again
def restoreLayout(self):
"""
Restore the layout of each widget
"""
settings=self.settings
try:
self.restoreGeometry(settings.value("geometry").toByteArray())
self.restoreState(settings.value("windowState").toByteArray())
size=settings.value('fontSize').toFloat()[0]
self.setFontSize(size)
except:
pass
def saveLayout(self):
"""
Save the layout of each widget
Save the main window id to your data base
"""
settings=self.settings
settings.setValue("geometry", self.saveGeometry())
settings.setValue("windowState", self.saveState())
settings.setValue("fontSize", app.font().pointSize())
def closeEvent(self, event):
QtGui.QMainWindow.closeEvent(self, event)
self.saveLayout()
a simple case/idea to save tha main win_id and a child button_id:
from functools import partial
import json
def close_ui(*args):
win_id = args[0]
if cmds.window(win_id, exists=True):
cmds.deleteUI(win_id, window=True)
with open('dataBase/ui/uidata.json', 'w') as outfile:
json.dump(args, outfile)
win = {}
win["main_win"] = cmds.window()
cmds.columnLayout()
cmds.text( label='closing it' )
win["btn"] = cmds.button( label='Close')
cmds.button(win["btn"],e=True, command=partial(close_ui, win["main_win"], win["btn"]))
cmds.showWindow(win["main_win"])
Here is what I came up with, it's surely not the "cleanest" solution but it works!
# List all the currently opened windows
uisBefore = cmds.lsUI (wnd = True)
# Execute the function which may or may not create a window
func(*args, **kwargs)
# List all the opened windows again
uisAfter = cmds.lsUI (wnd = True)
# Find all the windows that were opened after executing func()
newUIs = [ui for ui in uisAfter if ui not in uisBefore]
If you create a window with the window command, you'll get back the name of the window you just created:
import maya.cmds as cmds
w = cmds.window()
c= cmds.columnLayout()
def who_am_i(*_):
print "window is", w
b = cmds.button('push', c=who_am_i)
cmds.showWindow(w)
If for some reason you don't own the code that creates the window:
existing_windows = set(cmds.lsUI(type = 'window'))
// make your window here
new_windows = list(set(cmds.lsUI(type = 'window') - existing_windows))
I am creating a python program to detect and enable usb to usb data transfer between usb storage drives. However I am having an issue with updating the dev_label (device name of the drive) and passing it to Exchange. Here is the code :
serial_list=[]
context = Context()
monitor = Monitor.from_netlink(context)
monitor.filter_by(subsystem='block',device_type='partition')
observer = GUDevMonitorObserver(monitor)
def device_connected(observer, device):
Welcome.device_count+=1
flag =False
for iden in serial_list :
if iden == device.__getitem__('ID_SERIAL_SHORT'):
flag=True
if flag ==False:
serial_list.append(device.__getitem__('ID_SERIAL_SHORT'))
Welcome.dev_label.append(str(device.__getitem__('ID_FS_LABEL')))
size = len(Welcome.dev_label)
label = gtk.Label('Device connected :: {0!r}'.format(Welcome.dev_label[size-1]))
Welcome.vbox.pack_start(label)
Welcome.window.show_all()
if Welcome.device_count<2:
label = gtk.Label('Connect the second device')
Welcome.vbox.pack_start(label)
Welcome.window.show_all()
else :
Exchange()
observer.connect("device-added",device_connected)
monitor.start()
class Welcome:
device_count = 0
window = gtk.Window()
vbox= gtk.VBox(False, 5)
dev_label = []
def __init__(self):
self.window.set_default_size(300, 300)
self.window.set_title("Welcome")
label = gtk.Label("Connect the desired device")
self.vbox.pack_start(label)
self.window.add(self.vbox)
self.window.connect("destroy", lambda q: gtk.main_quit())
self.window.show_all()
class Exchange:
window1 = gtk.Window(Welcome.dev_label.pop())
window2 = gtk.Window(Welcome.dev_label.pop())
def __init__(self):
width = gtk.gdk.screen_get_default().get_width()
height = gtk.gdk.screen_get_default().get_height()
self.window1.resize(width/2,height)
self.window2.resize(width/2,height)
self.window2.move(self.window1.get_position()[0]+width/2, self.window1.get_position()[1])
label = gtk.Label("Hello")
self.window1.add(label)
self.window1.connect("destroy" , lambda q : gtk.main_quit())
self.window1.show_all()
label = gtk.Label("World")
self.window2.add(label)
self.window2.connect("destroy",lambda q : gtk.main_quit())
self.window2.show_all()
Welcome()
gtk.main()
The error shown in the trace back is :
Traceback (most recent call last):
File "project.py", line 70, in <module>
class Exchange:
File "project.py", line 71, in Exchange
window1 = gtk.Window(Welcome.dev_label.pop())
IndexError: pop from empty list
I can't figure out how to synchronize all these event so that the compiler doesn't throw an error. Values are being popped from Welcome.dev_label only after they've been updated in device_connected so why does the compiler have a problem? I am a python newbie so please be gentle.
This is not the compiler givin errors but the program.
You can change your class to this:
import time
class Exchange:
while not Welcome.dev_label: time.sleep(0.001)
window1 = gtk.Window(Welcome.dev_label.pop()) # line 4
while not Welcome.dev_label: time.sleep(0.001)
window2 = gtk.Window(Welcome.dev_label.pop())
This would be kind of a synchronization primitive given that only line 4 and 6 remove content.
In general you would use a queue for this.
import queue # Python3 # import Queue Python 2
Welcome.dev_label # = queue.Queue()
Welcome.dev_label.put(...) # instead of append
Welcome.dev_label.get(...) # instead of pop
But I do not know wether your code uses threads and runs in parallel. If the time.sleep example works then you can switch to a queue.