I have a very simple Python program that I am using to get familiar with the win32api message calls. I put a line in my program
mywin['button'].onclick = win32api.MessageBox(0, 'hello', 'title')
The problem is that the message box gets displayed as soon as the program starts. And it does not get displayed when the button is clicked. Any ideas what I am doing wrong?
Here is the rest of my code:
import gui
import win32api
gui.Window(name='mywin', title=u'gui2py minimal app', resizable=True, height='459px', width='400px', image='', )
gui.Button(label=u'Click me!', name='button', left='8', top='115', default=True, parent='mywin', )
# get a reference to the Top Level Window:
mywin = gui.get("mywin")
mywin['button'].onclick = win32api.MessageBox(0, 'hello', 'title')
if name == "main":
mywin.show()
gui.main_loop()
You are assigning the .onclick attribute to the return value of calling win32api.MessageBox. It is no different than doing:
value = win32api.MessageBox(0, 'hello', 'title')
mywin['button'].onclick = value
To fix the problem, you can use a lambda function:
mywin['button'].onclick = lambda: win32api.MessageBox(0, 'hello', 'title')
The above assigns the .onclick attribute to the lambda function. When the button is clicked, the lambda will be called and the win32api.MessageBox(0, 'hello', 'title') code will be executed.
Related
Whenever I run this code with the chopped = first_word.split() line I get an error (the window closes instantly).
import tkinter as tk
win = tk.Tk()
win.title("Conversation")
win.iconbitmap("cake.ico")
win.geometry("600x700")
#Lists
Hellos = ["greetings", 'hello', 'greetings', 'hi']
gday = ['good', 'great', 'incredible', 'not bad', 'okay']
bday = ['bad', 'awful', 'not the best', 'terrible']
fw_label = tk.Label(win, text="Hello user, it's nice to meet you.")
fw_label.pack()
first_word = tk.Entry()
first_word.pack()
chopped = first_word.split()
But when I change the line first_word = tk.Entry() to first_word="A normal string" , the split method highlights and when I hover it it gives its description, which wasn't happening with ```first_word = tk.Entry()``.
I've ran into this problem when using libraries like opencv, may I know what's causing it not to work?
The solution is simple. You have to make a function to be called while pressing the submit button. And the statement chopped = first_word.get().split() should be inside that function.
Coming to the error part, it was because first_word is a tkinter entry object without any attribute split().
The split method works only for strings. To get the text entered into the entry widget in form of string, you need to use the get() method...
import tkinter as tk
def click():
chopped = first_word.get().split()
print(chopped)
win = tk.Tk()
win.title("Conversation")
# win.iconbitmap("cake.ico")
win.geometry("600x700")
#Lists
Hellos = ["greetings", 'hello', 'greetings', 'hi']
gday = ['good', 'great', 'incredible', 'not bad', 'okay']
bday = ['bad', 'awful', 'not the best', 'terrible']
fw_label = tk.Label(win, text="Hello user, it's nice to meet you.")
fw_label.pack()
first_word = tk.Entry()
first_word.pack()
tk.Button(win, text="Submit", command=click).pack()
win.mainloop()
So, you get the text of the entry using the get() method and then split it
Note : The statement chopped = first_word.get().split() should be inside the function because if its outside it, it would be executed at the time of the creation of the entry widget and using get() there would result in an empty value as the entry doesn't contain anything at that point
Maybe this could work
Change
chopped = first_word.split()
to
chopped = first_word.get().split()
I'm unable to reply my comment on your last question because of my low reputation. https://www.shapedivider.app/ here you would easily make the curves you want and embed the code to your project. I use this often.
im getting this name error for my button. I cant figure out why. Im using tkinter and I think Ive imported all the ne
#this the sound shart
start_game = Button (text_box,command=start_game_pressed, fg='black',text = """
丂七闩尺七
""")
start_game.place(x=450, y=400)
def start_game_pressed (self):
print("sus")
#subprocess.call(["afplay", "soundscrate-not-done2.wav"])
#text and textbox configuration
text_box.pack(expand=True)
text_box.insert('end', titletext,start_game )
text_box.config(state = 'disabled')
text_box.config(bg='black')
text_box.config(fg='white')
text_box.place(x=150, y=125)
gui.mainloop()
this is the error message
File "/Users/odinschaefer/Desktop/torture my/main.py", line 43, in <module>
start_game = Button (text_box,command=start_game_pressed, fg='black',text = """
NameError: name 'start_game_pressed' is not defined
help pls.
You need to define the function before you try to reference it.
def start_game_pressed (self):
print("sus")
start_game = Button (text_box,command=start_game_pressed, fg='black',text = """
丂七闩尺七
""")
You need to write your function before referencing it in the button. Something like this:
# Notice that here, the function is
# defined before the button is.
def start_game_pressed(self):
print(“sus”)
start_game = Button(text_box,command=start_game_pressed,
fg='black',text = "丂七闩尺七")
I am currently struggling trying to use the panel library in Python, in order to build an interactive dashboard to analyze and display CSV data. My current goal is to let the user enter an initial and a final date, which will be used to filter a DataFrame once a button is pressed. However, whenever I press the button, the on_click function is not completely executed before the script stops running. The code snippet is the following:
import panel as pn
pn.extension()
def acquire_data(dateBeginning, dateEnd):
eventDF = pd.read_csv('multi.csv')
eventDF['Date']= pd.to_datetime(eventDF['Date'])
dateDF = eventDF[eventDF.upvotes > 8]
print(eventDF)
def register_dates(event, save=True):
dateBeginning = date1Picker.value
dateEnd = date2Picker.value
if dateBeginning < dateEnd:
text = pn.widgets.StaticText(name='Static Text', value='A string')
spinner = pn.indicators.LoadingSpinner(width=50, height=50, value=True, color='info', bgcolor='light')
layout = pn.Column(text, spinner, align='center')
layout.app()
print('getting in')
acquire_data(dateBeginning, dateEnd)
print('getting out')
spinner.value = False
else:
print('Not working')
#pn.pane.Alert('## Alert\nThis is a warning!')
return save
date1Picker = pn.widgets.DatePicker(name='Date Initiale', margin=25)
date2Picker = pn.widgets.DatePicker(name='Date Finale', margin=25)
button = pn.widgets.Button(name="Analyse", button_type='primary', margin=(25, 0, 20, 200), width=200)
button.on_click(register_dates)
dateLayout = pn.Row(date1Picker, date2Picker)
layout = pn.Column(dateLayout, button, width=200, align='center')
layout.app()
I was also aiming at having the first layout be replaced by the one with the spinner and the text once the button is pressed, but I haven't found anything in the doc mentioning how to do so. If anyone could give me a hint regarding these issues, that would really help me!
In def acquire_data(dateBeginning, dateEnd):
pd.read_csv('multi.csv'), pd.to_datetime(eventDF['Date'])
For start, in this function I think you forgot to import panda and your app just crash.
add: import pandas as pd
Ex:
import panel as pn
import pandas as pd
I'm building a toolbox UI using python in Maya, and I keep on getting a Nonetype error when I call one of the imported functions. This is the script for the toolbox:
class Toolbox():
import maya.cmds as cmds
def __init__(self):
self.window_name = "mlToolbox"
def create(self):
self.delete()
self.window_name = cmds.window(self.window_name)
self.m_column = cmds.columnLayout(p = self.window_name, adj = True)
cmds.button(p=self.m_column,label = 'MyButton', c=lambda *arg: cmds.polySphere(r = 2))
cmds.button(p=self.m_column, label = 'Make_Control', command = lambda *args: self.ControlBTN())
cmds.button(p=self.m_column, label = 'Find Center of All Selected', command = lambda *args: self.CenterBTN())
cmds.button(p=self.m_column, label = 'Find Center of Each Selected Object', command = lambda *args: self.IndiCenterBTN())
self.colorname = cmds.textField(placeholderText = 'Enter color name...')
cmds.button(p=self.m_column, label = 'ChangeColor', command = lambda *args: self.colorBtn())
self.MinAndMax = cmds.textField()
cmds.button(p=self.m_column, label = 'Random Scatter', command = lambda *args: self.ScatterBTN())
cmds.showWindow(self.window_name)
cmds.button(p=self.m_column, label = 'Select Everything', command = lambda *args: self.selectBTN())
def CenterBTN(self):
import CenterSelected
CenterSelected.Locator()
def ScatterBTN(self):
import Scatter
value = cmds.textField(self.MinAndMax, q=True)
Scatter.RandomScatter(value)
cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')
def IndiCenterBTN(self):
import ManySelected
ManySelected.LocatorMany()
def colorBtn(self):
import ColorControl
value = cmds.textField(self.colorname, q=True, text = True)
ColorControl.colorControl(value)
cmds.textField(self.colorname, e=True, text='')
def selectBTN(self):
import tools
tools.selectAll()
def delete(self):
if cmds.window(self.window_name, exists=True):
cmds.deleteUI(self.window_name)
def ControlBTN(self):
import CreateControl
CreateControl.createControl()
myTool = Toolbox()
myTool.create()
And this is the function that I'm having trouble with:
def RandomScatter(MinAndMax):
import random
import maya.cmds as cmds
Stuff = cmds.ls(sl=True)
i=0
for i in range(random.randint(1,100)):
Stuff.append(cmds.duplicate(Stuff))
cmds.move( (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), Stuff[i], absolute=True )
cmds.rotate( (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), Stuff[i], absolute=True )
cmds.scale( (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), Stuff[i], absolute=True )
i = i+1
RandomScatter() works fine as long as I call it on it's own using a RandomScatter([a, b, c, d, e, f]) format, but when I try to call it Toolbox(), I get "Scatter.py line 21: 'NoneType' object has no attribute 'getitem'" as an error. It also happens when I try to use the intField() command instead of textField(). The UI window builds just fine; the error only happens after I enter input into the text field and press the button that's supposed to call RandomScatter(). It seems like the input isn't making it to the MinAndMax list, so when it reaches "cmds.move( (random.randint(MinAndMax[0]," it can't find anything to put in the MinAndMax[0] slot, or any of the slots after that, but I can't figure out why. Does anyone have any advice?
I didn't test your code and didn't read it totally, but I can already say that your strange "lambda" usage doesn't make any sens.
lambda *args: self.ControlBTN()
this lambda execute self.ControlBTN during the cmds.button definition and provide to it a function which return None.
that like doing that:
self.ControlBTN()
function = def func(): return None
cmds.button(p=self.m_column, label = 'Make_Control', command=function)
I advise you to reread the documentation about the "python lambda".
replace this by:
cmds.button(p=self.m_column, label = 'Make_Control', command=self.ControlBTN)
...
def ControlBTN(self, *args)
...
That should help
good luck
As written self.MinAndMax is a text field; even if you get the value from it it'll be a string and you won't be able to index into it to get the individual items -- and your indexing will be thrown off if any of the numbers are negative or have decimals. The lazy solution is to use a FloatFieldGrp which lets you have 2-4 numberic inputs. It's a bit annoying to get at all of the values at once (see the way it's done below) but it will avoid many issues with trying to parse the text field.
Also, this line doesn't make sense in context:
cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')
You're not seeing the error because it's failing in the previous line, but the first argument ought to be the name of an existing intField.
In any case, I'd refactor this a bit to keep the argument parsing out of the scatter function, so you can separate out the working logic from the UI parsing logic. It'll make it much easier to spot where things have gone off the rails:
import random
import maya.cmds as cmds
class TestGUI(object):
def __init__(self):
self.window = cmds.window()
self.layout = cmds.rowLayout(nc=3)
self.min_xyz = cmds.floatFieldGrp( numberOfFields=3, label='min', value1=-10, value2=-10, value3=-10 )
self.max_xyz= cmds.floatFieldGrp( numberOfFields=3, label='min', value1=10, value2=10, value3=10 )
cmds.button(label='scatter', c = self.scatter)
cmds.showWindow(self.window)
def scatter(self, *_):
selected = cmds.ls(sl=True)
if not selected:
cmds.warning("select something")
return
min_xyz = (
cmds.floatFieldGrp(self.min_xyz, q=True, v1=True),
cmds.floatFieldGrp(self.min_xyz, q=True, v2=True),
cmds.floatFieldGrp(self.min_xyz, q=True, v3=True)
)
max_xyz = (
cmds.floatFieldGrp(self.max_xyz, q=True, v1=True),
cmds.floatFieldGrp(self.max_xyz, q=True, v2=True),
cmds.floatFieldGrp(self.max_xyz, q=True, v3=True)
)
print "scatter settings:", min_xyz, max_xyz
rand_scatter(selected, min_xyz, max_xyz)
def rand_scatter(selection, min_xyz, max_xyz):
dupe_count = random.randint(1, 10)
duplicates = [cmds.duplicate(selection) for n in range(dupe_count)]
for dupe in duplicates:
destination = [random.randint(min_xyz[k], max_xyz[k]) for k in range(3)]
cmds.xform(dupe, t=destination, absolute=True)
print (dupe, destination)
t = TestGUI() # shows the window; hit 'scatter' to test
My version changes your logic a bit -- you were duplicating your selection list, which would cause the number of items to grow exponentially (as each duplication would also duplicate the previous dupes). I'm not sure if that's inline with your intention or not.
You can avoid the extra lambdas by including a *_ in the actual button callback; it's a minor maya irritant that buttons always have that useless first argument.
As an aside, I'd try not to do imports inside of function bodies. If the imported module is not available, it's better to know at the time this file is imported rather than only when the user clicks a button -- it's much easier to spot a missing module if you do all your imports in a block at the top.
I want that when I go to secondpage and back to the mainpage it removes the buttons created in the mainloop. So when I open the second page again, it needs to make the buttons again. with the updated list
Now it shows the buttons 2 times. I know to not add it into a function it will render just 1 time but the point is it will be removed when it is in a function and it need to remaked every time I open the mainpage. So that I can edit for example the list when the application is open and it will be rendered again.
Here is my code:
from tkinter import *
items = ['ijs', 'water', 'lolly', 'laptop']
root = Tk()
def buttonmaker():
for x in items:
button = Button(master=secondpage, text=x ).pack()
def mainpagetosecondpage():
mainpage.pack_forget()
buttonmaker()
secondpage.pack()
def secondpagetomainpage():
secondpage.pack_forget()
mainpage.pack()
#mainpage
mainpage = Frame(master=root)
main_to_second_button = Button(master=mainpage, text='secondpage', command=mainpagetosecondpage).pack()
#scondpage
secondpage = Frame(master=root)
Second_to_main_button = Button(master=secondpage, text='mainpage', command=secondpagetomainpage).pack()
mainpage.pack()
root.mainloop()
If something is unclear, please ask
You need to call buttonmaker only once, during the setup of the second frame:
from tkinter import *
root = Tk()
def buttonmaker():
items = ['ijs', 'water', 'lolly', 'laptop']
for x in items:
button = Button(master=secondpage, text=x )
button.pack()
def mainpagetosecondpage():
mainpage.pack_forget()
secondpage.pack()
def secondpagetomainpage():
secondpage.pack_forget()
mainpage.pack()
#mainpage
mainpage = Frame(master=root)
main_to_second_button = Button(master=mainpage, text='secondpage', command=mainpagetosecondpage)
main_to_second_button.pack()
#scondpage
secondpage = Frame(master=root)
Second_to_main_button = Button(master=secondpage, text='mainpage', command=secondpagetomainpage)
Second_to_main_button.pack()
buttonmaker()
mainpage.pack()
root.mainloop()
Also, you need to avoid putting the layout on the same line as the initialization. Code like variable = Widget(args).pack() will lead to bugs. Use 2 lines like I did above.