Folks,
So I've been working on a little GUI using Tkinter for a capstone project, and given the circumstances, I've only been programming for about two weeks before I was thrown into this, so I'm still a newbie.
My issue today is that I cannot manage to get my checkbutton dictionary to update values; the output for my checkbutton is always 0 or False. The code is as follows:
...
datatype= {'Joint Angle' : 0,
'Joint Acceleration' : 0,
'Ground Reaction Force' : 0,
'Muscle Activation' : 0
}
for measure in datatype:
datatype[measure] = IntVar()
dt_cb = Checkbutton(root, text=measure,
variable=datatype[measure],command = enable_location_state)
dt_cb.grid(column=0, sticky='W', padx=20)
dt1 = datatype['Joint Angle'].get()
dt2 = datatype['Joint Acceleration'].get()
dt3 = datatype['Ground Reaction Force'].get()
dt4 = datatype['Muscle Activation'].get()
...
So I tried periodically printing values throughout the code and I continued to get 0 as soon as I booted the GUI, and after that, no matter what I clicked, the numbers did not update. I read that I should try BooleanVar() and StringVar() instead, but neither of those worked. The code is based off of another bit of code I found somewhere on stackoverflow, though I cannot remember exactly where.
I tried making it a list rather than a dictionary in order to overcome my problem because I was successful with lists previously, but the list created only a single checkbutton for all of those and I was unable to differentiate what is what.
The command enable_location_state configures other checkbuttons, and is as follows:
def enable_location_state():
if dt1 == 1 or dt2 == 1:
ja_cb.configure(state=ACTIVE)
if dt3 == 1:
grf_cb.configure(state=ACTIVE)
if dt4 == 1:
emg_cb.configure(state=ACTIVE)
Your problem is that you are getting the values of the IntVar only once: at the same moment you create your buttons. Move your .get() statements to the beginning of the enable_location_state() function. That way, every time your checkbutton is clicked, the function will check on (i.e., .get()) the value of the IntVar.
Related
I have a question that confused me for a long time. As you know, when we use an if condition in Modelica, that means if the expression is true, then Modelica will do the corresponding equation.
But when i test the following code, I am confused:
model Model134
Real a(start = 0);
equation
if not sample(0, 2) then
a = 1;
else
a = 3;
end if;
end Model134;
I think a will be changed every 2s (start time=0), but when I simulate this model, it dose not change and a is equal to 1 all the time.
Dose anybody know the root cause?
a does change its value, but depending on your simulation tool you might not see it in the plot.
sample(0, 2) creates a time event every 2 seconds. The return value of sample() is only true during the event. So the value of a changes, but after the event it immediately changes back.
In this answer to a similar question, it is mentioned that Dymola stores the value before and after the event in result file. Intermediate values are skipped for efficiency reasons (there can be many for every event, which would bloat up your result file). Hence you can not plot this change in Dymola. For OpenModelica see the answer by
Akhil Nandan.
To proof that a really does change its value you can use this code for example:
model Model134
import Modelica.Utilities.Streams.print;
Real a;
equation
if sample(0, 2) then
a = 1;
else
a = 0;
end if;
when a > 0.5 then
print("a is " + String(a) + " at t=" + String(time) + "s");
end when;
annotation (experiment(StopTime=10));
end Model134;
You should see something like this in the simulation log:
a is 1 at t=2s
a is 1 at t=4s
a is 1 at t=6s
a is 1 at t=8s
a is 1 at t=10s
This is the plot simulated when trying your above code in OpenModelica with settings shown in the second figure.
A time event is triggered when sample(startTime,interval) evaluates true at every multiple of 2 seconds and based on your code logic this should activate else
block and assign value of variable a to be 3.
Very simple. Cell A1 has an image in it, which I supply through Insert:Picture:From File...
Now I want Cell A3 to automatically show the same picture. I simply can't find a way-- certainly the "=" doesn't work. At this point, I don't care if the images are "links" or embedded, I just want it to work. Can it? Thx.
Edit, 09-01-17, based on Jim K's idea, here's macro code I have installed:
REM ***** BASIC *****
Private oListener as Object
Private cellA1 as Object
Sub AddListener
Dim Doc, Sheet, Cell as Object
Doc = ThisComponent
Sheet = Doc.Sheets.getByName("Sheet1")
cellA1 = Sheet.getCellrangeByName("A1")
'create a listener
oListener = createUnoListener("Modify_","com.sun.star.util.XModifyListener")
'register the listener
cellA1.addModifyListener(oListener)
End Sub
Sub Modify_disposing(oEv)
End Sub
Sub RmvListener
cellA1.removeModifyListener(oListener)
End Sub
' macro jumps here when oListener detects modification of Sheet
Sub Modify_modified(oEv)
Doc = ThisComponent
Sheet = Doc.Sheets.getByIndex(0)
originCell = Sheet.getCellByPosition(0,0)
originValue = originCell.Value
if originValue then
print "originValue is " & originValue
else
print "originValue zero"
end if
End Sub
The problem, ironically, is that it works. It works for integers and {non-value}, I mean an empty cell.
So any integer not zero prints TRUE, zero prints FALSE, and empty cell prints FALSE.
But that's where it quits working-- any kind of string "asdf" also returns FALSE.
Maybe that could be fixed, but there's something a lot worse: When I paste an image in the cell, or use the Insert/Image/From File... menu, or Cut an existing image... Nothing happens! The Sheet Modified business does not trigger the expected routine.
Any hope? Thx.
As you discovered, the solution in my comment does not work, because the Content changed event will not trigger when images are added. I looked into other events as well, but they did not work either.
So instead, we can set up a function that runs periodically. Each time it runs, it checks the count of images, and if any have been added or removed, it calls update_copied_images() below, which currently simply reports the value of cell A1, as in your code.
As explained here, I have not gotten a timer loop to work in Basic without crashing, so we can use Python instead (a better language, so this is not a drawback in my opinion).
import time
from threading import Thread
import uno
COLUMN_A, COLUMN_B, COLUMN_C = 0, 1, 2
FIRST_ROW = 0
def start_counting_images(action_event=None):
t = Thread(target = keep_counting_images)
t.start()
def keep_counting_images():
oDoc = XSCRIPTCONTEXT.getDocument()
oSheet = oDoc.getSheets().getByIndex(0)
oDrawPage = oSheet.getDrawPage()
messageCell = oSheet.getCellByPosition(COLUMN_C, FIRST_ROW)
messageCell.setString("Starting...")
prevCount = -1
while hasattr(oDoc, 'calculateAll'): # keep going until document is closed
count = oDrawPage.Count
if prevCount == -1 or prevCount != count:
prevCount = count
messageCell.setString("Number of Images: " + str(prevCount))
update_copied_images(oSheet)
time.sleep(1)
def update_copied_images(oSheet):
originCell = oSheet.getCellByPosition(COLUMN_A, FIRST_ROW)
originString = originCell.getString()
messageCell = oSheet.getCellByPosition(COLUMN_B, FIRST_ROW)
if len(originString):
messageCell.setString("originString '" + originString + "'")
else:
messageCell.setString("originString length is zero")
g_exportedScripts = start_counting_images,
To run, go to Tools -> Macros -> Run Macro, find the .py file under My Macros where you put this code, and run start_counting_images.
I'm trying to construct a game where you can play five-in-row and when someone wins I want the label to change from like "Game is going on" to "Player 1 won" and this is where I am stuck.
The way I have constructed it all is like this. I have one class for the graphics (a Frame) and I have one class for all the Buttons that you can click on to set it to "X" or "O". And then I have one last class that checks if the grid has five of some value in a row, and that one runs after each successful click.
The label is of course set in the Frame class and first I had it like this just to make sure that I could see something
def __init__(self, master = None, rows = 10, cols = 10):
Frame.__init__(self, master)
Some other selfs....
self.inforad = Label(master, text = "Game is going on")
and this prints out nicely, just like I want it. Now I have been trying for hours to make this change when someone wins and I just can't make it work! The last thing I tried is to use the StringVar() and I did it like this
self.info = StringVar()
self.info.set("Game is going on")
self.inforad = Label(master, text = self.info)
and for starter this doesn't work at all, it prints out PY_VAR0. My plan was to define a method to call this during the game, like this
def disp(self, string):
self.info.set(string)
return self.info
And this doesn't work at all. Can someone help me with this? I am really new to programming, did my first code for like 3 weeks ago.
(If self.inforad is placed within the Frame subclass instance, self, its master should be self, not the master of self.)
As for your specific question, change Label(master, text = self.info) to Label(self, textvariable = self.info).
Hi I’m developing a user interface for processing AI (Adobe illustrator) files, I have grouped sets of lines, using the tag feature. I want to know which set of lines is selected on click (which tag for example), but I can't figure out how, as the function click_poligono always gets the last tag, any help on how I'm supposed to do this??
part of my code is :
def click_poligono(self,event,poligono):
self.canvas.itemconfigure('poligono%s'%poligono , fill = 'blue')
def cambio_listbox(self,*args,**kwargs):
<-------Mysql queries and processes------->
for i in range(len(matriz_start)):
print i
self.canvas.tag_bind('poligono%s'%i , '<ButtonPress-1>' , lambda event: self.click_poligono(event,'%s' % i)
for j in range(len(matriz_start[i])):
if True: #if for possible matrix condition
self.canvas.create_line(10+matriz_start[i][j]['x']*680/maximo,690-(matriz_start[i][j]['y']*680/maximo),10+matriz_end[i][j]['x']*680/maximo,690-(matriz_end[i][j]['y']*680/maximo), width = 2 ,tags ='poligono%s'%i)
So the question here is , how can I manage to select the set of lines I click with the mouse , and process it on one function , as the set of lines is variable depending on the number of figures the file (Adobe Illustrator) has..
I hope I'm clear on what I'm asking, and I'm open to new suggestions on my code.
I guess it's because of lambda.
You have
lambda event: self.click_poligono(event,'%s' % i)
where event is local variable but i is not.
Try this
lambda event, i=i: self.click_poligono(event,'%s' % i)
I've been working in a code for some weeks, just trying to start with python and I've found a strange problem when I try to update the values in a top level window from Tk, the previous value of the label seems to be in the background of the label and I must remove it, here some pics to show the problem, thank you for reading my problem and also for all your help.
link to the pic:
http://oi57.tinypic.com/e6u2c2.jpg
PD: it is in spanish
PD2: if the code is needed I can paste the segments of the code that generates this issue.
The problem was generated when I hitted a button in the Tkinter interface, and every time it generated a new Label, this new Label displayed the updated information, but the older ones was still in the frame, then when I changed the value of the StringVar to something shorter I still could see the last Label there, the solution was to destroy the last Label when I update the value of the StringVar socitaed to the Label, then I get what I needed.
The code that generated the error:
self.varTotal = StringVar()
self.lblTotal = Label(self.master, textvariable = self.varTotal)
self.varTotalLetras = StringVar()
self.lblTotalLetras = Label(self.master, textvariable = self.varTotalLetras)
...
self.varTotal.set(total)
self.varTotalLetras.set(num2words(int(total), lang = 'es').upper() + " PESOS.")
Then every time when I clicked the button a new instance of the Label seemed to be created.
And My solution was to delete the current instance of the Labels and then create another one.