I wrote this code with turtle library. The problem is that when I run this code in IDLE,everything works fine until it gets to the input in the function 'putBall()' ,and the window become 'not responding'.
I tried several suggestions from google like 'turtle.done' in end of code or 'turtle.done' in the end of each one of the functions,but in seems do nothing in both cases.
I want to add that I tried this code in online service 'Trinket' and it work fine.
import turtle
def initialize_pen_screen():
s=turtle.getscreen()
s.setup(600,600)
t = turtle.Turtle()
ballOne = turtle.Turtle()
ballOne.shape('turtle')
ballOne.fillcolor("red")
ballOne.pencolor("red")
ballTwo = turtle.Turtle()
ballTwo.shape('turtle')
ballTwo.fillcolor("blue")
ballTwo.pencolor("blue")
t.shape("turtle")
s.bgcolor("gray")
return [t,ballOne,ballTwo]
def initialize_pen_screen_saviour():
t = turtle.Turtle()
ballOne = turtle.Turtle()
ballOne.shape('turtle')
ballOne.fillcolor("red")
ballOne.pencolor("red")
ballTwo = turtle.Turtle()
ballTwo.shape('turtle')
ballTwo.fillcolor("blue")
ballTwo.pencolor("blue")
t.shape("turtle")
return [t,ballOne,ballTwo]
def initialize_first(t,ballOne,ballTwo):
t.rt(180)
t.penup()
t.fd(150)
t.lt(90)
t.pensize(10)
ballOne.lt(90)
ballOne.penup()
ballOne.fd(90)
ballTwo.lt(90)
ballTwo.penup()
ballTwo.fd(150)
ballOne.rt(90)
ballTwo.rt(90)
#draw line that goes down
def stamp_up(t):
t.pendown()
t.stamp()
t.fd(250) #depends how long column
#print(t.pos(),'UP')
t.lt(90)
t.penup()
#draw line that goes up
def stamp_down(t):
t.fd(70)
#print(t.pos(),'Down')
t.lt(90)
t.pendown()
t.stamp()
t.fd(250) #depends how long column
t.rt(90)
t.penup()
t.fd(70)
t.rt(90)
#draw ball and save coordinate of reserved position in column
def move_ball(chosenBall,x,y):
chosenBall.goto(x+20,y+20)
chosenBall.fd(15)
chosenBall.dot(50)
newClosedPos=[x,y+50]
chosenBall.goto(0,150)
return newClosedPos
#put ball in table,and save another reserved position in column
def putBall(currentMove):
print("which column to put your ball?")
column=input()
if(column=='1'):
x=closedColumnOne[len(closedColumnOne)-1][0]
y=closedColumnOne[len(closedColumnOne)-1][1]
newClose=move_ball(currentMove,x,y)
closedColumnOne.append(newClose)
elif(column=='2'):
x=closedColumnTwo[len(closedColumnTwo)-1][0]
y=closedColumnTwo[len(closedColumnTwo)-1][1]
newClose=move_ball(currentMove,x,y)
closedColumnTwo.append(newClose)
elif(column=='3'):
x=closedColumnThree[len(closedColumnThree)-1][0]
y=closedColumnThree[len(closedColumnThree)-1][1]
newClose=move_ball(currentMove,x,y)
closedColumnThree.append(newClose)
elif(column=='4'):
x=closedColumnFour[len(closedColumnFour)-1][0]
y=closedColumnFour[len(closedColumnFour)-1][1]
newClose=move_ball(currentMove,x,y)
closedColumnFour.append(newClose)
elif(column=='5'):
x=closedColumnFive[len(closedColumnFive)-1][0]
y=closedColumnFive[len(closedColumnFive)-1][1]
newClose=move_ball(currentMove,x,y)
closedColumnFive.append(newClose)
return column
#tell state of world after put ball in table
def afterPutBall(SelectedColumn,columnBalls,tableSize,tableBall):
for k in range(0,tableSize):
for i in range(0,tableSize):
if(int(SelectedColumn)==k+1 and columnBalls[k][i]==0):
columnBalls[k][i]=tableBall
break
else:
continue
break
return columnBalls
#check if we in a win state
def checkWin(tableSize,columnBalls):
for k in range(0,tableSize-1):
for i in range(0,tableSize-1):
flagRow=1
flagColumn=1
flagDiagonalRight=1
flagDiagonalLeft=1
for j in range(0,tableSize-1):
#row win
if(columnBalls[j][i]==columnBalls[j+1][i] and columnBalls[j][i]!=0):
flagRow+=1
elif(flagRow!=0):
flagRow=1
#column win
if(columnBalls[i][j]==columnBalls[i][j+1] and columnBalls[i][j]!=0):
flagColumn+=1
#print(flagColumn)
elif(flagColumn!=0):
flagColumn=1
#diagonal right
if(i+j+1<=tableSize-1 and i+j<=tableSize-1 and j+k<=tableSize-1 and j+k+1<=tableSize-1): #end table
if(columnBalls[j+k][i+j]==columnBalls[j+k+1][i+j+1] and columnBalls[j+k][i+j]!=0):
flagDiagonalRight+=1
elif(flagDiagonalRight!=0):
flagDiagonalRight=1
#diagonal left
if(tableSize-j-i-1>=0 and tableSize-j-i-2>=0 and j+k<=tableSize-1 and j+k+1<=tableSize-1): #end table
if(columnBalls[j+k][tableSize-j-i-1]==columnBalls[j+k+1][tableSize-j-i-2] and columnBalls[j+k][tableSize-j-i-1]!=0):
flagDiagonalLeft+=1
elif(flagDiagonalLeft!=0):
flagDiagonalLeft=1
if flagRow==4 or flagColumn==4 or flagDiagonalLeft==4 or flagDiagonalRight==4:
return True
return False
def score_board():
score=turtle.Turtle()
score.ht()
score.color("green")
#score board
turtle.pensize(5)
turtle.speed(6)
turtle.penup()
turtle.goto(-250,150)
turtle.pendown()
turtle.rt(90)
for i in range(0,2):
turtle.fd(100)
turtle.lt(90)
turtle.fd(130)
turtle.lt(90)
turtle.fd(100)
turtle.lt(90)
turtle.fd(150-i*20)
turtle.lt(90)
turtle.penup()
turtle.ht()
#turtle.setposition(150,100)
#score write
score.speed('fastest')
score.penup()
score.goto(-250,150)
score.rt(90)
score.fd(50)
score.lt(90)
score.fd(35)
return score
def write_score(score,redPoints,bluePoints):
score.clear()
score.write(str(redPoints)+'-'+str(bluePoints),move=False ,font=("Verdana",
18, "normal"), align="left")
#build table
def build_table(tableSize,table,opponentOne,opponentTwo):
table.speed(6)
initialize_first(table,opponentOne,opponentTwo)
size_iter=int((tableSize-1)/2)
for i in range(0,size_iter+1):
stamp_up(table)
stamp_down(table)
if(tableSize%2==0): #even size table
stamp_up(table)
table.goto(0,250)
table.lt(90)
#tableSize=(2*(i+1)-1)
if 'main':
playAgain='yes'
s=turtle.getscreen()
s.setup(1000,1000)
s.bgcolor("gray")
score=score_board()
redPoints=0
bluePoints=0
while(playAgain=='yes' or playAgain=='Yes'):
tools=initialize_pen_screen_saviour()
table=tools[0]
opponentOne=tools[1]
opponentTwo=tools[2]
closedColumnOne=[[-150.0, -250.0]]
closedColumnTwo=[[-80.0, -250.0]]
closedColumnThree=[[-10.0, -250.0]]
closedColumnFour=[[60.0, -250.0]]
closedColumnFive=[[130.0, -250.0]]
tableSize=8
build_table(tableSize,table,opponentOne,opponentTwo)
#initilize table state balls
columnBalls=[]
for i in range(0,tableSize):
columnBall=[0]*tableSize
columnBalls.append(columnBall)
print(columnBalls)
myBall='A'
playAgain='yes'
#max moves:25
for i in range(0,25):
win=False
print("Player "+myBall+" play now")
if(myBall=='A'):
currentMove=opponentOne
myBall='B'
tableBall='A'
else:
currentMove=opponentTwo
myBall='A'
tableBall='B'
SelectedColumn=putBall(currentMove)
columnBalls=afterPutBall(SelectedColumn,columnBalls,tableSize,tableBall)
print(columnBalls)
win=checkWin(tableSize,columnBalls)
if(win):
#update score player blue
if(tableBall=='B'):
write_score(score,redPoints,bluePoints+1)
bluePoints+=1
#update score player red
else:
write_score(score,redPoints+1,bluePoints)
redPoints+=1
print('player '+tableBall+' WIN!!')
print('Do you want to play again?')
playAgain=input()
if(playAgain=='no' or playAgain=='No'):
break
elif(playAgain=='yes' or playAgain=='Yes'):
table.reset()
opponentOne.reset()
opponentTwo.reset()
break
#t.reset()
#t.clear()
Please read https://stackoverflow.com/help/minimal-reproducible-example.
Lines 80-81 of your code
print("which column to put your ball?")
column=input('')
print a prompt to the interactive shell and pause the turtle screen while the turtle code waits for a response entered in the separate shell or terminal window. (column = input('which column' would do the same.) To enter a column, the user must click on the window with the 'which column' prompt. One you do so, entering numbers works fine.
A difference between IDLE and other ways from running a Python module is that IDLE sends your code to a separate process, different from the IDLE UI process, for execution. I believe that this is why clicking on the turtle window gives you the paused message that does not appear when running your code otherwise. I would have to do more experiements to determine whether this is true for all turtle programs that seek input from the terminal/shell.
In any case, it is not normal for GUI programs to request input from the terminal/shell. Turtle provides textinput and numinput methods and function. Try using one of them.
Related
I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!
I don't understand why the following code produces error.
The code begins with the main() function at the bottom.
heads = {}
function push(t)
if (#t == 2) then
table.insert(heads, t)
end
end
function remove(id)
for i = 1, #heads do
if (heads[i][2] == id) then
table.remove(heads, i)
end
end
end
function main()
push({50, 1})
push({50, 2})
push({50, 3})
remove(2)
end
When I run the code, I get attempt to index a nil value (field '?') error.
I expect to push the subtable elements into the table and then remove only the second one. So the resulting elements can be {50, 1} and {50, 3}.
Why is my code not working and how to fix this?
Andrew got it right. Never try to remove a value inside a table when you iterate the table. This is a common issue in many languages. Usually, you would store the value first and then remove like so:
local e
for i = 1, #heads do
if (heads[i][2] == id) then
e = i
end
end
if e then table.remove(heads, e) end
However, this solution is slow. Simply use the ID as key of your table:
local heads = {}
heads[1] = 50 -- push
heads[2] = 50
heads[3] = 50
heads[2] = nil -- remove
No need for unnecessary function calls and iterations.
According to 5.1 manual table.remove "Removes from table the element at position, shifting down other elements to close the space, if necessary"
size of heads (#heads) is calculated once before loop execution, when i==2 you call table.remove, and so size of the table shrinks to 2, and on next iteration you try index heads[3][2], but heads[3] is nil, therefore "attempt to index a nil value" error message.
As Andrew mentioned, for i = 1, #heads do will go to the original length of the list; if you shorten heads during the loop, then the final iteration(s) will read heads[i] and find only nil.
A simple way to fix this is to move backwards through the list, since removing an element only affects indices after the index you have removed from:
for i = #heads, 1, -1 do
if heads[i][2] == id then
table.remove(heads, i)
end
end
Note that in any case, this is O(n*d) complexity and could be very slow if you are deleting many elements from the list. And, as others pointed out, there's a O(1) approach where you use a map from v[1] => v instead.
To avoid problems caused by removing fields while iterating over an array, I've used a while loop with an index variable, which is incremented at the end of each iteration, but decremented when an index is removed. So, for instance, to remove all elements with an even index:
local t = { 1, 2, 3, 4, 5 }
local i = 1
while t[i] do
if t[i] % 2 == 0 then
table.remove(t, i)
i = i - 1
end
i = i + 1
end
This method allows you to iterate over array indices in ascending order.
Addressing this iteration, in case of many items that are to be removed, I'd rather go for
local result = {}
for _, v in ipairs(myTab) do
if v == 'nice' then
table.insert(result, v)
end
end
myTab = result
as table.remove is slow when shifting many elements.
I've searched this on the internet, but can't seem to find anything. I know there are hotkeys to skip back a few seconds, and I know there are hotkeys to to pause and play audio/video in VLC Media Player. However, I am using a single foot pedal for transcription and essentially need it to do both. I would like the pedal tap to pause the audio. Then, after tapping again, I would like it to play the audio, but skipping a few seconds back when doing so. Is this possible?
Save this code as rollback.lua and place it in Program Files\VideoLAN\VLC\lua\extensions folder. Then activate it through View > Rollback X Seconds.
function descriptor()
return {
title = "Rollback X Seconds",
capabilities = {"input-listener", "playing-listener"}
}
end
function activate()
end
function close()
end
function deactivate()
end
function input_changed()
end
function playing_changed()
local TIME_DELTA = -3
if vlc.playlist.status()=="paused" then
local timePassed = vlc.var.get(vlc.object.input(), "time")
local newTime = timePassed + TIME_DELTA
vlc.osd.message(TIME_DELTA, vlc.osd.channel_register(), "top-left", 1400000)
vlc.var.set(vlc.object.input(), "time", newTime)
end
end
Change the variable TIME_DELTA to whatever time change you want on pause
I expanded on the code provided by Tee by adding a GUI.
I would also like to add a few details of how to get it working.
Create a empty file, name it rollback.lua.
Copy the code provided underneath this list, paste into the file and save.
Move the file to VLCs folder for lua extensions, it should look something like this:
c:/Program Files/VideoLAN/VLC/lua/extensions
Restart VLC player.
Activate the script by going to (Note! Needs to be done each time you start VLC to use the plugin)
view > Rollback X Seconds
Select time in seconds you want to rollback and hit save (or save and close).
In order to get your pedal working with this script, simply configure the hotkey in VLC for play/pause toggle.
VLC > Tools > Preferences > Hotkeys > Set "Play/Pause" Global value to be your pedal.
(After you change a Global hotkey, you need to restart VLC in order to get it working...)
The code:
micro_second_unit = 1000000
TIME_DELTA = 1 --Default,
SHOW_OUTPUT = true
TIME_TO_DISPLAY = 1.5 --Default
function descriptor()
return {
title = "Rollback X Seconds",
capabilities = {"input-listener", "playing-listener"}
}
end
function activate()
dlg = vlc.dialog("Rollback X Seconds")
rollback_input = dlg:add_text_input("1", 2, 1 )
rollback_input_label = dlg:add_label("Seconds to back", 1, 1)
checkBox = dlg:add_check_box("Show output time ", wasChecked, 3, 3 )
timeTo_display_box = dlg:add_text_input(1.5, 2 ,3)
timeTo_display_box_label = dlg:add_label("Seconds To Display", 1, 3)
w2 = dlg:add_button("Save settings", change_step, 3, 4, 1, 1)
w2 = dlg:add_button("Save and close", updateAndClose, 3, 5, 1, 1)
done = dlg:add_label( "" , 3, 6)
end
function close()
end
function deactivate()
vlc.deactivate()
end
function input_changed()
end
function playing_changed()
if vlc.playlist.status()=="paused" then
local timePassed = tonumber(vlc.var.get(vlc.object.input(), "time"))
local newTime = timePassed - seconds_to_microsecond(TIME_DELTA)
local newTime_inSeconds = (newTime/1000000)
local newTime_inMinutes = (newTime_inSeconds/60)
local newTime_inSeconds_restOfMin = math.fmod(newTime_inSeconds,60)
local newTime_str = math.floor(newTime_inMinutes) .. "min " .. round(newTime_inSeconds_restOfMin,1) .."sec"
local timePassed_inSeconds = (timePassed/1000000)
local timePassed_inMinutes = (timePassed_inSeconds/60)
local timePassed_inSeconds_restOfMin = math.fmod(timePassed_inSeconds,60)
local timePassed_str = math.floor(timePassed_inMinutes) .. "min " .. round(timePassed_inSeconds_restOfMin,1) .."sec"
if SHOW_OUTPUT == true then
vlc.osd.message("Seconds to Back:" .. TIME_DELTA .. "sec", vlc.osd.channel_register(), "top-right", seconds_to_microsecond(TIME_TO_DISPLAY))
vlc.osd.message("New time:" .. newTime_str, vlc.osd.channel_register(), "top-left", seconds_to_microsecond(TIME_TO_DISPLAY))
vlc.osd.message("Old time:" .. timePassed_str, vlc.osd.channel_register(), "bottom-left", seconds_to_microsecond(TIME_TO_DISPLAY))
end
vlc.var.set(vlc.object.input(), "time", newTime)
end
end
function updateAndClose()
change_step()
dlg:delete()
end
function change_step()
done:set_text("Saved")
TIME_DELTA = tonumber(rollback_input:get_text())
SHOW_OUTPUT = checkBox:get_checked()
if SHOW_OUTPUT == true then
TIME_TO_DISPLAY = tonumber(timeTo_display_box:get_text())
end
end
function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
function microsecond_to_seconds(timeToConvert)
return timeToConvert / micro_second_unit;
end
function seconds_to_microsecond(timeToConvert)
return timeToConvert * micro_second_unit;
end
This will work just like Tee's script, the video will jump back each time it's paused.
Only difference is that you can set the amount of time to jump back each time you start the script.
The amount is given in seconds, however you can use decimals for more control...
There's also a checkbox you can tick if you want to display information about the jump.
I also want to thank Tee for his answer!
This is the first lua code I've written (or rather, modified) and it's a bit messy, but it works and I have used it every day since so I thought I might as well share it.
I've run into an issue with the TabularAdapter in the TraitsUI package...
I've been trying to figure this out on my own for much too long now, so I wanted to ask the experts here for some friendly advise :)
I'm going to add a piece of my program that illustrates my problem(s), and I'm hoping someone can look it over and say 'Ah Ha!...Here's your problem' (my fingers are crossed).
Basically, I can use the TabularAdapter to produce a table editor into an array of dtypes, and it works just fine except:
1) whenever I change the # of elements (identified as 'Number of fractures:'), the array gets resized, but the table doesn't reflect the change until after I click on one of the elements. What I'd like to happen is that the # of rows (fractures) changes after I release the # of fractures slider. Is this doable?
2) The second issue I have is that if the array gets resized before it's displayed by .configure_traits() (by the notifier when Number_of_fractures gets modified), I can shrink the size of the array, but I can't increase it over the new size.
2b) I thought I'd found a way to have the table editor display the full array even when it's increased over the 5 set in the code (just before calling .trait_configure()), but I was fooled :( I tried adding another Group() in front of the vertical_fracture_group so the table wasn't the first thing to display. This more closely emulates my entire program. When I did this, I was locked into the new smaller size of the array, and I could no longer increase its size to my maximum of 15. I'm modifying the code to reflect this issue.
Here's my sample code:
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import zeros, dtype
from traits.api import HasTraits, Range
from traitsui.api import View, Group, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
vertical_frac_array = zeros((max_cracks), dtype=vertical_frac_dtype)
vertical_fracture_group = Group(
Item(name = 'vertical_frac_array',
show_label = False,
editor = TabularEditor(adapter = VertFractureAdapter()),
width = 0.5,
height = 0.5,
)
)
#-- THIS is the actual 'View' that gets put on the screen
view = View(
#Note: When as this group 'displays' before the one with the Table, I'm 'locked' into my new maximum table display size of 8 (not my original/desired maximum of 15)
Group(
Item( name = 'Number_Of_Fractures'),
),
#Note: If I place this Group() first, my table is free to grow to it's maximum of 15
Group(
Item( name = 'Number_Of_Fractures'),
vertical_fracture_group,
),
width = 0.60,
height = 0.50,
title = '****** Setup',
resizable=True,
)
#-- Traits Event Handlers --------------------------------------------------
def _Number_Of_Fractures_changed(self):
""" Handles resizing arrays if/when the number of Fractures is changed"""
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
#if not self.user_StartingUp:
self.vertical_frac_array.resize(self.Number_Of_Fractures, refcheck=False)
for crk in range(self.Number_Of_Fractures):
self.vertical_frac_array[crk]['Fracture'] = crk+1
self.vertical_frac_array[crk]['x'] = crk
self.vertical_frac_array[crk]['y'] = crk
self.vertical_frac_array[crk]['z'] = crk
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
fileDialog.configure_traits()
fileDialog.Number_Of_Fractures = 8
In my discussion with Chris below, he made some suggestions that so far haven't worked for me :( Following is my 'current' version of this test code so Chris (or anyone else who wishes to chime in) can see if I'm making some glaring error.
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import zeros, dtype
from traits.api import HasTraits, Range, Array, List
from traitsui.api import View, Group, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
even_bg_color = 0xf4f4f4 # very light gray
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
dummy = Range(1, max_cracks)
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
vertical_frac_array = Array(dtype=vertical_frac_dtype)
vertical_fracture_group = Group(
Item(name = 'vertical_frac_array',
show_label = False,
editor = TabularEditor(adapter = VertFractureAdapter()),
width = 0.5,
height = 0.5,
)
)
#-- THIS is the actual 'View' that gets put on the screen
view = View(
Group(
Item( name = 'dummy'),
),
Group(
Item( name = 'Number_Of_Fractures'),
vertical_fracture_group,
),
width = 0.60,
height = 0.50,
title = '****** Setup',
resizable=True,
)
#-- Traits Event Handlers --------------------------------------------------
def _Number_Of_Fractures_changed(self, old, new):
""" Handles resizing arrays if/when the number of Fractures is changed"""
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
vfa = self.vertical_frac_array
vfa.resize(self.Number_Of_Fractures, refcheck=False)
for crk in range(self.Number_Of_Fractures):
vfa[crk]['Fracture'] = crk+1
vfa[crk]['x'] = crk
vfa[crk]['y'] = crk
vfa[crk]['z'] = crk
self.vertical_frac_array = vfa
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
# put the actual dialog up...if I put it up 'first' and then resize the array, I seem to get my full range back :)
fileDialog.configure_traits()
#fileDialog.Number_Of_Fractures = 8
There are two details of the code that are causing the problems you describe. First, vertical_frac_array is not a trait, so the tabular editor cannot monitor it for changes. Hence, the table only refreshes when you manually interact with it. Second, traits does not monitor the contents of an array for changes, but rather the identity of the array. So, resizing and assigning values into the array will not be detected.
One way to fix this is to first make vertical_frac_array and Array trait. E.g. vertical_frac_array = Array(dtype=vertical_frac_dtype). Then, inside of _Number_Of_Fractures_changed, do not resize the vertical_frac_array and modify it in-place. Instead, copy vertical_frac_array, resize it, modify the contents, and then reassign the manipulated copy back to vertical_frac_array. This way the table will see that the identity of the array has changed and will refresh the view.
Another option is to make vertical_frac_array a List instead of an Array. This avoids the copy-and-reassign trick above because traits does monitor the content of lists.
Edit
My solution is below. Instead of resizing the vertical_frac_array whenever Number_Of_Fractures changes, I instead recreate the array. I also provide a default value for vertical_frac_array via the _vertical_frac_array_default method. (I removed from unnecessary code in the view as well.)
# -*- coding: utf-8 -*-
"""
This is a first shot at developing a ****** User Interface using Canopy by
Enthought. Canopy is a distribution of the Python language which has a lot of
scientific and engineering features 'built-in'.
"""
#-- Imports --------------------------------------------------------------------
from traitsui.api import TabularEditor
from traitsui.tabular_adapter import TabularAdapter
from numpy import dtype, zeros
from traits.api import HasTraits, Range, Array
from traitsui.api import View, Item
#-- FileDialogDemo Class -------------------------------------------------------
max_cracks = 15 #maximum number of Fracs/cracks to allow
vertical_frac_dtype = dtype([('Fracture', 'int'), ('x', 'float'), ('y', 'float'),
('z', 'float'), ('Horiz Length', 'float'), ('Vert Length', 'float')
, ('z-axis Rotation, degrees', 'float')])
class VertFractureAdapter(TabularAdapter):
columns = [('Frac #',0), ('X Cen',1), ('Y Cen',2), ('Z Cen',3),
('Horiz',4), ('Vert',5), ('Angle',6)]
class SetupDialog ( HasTraits ):
Number_Of_Fractures = Range(1, max_cracks) # line 277
vertical_frac_array = Array(dtype=vertical_frac_dtype)
view = View(
Item('Number_Of_Fractures'),
Item(
'vertical_frac_array',
show_label=False,
editor=TabularEditor(
adapter=VertFractureAdapter(),
),
width=0.5,
height=0.5,
),
width=0.60,
height=0.50,
title='****** Setup',
resizable=True,
)
#-- Traits Defaults -------------------------------------------------------
def _vertical_frac_array_default(self):
""" Creates the default value of the `vertical_frac_array`. """
return self._calculate_frac_array()
#-- Traits Event Handlers -------------------------------------------------
def _Number_Of_Fractures_changed(self):
""" Update `vertical_frac_array` when `Number_Of_Fractures` changes """
print "I've changed the # of Fractures to " + repr(self.Number_Of_Fractures)
#if not self.user_StartingUp:
self.vertical_frac_array = self._calculate_frac_array()
#-- Private Interface -----------------------------------------------------
def _calculate_frac_array(self):
arr = zeros(self.Number_Of_Fractures, dtype=vertical_frac_dtype)
for crk in range(self.Number_Of_Fractures):
arr[crk]['Fracture'] = crk+1
arr[crk]['x'] = crk
arr[crk]['y'] = crk
arr[crk]['z'] = crk
return arr
# Run the program (if invoked from the command line):
if __name__ == '__main__':
# Create the dialog:
fileDialog = SetupDialog()
fileDialog.configure_traits()
I have done lots of research on invetory system for point and click game in Lua and corona.
I have come across this example,I am doing something similar to this,but I need a dynamic inventory system.
I mean if I have 4 slots,and all them are full the fifth object go to next slot,so there will be an arrow to the right so I can click on ;and go to the next page.
And imagine there are 5 items,and I have 4 slots,the fifth slot would be on the next page.
I use the third item,and third slot would then be empty,so I want the fourth and fifth item automatically move back to third and fourth slot.
I have hard time figuring this out.
Thanks for advance.
local myInventoryBag={}
local maxItems = 10 -- change this to how many you want
myInventoryBag[5]=3 -- Hammer for instance
myInventoryBag[4]=7 -- A metal Pipe for instance
local function getImageForItem(thisItem)
local itemNumber = tonumber(thisItem)
local theImage=""
if itemNumber==3 then
theImage="hammer.png"
elseif itemNumber == 7 then
theImage="metalpipe.png"
elseif ... -- for other options
...
else
return nil
end
local image = display.newImage(theImage)
return image
end
local function displayItems()
local i
for i=1,#myInventoryBag do
local x = 0 -- calculate based on the i
local y = 0 -- calculate based on the i
local image = getImageForItem(myInventoryBag[i])
if image==nil then return end
image.setReferencePoint(display.TopLeftReferencePoint)
image.x = x
image.y = y
end
end
local itemImages =
{
[0] = display.newImage('MISSING_ITEM_IMAGE.PNG'),
[3] = display.newImage('hammer.png'),
[7] = display.newImage('metalpipe.png'),
}
function getImageForItem(itemId)
return itemImages[itemId] or itemImages[0]
end
local myInventoryBag={}
local maxItems = 10 -- change this to how many you want
local visibleItems = 4 -- show this many items at a time (with arrows to scroll to others)
-- show inventory items at index [first,last]
local function displayInventoryItems(first,last)
local x = 0 -- first item goes here
local y = 0 -- top of inventory row
for i=first,last do
image = getImageForItem(myInventoryBag[i])
image.x = x
image.y = y
x = x + image.width
end
end
-- show inventory items on a given "page"
local function displayInventoryPage(page)
page = page or 1 -- default to showing the first page
if page > maxItems then
-- error! handle me!
end
local first = (page - 1) * visibleItems + 1
local last = first + visibleItems - 1
displayInventoryItems(first, last)
end
myInventoryBag[5] = 3 -- Hammer for instance
myInventoryBag[4] = 7 -- A metal Pipe for instance
displayInventoryPage(1)
displayInventoryPage(2)
Basically what you would do is loop through all the inventory slots and check if the slot is empty. If it's empty, place the item in that slot and stop the loop. If it's not, go to the next one.
If you want to remove an item from the inventory, you can simply call table.delete(myInventoryBag, slotToEmpty).
For pages, you'd simply have a page variable. When drawing the inventory slots, just loop from slots (page-1) * 4 + 1 to page * 4.
(Edit: I'd highly recommend using proper indentation, as it will make the code much much more readable.)