I'm writing a music player in python, with a cli using urwid. I intend to have the current playlist in a simpleListWalker, wrapped by a listbox, then columns, a pile, and finally a frame.
How do I replace the entire contents of this listbox (or simpleListWalker) with something else?
Relevant code:
class mainDisplay(object):
...
def renderList(self):
songList = db.getListOfSongs()
songDictList = [item for item in songList if item['location'] in
commandSh.currentPlaylists[commandSh.plyr.currentList]]
self.currentSongWidgets = self.createList(songDictList)
self.mainListContent = urwid.SimpleListWalker([urwid.AttrMap(w, None,
'reveal focus') for w in self.currentSongWidgets])
def initFace(self):#this is the init function that creates the interface
#on startup
...
self.scanPlaylists()
self.renderList()
self.mainList = urwid.ListBox(self.mainListContent)
self.columns = urwid.Columns([self.mainList, self.secondaryList])
self.pile = urwid.Pile([self.columns,
("fixed", 1, self.statusDisplayOne),
("fixed", 1, self.statusDisplayTwo),
("fixed", 1, self.cmdShInterface)], 3)
self.topFrame = urwid.Frame(self.pile)
Full code at: http://github.com/ripdog/PyPlayer/tree/cli - Check main.py for interface code.
The code is in a pretty bad state right now, and I've only been programming for two months. Any suggestions on code style, layout, or any other tips you may have are very much appreciated.
self.mainListContent[:] = [new, list, of, widgets]
should replace the whole list of widgets in place.
Next time post your question to the mailing list or the IRC channel if you want a faster response!
Related
I'm trying to make a procedure that updates the stacking order of randomly created windows based on their y value (so that things that are closer to the top of the screen display under things that are lower down).
Basically I have a button that creates a window by calling a class statement. Each time a window is created, its id and y value get put in an array, which would get sorted and looped through to update the stacking order.
I figured having the id of each window that is created would be enough to change the variables of specific windows, using the id of the window.lift(), but it looks like you can't point to an object with its id like that. If I'm not mistaken I can't just use the class name because I don't want to change the whole class, just the specific window.
Anybody know what I can use instead of the id to get this to work? Is it just impossible the way I have it planned?
Here's my code in case it's helpful, unfinished because obviously it doesn't work:
import tkinter as tk
import random
# creates a new window
def makewndw(event):
a = testwindow()
# create main window - click to create a new window
mainwindow = tk.Tk()
mainwindow.bind('<Button-1>', makewndw)
# this sorts the windows
class stacker():
stackerwindow = tk.Toplevel()
yarray = [{'ident': 0, 'ypos': 0}]
def arupdate(self):
#sort array by ypos
self.yarray.sort(key=lambda x: x.get('ypos'))
# print(self.yarray)
# get length of array
arlen = len(self.yarray)
# loop through array between pos 1 and end
for x in range(1,arlen):
# extract dictionary from that position
tempex = self.yarray[x]
# populate temp list with values from tempex
templist = []
for i in tempex.values():
templist.append(i)
# get just the id
tempid = templist[0]
# use id to update stacking order
tempid.lift()
# ^^^ this is where i'm suck because clearly this isn't working
self.stackerwindow.after(10, self.arupdate)
class testwindow():
def __init__(self):
# create a window
self.window = tk.Toplevel()
self.y = random.randrange(100, 500)
self.window.geometry('200x200+800+{y}'.format(y=str(self.y)))
# give info to sorter
self.infdict = {'ident': id(self.window), 'ypos': self.y}
stacker.yarray.append(self.infdict)
st = stacker()
st.arupdate()
mainwindow.mainloop()
I'm a beginner so I'm sorry if the answer here is obvious, and sorry about how messy I'm sure my code is.
I want to write a LibreOffice Calc document from within a Python3 program. Using pyoo I can do almost everything I want, including formatting and merging cells. But I cannot adjust row heights and column widths.
I found Change the column width and row height very helpful, and have been experimenting with it, but I can't seem to get quite the result I want. My present test file, based on the answer mentioned above, looks like this:
#! /usr/bin/python3
import os, pyoo, time, uno
s = '-'
while s != 'Y':
s = input("Have you remembered to start Calc? ").upper()
os.popen("soffice --accept=\"socket,host=localhost,port=2002;urp;\" --norestore --nologo --nodefault")
time.sleep(2)
desktop = pyoo.Desktop('localhost', 2002)
doc = desktop.create_spreadsheet()
class ofic:
sheet_idx = 0
row_num = 0
sheet = None
o = ofic()
uno_localContext = uno.getComponentContext()
uno_resolver = uno_localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", uno_localContext )
uno_ctx = uno_resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
uno_smgr = uno_ctx.ServiceManager
uno_desktop = uno_smgr.createInstanceWithContext( "com.sun.star.frame.Desktop", uno_ctx)
uno_model = uno_desktop.getCurrentComponent()
uno_controller = uno_model.getCurrentController()
uno_sheet_count = 0
doc.sheets.create("Page {}".format(1), index=o.sheet_idx)
o.sheet = doc.sheets[o.sheet_idx]
o.sheet[0, 0].value = "The quick brown fox jumps over the lazy dog"
o.sheet[1, 1].value = o.sheet_idx
uno_controller.setActiveSheet(uno_model.Sheets.getByIndex(uno_sheet_count))
uno_sheet_count += 1
uno_active_sheet = uno_model.CurrentController.ActiveSheet
uno_columns = uno_active_sheet.getColumns()
uno_column = uno_columns.getByName("B")
uno_column.Width = 1000
The main problem with the above is that I have 2 Calc documents on the screen, one of which is created before the Python program gets going; the other is created from Python with a pyoo function. The first document gets the column width change, and the second receives the text input etc. I want just the second document, and of course I want the column width change applied to it.
I am sure the answer must be fairly straightforward, but after hours of experimentation I still can't find it. Could someone point me in the right direction, please?
Your code alternates between pyoo and straight Python-UNO, so it's no wonder that it's giving messy results. Pick one or the other. Personally, I use straight Python-UNO and don't see the benefit of adding the extra pyoo library.
the other is created from Python with a pyoo function
Do you mean this line of code from your question, and is this the "second document" that you want the column change applied to?
doc = desktop.create_spreadsheet()
If so, then get objects from that document instead of whichever window the desktop happens to have selected.
controller = doc.getCurrentController()
sheets = doc.getSheets()
Or perhaps you want the other document, the one that didn't get created from Python. In that case, grab a reference to that document before creating the second one.
first_doc = uno_desktop.getCurrentComponent()
second_doc = desktop.create_spreadsheet()
controller = first_doc.getCurrentController()
sheets = first_doc.getSheets()
If you don't have a reference to the document, you can find it by iterating through the open windows.
oComponents = desktop.getComponents()
oDocs = oComponents.createEnumeration()
Finally, how to resize a column. The link in your question is for Excel and VBA (both from Microsoft), so I'm not sure why you think that would be relevant. Here is a Python-UNO example of resizing columns.
oColumns = oSheet.getColumns()
oColumn = oColumns.getByName("A")
oColumn.Width = 7000
oColumn = oColumns.getByName("B")
oColumn.OptimalWidth = True
For a game I am planning, I want to create a piece of code that will write one specific value from a list of all the items in my game into the player's inventory (e.g.: player gets item "potion", which would require searching the items CSV for potion and then putting the relevant info into the CSV). Whenever I run my code however I get the error "TypeError: '_io.TextIOWrapper' object is not subscriptable".
I've tried researching and asking peers but the closest I've gotten to a clear solution is someone mentioning writing to a list from the CSV, but they didn't explain much more. Hoping someone could elaborate on this for me or provide an easier solution.
import csv
allitems = open("ALLITEMS.csv")
checkallitems = csv.reader(allitems)
playerinv = open("INVENTORY.csv")
checkinv = csv.reader(playerinv)
item = input("")
for x in checkallitems:
print(allitems[x][0])
if item == allitems[x][0]:
playerinv.write(allitems[x][0]+"\n")
allitems.close()
playerinv.close()
The problem is allitems is a file object returned by open and the statement for x in checkallitems iterates over the lines of such file so, you are trying to use a list as index in that file. Also, you have to open INVENTORY.csv in write mode (using 'w' or 'a') to be able to write to it.
Just use x instead of allitems[x]. The snippet below should do the job:
for x in checkallitems:
if item == x[0]:
playerinv.write(x[0]+"\n")
So, the complete code could be:
Code
import csv
allitems = open("ALLITEMS.csv")
checkallitems = csv.reader(allitems)
playerinv = open("INVENTORY.csv", 'a')
checkinv = csv.reader(playerinv)
item = input("")
for x in checkallitems:
if item == x[0]: # Check if the item is equal to the first item on the list
playerinv.write(x[0]+"\n")
allitems.close()
playerinv.close()
I dont know what do you want to accomplish, so I tried to stick as much as possible to your code.
If you want to only write the item provided by the user if it is found the current list of items, this would do the job:
Code
import csv
allitems = open("ALLITEMS.csv")
checkallitems = csv.reader(allitems)
playerinv = open("INVENTORY.csv", 'a')
checkinv = csv.reader(playerinv)
item = input("")
for x in checkallitems:
if item in x: # Check if the item is in the current list
playerinv.write(item +"\n")
allitems.close()
playerinv.close()
I hope this can help you. Let me know if any of this worked for you, otherwise, tell me what went wrong.
I am trying to create a list like in outlook. With list items with an layout like this:
Don't get me wrong this isn't a "give me the full answer" question. I just have the problem of the right naming. I would appreciate it a lot if some could throw in the right words and I will look for them by my own.
I used tkinter at the moment but in that it seems like there isn't a solution for that.
Kind regards.
I think Tkinter can do this by using a bit of object oriented programming you could define how one list element should look like and then with static variables you could define a position of a new line relative to the position of the previous line. Something like:
from tkinter import *
class Line:
y = 0 # static variable for the y position
def __init__(self):
self.y_local = Line.y
Line.y = Line.y + 40 # increase the static variable for the next line
print(self.y_local)
def draw(self, tk, h_line="Headline", a_info="Addtional Information", date="01/01/1970"):
self.label_head = Label(text=h_line)
self.label_head.place(x=20, y=self.y)
self.label_info = Label(text=a_info)
self.label_info.place(x=20, y=self.y+20)
self.label_date = Label(text='Date')
self.label_date.place(x=200, y=self.y)
self.label_ndate = Label(text=date)
self.label_ndate.place(x=200, y=self.y+20)
self.chkbtn = Checkbutton(tk, text="Checkbox")
self.chkbtn.place(x=300, y=self.y+20)
tk = Tk()
data = [
["News", "WWIII has been avoided", "02/04/2018"],
["Python", "Python solves 42 riddles", "02/04/2018"]
]
for line in data:
temp = Line()
temp.draw(tk, line[0], line[1], line[2])
mainloop()
Hope I understood your question well. That you have a list with information and want to display that in an easy and scalable way. I have not looked to add the lines around the information as I've never done that before I know there are separators I've used vertical once before but I wouldn't be surprised if you can draw a box around each line either.
I was making an application using tkinter and came across an error. I wanted people to input a variable, which I have made, and then have that many Entry boxes popup on the screen for input. I was wondering what is wrong with my code, if it is possible, or if there is a better way. Thanks in advance!
p.s. the NoOfBoxes has been predefined
int(NoOfBoxes)
x = 1
while(NoOfBoxes>=x):
a = a + 50
fill_empty(a)
x = x + 1
def fill_empty():
empty = tk.Entry(self)
empty.grid(row=200,column=a)
return empty
In first line of shown code, you are converting NoOfBoxes to an integer but you are not assigning back it to NoOfBoxes hence, when while line comes, NoOfBoxes is still not an integer. Also, there is no parameter on your fill_empty definition.
Most likely you will need those Entry widgets at some point in your code, so it'll be much better if you keep references.
listOfEntries = [fill_empty(idx) for idx in range(int(NoOfBoxes))]
def fill_empty(a):
empty = tk.Entry(self)
empty.grid(row=200,column=a)
return empty
When you want to make any operation on those, you can easily do something like:
listOfEntries[0].get()