Olen tekemässä RSS-virran lukuohjelmaa ja syötteet pitäisi saada lajiteltua hakemistoihin, ja niih vieltä mahdollisuus tehdä kansioita, periaatteessa kansioita voi olla vaikka 10 sisäkkäin, jos vain joku tarvii.
Ihmettelen, miten tämänlainen olisi järkevintä toteuttaa. Nykyisiltään on vain yksi lista, jossa on kaikki virrat alkioissaan.
virrat = [virta1, virta2, virta3]
No, tuhonhan pitäisi vielä saada mukaan kansiot, joten ajattelin tehdä uuden listan, jossa on kansiot
kansiot = [kansio1, kansio2, kansio3]
Sitten törmäsin ongelmaan, entäpäs jos käyttäjä haluaa siirrellä kansioita esim. kansio1:n virta1 ja virta2 väliin? Eihän tämmöinen voisi toimia, koska virta-listassa ei ole missäänkohdassa määritelty, että tähän tulee kansio1.
kansio2 = [ virta3 ] kansio1 = [ kansio2, virta1, virta2, ] virrat = [ kansio1 ]
Mutta muuttujiahan ei voi tehdä valmiiksi, koska niitä täytyy voida tehdä ihan suorituksen aikanakin, ei lähdekoodia muokkaamalla, joten mitenhän tämänlainen ominaisuus olisi kaikkein viisainta tehdä?
EDIT: Ainiin, ja kielenähän on python
ZcMander kirjoitti:
Sitten törmäsin ongelmaan, entäpäs jos käyttäjä haluaa siirrellä kansioita esim. kansio1:n virta1 ja virta2 väliin? Eihän tämmöinen voisi toimia, koska virta-listassa ei ole missäänkohdassa määritelty, että tähän tulee kansio1.
Jooh, eihän se noin pelaa. Sun pitää laittaa samaan listaan sekä virrat, että kansiot. Kantsii varmaan tehä joku yhteinen yliluokka/interface niille.
Meinaatkos jotenkin näin:
class kansio: nimi = "" virrat = [kansio4, virta, kansio5] kansio1, kansio2, kansio3 = kansio() virrat = [kansio1, kansio2, kansio3]
Väsäsin pikaisesti esimerkin. Huomaa, että Kansio-luokan __str__-metodi on rekursiivinen. Jokaisessa kansiossa on lista alkioita, jotka voivat olla joko kansioita tai virtoja. Kun ne käydään läpi, valitaan uusi __str__-metodi alkion tyypin mukaan, joten virrat vain tulostetaan ja kansiot puolestaan tulostetaan sisallon kanssa rekursiivisesti.
Kansioita rakentaessa ja kasvatettaessa lisaa-metodilla tarkistan, että tuliko argumenttina lista vai jotain muuta. Oletan, että jotain muuta on sellainen, jonka voi suoraan pistää sinne näytille listan sisällä (ne []-merkit rakentavat sinne listan). Oikeassa ohjelmassa laajempi tarkistus on ehkä paikallaan.
Pythonin rekursioraja on jossain tuhannen paikkeilla oletuksellisesti, jos nyt äkkiä muistan oikein. Lienee aika turvallinen oletus, että käyttäjä ei niin paljon laita kansioita sisäkkäin. Voi sen estääkin, jos jokaiseen kansioon liittää vaikkapa tiedon, kuinka syvällä se on kansiohierarkiassa ja hylkää jonkin rajan ylittävät.
Tulostuksessa on hyvin yksinkertainen sisennystapa. Voit myös kokeilla ohjelmaani Python-tulkissa ja katsella siellä olioiden sisältöjä. Menettelyni varmasti valkenee parhaiten juuri siten. Yksi esimerkkiaineisto on koodissa mukana. Tein aika kiireessä tämän...
Huomaapa Pythonille sopiva tagi Putkassa :-)
# virrat.py - Putkaan esimerkki class Virta(object): def __init__(self, nimi): self.nimi = nimi def __str__(self): return "virta: " + self.nimi class Kansio(object): def __init__(self, nimi, sisalto): self.nimi = nimi if type(sisalto) == list: self.sisalto = sisalto else: self.sisalto = [sisalto] def lisaa(self, muut): if type(muut) == list: self.sisalto += muut else: self.sisalto += [muut] def __str__(self): esitys = "kansio: " + self.nimi + "\n" for alkio in self.sisalto: sisaesitys = str(alkio) for rivi in sisaesitys.split('\n'): if rivi: esitys += "** " + rivi + "\n" return esitys if __name__=='__main__': paa = Kansio ("paakansio", Virta ("virta1")) kan1 = Kansio ("alikansio 1", [Virta("virta2"), Virta("virta3")]) kan2 = Kansio ("alikansio 2", Virta ("virta4")) paa.lisaa (kan2) paa.lisaa (kan1) kan2.lisaa (Kansio ("tyhja", [])) kan1.lisaa (Kansio ("alikansio 3", [Virta ("extra 1"), Virta("extra 2"), Virta ("extra 3")])) print paa
En ole varma ymmärsinkö vaatimuksesi oikein. Jos meni mistiin, kerro lisää.
Jooh, sain jotain saman kaltaista aikaan:
#!/usr/bin/env python # -*- coding: utf8 -*- # Author: Teijo Mursu # Purpose: Puu # Created: 13.01.2007 ######################################################################## class Content: #---------------------------------------------------------------------- def __init__(self, iterator=None, parent=None): """Constructor""" self.iterator = None self.parent = parent ######################################################################## class Feed(Content): """Tiedot virrasta """ #---------------------------------------------------------------------- def __init__(self, title, parent=None): """Constructor""" Content.__init__(self, parent=parent) self.feed = {"title" : title} #---------------------------------------------------------------------- def __str__(self): """Palauttaa syötteen nimen """ return self.feed["title"] ######################################################################## class Folder(Content): """Sisältää virrat ja muut kansiot """ #---------------------------------------------------------------------- def __init__(self, name, parent=None): """Constructor""" Content.__init__(self, parent=parent) self.name = name self.content = [] #---------------------------------------------------------------------- def __str__(self): """Palauttaa kansion nimen """ return self.name #---------------------------------------------------------------------- def add(self, content): """Lisää kansion/syotteen sisaltoon """ self.content.append(content) #---------------------------------------------------------------------- def remove(self, item): """Poistaa sisällöstä kansion/syotteen """ if type(item) == Folder: item.remove_all() self.content.remove(item) #---------------------------------------------------------------------- def remove_all(self): """Poistaa kaiken sisällön """ self.content = [] #---------------------------------------------------------------------- def PrintTree(folder, depth=0): """Tulostaa puun """ for content in folder.content: #print type(content) = <type 'instance'> if type(content) == Folder: PrintTree(content, depth+1) else: print ("*" * depth) + str(content) if __name__ == '__main__': root = Folder("ROOT") folder1 = Folder("Folder1", root) folder2 = Folder("Folder2", folder1) root.add(folder1) folder1.add(folder2) root.add(Feed("Nidekon")) folder1.add( Feed("Folder1-feed1") ) folder1.add( Feed("Folder1-feed2") ) folder2.add( Feed("Folder2-feed1") ) folder2.add( Feed("Folder2-feed2") ) folder2.add( Feed("Folder2-feed3") ) PrintTree(root)
On siinä vielä sellainen ongelma, että type(content) ei palauta muuta kuin <type 'instance'>
Ongelma ratkesi, tarvitsi muokata vain Content-luokkaa:
######################################################################## class Content(object): #---------------------------------------------------------------------- def __init__(self, iterator=None, parent=None): """Constructor""" self.iterator = None self.parent = parent
Tuon rekursion voi tietenkin poistaa tutulla tekniikalla, eli käyttää pinoa. Pythonin listasta saa hyvin pinon appendilla ja popilla. Luultavasti se ei tässä ole tarpeellinen muutos, koska ohjelman varsinainen tarkoitus ei ole juosta koko ajan tuota kansiopuuta ylös ja alas.
Edelleen vallan erikoista ongelmaa. Eli, mulla on käytössä äsköiset luokat. Lisään kansion kansioon näin:
#---------------------------------------------------------------------- def create_folder(self, name, iter=None): """Lisää kansion puuhun """ #Tarkistaa, oliko tyhjä, joka annettiin iter = self.is_iter_none(self.feeds) #Tarkistetaan, että yritetään lisätä kansioon, muuten ei onnistu if type(iter) == feed.Folder: iter.add( feed.Folder(name) ) return True else: return False #---------------------------------------------------------------------- def is_iter_none(self, iter): """Tarkistaa onko iter-muuttuja None, jos on niin palautetaan puun alku """ if iter == None: return self.feeds #Juuritason kansio else: return iter
Ja gtk:n TreeViewin valittu kohta haetaan ja kutsutaan tuota funktiota:
def on_editfeed_create_folder_activate(self, widget, *args): print "Create folder" #Palauttaa valitun kohdat (model, iter) = self.controller.ui.get_selected_feed() #Jos ei ole valittu, jos esim TreeStore on tyhjä if iter == None: cont = self.controller.feeds.feeds #Juuritason kansio else: #Muutetaan iteraattori mukavempaan muotoon, poluksi iter = model.get_path(iter) #Haetaan kansio/syöte iteraattorin perusteella, toimiva funktio cont = self.controller.feeds.feeds.find_iter(iter) self.controller.feeds.create_folder("Example", cont)
Ja kun TreeView päivitetään, silloin vasta kansiot ja sen sisältö saa iteraattorin, jotta voidaan saada tietoon missä kohden kyseinen kansion/syöte on gtkTreeViewissä.
#---------------------------------------------------------------------- def refresh_feeds_list(self): """Päivittää syötteet-listan """ print "Refresh feeds list" curfolder = None #Tyhjentää TreeStoren, etttei vain lisätä self.window.feeds.get_model().clear() for i in self.controller.feeds.feeds.content: #Lisää yhden valinnan lisää, ensin tulee nimi ja sitten minkä kansion sisässä sisältö on. i.iterator = self.window.add_choice_feeds([str(i)], i.parent) #Iteraattori mukavempaan muotoon i.iterator = self.window.feeds.get_model().get_path(i.iterator) #Tarkistetaan onko lisättävän typpi kansio vai syöte if i == feed.Folder: #Vaihdetaan nykyinen kansio siihen curfolder = i.iterator else: #Muuten syötteen yllä on kansio i.parent = curfolder
Kuitenkin, ennen "self.controller.feeds.create_folder("Example", cont)" kohtaa on_editfeed_create_folder_activate-funktiossa on kaikki oikein, mutta kun tuo funktio suoritetaan ja päivitettään TreeViewi niin kansio onkin luotu juuritasolle, vaikka pitäisi olla luotu kansio kansion sisälle.
EDIT: Juuri tarkistin asian, kansio luodaan oikeastikkin juuritasolle, joten vika ei luultavasti ole mitenkään liittyvä TreeViewiin.
EDIT2: Feed-luokassa suorittamani testi osoitti, että kun lisäykset tehdään oikein, kansiot menevät sisäkkäin, kuten pitääkin. Ongelma ei ole Feed-luokassa.
EDIT3: Ehkä hieman selventävä kuva: http://zcmander.lagaakympil.org/kuvat/debug_jodiko.png
cont-muuttuja on saanut oikean arvon, mutta silti kansio tulee <feed.Folder 0x9b0966c>:n content-listaan vaikka pitäisi tulla <feed.Folder 0x9b6d6ec>:n content-listaan.
Hoh, jos poistan create_folder-funktiosta rivin: iter = self.is_iter_none(self.feeds) niin kansio luodaan oikeaan paikkaan, mutta niitä kansioita ei lisätä koskaan Treeviewin TreeStoreen.
Aihe on jo aika vanha, joten et voi enää vastata siihen.