I am writing a script which has an UI in Maya. I have a text box that is supposed to constantly update based on the last item in the users selection list. How would I go about something that constantly keeps checken whithout having the user to push a button or something manually to call a function.
Thx
Edit: Cool that is what I was looking for. Thx. Your script works just fine. I tried implementing that into my big script which resulted in that every button in the UI had to be pushed twice in order to take effect. But I will deal with that later. However testing my own version in a seperate script as follows sometimes produces the following error: 'sl' must be passed a boolean argument
#________________________________________________________________________________________________________________________________________________
import maya.cmds as cmds
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_label(*_):
upCurrentObjectSel = cmds.ls(sl=True)
upCurrentObjectSelShapes = cmds.listRelatives(upCurrentObjectSel)
upLastobj = upCurrentObjectSelShapes[-1]
print upLastobj
cmds.text(curSelTxt, e=True, label = upLastobj)
cmds.scriptJob(event=("SelectionChanged", update_label), p= curSelTxt)
cmds.showWindow(idManagerUI)
Also, making two of these ScriptJobs makes the script stop working properly entirely.
#________________________________________________________________________________________________________________________________________________
import maya.cmds as cmds
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
curSelShadTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_obj_label(*_):
upCurrentObjectSel = cmds.ls(sl=True)
upCurrentObjectSelShapes = cmds.listRelatives(upCurrentObjectSel)
upLastobj = upCurrentObjectSelShapes[-1]
objID = cmds.getAttr(upLastobj + '.vrayObjectID')
print objID
cmds.text(curSelObjTxt, e=True, label = objID)
def update_shader_label(*_):
upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)
upCurrentShaderSelLast = upCurrentShaderSel[-1]
shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
cmds.text(curSelShadTxt, e=True, label = shadID)
print shadID
cmds.scriptJob(event=("SelectionChanged", update_obj_label), p= curSelObjTxt)
cmds.scriptJob(event=("SelectionChanged", update_shader_label), p= curSelShadTxt)
cmds.showWindow(idManagerUI)
Edit:
still your latest version of the script produces the error from time to time.
Also, I noticed in my own version of it, that it sometimes works lovely, then not at all, once I e.g. switched my active window to Firefox or so and then get back to Maya, and sometimes it does not work at all. That is with just one of the functions in my script. With both of them (s.below) it is totally unusable. Very unstable results.
import maya.cmds as cmds
def curSelTxtShower():
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
curSelShadTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_obj_label(*_):
upCurrentObjectSelShapes = cmds.listRelatives(s=True) or ["nothing selected"]
upLastobj = upCurrentObjectSelShapes[-1]
if upLastobj is not "nothing selected":
if cmds.attributeQuery('vrayObjectID', node = upLastobj, ex = True) is True:
objID = cmds.getAttr(upLastobj + '.vrayObjectID')
cmds.text(curSelObjTxt, e=True, label = objID)
else:
cmds.text(curSelObjTxt, e=True, label = 'curSel has no ObjID assigned')
def update_shader_label(*_):
upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)
upCurrentShaderSelLast = upCurrentShaderSel[-1]
if cmds.attributeQuery('vrayMaterialId', node = upCurrentShaderSelLast, ex = True) is True:
shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
cmds.text(curSelShadTxt, e=True, label = shadID)
print shadID
else:
cmds.text(curSelShadTxt, e=True, label = 'curSel has no MatID assigned')
cmds.scriptJob(event=("SelectionChanged", lambda *x: update_obj_label()), p= curSelObjTxt)
cmds.scriptJob(event=("SelectionChanged", lambda *x: update_shader_label()), p= curSelShadTxt)
cmds.showWindow(idManagerUI)
curSelTxtShower()
You need to use a scriptJob to watch for selection change events and respond. You'll want to parent the scriptJob to a particular piece of UI so it deletes itself when the UI object goes away.
An absolutely minimal example looks like this:
import maya.cmds as cmds
wind = cmds.window()
col = cmds.columnLayout()
txt = cmds.text(label="", width = 240)
def update_label(*_):
cmds.text(txt, e=True, label = str(cmds.ls(sl=True)))
cmds.scriptJob(event=("SelectionChanged", update_label), p= txt)
cmds.showWindow(wind)
Edit
This version of OP's code helps avoid the false error message. the actual error was happening when due to an empty selection - but the scriptJob falsely reports it in the previous line:
def scoped():
idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
cmds.columnLayout(adj = True)
cmds.text (l = '__________________________________________ \n your current selection has this ID: \n')
curSelTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
def update_label(*_):
# listRelatives works off the current selection already
upCurrentObjectSelShapes = cmds.listRelatives(s=True) or ["nothing selected"]
upLastobj = upCurrentObjectSelShapes[-1]
cmds.text(curSelTxt, e=True, label = upLastobj)
cmds.showWindow(idManagerUI)
cmds.scriptJob(event=("SelectionChanged", update_label), p= idManagerUI)
scoped()
Related
I understand scrollY should constrain the height of the data table. I have a data table configured as below, but when I choose a page size of 100, the table just expands. I want the table to remain visible on the page, with the page navigation at the bottom always visible, and the user to have to scroll through the content.
output$search_results <- DT::renderDataTable(filtered_df(),
server=TRUE,
extensions = c('Buttons', 'ColReorder', 'FixedColumns','FixedHeader', 'KeyTable'),
options = list(
#dom = 'Blfrtip',
dom = 'Blptilp',
colReorder = TRUE,
buttons = c('copy', 'csv', 'excel'),
autoWidth = TRUE,
scrollX = TRUE,
scrollY = "500px",
fixedColumns = list(leftColumns = 2),
fixedHeader = TRUE,
keys=TRUE,
lengthMenu = c(5,10,20,50,100),
columnDefs = list(list(width = '500px', targets = c(0,1)))
)
)
I have a project that needs me to remove items if one of the properties of the item I'm trying to find within the list is true. Just so it's easier understand the project I am pasting all code needed to understand it below.
fun main() {
val acct1 = AccountId(72)
val calendars = mutableListOf<CalendarDrawerCalendarItem>()
val calendars2 = mutableListOf<CalendarDrawerCalendarItem>()
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 3),"toast", true)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 4), "chicken", false)))
calendars.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 5), "pizza", true)))
calendars2.add(CalendarDrawerCalendarItem(CalendarDescriptor(acct1, CalendarId(acct1, 1), "bagel", true)))
// These are example calls to collapse
collapse(calendars, CalendarDrawerGroupItem(true, CalendarGroupDescriptor( acct1, "My Calendars")))
collapse(calendars2, CalendarDrawerGroupItem(false, CalendarGroupDescriptor(acct1, "Group Calendars")))
}
fun collapse(calendars: List<CalendarDrawerListItem>, group: CalendarDrawerGroupItem): List<CalendarDrawerListItem> {
val collapsedResults = mutableListOf<CalendarDrawerListItem>()
val findGroupGiven = group
collapsedResults.addAll(calendars)
if (collapsedResults.contains(findGroupGiven)) {
group.collapsed = true
// logic for deleting items here
}
return collapsedResults
}
I'll also put the classes so you can see how they're defined
data class AccountId(
val accountId: Int
)
data class CalendarId(
val accountId: AccountId,
val calendarId: Int)
data class CalendarDescriptor(
val accountId: AccountId,
val calendarId: CalendarId,
val name: String,
val isGroupCalendar: Boolean
)
data class CalendarGroupDescriptor(
val accountId: AccountId,
val name: String,
)
sealed class CalendarDrawerListItem
data class CalendarDrawerGroupItem(var collapsed: Boolean, val groupDescriptor: CalendarGroupDescriptor) : CalendarDrawerListItem()
data class CalendarDrawerCalendarItem(val calendarDescriptor: CalendarDescriptor) : CalendarDrawerListItem()
The first step I have done is I must find the given group from the group variable, within calendars. (I did this with the contains() method). Next when I find the group I have to set its collapsed variable to true and any CalendarDrawerCalendarItems after it have to be deleted.
The input will look something like (the exact numbers and values are not the important part):
Input:
calendars:
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 1, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 2, isGroup = false))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 3, isGroup = false))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
group: CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
The output should look something like this:
Output:
CDGroupItem(collapsed = true, groupDescriptor = GroupDescriptor(accountId = 1, name = "My calendars"))
CDGroupItem(collapsed = false, groupDescriptor = GroupDescriptor(accountId = 1, name = "Group calendars"))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 4, isGroup = true))
CDCalendarItem(calendarDescriptor = CalendarDescriptor(accountId = 1, calendarId = 5, isGroup = true))
Any group item that has its collapsed boolean set to true should have all calendar items deleted after it since its collapsed is set to true. Again the names and numbers are not super important. The collapsed bool is. How can I do this without hardcoding or using indicies?
Your example code doesn't use that input and output as-is so I can only give you a general example, but you could use a fold:
val result = calendars.fold(mutableListOf<CalendarDrawerListItem>()) { items, current ->
// basically 'is there a last item stored, and is it a group item, and is it collapsed'
val lastStoredIsCollapsed =
(items.lastOrNull() as? CalendarDrawerGroupItem)?.collapsed == true
if (current is CalendarDrawerCalendarItem && lastStoredIsCollapsed) items
else items.apply { add(current) }
}
It basically pipes out each item into a list, but if the last one it stored is a CalendarDrawerGroupItem with collapsed set to true, it drops drawer items. If the last one is a non-collapsed group item, it can store a drawer item, and that means the next drawer item will be stored (since the last item isn't a collapsed group)
edit: here's the for loop equivalent if it helps, with the full logic for when a calendar is not dropped (the logic in my other example is for whether it should be dropped, which can be condensed a bit):
// assuming 'calendars' is your list of items with 'collapsed' set appropriately
val result = mutableListOf<CalendarDrawerListItem)
for (calendar in calendars) {
val lastStored = result.lastOrNull()
when {
lastStored == null ->
result.add(calendar)
lastStored is CalendarDrawerGroupItem && !lastStored.collapsed ->
result.add(calendar)
lastStored is CalendarDrawerCalendarItem ->
result.add(calendar)
}
}
return result
If you're asking how to actually mutate your list so a collapsed property is set to true, that would be easy if the property was a var in your data class. Since it's a val you'll have to do something like this:
val calendarInputWithCollapsedSet = calendars.map { calendar ->
if ((calendar as? CalendarDrawerGroupItem)?.groupDescriptor == group.groupDescriptor)
calendar.copy(collapsed = true) else calendar
}
So if you find a matching group (you'll have to work out how to match them, I'm guessing) you transform it into a copy with its collapsed property set
And then you can run the fold or whatever on that new list.
In Odoo v10 this on_change method worked pretty well:
#api.onchange("partner_id")
def onchange_partner_id(self):
self.zapocet_line_pohledavky = False
self.zapocet_line_zavazky = False
account_move_line_obj = self.env['account.move.line']
val = {'value': {'zapocet_line_pohledavky': [], 'zapocet_line_zavazky': []}}
for statement in self:
if statement.partner_id:
domain = [('account_id.user_type_id.type', 'in', ('payable', 'receivable')), ('move_id.state', '=', 'posted'),
('partner_id.id', '=', statement.partner_id.id),]
line_ids = account_move_line_obj.search(domain, order="date asc")
for line in line_ids:
if line.amount_residual != 0 and line.credit > 0:
res = {
"move_line_id": line.id,
}
val['value']['zapocet_line_zavazky'].append(res)
if line.amount_residual != 0 and line.debit > 0:
qes = {
"move_line_id": line.id,
}
val['value']['zapocet_line_pohledavky'].append(qes)
self.zapocet_line_pohledavky = val['value']['zapocet_line_pohledavky']
return val
Does anybody have a clue why in v11 it loads the lines well, but they disappear on saving?
I am using iOS-Charts to show a horizontal bar chart.
The x-Axis labels on the left are cut-off.
Only when I double tap on the chart, the correct sizing appears to happen and the labels are not cut off anymore.
Here's the code I'm using
func setChart(_ dataPoints: [(String,Int)], chart: HorizontalBarChartView) {
chart.noDataText = "No data available."
var dataEntries: [BarChartDataEntry] = []
let maxNumberEntries = dataPoints.count
var xAxisLabel: [String] = []
var counter:Int = maxNumberEntries-1
for _ in 0..<maxNumberEntries {
let dataEntry = BarChartDataEntry(x: Double(counter), yValues: [Double(dataPoints[counter].1)], label: dataPoints[counter].0)
dataEntries.append(dataEntry)
xAxisLabel.append(dataPoints[counter].0)
counter -= 1
}
xAxisLabel = xAxisLabel.reversed()
let chartDataSet = BarChartDataSet(values: dataEntries, label: "")
let chartData = BarChartData(dataSet: chartDataSet)
chart.data = chartData
chart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
// disable zoom of chart
chart.pinchZoomEnabled = false
chart.scaleXEnabled = false
chart.scaleYEnabled = false
chart.chartDescription?.text = ""
chart.legend.enabled = false
// disable selection of bars
chartDataSet.highlightEnabled = false
chartDataSet.valueFont = NSUIFont.systemFont(ofSize: 10)
let numberFormatter = ValueFormatter()
chartData.setValueFormatter(numberFormatter)
// specify the width each bar should have
let barWidth = 0.8
chartData.barWidth = barWidth
let formato:BarChartFormatter = BarChartFormatter()
formato.strings = xAxisLabel
let xaxis:XAxis = XAxis()
_ = formato.stringForValue(Double(1), axis: xaxis)
xaxis.valueFormatter = formato
chart.xAxis.valueFormatter = xaxis.valueFormatter
let xAxis = chart.xAxis
xAxis.labelPosition = XAxis.LabelPosition.bottom // label at bottom
xAxis.drawGridLinesEnabled = false
xAxis.granularity = 1.0
xAxis.labelCount = maxNumberEntries
xAxis.labelRotationAngle = 0
// Don't show other axis
let leftAxis = chart.leftAxis
leftAxis.enabled = false
let rightAxis = chart.rightAxis
rightAxis.enabled = false
}
Any idea how to fix that?
Screenshots:
cut-off xAxis labels
after double tap the labels are not cut-off anymore
If you values are cut off even after notifyDataSetChanged, try offseting it like this:
mChart.extraTopOffset = 20
I solved this issue by calling
chart.fitScreen()
for every bar chart once all the data is passed.
HorizontalBarChart label cut issue solved you just only put this code in your chart setup:
chart.extraRightOffset = 30
If anyone has been struggling and answer did not help, once you set a chart with a new data, do not forget to call notifyDataSetChanged on chart, otherwise labels will be cut. That was my case.
I am just downloaded gtk3+, and I'm working through some sample code from:
https://python-gtk-3-tutorial.readthedocs.io/en/latest/layout.html#listbox
Here is the sample code:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class ListBoxRowWithData(Gtk.ListBoxRow):
def __init__(self, data):
super(Gtk.ListBoxRow, self).__init__()
self.data = data
self.add(Gtk.Label(data))
class ListBoxWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="ListBox Demo")
self.set_border_width(10)
box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(box_outer)
listbox = Gtk.ListBox()
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
box_outer.pack_start(listbox, True, True, 0)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label1 = Gtk.Label("Automatic Date & Time", xalign=0)
label2 = Gtk.Label("Requires internet access", xalign=0)
vbox.pack_start(label1, True, True, 0)
vbox.pack_start(label2, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
hbox.pack_start(switch, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label("Enable Automatic Update", xalign=0)
check = Gtk.CheckButton()
hbox.pack_start(label, True, True, 0)
hbox.pack_start(check, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label("Date Format", xalign=0)
combo = Gtk.ComboBoxText()
combo.insert(0, "0", "24-hour")
combo.insert(1, "1", "AM/PM")
hbox.pack_start(label, True, True, 0)
hbox.pack_start(combo, False, True, 0)
listbox.add(row)
listbox_2 = Gtk.ListBox()
items = 'This is a sorted ListBox Fail'.split()
for item in items:
listbox_2.add(ListBoxRowWithData(item))
def sort_func(row_1, row_2, data, notify_destroy):
return row_1.data.lower() > row_2.data.lower()
def filter_func(row, data, notify_destroy):
return False if row.data == 'Fail' else True
listbox_2.set_sort_func(sort_func, None, False)
listbox_2.set_filter_func(filter_func, None, False)
listbox_2.connect('row-activated', lambda widget, row: print(row.data))
box_outer.pack_start(listbox_2, True, True, 0)
listbox_2.show_all()
win = ListBoxWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
I get an error of "incorrect syntax" in
listbox_2.connect('row-activated', lambda widget, row: print(row.data))
This is straight from the sample code, and I'm completely at a loss here. Please help.
Other way for your problem instead of import print function is use repr()
listbox_2.connect('row-activated', lambda widget, row: repr(row.data))
You can use this way too:
def on_row_activated(listbox, row):
print(row.data)
listbox_2.connect('row-activated', on_row_activated)
References: https://github.com/ailtonbsj/course-python-gtk3/blob/master/listBoxLayout.py
https://lazka.github.io/pgi-docs/Gtk-3.0/classes/ListBox.html#Gtk.ListBox.signals.row_activated