refresh the textScrollList in maya with Python - maya

I have an array with lights , everytime I create a light it stores is my array.
I have a textScrollList that displays all lights in my Array.
When I add lights , it doesn't refersh the textScrollList.
Can someone tell me how I can do this , so everytime I make a light it display it in the textScrollList. Or with a refresh button.
Thanks !
Code I have now :
import maya.cmds as cmds
lights=[]
myWindow = cmds.window(title='My Lights', wh=(200,400),sizeable =False )
cmds.columnLayout()
cmds.showWindow(myWindow)
LightsButton = cmds.button(label='Make Lights', command = "makeLights()", width =200,height = 25,align='center')
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
LightSelector = cmds.textScrollList( numberOfRows=8, allowMultiSelection=True,append=(lights), showIndexedItem=4, selectCommand = 'selectInTextList()' )

You can add a function that will refresh the list with the lights. This can be called after you create a new light so it adds to the list. You can also add a refresh button to call this same function in case you add/delete lights in the scene, and it will update properly.
You don't need to add the lights to a list and keep track of it. Instead you can use cmds.ls() to collect all the lights in the scene. Unless you really do need the list for some reason, it's easy to edit the example below to use it:
import maya.cmds as cmds
# Clear the listview and display the current lights in the scene.
def refreshList():
# Clear all items in list.
cmds.textScrollList(lightSelector, e=True, removeAll=True)
# Collect all lights in the scene.
allLights = cmds.ls(type='aiAreaLight')
# Add lights to the listview.
for obj in allLights:
cmds.textScrollList(lightSelector, e=True, append=obj)
# Create a new light and add it to the listview.
def makeLights():
lights.append(cmds.shadingNode('aiAreaLight', asLight=True))
refreshList()
def selectInTextList():
# Collect a list of selected items.
# 'or []' converts it to a list when nothing is selected to prevent errors.
selectedItems = cmds.textScrollList(lightSelector, q=True, selectItem=True) or []
# Use a list comprehension to remove all lights that no longer exist in the scene.
newSelection = [obj for obj in selectedItems if cmds.objExists(obj)]
cmds.select(newSelection)
# Create window.
myWindow = cmds.window(title='My Lights', wh=(200,400), sizeable=False)
cmds.columnLayout()
cmds.showWindow(myWindow)
# Create interface items.
addButton = cmds.button(label='Make Lights', command='makeLights()', width=200, height=25, align='center')
lightSelector = cmds.textScrollList(numberOfRows=8, allowMultiSelection=True, append=cmds.ls(type='aiAreaLight'), showIndexedItem=4, selectCommand='selectInTextList()')
refreshButton = cmds.button(label='Refresh list', command='refreshList()', width=200, height=25, align='center')
Hope that helps.

Related

pyqgis plugin change QDialog to QMainWindow

I have a plugin window is QDialog, but I want to add QMenubar or QStatusBar
I have tried to find a way to convert QDialog to QMainWindow, but there is no result,
So I try to add QMenubar in QDialog again and everything works fine
Until the position of the object I added to the layout screen ran to the upper left corner.
I am not a native English speaker
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
#建立menuBar的父節點物件
file_menu = QMenu("File")
#建立一個
open_action = QAction("Open",file_menu)
open_action.setShortcut('Alt+F4')
#把剛才建立的open action 加入file 節點
file_menu.addAction(open_action)
#建立一個menubar物件
menubar = QMenuBar(self.dlg)
#將父節點加入menubar
menubar.addMenu(file_menu)
#將self.dlg的menubar設定為menubar物件
self.dlg.setMenuBar(menubar)
# 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.
pass

F# winform handling click events

Hi I am doing a simple 2d drawing program in f#. What i want to do is add a form click event where i will add a Type DrawObject to a list of DrawObject. But the event need to return a unit but when i try to add the DrawObject to my list it will return a Drawobject list, how can i solve this.
let DrawObjectList: DrawObject list = []
let mouseClick = new System.EventHandler(fun _ _ -> (new DrawObject(...))::DrawObjectList)
form.Click.AddHandler(mouseClick);
This is what i have done so far.

How to update values to the listbox under Combobox in ttk Python33

When I create the Combobox, it has no items in the list. Now when I click on the dropdown button a function is called (via the postcommand option), but once in my function I don't know how to set the values in the listbox of the Combobox.
Code something like this:
#update list upon drop down
self.cbox = Combobox(self, width = 10, postcommand = self.updtcblist)
def updtcblist(self):
list = self.getPortLst()
self.cbox.getlistbox.set(list) #getlistbox doesn't work
Thanks,
Harvey
Answered my own question.
I Finally found an example that helped, and got it to work with the following code:
#update list upon drop down
self.cbox = Combobox(self, width = 10, postcommand = self.updtcblist)
def updtcblist(self):
list = self.getPortLst()
self.cbox['values'] = list
This works as desired.

