Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Python tkinter opiskelua

käärme [20.06.2011 23:15:15]

#

Hei

Kokeilen GUI:n tekoa. Käytössä olevat ohjelmat ovat kaikki uusia tuttuavuuksia minulle, samoin GUI:n teko. Siis hyvä lähtökohta uuden opettelulle ;-)

Python3, tkinter 8.5 ja Linux (Lubuntu)

Opettelussa käytetty esim dokkaria osoitteesta.
http://www.tkdocs.com/tutorial

Ohjelma lähettää sarjaliikenteellä lyhyitä merkkijonoja. Se jopa toimii, mutta
päätarkoitus on opetella GUI:n tekoa, eikä tehdä ohjelmaa

Ongelma: textvariablen käyttö on hukassa, vaikka sitä on tahkottu hartaasti esim. tkdocs ohjeista.

Frame3:ssa on Button +++. Siitä painamalla ilmestyy frame2 teksti Modemin STATUS, mutta ei OK. Sitä yritän saada näkyviin textvariable muuttujalla. Terminaalissa debukkaus näyttää oikein OK.

Samoin SEND nappulaa painamalla on tarkoitus nähdä frame2:ssa mitä lähetettiin. Ei näy. Terminaalissa debukkaus näyttää oikein

Tämän perusasian ratkettua on tarkoitus frame4:n OPEN ja CLOSE buttonien avulla avata ja sulkea sarjaliikenne.
Nythän teen sen kummassakin aliohjelmassa.

Löytyisikö näihin kahteen ongelmaan vinkkejä.

Vaikka tkinterille on joidenkin mielestä olemassa "parempiakin vaihtoehtoja", niin tarkoitus on pysytellä ihan Pythonin perustyökaluissa

from tkinter import *
from tkinter import ttk

import serial
import time

def send():
    ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
    print (ser.portstr)     # check which port was really used

    merkkijono=str(laheta.get())
    kpl=ser.write(bytes(merkkijono, encoding='ascii'))

#   Miten *merkkijono* on käsiteltävä, jotta siitä saadaan textvariable
    print("Debukkausta, lähetettiin", merkkijono ,"lukumäärä=", kpl)
    ttk.Label(frame2, text="Lähetettiin" ).grid()
    ttk.Label(frame2, textvariable=merkkijono).grid() #EI tulosta frame2:lle
    ser.close()             # close port

def wake_up_AT():
    ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
    print (ser.portstr) # check which port was really used

    kpl=ser.write(b'+++') #Modemi vastaa tähän OK jos kaikki kunnossa
    print("Debukkausta, lähetetyt merkit=", kpl, "kpl" )

    time.sleep(3)
    modeminkuittaus = ""    #Muuttuja modemin lähettämälle status viestille

    while ser.inWaiting() > 0:
        modeminkuittaus += str(ser.read(1), encoding='ascii')

#   Miten *modeminkuittaus* on käsiteltävä, jotta siitä saadaan textvariable
    print("Debukkausta, Modemin STATUS=", modeminkuittaus)
    ttk.Label(frame2, text="Modemin STATUS" ).grid() #EI tulosta frame2:lle
    ttk.Label(frame2, textvariable=modeminkuittaus).grid()

    ser.close()             # close port


 #def set_up():  Tähän tulee portin alustus

######

root = Tk()
root.geometry("200x300")

laheta = StringVar()    # onko muuttuja esitelty paikka oikea

####
frame2 = ttk.Frame(root, width=100, height=200, borderwidth=5, relief=GROOVE)
frame2.grid(column=0, row=1)
ttk.Label(frame2, text="Sarjaliikenne" ).grid()

####
frame3 = ttk.Frame(root, width=100, height=200, borderwidth=5, relief=SUNKEN)
frame3.grid(column=0, row=0)
ttk.Button(frame3, text="+++", command=wake_up_AT).grid(column=1, row=0)

lahetys_entry = ttk.Entry(frame3, width=7, textvariable=laheta)
lahetys_entry.grid(column=0, row=1)
ttk.Button(frame3, text="Send", command=send).grid(column=1, row=1)

lahetys_entry.focus()

#### Ei vielä toiminnassa
frame4 = ttk.Frame(root, width=100, height=200, borderwidth=5, relief=GROOVE)
frame4.grid(column=0, row=2)
ttk.Label(frame4, text="Portin alustus (tulossa)" ).grid()
#ttk.Button(frame4, text="SET UP", command=set_up).grid(column=0, row=3)


root.mainloop()

-tossu- [20.06.2011 23:45:41]

#

Koodi ei toimi, koska frame2-muuttuja ei näy funktioiden sisällä, ellei sitä erikseen määritä globaaliksi. Esimerkki selventänee asiaa:

def spam ():
	foo = "xyzzy"

def eggs ():
	global foo
	foo = "xyzzy"

foo = "bar"

spam ()
print (foo)
eggs ()
print (foo)

Toki muitakin vikoja, joita en pikaisesti katsoen huomannut, saattaa olla.

käärme [20.06.2011 23:57:08]

#

Kiitos vastauksesta

Joskus liianmonta vuotta sitten tein C:llä koodia ja sitäkautta on globaalit muuttujat ja nimiavaruus tuttuja.

Kokeilin ja tajusin esimerkkisi, mutta valitettavasti en osaa soveltaa sitä tohon mun ongelmaan

Metabolix [21.06.2011 00:03:04]

#

Kysymyksiä varten kannattaa yleensä laatia minimaalinen koodi, jossa ongelma ilmenee. Tästäkin olisit voinut karsia kaikki modeemitoiminnot ja tehdä suunnilleen kymmenen rivin koodin, kuten alla on. Lyhyttä koodia on helpompi ulkopuolistenkin testata, ja usein myös vika löytyy aivan itsestään eikä tarvitsekaan kysyä mitään.

En ole Tk-ekspertti, mutta koodissasi on pari virhettä: Ensinnäkin textvariable-kikkailu on väärin, netistä voit selvittää, miten se oikeasti toimii. Kikkailu on myös turha, koska voit antaa muuttujan text-parametrina aivan yhtä hyvin kuin vakiotekstinkin. Lisäksi näyttäisi, että yrität vain lisätä uusia tekstielementtejä samaan frameen, vaikka sinun pitäisi muokata vanhaa.

Minimaalinen koodi ratkaisusta:

from tkinter import *
from tkinter import ttk

def main():
	global root, status

	root = Tk()
	ttk.Button(root, text = "Muuta", command = send).grid()

	# Ota Label muuttujaan talteen.
	status = ttk.Label(root, text = "Status: ?")
	status.grid()
	root.mainloop()

def send():
	# Muuta tekstiä.
	# Tapa 1:
	status.config(text = "Status: SEND")
	# Tapa 2:
	status["text"] = "Status: SEND"

main()

-tossu-, muuttuja kyllä näkyy, sitä ei vain voi muokata. Esimerkki selventänee asiaa:

def spam ():
	print ("spam:", foo)
	# foo = "xyzzy" # virhe!

def eggs ():
	global foo
	print ("eggs:", foo)
	foo = "xyzzy"

foo = "bar"

spam ()
print (foo)
eggs ()
print (foo)

-tossu- [21.06.2011 00:21:44]

#

Metabolix kirjoitti:

-tossu-, muttuja kyllä näkyy, sitä ei vain voi muokata.

Tajusin tuon luonnollisesti vasta sen jälkeen kun olin kirjoittanut viestini. Aloin testata käärmeen koodia ja huomasin, että kyllähän se tekstin vaihto toimii osittain. Olit kuitenkin ehtinyt korjata virheeni ennen kuin ehdin tehdä sen itse.

Yöaikaan näitä pieniä mutta ratkaisevia virheitä näköjään sattuu melko paljon; tämä oli jo kolmas vastaava. Pitääkin olla jatkossa tarkempi, ettei Metabolix ala hermostua.

Chiman [21.06.2011 12:54:55]

#

Ajattelin kommentoida lyhyesti globaalien muuttujien näkymistä ja muokkaamista funktioiden sisältä.

Globaali muuttuja siis näkyy funktioiden sisälle, mutta ilman global-avainsanan käyttöä globaalissa nimiavaruudessa olevan muuttujan nimeä ei voida sitoa funktiosta käsin toiseen olioon. Toisin sanoen globaaliin listaan voidaan lisätä alkioita funktion sisälläkin, koska itse listaolio pysyy samana. Sen sijaan esim. kokonaislukua tai merkkijonoa ei voi muuttaa samoin, koska ne ovat olioina muokkaamattomia (engl. immutable).

rax [22.06.2011 20:20:15]

#

Itse käyttäisin jo PyQT, mielestäni Tkinter on jo melko vanhentunut GUI

Vastaus

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

Tietoa sivustosta