Yleensä televisioilla, radioilla, digibokseilla, DVD-soittimilla ja monilla muilla on kaukosäädin, jolla voi lisätä äänenvoimakkuutta ja tehdä kaikenlaista. Miten pystyisin tekemään Photonavista, joka pyöritää Windows CE:tä, ohjelman, joka toimisi kaukosäätimenä tietokoneelleni? Ajattelin toteuttaa tähän ainakin seuraavat asiat:
Näiden ominaisuuksien hallinta pitäisi pystyä toteuttamaan Photonaviin. Esimerkki toiminnasta: http://s759.photobucket.com/albums/xx231/
Osaan Pythonia ohjelmoida, ja jotenkuten C++:aa. Paras olisi kun voisi tehdä Pythonilla ja jokin ohjelma/joku osaisi kääntää sen C++:ksi.
Macro kirjoitti:
Paras olisi kun voisi tehdä Pythonilla ja jokin ohjelma/joku osaisi kääntää sen C++:ksi.
Miksi se pitäisi C++:ksi muuttaa? Eikös Windows CE:nkin pitäisi pyörittää Python-tulkkia jos sillä voi C++:lla ohjelmoituja exejä käynnistää.
Minkäs välityksellä ajattelit tämän tehdä? Löytyykö tuosta Photonavista minkäänlaista nettiyhteyttä? Tai bluetoothia? Jos WLAN löytyy, se olisi helpointa tehdä sillä. Eihän tuossa muuta kuin että teet Photonaviin Pythonilla clientin, joka lähettää esim. ääntä säätäessä seuraavan viestin: "sound|25" serverille, jossa 25 on volumen määrä. Serveri (hallittava kone) siis looppaa, onko clientiltä tullut uusia viestejä ja jos on, niin parsitaan se ja säädetään äänenvoimakkuus.
No, C++ on nyt "kaikkivaltainen". Voihan siihen Python-tulkinkin asentaa.
En ole varma, onko laitteessa bluetooth tai WLAN, mutta samalla tavalla kaapeliakin pitkin se kulkee. Siinä ei voi tosin käyttää mitään sokketteja tms, vaan pitää kuunnella sarjaporttia (Joku taisi sanoa, että USB-portti ei ole sarjaportti, vaan sarjaväylä?). Onnistuuhan tämä Pythonilla?
Sarjaportin kuuntelemisesta en taas paljonkaan tiedä, luultavasti kuitenkin vaikeampia kuin socketit.
Ainakin tällaiset lisäkirjastot Pythonille löysin:
http://sourceforge.net/apps/mediawiki/pyusb/
http://pyserial.sourceforge.net/
Viestistäsi jäi taas kerran epäselväksi, tarkoitatko sarjaporttia vai USB:tä. Kannattaa ehdottomasti tehdä selvä ero näiden välille. Myös "sarjaväylä" on siinä määrin epämääräisempi termi kuin USB, että sitä on parasta olla käyttämättä lainkaan.
Ohho, muistaakseni kirjoitin kyllä USB, mutta kirjoitinkin jotain muuta. USB:tä tarkoitin.
Kirjoitin eilen illalla vähän itse ohelmaa, tässä olisi runko mitä siihen tulee.
# -*- coding: iso-8859-1 -*- from tkinter import * root = Tk() def Pyyhi(): print("Pyyhitään ruutu...") # Miten tämä toteutetaan? def MenuAanet(): print("Siirrytään kohtaan äänet.") def MenuKappaleet(): print("Siirrytään kohtaan kappaleet.") def MenuKuvat(): print("Siirrytään kohtaan kuvat.") def MenuHiiri(): print("Siirrytään kohtaan hiiri.") def MenuNappaimisto(): print("Siirrytään kohtaan näppäimistö.") def Painettu(event): x = event.x y = event.y if x <= 110 and x >= 10 and y <= 90 and y >= 50: MenuAanet() if x <= 220 and x >= 120 and y <= 90 and y >= 50: MenuKappaleet() if x <= 330 and x >= 230 and y <= 90 and y >= 50: MenuKuvat() if x <= 160 and x >= 60 and y <= 140 and y >= 100: MenuHiiri() if x <= 270 and x >= 170 and y <= 140 and y >= 100: MenuNappaimisto() def Menu(): can = Canvas(root, width=340, height=150) a = 10 b = 50 c = 110 d = 90 for i in range(1, 4): if i != 1: a += 110 c += 110 can.create_rectangle(a, b, c, d, outline="white", fill="green") can.pack() a = 60 b += 50 c = 160 d += 50 for i in range(1, 3): if i != 1: a += 110 c += 110 can.create_rectangle(a, b, c, d, outline="white", fill="green") can.pack() Menu() root.bind("<Button-1>", Painettu) root.mainloop()
Funktioihin MenuXXX() tulee aina kyseisen toiminnon toiminnalisuus (tyhmästi sanottu). Miten saisin funktion Pyyhi() tyhjentämään tkinter-ikkunan? Menu()-funktiossa on aloitustiedot, päävalikko. Kun jotain palkkia klikkaa, suoritettaisiin Pyyhi() ja sitten esimerkiksi MenuAanet(). Miten ruudun tyhjennys onnistuu?
Macro kirjoitti:
Miten saisin funktion Pyyhi() tyhjentämään tkinter-ikkunan? Menu()-funktiossa on aloitustiedot, päävalikko. Kun jotain palkkia klikkaa, suoritettaisiin Pyyhi() ja sitten esimerkiksi MenuAanet(). Miten ruudun tyhjennys onnistuu?
Tk-ikkunaa ei varsinaisesti pyyhitä. Tkinter toteutuksesta en ole varma, mutta ainakin Infernon toteutuksessa voit poistaa haluamasi widgetit Tk:n destroy komennolla.
Haluat ilmeisesti, että kun päävalikosta valitaan jotain niin tyhjennetään päävalikko ruudulla ja näytetään uusi valinnasta riippuva valikko sen sijaan?
Homma toimii siis siten, että kun päävalikosta valitaan jotain, niin poistat päävalikon widgetit destroy-komennolla (laita framen sisään ja poista koko frame kerralla). Tämän jälkeen luot normaalisti uuden valikkosi nappulat ja muut härpäkkeet (määrittely, pakkaus ja päivitys).
Kiitos tiedosta. Jatkan tämän tekemistä. Nyt on menossa näppäimistön tekeminen, tässä on vähän laskemista.
# Yhdistää komennettavaan tietokoneeseen def ConnectToServer(ip, port): global socket socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: socket.connect((ip, port)) except: print("Virhe! Ei voitu yhdistää!") # Lähettää dataa def SocketSend(data): global socket try: socket.send(data) except: print("Virhe! Datan lähetys epäonnistui!") # Sulkee yhteyden def SocketClose(): global socket socket.close() ConnectToServer("192.168.0.114", 1337) for i in range(0, 10): SocketSend("Testidata " + str(i)) SocketClose()
Miksei datan lähetys onnistu? Yhteydenotto serverikoneeseen onnistuu, mutta data ei lähde.
Kyllä tuo tuntuu toimivan, tosin siitä puuttuu "import socket". Miten vastaanotat datan serverillä?
Niin puuttuu, koska tuo on pätkä yllä olevaa koodia. import socket on koodin alussa, tämä on myöhemmin. Kun client on hyväksytty, niin datan hakeminen alkaa while-silmukassa recv()-funktiolla. Sain ohjelman toimimaan.
Kuinka Pythonissa Tkinterillä voisi tehdä vaakasuuntaisen "vivun" (vierityspalkin), jonka vasen pääty olisi arvolla 0 ja oikea 255? Eli äänensäätöön, kuten useissa ohjelmissa on.
Jatkan edellistä viestiäni.
Tämän vierityspalkin pitäisi olla sellainen, että... No, katsokaa kuvasta ja päätelkää: http://s759.photobucket.com/albums/xx231/
Kun tuota punaista viivaa siirretään hiirellä (vasen nappi pohjassa), niin sen pitäisi välittää sijainti (0-255) funktiolle X.
Macro kirjoitti:
Tämän vierityspalkin pitäisi olla sellainen, että... No, katsokaa kuvasta ja päätelkää: http://s759.photobucket.com/albums/xx231/
Macrosphotos/None/volumecontrol.jpg
Tuonnäkösen kontrollin nimi on slider.
Tk:ssa sen nimi näyttäisi olevan Scale.
Kymmenen pistettä ja papukaijamerkki molemmille!
http://www.tutorialspoint.com/python/tk_scale.
Kun scalen arvo muuttuu = hiiren vasen näppäin on painettu pohjaan ja hiirtä liikutetaan johonkin suuntaan.. Kutsutaan funktiota ja annetaan parametrinä scalen sen hetkinen arvo.
Eli suomeksi annetaan command-parametrille funktion nimi joka hakee arvon scale.get():llä.
Ei tarvitse edes gettiä käyttää:
from Tkinter import * def f(x): print x root = Tk() scale = Scale(root, command = f) scale.pack()
Python ei ole nähtävästi mikään kovin nopea kieli, koska tässä datan lähetyksessä tulee päällekkäisyyksiä.
Kun tuota Scalea säädetään, ja callback funktiona (command) on SocketSend(vol) funktio (lähettää datan), tulee päällekkäisyyksiä: Data ei lähdekkään enään muodossa Aanenvoimakkuus:arvo, vaan voi käydä näin "8Aanenvoimakkuus". Tämä viittaa siihen, että edellistä dataa on vielä lähdössä kun seuraava lähtee, eikö vain? Tai, mistä sä johtuu ja miten se korjataan? Lisäänkö jonkin viiveen (import time, time.sleep?), vai voiko sitä datan lähetystä nopeuttaa, tai muuten parantaa?
Vastaanotto tapahtuu näin:
serveri = (socket.gethostname(), 1360) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(serveri) print("Yhdistetty localhostiin") yhteys = False while True: if not yhteys: s.listen(1) asiakas, osoite = s.accept() yhteys = True print("%s yhdistetty." % ':'.join(map(str, osoite))) else: data = str(asiakas.recv(1024)) if not data or data == "b\'\'": asiakas.close() yhteys = False print("Yhteys kohteeseen %s suljettu." % ':'.join(map(str, osoite))) else: rs = re.search('(?<=Aanenvoimakkuus:)\w+', data) if rs: m = Aanenvoimakkuus() m.setVolume(int(rs.group(0))) print("Äänenvoimakkuus asetettu arvoon " + str(rs.group(0))) else: if data != "b\'\'": print(data) s.close()
Ja lähetys:
# Lähettää dataa def SocketSend(data): global socket try: socket.send(bytes(data.encode("UTF-8"))) except Exception as err: print("Error: %s" % str(err)) print(data.encode("UTF-8")) def ScaleCallback(e): SocketSend("Aanenvoimakkuus:" + str(e)) def MenuAanet(): w = Scale(root, from_=0, to=255, orient=HORIZONTAL, command=ScaleCallback) w.pack() MenuAanet()
Miksi Python 3:ssa pitää encoodata lähetettävä data ja muuttaa se biteiksi?
Kyllä Python varmasti riittävän nopea on.
Itse pitäisin huolen, että lähetettävä teksti komento päättyy rivinvaihtoon (LF = '/n') tai sitten Windows tyylisesti (CRLF = '/r/n').
Serverin päässä vastaanottaisin tavu kerrallaan niin kauan, kunnes on vastaanotettu komennon päättävä rivinvaihtomerkki tai vastaanotettu komento rupeaa olemaan jo liian pitkä.
Tavujen enkoodauksesta ei yleensä tarvitse välittää, jos vastaanotetut tekstikomennot eivät sisällä ääkkösiä. Muussa tapauksessa kannattaa muistaa, että yksi unicode-merkki saattaa koostua useammasta tavusta.
Tai, miten olisi jos ennen äänenvoimakkuuden säätöä lähetettäisiin serverille viesti (esim.) "SendingVolume" ja sitten lähetettäisiin vain numeroarvoja? Sitten kun lähetettäisin "Stop" niin lopetettaisiin kokonaan volumen lähetys.
Macro kirjoitti:
Tai, miten olisi jos ennen äänenvoimakkuuden säätöä lähetettäisiin serverille viesti (esim.) "SendingVolume" ja sitten lähetettäisiin vain numeroarvoja? Sitten kun lähetettäisin "Stop" niin lopetettaisiin kokonaan volumen lähetys.
Itse lähettäisin kyllä komennon ja asetusarvon yhdellä kertaa.
Katso edellinen viestini. En Pythonia osaa, mutta näyttäisi, että lähettämälläsi komento merkkijonolla ei ole lopetusmerkkiä. Toisin sanoen, jos lähetät peräkkäin nopeasti useamman komennon, niin serverin päässä ohjelma ei tiedä, missä kohtaa vastaanotto puskuria edellinen komento loppuu ja seuraava alkaa.
Niinpä tietenkin, voisihan sinne lisätä lopetusmerkin. Mutta, miten Pythonilla luetaan aina tiettyyn merkkiin asti (esimerkiksi juuri \r\n)?
Ja voinhan myös Googlettaa "Python read socket until \r\n" tms (muokkaus. joka ei tuottanut tulosta).
Macro kirjoitti:
Niinpä tietenkin, voisihan sinne lisätä lopetusmerkin. Mutta, miten Pythonilla luetaan aina tiettyyn merkkiin asti (esimerkiksi juuri \r\n)
Mitäs, jos laitat vastaanottopuskurin kooksi yhden tavun. Lisäät sitten aina tämän vastaanotetun tavun toisen merkkijonon loppuun, mikä tallentaa vastaanotetun komennon. Nyt voit vain yksinkertaisesti vertailla tämän merkkijonon viimeisisiä merkkejä lopetusmerkin varalta.
Voit katsoa ideaa koodivinkistäni: Chat serveri ja asiakas Infernolle limbolla. Pistä hakuun, ei taida löytyä muuten.
Jep, muutin sitä toisella tavalla (Laitoin vaan rivinvaihdon loppuun), ja se toimii. Se voi ollakkin juuri syys siihen, että säätö toimii huonosti: Jos clientillä näyttää nollaa, niin serveriltä tulee voimakkuudella 8.
Serveri (Ei sisällä headereita tai Aanenvoimakkuus luokkaa)
serveri = (socket.gethostname(), 1370) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(serveri) mix = Aanenvoimakkuus() print("Yhdistetty localhostiin") yhteys = False while True: if not yhteys: s.listen(1) asiakas, osoite = s.accept() yhteys = True print("%s yhdistetty." % ':'.join(map(str, osoite))) else: data = str(asiakas.recv(1024)) data = data.replace("b\'", "") data = data.replace("\'", "") if not data: asiakas.close() yhteys = False print("Yhteys kohteeseen %s suljettu." % ':'.join(map(str, osoite))) else: if data == "AskingCurrentVolume": print("\r\n\r\n") print("Client is asking current volume...") print("Sending the current volume to client") try: asiakas.send(bytes(mix.getVolume())) print("Sended succesful volume", str(mix.getVolume())) except Exception as err: print("Error: %s" % str(err)) print("\r\n\r\n") continue rs = re.search('(?<=Aanenvoimakkuus:)\w+', data) if rs: mix.setVolume(int(rs.group(0))) print("Äänenvoimakkuus asetettu arvoon " + str(rs.group(0))) else: print(data) s.close()
Client (Vähän turhan monimutkainen, mutta toimii melkein)
# -*- coding: UTF-8 -*- from tkinter import * import socket, time # Alustetaan ikkuna, asetetaan otsikko root = Tk() root.title("Beta") root.configure(background="white") root.resizable(width=FALSE, height=FALSE) paavalikkotrue = True # Yhdistää komennettavaan tietokoneeseen def ConnectToServer(ip, port): global socket socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: socket.connect((ip, port)) except: print("Virhe! Ei voitu yhdistää!") # Lähettää dataa def SocketSend(data): global socket try: socket.send(bytes(data.encode("UTF-8"))) except Exception as err: print("Error: %s" % str(err)) print(data.encode("UTF-8")) def SocketRecv(b): global socket try: return socket.recv(b) except Exception as err: print("Error: %s" % str(err)) # Sulkee yhteyden def SocketClose(): global socket socket.close() ConnectToServer("192.168.0.101", 1370) def ScaleCallback(e): SocketSend("Aanenvoimakkuus:" + str(e) + "\r\n") def MenuAanet(): SocketSend("AskingCurrentVolume") while True: vol = str(SocketRecv(1024)) vol = vol.replace("b\'", "") vol = vol.replace("\'", "") if vol: break w = Scale(root, from_=0, to=255, orient=HORIZONTAL, command=ScaleCallback) w.pack() w.set(int(vol)) def MenuKappaleet(): print("Siirrytään kohtaan kappaleet.") def MenuKuvat(): print("Siirrytään kohtaan kuvat.") def MenuHiiri(): print("Siirrytään kohtaan hiiri.") def MenuNappaimisto(): canvas = Canvas(width=330, height=150, bg="white") canvas.pack() kuva = PhotoImage(file='nappaimisto.gif') canvas.create_image(0, 0, image=kuva, anchor=NW) root.bind("<Button-1>", MenuNappaimistoPainettu) mainloop() def Spechar(sk): NappaimistoSpecialChr(sk) spechar.destroy() last = "" m = "" def NappaimistoSpecialChr(k): global last, m erikoisnappaimet = { "Q" : "1", "W" : "2", "E" : "3", "R" : "4", "T" : "5", "Y" : "6", "U" : "7", "I" : "8", "O" : "9", "P" : "0", "A" : "!", "S" : "(", "D" : ")", "F" : "€", "G" : "-", "H" : "+", "J" : "#", "K" : "*", "L" : "å", "Ö" : "'", "Ä" : "?", "@" : "/", "," : ";", "." : ":" } if k == "CHR": global spechar spechar = Toplevel() spechar.title("Valitse erikoismerkki") merkit = "/\\.:@,'?!\"-()_;+&%*=<>£€$¤[]{}~^§#|" for i in range(0, len(merkit)): button = Button(spechar, text=merkit[i], borderwidth=0, command=lambda i = i: Spechar(merkit[i])) button.pack(side = LEFT) else: if last == "->": if k in erikoisnappaimet: m = erikoisnappaimet[k] else: print("Virhe!", k, "ei ole erikoisnäppäimissä!") else: m = k if m != "->": SocketSend(m) last = k def MenuNappaimistoPainettu(event): sx = event.x sy = event.y # Näppäimistötilassa tarkistetaan mitä nappulaa painettiin # Rivi 1. if sx > 1 and sx < 33 and sy > 1 and sy < 33: NappaimistoSpecialChr("Q") if sx > 33 and sx < 66 and sy > 1 and sy < 33: NappaimistoSpecialChr("W") if sx > 66 and sx < 99 and sy > 1 and sy < 33: NappaimistoSpecialChr("E") if sx > 99 and sx < 132 and sy > 1 and sy < 33: NappaimistoSpecialChr("R") if sx > 132 and sx < 165 and sy > 1 and sy < 33: NappaimistoSpecialChr("T") if sx > 165 and sx < 198 and sy > 1 and sy < 33: NappaimistoSpecialChr("Y") if sx > 198 and sx < 231 and sy > 1 and sy < 33: NappaimistoSpecialChr("U") if sx > 231 and sx < 264 and sy > 1 and sy < 33: NappaimistoSpecialChr("I") if sx > 264 and sx < 297 and sy > 1 and sy < 33: NappaimistoSpecialChr("O") if sx > 297 and sx < 329 and sy > 1 and sy < 33: NappaimistoSpecialChr("P") # Rivi 2. if sx > 1 and sx < 33 and sy > 33 and sy < 66: NappaimistoSpecialChr("A") if sx > 33 and sx < 66 and sy > 33 and sy < 66: NappaimistoSpecialChr("S") if sx > 66 and sx < 99 and sy > 33 and sy < 66: NappaimistoSpecialChr("D") if sx > 99 and sx < 132 and sy > 33 and sy < 66: NappaimistoSpecialChr("F") if sx > 132 and sx < 165 and sy > 33 and sy < 66: NappaimistoSpecialChr("G") if sx > 165 and sx < 198 and sy > 33 and sy < 66: NappaimistoSpecialChr("H") if sx > 198 and sx < 231 and sy > 33 and sy < 66: NappaimistoSpecialChr("J") if sx > 231 and sx < 264 and sy > 33 and sy < 66: NappaimistoSpecialChr("K") if sx > 264 and sx < 297 and sy > 33 and sy < 66: NappaimistoSpecialChr("L") if sx > 297 and sx < 329 and sy > 33 and sy < 66: NappaimistoSpecialChr("BACKSPACE") # Rivi 3. if sx > 1 and sx < 33 and sy > 66 and sy < 99: NappaimistoSpecialChr("Z") if sx > 33 and sx < 66 and sy > 66 and sy < 99: NappaimistoSpecialChr("X") if sx > 66 and sx < 99 and sy > 66 and sy < 99: NappaimistoSpecialChr("C") if sx > 99 and sx < 132 and sy > 66 and sy < 99: NappaimistoSpecialChr("V") if sx > 132 and sx < 165 and sy > 66 and sy < 99: NappaimistoSpecialChr("B") if sx > 165 and sx < 198 and sy > 66 and sy < 99: NappaimistoSpecialChr("N") if sx > 198 and sx < 231 and sy > 66 and sy < 99: NappaimistoSpecialChr("M") if sx > 231 and sx < 264 and sy > 66 and sy < 99: NappaimistoSpecialChr("Ö") if sx > 264 and sx < 297 and sy > 66 and sy < 99: NappaimistoSpecialChr("Ä") if sx > 297 and sx < 329 and sy > 66 and sy < 99: NappaimistoSpecialChr("ENTER") # Rivi 4. if sx > 1 and sx < 33 and sy > 99 and sy < 131: NappaimistoSpecialChr("->") if sx > 33 and sx < 66 and sy > 99 and sy < 131: NappaimistoSpecialChr("SHIFT") if sx > 66 and sx < 99 and sy > 99 and sy < 131: NappaimistoSpecialChr("CHR") if sx > 99 and sx < 132 and sy > 99 and sy < 131: NappaimistoSpecialChr("@") if sx > 132 and sx < 198 and sy > 99 and sy < 131: NappaimistoSpecialChr("SPACE") if sx > 198 and sx < 231 and sy > 99 and sy < 131: NappaimistoSpecialChr(",") if sx > 231 and sx < 264 and sy > 99 and sy < 131: NappaimistoSpecialChr(".") if sx > 264 and sx < 297 and sy > 99 and sy < 131: NappaimistoSpecialChr("SHIFT") if sx > 297 and sx < 329 and sy > 99 and sy < 131: NappaimistoSpecialChr("CTRL") paavalikko = Frame(root, width=340, height=150, bg="white") paavalikko.pack() # MenuPainettu()-funktio tarkistaa mitä nappia painettiin aloitusmenussa. def MenuPainettu(event): x = event.x y = event.y # Arvojen vertailua, katsotaan onko hirii tiettyjen koordinaattien sisällä if x <= 110 and x >= 10 and y <= 90 and y >= 50: paavalikko.destroy() paavalikkotrue = False MenuAanet() if x <= 220 and x >= 120 and y <= 90 and y >= 50: MenuKappaleet() if x <= 330 and x >= 230 and y <= 90 and y >= 50: MenuKuvat() if x <= 160 and x >= 60 and y <= 140 and y >= 100: MenuHiiri() if x <= 270 and x >= 170 and y <= 140 and y >= 100: paavalikko.destroy() paavalikkotrue = False MenuNappaimisto() def MenuAloitus(): # Alustetaan Canvas oikean kokoiseksi can = Canvas(paavalikko, width=340, height=150) # Ensimmäisen valikkorivin aloituspaikat a = 10 b = 50 c = 110 d = 90 # Luodaan rivi for i in range(1, 4): # Jos ei olla ensimmäisessä napissa, siirretään napin paikkaa if i != 1: a += 110 c += 110 # Piirretään täytetty neliö can.create_rectangle(a, b, c, d, outline="white", fill="green") can.pack() # Toisen rivin arvot a = 60 b += 50 c = 160 d += 50 # for loopissa jottei koodia tule liikaa for i in range(1, 3): if i != 1: a += 110 c += 110 # Piirretään can.create_rectangle(a, b, c, d, outline="white", fill="green") can.pack() # Kuunnellaa Button-1:stä root.bind("<Button-1>", MenuPainettu) if paavalikkotrue: MenuAloitus() root.mainloop()
Miten tuota scalea saa pidennettyä? Nyt se on ärsyttävän tynkä.
Et sitten viitsinyt itse selata annettuja linkkejä? Ei ole vaikea arvata, että asetukset width ja length voisivat liittyä tähän...
Argh. Nyt taitaa olla huono päivä, kun menee noissa jutuissa ihan miten sattuu. Pahoitteluni. (Muokkaus. Pah. Olin kirjoittanut width, mutta tämä vaikutti korkeuteen. Kirjotin height, tämä antoi virheen. Sen takia kysyin. Huomasin kun katsoin uudelleen.)
Kun lisään erillaisia elementtejä (frameja, canvaseja ja buttoneja), niin jokaisen elementin (onko tämä oikea nimike?) ympärille tulee harmaa reuna.
http://s759.photobucket.com/albums/xx231/
Olen koittanut kaikki borderwidth-arvot ja background-arvot.
Macro kirjoitti:
Kun lisään erillaisia elementtejä (frameja, canvaseja ja buttoneja), niin jokaisen elementin (onko tämä oikea nimike?) ympärille tulee harmaa reuna.
Kokeilepa huviksesi asettaa: relief = FLAT.
Ei tuo auttanut, samalta se näyttää edelleenkin.
Lisäksi minulla on nämä socket-funktiot. Miten nämä muunnettaisiin siten, että sockettien tilalla käytettäisiin jotain tekniikkaa, jolla dataa voitaisiin siirtää USB-portin kautta (Koska navigaattori ei sisällä Wlania, niin data pitää siirtää USB:tä pitkin).
# Sulkee yhteyden def SocketClose(): global socket try: socket.close() except Exception as err: print("Virhe sokketin sulkemisessa: %s" % str(err)) # Yhdistää def ConnectToServer(ip, port): global socket socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: socket.connect((ip, port)) except: print("Virhe! Ei voitu yhdistää!") # Lähettää dataa def SocketSend(data): global socket data = data + "|" try: socket.send(bytes(data.encode("UTF-8"))) except Exception as err: print("Dataa ei voitu lähettää: %s" % str(err)) #print(data.encode("UTF-8")) def SocketRecv(b): global socket try: return socket.recv(int(b)) except Exception as err: print("Ei voitu vastaanottaa dataa: %s" % str(err))
Tuolta näyttävät datan lähetysfunktiot. Käytän siis Python 3:sta.
Macro kirjoitti:
Ei tuo auttanut, samalta se näyttää edelleenkin.
Infernolla tuota ongelmaa ei ole. Kokeile vielä asettaa canvakselle: highlightthicknes = 0
Hei kiitos! Tuo toimi hyvin. Nyt nuo reunat ovat poissa.
Ylhäällä on vielä yksi kysymys.
USB-portin kautta kommunikointi ei ole oikein verrattavissa sarjaporttiin, jonka kautta voi helposti siirtää raakaa dataa, tai TCP-yhteyksiin, jotka toimivat yhden standardin mukaan. Selvitä ensin, millaisena laitteena tietokone tunnistaa navigaattorin ja miten ne yleensäkään kommunikoivat, ja mieti sitten, miten tämän kommunikaatiomenetelmän päälle saisi rakennettua oman.
Eikö PyUSB-lisäkirjasto auttaisi tässä? Sitä ei nähtävästi ole Python 3:lle, onko tämä niin huomattava apu, että kannattaisi asentaa Python 2.6 nykyisen tilalle? Onko muista USB-kirjastoja Pythonille?
Yhdistyykö tuo verme activesync:illä pc-koneeseen?
Nopealla haulla löysin tälläisen viestiketjun: http://www.mail-archive.com/pythonce@python.org/msg00426.html
Tästä sain sen käsityksen, että activesync emuloi osittain tcp/ip-yhteyttä. Toisin sanoen asiakasohjelman ajaminen WinCE laitteella ja serveriohjelman ajaminen pc-koneella pitäisi jossakin määrin olla mahdollista.
Katsotaan tuota USB-yhteyttä myöhemmin, tämä toimii nyt ihan hyvin.
Nyt on ongelmana sellainen asia, kuin funktioiden järjestys.
Minulla on funktiot TelnetConnect- ja TelnetSend-funktiot. Lisäksi on funktio MenuKappaleet. Olen laittanut TelnetConnect-funktioon avauskoodin, joka avaa Telnet-yhteyden VLC:hen. TelnetSend-funktio lähettää dataa VLC:lle. Telnet-yhteyden avaus tapahtuu kutsumalla TelnetConnect-funktiota parametreillä ip ja portti funktiossa MenuKappaleet.
Ongelma: Kun olen avannut Telnet-yhteyden MenuKappaleet-funktiossa, ja toisessa funktiossa koitan lähettää dataa TelnetSend-funktiolla, se ei onnistu. Mistä tämmöinen johtuu, todennäköisesti funktioiden järjestyksestä. Olisi heti aluksi kannattanut alkaa jakamaan näitä eri tiedostoihin, ja kommentoimaan enemmän: Nyt funktioita ja muuta koodia on 600 rivin edestä ja hallinta on hankalaa.
Tässä vielä nuo funktiot.
# Telnet-funktiot ohjelman alussa # Telnet-yhteyden avaus def TelnetConnection(ip, port): global tn # Yritetään luoda yhteyttä (ip, port) try: tn = telnetlib.Telnet(ip, port) except Exception as err: print("Virhe Telnetin avauksessa: %s" % str(err)) # Telnetillä lähetys def TelnetSend(v): global tn # Yritetään lähettää dataa v try: tn.write(v.encode("ascii") + b"\n") except Exception as err: print("Virhe Telnetillä lähetyksessä: %s" % str(err)) # MenuKappaleet() Telnet-funktioiden jälkeen def MenuKappaleet(): global vol, menuvalikko # Ilmoitetaan mitä pitää tehdä. SocketSend("AskingCurrentVolume") # Pyydetään serverikoneen äänenvoimakkuus SocketSend("MenuKappaleet") # Ilmoitetaan siirtymisestä kappaleet-menuun SocketSend("StartVLC") # Pyydetään avaamaan VLC print("DEBUG: Yhteydenotto Telnetillä...") # Telnet-yhteys TelnetConnection("192.168.100.21", 1234) print("DEBUG: Yhteydenottoyritys Telnetillä valmis") k = 0 while True: try: vol = str(SocketRecv(1024)) vol = vol.replace("b\'", "") vol = vol.replace("\'", "") if vol: vol = int(vol) break except Exception as err: print("Error: %s" % str(err)) break # Luodaan frame johon sisältö tulee luoValikkoFrame() canvas = Canvas(menuvalikko, width=340, height=100, bg="white", highlightthicknes=0) canvas.pack(expand=YES) kuva = PhotoImage(file="kappaleet.gif") canvas.create_image(0, 0, image=kuva, anchor=NW) root.bind("<Button-1>", MenuKappaleetPainettu) w = Scale(menuvalikko, from_=0, to=255, length=340, orient=HORIZONTAL, command=ScaleCallback) w.pack() w.set(int(vol)) # Koodin lopussa def lisaa_kappale_sl(): nimi = filedialog.askopenfilename() TelnetSend(nimi.encode("ascii")) def lisaa_kansio_sl(): nimi = filedialog.askdirectory() TelnetSend(nimi.encode("ascii")) # Valikko def Valikko(): global valikko, valikko1 # Luodaan menu valikko = Menu(root) valikko1 = Menu(valikko, tearoff=0) kappaleetm = Menu(valikko1, tearoff=0) # Pääelementit valikko.add_cascade(label="Komennot", menu=valikko1) valikko1.add_command(label="Äänenvoimakkuus") valikko1.add_cascade(label="Kappaleet", menu=kappaleetm) valikko1.add_command(label="Hiiri") valikko1.add_command(label="Näppäimistö") valikko1.add_separator() valikko1.add_command(label="Poistu", command=sulje_ohjelma) # Kappaleet-menun sisältö kappaleetm.add_command(label="Play") # play kappaleetm.add_command(label="Pause") # pause kappaleetm.add_command(label="Stop") # stop kappaleetm.add_separator() kappaleetm.add_command(label="Lisää kansio soittolistaan", command=lisaa_kansio_sl) # queue & for kappaleetm.add_command(label="Lisää kappale soittolistaan", command=lisaa_kappale_sl) # queue kappaleetm.add_separator() kappaleetm.add_command(label="Seuraava kappale") # next kappaleetm.add_command(label="Edellinen kappale") # prev root.config(menu=valikko) Valikko()
Funktiot ovat tuossa järjestyksessä, tosin välissä on tavaraa. Kumminkaan mikään muu kohta ohjelmassa ei käytä noita funktioita.
Ohjelman palauttama virhe: global name 'tn' is not defined
Virhe tulee TelnetSend-funktiossa.
^^ Ihan PHP-kokemuksen perusteelta heitän tämän, mutta eikö tuo "tn"-muuttuja pitäisi määritellä koodin alussa, niin kuin nuo "vol" ja "menuvalikko" -muuttujatkin. Niistäkin tulkki varmasti valittaa seuraavaksi, jos ongelma on tuo.
Virhe ei ole tuo, vaan se ettei jostain syystä TelnetConnection-funktio (kirjoitin väärin äskeiseen viestiin funktioiden nimet) palauta tn-muuttujaa. Eli, joko TelnetConnection-funktio ei osaa palauttaa tn-muuttujaa tai TelnetWrite-funktio ei löydä sitä. Näkyvyysalueiden syytäkö?
TelnetConnection-funktiota ei voi suorittaa muussa vaiheessa, sillä kohdekone ei ole muutoin avannut vielä VLC:tä.
Pieni ehdotus toteutuksen rakenteeseen: Pc:llä pyörivä serveri-ohjelma kannattaisi pitää mahdollisimman yksinkertaisena. Itse en tähän toteuttaisi muuta graafista, kuin korkeintaan ikkunan, missä näkyy asiakkaan ja serverin välinen viestiliikenne testausta ja debug-tietoa varten.
Toiseksi eikö tuo VLC kannattaisi käynnistää suoraan serverikoneelle valmiiksi odottelemaan yhteydenottoja, eikä käynnistää sitä aina uudelleen asiakasohjelman pyynnöstä?
Itse tekisin niin, että käynnistäisin VLC:n serverikoneella kuuntelemaan yhteydenottoja loop back interfaceen (localhost). Serveri-ohjelma hoitaisi keskustelun VLC:n kanssa itse käskyttäen sitä asiakasohjelman pyyntöjen mukaan.
Tuo on hyvä idea. Ajattelin lisäksi jakaa näitä tiedostoiksi, ja toteuttaa nämä luokkina. Onko se viisasta? Ajattelin myös importata tiedoston vain silloin, kun sitä tarvitaan. Koska navigaattorin tehot eivät ole kovin suuret, voi sillä vähän kestää koodin suorittaminen.
jalski kirjoitti:
Yhdistyykö tuo verme activesync:illä pc-koneeseen?
Nopealla haulla löysin tälläisen viestiketjun: http://www.mail-archive.com/pythonce@python.org/msg00426.html
Tästä sain sen käsityksen, että activesync emuloi osittain tcp/ip-yhteyttä. Toisin sanoen asiakasohjelman ajaminen WinCE laitteella ja serveriohjelman ajaminen pc-koneella pitäisi jossakin määrin olla mahdollista.
Itselläni on tuo Photonav ja vahvistan, että Activesyncillä voi sen yhdistää. Mutta sitten pitää ottaa huomioon, että vistalla ei pysy käyttämään sitä.
Siksi käytänkin XP:tä, kun jotain haluan tehdä. Vista on vähän jälkeenjäänyt, 7 tosin vähän lievittää sitä Vistan tuottamaa pettymystä. Kumpaankaan en sitä XP:tä silti vaihtaisi.
Nyt kun toisen keskustelun tuloksena saatiin se tiedostojen valitseminen kuntoon, niin nyt on hyvä jatkaa tämän pääohjelman tekoa.
Jalski antoi hyvän neuvon, että telnet-yhteys otettaisiinkin serverikoneella VLC:hen, ja lähetettäisiin komennot socketeilla. Nyt on tuo vaihe varmaan seuraavaksi, kunhan sana liitettyä tiedostovalitsimen ohjelmaan.
Mutta, miksi IDLE:ä ei voi käyttää, jollei ole nettiyhteyttä, tai tietokone on verkossa puhelimella? Saan virheen, että IDLE ei voi muodostaa yhteyttä, koska palomuuri blokkaa. Jos olen kiinteässä verkossa (ADSL), niin tämä toimii ihan hyvin.
Virhe PythonCE:n asennuksen jälkeen, kun koitin käynnistää Pythonin:
PythonCE, python.exe kirjoitti:
Cannot find 'python' (or one of its components). Make sure the patth and filename are correct and dthat all the required libraries are available.
Latasin PythonCE:n Pythonin sivuilta python.orgista, ja asensin sen suorittamalla ohjelman (ActiveSyncin välityksellä asentui). Tein sen toiseenkin kertaan, jos aluksi jokin epäonnistui.
Kun kerran lähetän telnet-komennot serverille sokketeilla, ja otan yhteyden serverillä paikalliseen telnettiin, niin miksi tarvitsee edes käyttää telnet-funktiota? Voihan sitä käynnistää ensin ohjelman os.system(käynnistyskomento) ja sitten komentaa telnettiä Windowsin omalla telnet-komennolla. Kun avaan ensin VLC:n os.system(käynnistyskomento):lla, niin miksen voi suorittaa muita komentoja komentorivillä ohjelman (os.system) avulla, ennen kuin VLC on sammutettu? Koko ohjelma jumittuu, kunnes VLC sammutetaan. Koodi tyssää os.system(...)-riviin.
Koska ohjelmalle on varattuna 1 säie ja tuo funktio-kutsu varaa sitä niin kauan, että se on saatu suoritettua...
Eli threading... Miten voin suorittaa funktion X toisessa säikeessä, ja lopun ohjelman toisessa? Eli funktio X käynnistää VLC:n.
Mitä jos etsisit sanoilla "Python threading" ja katsoisit, löydätkö sen vanhan aiheen, jossa on kirjoittamani esimerkki säikeistä (ja jopa datan lukituksesta, jota tosin et nyt taida tarvita)? Lisätietoja löytyy erittäin helposti Pythonin dokumentaatiosta.
Joo. En tiennytkään, että noinkin voi tehdä, että laittaa yhden funktion käyntiin threading.Thread().start():lla ja muu koodi suoritetaan siinä niin kuin toisessa säikeessä. Oletin, että pitää määrittää molemmat säikeet erikseen, eikä voi olla "raakaa koodia" (koodia ilman isännöivää funktiota).
Terve taas
Nyt koitin taas jatkaa ohjelman tekemistä, ja toiselta tietokoneelta voi jo vaihtaa kappaleita ja pysäyttämään kappaleen (pause). Ongelma: Koska komento "pause" ei aloita kappaletta, jota ei ole vielä aloitettu tai se on keskeytetty stopilla, niin tarvitsee käynnistää se komennolla "play". Miten voin tarkistaa, soiko jokin kappale, tai milloin Play/Pause-nappulan painalluksella pitää lähettää "play"? (Muokkaus. Komennoissa olikin is_playing komento.)
Miten pystyn lukemaan VLC:n palauttamaa dataa? Käytän edelleenkin Pythonin telnetlib-kirjastoa. read_all()-funktiolla?
Toinen ongelma: Koska hakemistolistaus pitää tehdä serverillä, ja lähettää se sokketeilla clientille joka tekee siitä listan Treeviewillä, niin millaisessa muodossa data kannattaa lähettää? Olisiko tälläinen hyvä järjestely?
[ "kansion sijainti" [ "kappale 1", "kappale 2", "kappale 3" ], "kansion 2 sijainti" [ "kappale 1", "kappale 2", "kappale 3" ] ]
Olisiko muita ideoita toteuttamisesta?
Datan siirtoon kannattaa käyttää jotain valmista formaattia, joka toimii taatusti ja jonka tekijät ovat huomioineet myös kaikenlaiset poikkeukset (kuten lainausmerkit nimissä). Pythonin kohdalla kätevä valinta on pickle-moduuli, jolla voi suoraan pakata ja purkaa Pythonin omia objekteja.
Selvä.
read_all() lukee nähtävästi siihen asti, että yhteys suljetaan. read_until(..) taas ei toimi, koska komennot palauttavat monta riviä dataa, joten \n:ään asti luettaessa se lukee väärin. Miten voin lukea kaiken, mitä komento palauttaa? Komennon viimeinen palauttama rivi (is_playingin tapauksessa 0 tai 1) olisi tarpeellinen, mutta tätä en ole saanut hankittua.
Voitko antaa myös pienen esimerkin picklen käytöstä, sillä en ole ihan saanut kiinni sen ideasta luettuani manuaalia.
# Testidata: data = {"testi": ["juttu", "jee"], "oho": "toimii"} teksti = pickle.dumps(data) laheta(teksti)
teksti = vastaanota() data = pickle.loads(teksti) print(data) # {'testi': ['juttu', 'jee'], 'oho': 'toimii'}
Toiseen kysymykseesi: voit joko tulostaa ennen viestiä tiedon, miten pitkä viesti on, tai enkoodata viestin jollain tavalla yhdelle riville tai lisätä viestin loppuun ylimääräisen rivin (--Macron-skriptin-viestin-loppu--), josta tunnistat loppumisen.
Miten pystyn ilmoittamaan datan pituuden, kun se voi olla erillainen joka kerralla? Toista tapaa en koe mahdolliseksi, koska en pääse sörkkimään VLC:n palauttamaa dataa.
PS. Missä ovat Python 3.1 Win32Api-moduulit? Koodia suorittaessa tulee virheilmoitus, ettei löydy win32apia.
Muokkaus. Mitä voin tehdä, kun 1.0.5 VLC-versiossa ei ole oldrc (vai onko 1.0.5:n RC sama kuin 1.1.1:n oldrc?) ja uusin versio ei toista Elisa Viihteen videoita fullscreen-tilassa? Eli, en voi katsoa tietokoneeltani fullscreen-tilassa Viihteen nauhoituksia, ja vanhemmalla versiolla en voi käyttää oldrc:tä...?
Ai niin, kyse olikin jatkuvasti käynnissä olevalta VLC:ltä ohjelmalle tulevasta datasta eikä siitä, mitä ohjelma lähettää toiselle ohjelmalle.
Käytätkö nyt VLC:n oldrc-käyttöliittymää? Siinähän useimpien komentojen varsinainen vastaus loppuu näin:
add: returned 0 (no error) status: returned 0 (no error) pause: returned 0 (no error)
Toki voi olla muukin tila kuin "0 (no error)". Lisäksi kannattaa varautua siihen, että status change -viestejä tulee muulloinkin kuin heti komentojen jälkeen.
Macro kirjoitti:
Miten pystyn ilmoittamaan datan pituuden, kun se voi olla erillainen joka kerralla? Toista tapaa en koe mahdolliseksi, koska en pääse sörkkimään VLC:n palauttamaa dataa.
Lasket sen itse? Jos koostat datan itse, niin eiköhän Pythonissa ole suoraan operaattori tuota varten? Limbolla tuo operaattori on len.
Ehdotus:
Voit myös käyttää jotain tietokantatiedostoa serveriltä mediatiedostolistauksen tietojen välittämiseen asiakasohjelmalle. Eli serveri lähettäisi tietokantatiedoston asiakkaalle tarvittaessa, eli käytännössä asiakas kysyisi serveriltä uusinta tiedostoa ja jos oma tiedosto olisi vanhempi, niin vastaanottaisi uuden tiedoston. Itse tykkään vanhasta DBF-formaatista, mikä on käytössä Clipper, Harbour ja xHarbour kääntäjillä.
Kyllä, joudun nyt käyttämään uusinta VLC:tä, jotta saan oldrc:n. Eli, voin lukea dataa esimerkiksi read_until("komento: returned"), vai kuinka? (Muokkaus. Tuo ei toiminutkaa, sillä is_playing ei palauta muuta kuin numeron 0 tai 1.)
jalski: En jaksa edes nyt ajatella miten tuo toimisi, koska en jaksa noin pitkästä koodista alkaa etsimään ja muuttamaan kaikkia datan käsittelyyn liittyviä asioita.
Macro kirjoitti:
Tuo ei toiminutkaa, sillä is_playing ei palauta muuta kuin numeron 0 tai 1.
Sitten sinun pitää erikseen selvittää, mitkä komennot palauttavat mitäkin. Toinen vaihtoehto on vain lukea dataa seuraavan puolen sekunnin ajan ja toivoa, että saa oikeat asiat. Vielä yksi mahdollisuus olisi, että komentojen lähetys ja vastausten luku tapahtuisivat täysin toisistaan riippumattomasti eri säikeissä; tällöin komennon is_playing kaltaisia kysymyskomentoja tosin ei voisi käyttää yhtä helposti mutta toisaalta taas muut komennot toimisivat aivan mutkattomasti.
Mikä nyt edes on ongelma? Mitä haluat saada selville VLC:n komentojen suorituksesta? Entä miksi käytät telnet-moduulia, kun tavallinen socket kävisi aivan hyvin?
Metabolix kirjoitti:
Mikä nyt edes on ongelma? Mitä haluat saada selville VLC:n komentojen suorituksesta? Entä miksi käytät telnet-moduulia, kun tavallinen socket kävisi aivan hyvin?
Kun serverille lähetetään "telnet:pause", niin haluan hakea tiedon is_playingillä, onko kappale soimassa vai ei. Sen avulla voin laittaa play-pause-nappulaan kolme toimintoa. Siitä pitäisi pystyä lähettämään myös play-komento, koska stopilla pysäytetty kappale ei lähde käymään pausella.
Mihin ottaisin socketilla yhteyden? Koodini käyttää jo yhtä sokkettia, eikö vain yksi ole mahdollinen? Ainakin virheilmoitus on kanssani samaa mieltä: Vain yksi sokketti per ip/portti.
Kun tämä tulee vain omaan tarkoitukseen, niin vedän tämän erillaisella tavalla: Kun VLC:llä avaa kappaleen, kappaleita tai kansion soitettavaksi, niin se alkaa suoraan toistamaan niitä. Luon muuttujan "soi" (tms), johon tallennan aina tiedon siitä, soiko kappale vai ei. Toisaalta, sitten kun itse soittimesta painaa pauselle, niin se tieto ei välity klientille ja sitä ei tallenneta muuttujaan...
Vielä muita ratkaisuja? Kuinka voin lukea dataa tietyn ajan?
Edit. Onko siitä muuten jotain haittaa, jos joudun koodissa käyttämään mainloop():a kahdesti? En saa kuvaa esille, jollen laita mainlooppia kuvan määrittelyn jälkeen.
Macro kirjoitti:
jalski: En jaksa edes nyt ajatella miten tuo toimisi, koska en jaksa noin pitkästä koodista alkaa etsimään ja muuttamaan kaikkia datan käsittelyyn liittyviä asioita.
Tuo ehdottamani juttu on oikeasti aika helppo toteuttaa. Pythonille näyttää löytyvän kirjasto DBF-tiedostojen yksinkertaiseen käsittelyyn (lisäys/poisto/listaus). Tuo ei kylläkään tue indeksi-tiedostoja tai muuta monimutkaisempaa käsittelyä. Etuna olisi tietenkin, että tietoja ei tarvitsisi aina siirtää serveriltä ja mediatiedoston kaikki tiedot olisi helppo kukin tallentaa omiin kenttiinsä.
Miksi muuten serveriohjelma ei vain yksinkertaisesti aina lähetä asiakkaalle komennon jälkeen sen tilaa. Tarvitset vain yksinkertaisen parserin asiakkaan päähän käsittelemään serveriltä tulevat viestit, jotta asiakas osaa reagoida niihin.
jalski kirjoitti:
Miksi muuten serveriohjelma ei vain yksinkertaisesti aina lähetä asiakkaalle komennon jälkeen sen tilaa. Tarvitset vain yksinkertaisen parserin asiakkaan päähän käsittelemään serveriltä tulevat viestit, jotta asiakas osaa reagoida niihin.
Koska asiakkaan ei tarvitse tietää mitä serverillä tapahtuu. Siellä ei tapahdu mitään, mistä asiakas hyötyisi jotain tietäessään tilanteen. Ohjelma ilmoittaa mahdollisista virhetilanteista, joten kyllä käyttäjä huomaa mahdolliset ongelmat.
Macro kirjoitti:
Koska asiakkaan ei tarvitse tietää mitä serverillä tapahtuu. Siellä ei tapahdu mitään, mistä asiakas hyötyisi jotain tietäessään tilanteen. Ohjelma ilmoittaa mahdollisista virhetilanteista, joten kyllä käyttäjä huomaa mahdolliset ongelmat.
??? Serveriohjelmahan sinulla keskustelee VLC:n kanssa, eikä asiakasohjelma. Asiakashan ei tiedä mitään VLC:n tilasta eikä serveriohjelman tilasta, jollei serveriohjelma välitä tietoa eteenpäin. Ainoa mitä asiakasohjelma itsenäisesti tietää on se, että onko sillä yhteys serveriohjelmaan, ei muuta.
Ai, tarkoititkin asiakkaalla ohjelmaa etkä käyttäjää (Olisihan tuo pitänyt arvata, kun itse käytin samaa sanaa samassa tarkoituksessa). Kyllä asiakkasohjelmalla ja serveriohjelmalla on puhevälit kunnossa.
Ohjelmani testaus on hyvin epämiellyttävää, kun tarvitsee joka ajokerralla vaihtaa porttia, kun ohjelma ei sammu oikein. Miten pystyn vapauttamaan aina portin ohjelman alussa?
Toinen ongelma on picklen kanssa. Enkö voi "picklettää" (Mitä lie suomeksi) ttk.Treeviewiä dumpsilla? "Can't pickle <class 'tkapp'>: attribute lookup builtins.tkapp failed" Mitä tämä on tarkoittavinaan?
Teen tuon listauksen aikaisemmassa keskustelussa puhutun listaajan kanssa, ja sen valmistuttua koitan käyttää tätä picke.dumps(puu):ta.
Jos välitän tiedon puurakenteesta listana, niin miten se pitäisi tehdä?
Tuskin voit vapauttaa toisen ohjelman varaamaa porttia. Tapa se pyörimään jäänyt ohjelma, niin luulisi portinkin vapautuvan.
Tietty voisit ehkä tehdä sen "portin sulkemisen ohjelman alussa" juuri niin, että se etsii muita prosesseja ja tappaa ne.
Taidan kumminkin tehdä jonkin toisen tavan, joka sulkee yhteyden. Porttien vaihtelu on tosi rasittavaa, kun olisi muutakin tekemistä.
Entä, onko jollain vastausta tuohon toiseen kysymykseeni?
Ööh. Tuohon porttiongelmaan voisi auttaa SO_REUSEADDR-asetus serveripäässä, jos räpläät sokettien kanssa.
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # sitten bindaaminen ja muu
Miksi ihmeessä kyseisen socketin pitäisi edes liittyä juuri tiettyyn porttiin? Eihän se kuuntele vaan yhdistää, jolloin se ei vaadi juuri tietyn portin varaamista.
Mietin tuota ongelmaa vielä myöhemmin, mutta miksen pysty ttk.Treeviewiä picklettämään? Virhe ylhäällä.
No hyvänen aika, et tietenkään voi picklellä pakata käyttöliittymäkomponentteja tai muita järjestelmän resursseja sisältäviä asioita. Voit pakata vain tavallista Pythonin dataa eli tekstejä, lukuja, listoja, sanakirjoja ym.
Ai. En tiennytkään tuota asiaa. No, tehdään se taulukkona sitten, ja käsitellään asikkaan päässä.
Hei muuten, miten pystyn asettamaan buttonin kuvan päälle framen alareunaan? anchor=S ei kelvannut, siellä se on yläreunassa.
En nyt ole ihan varma, mitä haet, mutta tuo anchor ja justify hoitavat esim. label-widgetissä tekstin sijoituksen määrityksen (esim. tasaus vasempaan reunaan anchor=w, justify=LEFT).
Pakkaajan (grid tai pack) tehtävänä taas on hoitaa widgettien sijoitus esim. kehyksen sisällä ja se ei kyllä anna laittaa widgettejä toistensa päälle (sain sen kuvan, että haluat laittaa kehyksen sisällä imagen päälle buttonin).
Joudut varmaan käyttämään canvasta toteuttaaksesi haluamasi (sikäli, kun tajusin oikein mitä haluat tehdä).
Aihe on jo aika vanha, joten et voi enää vastata siihen.