Multi-column lists in WPF with rich cell contents

I'm trying to write an automated test harness using WPF and F#. I'd like to display aggregate test results as rows in a multi-column list. Ideally, I would like to present rich content in each cell, e.g. highlighting issues with specific tests using color or making details available via tooltips. However, I cannot figure out how to put anything richer than a plain string into a multi-column ListView.
Furthermore, I'm not a fan of XAML or data binding and prefer to write vanilla F# code. The simplest program I have been able to write that displays a multi-column WPF ListView is:
open System.Windows
let gridView = Controls.GridView()
let listView = Controls.ListView(View=gridView)
type SystemParams = { Name: string; Value: obj }
[<System.STAThread>]
do
let column header binding =
let binding = Data.Binding binding
Controls.GridViewColumn(Header=header, DisplayMemberBinding=binding)
for header, binding in ["Name", "Name"; "Value", "Value"] do
column header binding
|> gridView.Columns.Add
for prop in typeof<SystemParameters>.GetProperties() do
if prop.PropertyType <> typeof<ResourceKey> then
{ Name = prop.Name; Value = prop.GetValue(null, null) }
|> listView.Items.Add
|> ignore
Application().Run(Window(Content=listView)) |> ignore
Although this works, I don't like the way it requires the field names to be duplicated both in the type definition and as strings that are fed to WPF which presumably then uses reflection to resolve them at run-time (yuk!). Ideally, I would like to Add an obj array giving the WPF controls for each cell.
Is ListView capable of this? If so, how do you write a function that accepts a 2D array of controls and returns a ListView that visualizes them?
If not, I will probably use a Grid instead. I have tried DataGrid before and it is just a world of pain in comparison...
EDIT:
Thanks to the answers below, I have been able to come up with a solution. The multiColumnList function in the program below creates list of controls with the given headers and content with selectable rows:
open System.Windows
let multiColumnList columns contents onSelection =
let gridView = Controls.GridView()
let list = Controls.ListView(View=gridView)
let column index header =
let binding = Data.Binding(sprintf "[%d]" index)
Controls.GridViewColumn(Header=header, DisplayMemberBinding=binding)
|> gridView.Columns.Add
Seq.iteri column columns
list.ItemsSource <-
[|for row in contents ->
[|for elt in row ->
box elt|]|]
list.SelectionChanged.Add onSelection
list
[<System.STAThread>]
do
let columns = ["Name"; "Value"]
let contents =
[ for prop in typeof<SystemParameters>.GetProperties() do
if prop.PropertyType <> typeof<ResourceKey> then
yield [box prop.Name; prop.GetValue(null, null)] ]
Application().Run(Window(Content=multiColumnList columns contents ignore))
|> ignore
Yes, it possible but it's a little tricky, but once you've mastered the approach it's quite flexible. WFP has a flexible templating system that this available both though code and XAML, except there are far less examples of how to do this in code.
It basically involves working how to to use the FrameworkElementFactory to override the list box default template and show the UI elements you want. Then using the Binding class to specify how the controls should be bound to the data.
I wrote a twitter client in WPF and F# and I use this approach to display the columns of tweets in list boxes. Take a look at how the createTweetContainerTemplate function works.
https://github.com/robertpi/TwitMemento/blob/master/Strangelights.TwitMemento.WPF/View.fs
Then again unless you really need a high level of control over how each row in the list box should be laid out, it maybe simpler to use a datagrid.
Your specific problem of duplicating the field names could be avoided by using an index based binding, instead of member name. See the changes to your example here:
open System
open System.Windows
let gridView = Controls.GridView()
let listView = Controls.ListView(View=gridView)
[<System.STAThread>]
do
let column index header =
let binding = Data.Binding(sprintf "[%d]" index)
Controls.GridViewColumn(Header=header, DisplayMemberBinding=binding)
["Name"; "Value"]
|> List.mapi column
|> List.iter gridView.Columns.Add
for prop in typeof<SystemParameters>.GetProperties() do
if prop.PropertyType <> typeof<ResourceKey> then
([| prop.Name; prop.GetValue(null, null) |] : Object array)
|> listView.Items.Add
|> ignore
Application().Run(Window(Content=listView)) |> ignore
Regarding giving the ListView a sequence of sequences of controls, that is somewhat lower level than ListView is intended to be used. ListView and DataGrid both assume that you have some roughly homogeneous collection of objects that you want show (generally as rows) and some idea of what information you want to show about those objects (the column definitions). Both controls will help in that situation, although I do agree that their general assumption that you want to use reflection over the members of a type can be annoying.
If you want to be able to specify a grid of any controls, then as you mention the Grid panel layout is probably more suitable.
I made a simple combinator library to build WPF UI thru code, I use this pattern in my pit project for creating HTML elements.
namespace FSharp.WPF
open System
open System.Windows
open System.Windows.Controls
[<AutoOpen>]
module Combinator =
type XDef =
| Attr of string * obj
| Tag of Type * XDef list
//| Element of FrameworkElement
[<AutoOpen>]
module Operators =
let (#=) (p:string) (v:obj) : XDef = Attr(p,v)
module internal Helpers =
let createEl (ty:Type) = new FrameworkElementFactory(ty)
let tag name attr = Tag(name,attr)
//let el dom = Element(dom)
let rec build (tag:XDef) =
match tag with
| Tag(ty,defs) ->
let attrs = defs |> List.choose(fun t -> match t with | Attr(k,v) -> Some(k,v) | _ -> None)
let tags = defs |> List.choose(fun t -> match t with | Tag(k,v) -> Some(t) | _ -> None)
/// create the element and set attributes
let el = Helpers.createEl(ty)
let rec setProps (d:(string*obj) list) =
match d with
| [] -> ()
| (p,v) :: t ->
let dp = System.ComponentModel.DependencyPropertyDescriptor.FromName(p, el.Type,el.Type)
el.SetValue(dp.DependencyProperty,v)
setProps attrs
let rec gen (d:XDef list) =
match d with
| [] -> ()
| h::t ->
let childEl = build(h)
el.AppendChild(childEl)
gen(t)
gen tags
el
//| Element(el) -> el
| Attr(key,value) -> failwith "Unrecognized sequence"
let make xdef =
let fEl = build xdef
let contentEl = new ContentControl()
contentEl.ContentTemplate <- new DataTemplate(VisualTree=fEl)
contentEl :> FrameworkElement
Its very low profile now, just create objects, but it could be extended to do much more with databinding and other things etc., and a bit of type checking should find errors in object creation.
Usage:
module Test =
open System.Windows.Controls
let create() =
tag typeof<System.Windows.Controls.Button> ["Content"#="Hello World"]
|> Combinator.make
let create2() =
tag typeof<StackPanel> [
tag typeof<Button> ["Content"#="Button 1"]
tag typeof<Button> ["Content"#="Button 2"]
]
|> Combinator.make
[<STAThread>]
[<EntryPoint>]
let main(_) =
let el = Test.create2() // Test.create1()
let window = new Window(Content = el, Height = 600.0, Width = 800.0, Title = "WpfApplication1")
let app = new Application()
app.Run(window)
As you see, nesting elements means Panel elements, but there could some extra leverage that allows the type to identify panel elements or content elements. But you get the idea, this could be useful. What do you think?
-Fahad

PyQT and QTreeView: Need to ask for childrens when user clicks on an item

I need to create a QTreeView based on requests.
So, when the user open the application, it should make a request to get the root item for the tree. Once the user clicks on that item, it should ask for the children, and so on.
I couldn't find any working example with requests as I want and I don't even know if this is possible.
It's quite simple really.
Firstly, connect the tree's expanded signal to a handler, and populate the tree with the root's top-level items.
When the signal is fired, it will pass the index of the expanded item to the handler. The handler can then use this to check whether the item has any children using, say, the model's hasChildren method.
If the item already has children, do nothing; otherwise, populate it with whatever top-level items are appropriate for that item.
UPDATE
Below is a script demonstrates how to build a tree dynamically.
For simplicity, the demo uses a QTreeWidget, thus avoiding the need for a separate model. Additional data is stored within the tree by using QTreeWidgetItem.setData.
Note that the sip import at the top is only needed for compatibilty between Python 2 and 3 (see here for details). If you're using Python 2, it's not needed.
import sip
sip.setapi('QVariant', 1)
from PyQt4 import QtGui, QtCore
class Window(QtGui.QTreeWidget):
def __init__(self):
QtGui.QTreeWidget.__init__(self)
self.setHeaderHidden(True)
self.itemExpanded.connect(self.handleExpanded)
self.itemClicked.connect(self.handleClicked)
self.handleExpanded(self.invisibleRootItem())
def depth(self, item):
depth = 0
while item is not None:
item = item.parent()
depth += 1
return depth
def requestData(self):
for title in 'One Two Three Four Five'.split():
yield title, 'additional data'
def addItems(self, parent):
depth = self.depth(parent)
for title, data in self.requestData():
item = QtGui.QTreeWidgetItem(parent, [title])
item.setData(0, QtCore.Qt.UserRole, data)
if depth < 3:
item.setChildIndicatorPolicy(
QtGui.QTreeWidgetItem.ShowIndicator)
def handleExpanded(self, item):
if item is not None and not item.childCount():
self.addItems(item)
def handleClicked(self, item, column):
print(item.data(column, QtCore.Qt.UserRole).toPyObject())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Resources