Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Photonav Windows CE

Sivun loppuun

Macro [18.06.2010 21:01:12]

#

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/Macrosphotos/None/Photonavpch.jpg

Osaan Pythonia ohjelmoida, ja jotenkuten C++:aa. Paras olisi kun voisi tehdä Pythonilla ja jokin ohjelma/joku osaisi kääntää sen C++:ksi.

pake10 [18.06.2010 21:27:54]

#

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.

Macro [18.06.2010 21:37:41]

#

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?

pake10 [18.06.2010 21:48:00]

#

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/index.php?title=Main_Page
http://pyserial.sourceforge.net/

Metabolix [18.06.2010 22:21:42]

#

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.

Macro [18.06.2010 22:24:53]

#

Ohho, muistaakseni kirjoitin kyllä USB, mutta kirjoitinkin jotain muuta. USB:tä tarkoitin.

Macro [19.06.2010 13:02:00]

#

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?

jalski [19.06.2010 19:31:24]

#

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).

Macro [20.06.2010 10:16:56]

#

Kiitos tiedosta. Jatkan tämän tekemistä. Nyt on menossa näppäimistön tekeminen, tässä on vähän laskemista.

Macro [20.06.2010 21:23:35]

#

# 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.

-tossu- [21.06.2010 01:12:44]

#

Kyllä tuo tuntuu toimivan, tosin siitä puuttuu "import socket". Miten vastaanotat datan serverillä?

Macro [21.06.2010 10:23:27]

#

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.

Macro [21.06.2010 14:00:24]

#

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/Macrosphotos/None/volumecontrol.jpg

Kun tuota punaista viivaa siirretään hiirellä (vasen nappi pohjassa), niin sen pitäisi välittää sijainti (0-255) funktiolle X.

Blaze [21.06.2010 14:12:42]

#

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.

Metabolix [21.06.2010 14:15:24]

#

Tk:ssa sen nimi näyttäisi olevan Scale.

Macro [21.06.2010 14:18:59]

#

Kymmenen pistettä ja papukaijamerkki molemmille!

jimi-kimi [21.06.2010 14:25:59]

#

http://www.tutorialspoint.com/python/tk_scale.htm
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.

Macro [21.06.2010 14:27:20]

#

Eli suomeksi annetaan command-parametrille funktion nimi joka hakee arvon scale.get():llä.

Metabolix [21.06.2010 14:37:46]

#

Ei tarvitse edes gettiä käyttää:

from Tkinter import *

def f(x):
    print x

root = Tk()
scale = Scale(root, command = f)
scale.pack()

Macro [21.06.2010 15:32:52]

#

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?

jalski [21.06.2010 15:53:14]

#

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.

Macro [21.06.2010 15:57:14]

#

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.

jalski [21.06.2010 16:07:30]

#

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.

Macro [21.06.2010 16:12:25]

#

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).

jalski [21.06.2010 16:39:05]

#

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.

Macro [21.06.2010 16:57:43]

#

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()

Macro [29.06.2010 20:49:40]

#

Miten tuota scalea saa pidennettyä? Nyt se on ärsyttävän tynkä.

Metabolix [29.06.2010 20:54:21]

#

Et sitten viitsinyt itse selata annettuja linkkejä? Ei ole vaikea arvata, että asetukset width ja length voisivat liittyä tähän...

Macro [29.06.2010 20:57:41]

#

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.)

Macro [30.06.2010 20:42:19]

#

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/Macrosphotos/None/bd.jpg

Olen koittanut kaikki borderwidth-arvot ja background-arvot.

jalski [01.07.2010 10:03:19]

#

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.

Macro [01.07.2010 17:01:41]

#

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.

jalski [01.07.2010 18:03:58]

#

Macro kirjoitti:

Ei tuo auttanut, samalta se näyttää edelleenkin.

Infernolla tuota ongelmaa ei ole. Kokeile vielä asettaa canvakselle: highlightthicknes = 0

Macro [01.07.2010 18:09:57]

#

Hei kiitos! Tuo toimi hyvin. Nyt nuo reunat ovat poissa.

Ylhäällä on vielä yksi kysymys.

Metabolix [01.07.2010 19:05:51]

#

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.

Macro [01.07.2010 19:32:11]

#

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?

jalski [02.07.2010 18:37:45]

#

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.

Macro [03.07.2010 18:43:50]

#

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.

pake10 [03.07.2010 18:59:27]

#

^^ 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.

Macro [03.07.2010 19:03:44]

#

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ä.

jalski [04.07.2010 15:09:01]

#

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.

Macro [08.07.2010 15:59:56]

#

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.

gamehouse [16.07.2010 19:16:48]

#

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ä.

Macro [16.07.2010 19:24:30]

#

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.

Macro [19.07.2010 17:32:00]

#

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.

Macro [21.07.2010 20:37:24]

#

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.

vehkis91 [21.07.2010 23:16:01]

#

Koska ohjelmalle on varattuna 1 säie ja tuo funktio-kutsu varaa sitä niin kauan, että se on saatu suoritettua...

Macro [21.07.2010 23:18:59]

#

Eli threading... Miten voin suorittaa funktion X toisessa säikeessä, ja lopun ohjelman toisessa? Eli funktio X käynnistää VLC:n.

Metabolix [22.07.2010 09:17:23]

#

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.

Macro [22.07.2010 19:01:17]

#

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).

Macro [30.07.2010 10:47:06]

#

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?

Metabolix [30.07.2010 11:28:29]

#

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.

Macro [30.07.2010 11:32:49]

#

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.

Metabolix [30.07.2010 13:50:41]

#

# 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.

Macro [30.07.2010 14:19:40]

#

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ä...?

Metabolix [30.07.2010 14:35:59]

#

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.

jalski [30.07.2010 14:37:16]

#

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ä.

Macro [30.07.2010 14:44:44]

#

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.

Metabolix [30.07.2010 15:04:34]

#

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?

Macro [30.07.2010 15:11:10]

#

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.

jalski [30.07.2010 16:32:46]

#

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.

Macro [30.07.2010 16:39:32]

#

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.

jalski [30.07.2010 16:48:25]

#

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.

Macro [30.07.2010 16:55:31]

#

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.

Macro [31.07.2010 13:29:09]

#

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ä?

Grez [31.07.2010 13:56:10]

#

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.

Macro [31.07.2010 16:00:14]

#

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?

Deffi [31.07.2010 18:56:33]

#

Öö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

Metabolix [31.07.2010 18:57:31]

#

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.

Macro [31.07.2010 21:09:12]

#

Mietin tuota ongelmaa vielä myöhemmin, mutta miksen pysty ttk.Treeviewiä picklettämään? Virhe ylhäällä.

Metabolix [31.07.2010 21:23:00]

#

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.

Macro [01.08.2010 15:57:23]

#

Ai. En tiennytkään tuota asiaa. No, tehdään se taulukkona sitten, ja käsitellään asikkaan päässä.

Macro [02.08.2010 14:28:16]

#

Hei muuten, miten pystyn asettamaan buttonin kuvan päälle framen alareunaan? anchor=S ei kelvannut, siellä se on yläreunassa.

jalski [02.08.2010 20:29:54]

#

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ä).


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta