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()
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.
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
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)
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.
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).
Itse käyttäisin jo PyQT, mielestäni Tkinter on jo melko vanhentunut GUI
Aihe on jo aika vanha, joten et voi enää vastata siihen.