Python - Ayarlar penceresinden ana pencereyi güncellemek

Başlatan empax, 10 Şubat 2014 - 00:49:50

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

empax

Merhabalar.

Tkinter-Python ile ufak bir uygulama yapımıkla uğraşıyorum ama bir yerde takıldım kaldım.
Şöyle;
anaPencere.py ve ayarlar.py olmak üzere iki dosyamız olsun.
anaPencere.py veri tabanından aldığı verilere göre event, boyut, renk vs. özelliklerle açılıyor.
ayarlar.py ise veri tabanındaki, ana pencerenin özelliklerini değiştiriyor..
Program ilk olarak anaPencereden başlayacak ve sürekli açık kalacak. ayarlar.py üzerinden de ana pencerenin ayarları yapılacak ve kaydet yapınca Ana pencere güncellenecek. İşte bu güncelleme bölümünde kafam durdu. Bunu anaPencereye nasıl söyleyeceğim? Tkinter güncelleme metodunu1 kullan ya da bir kapan aç yaptırmam lazım.

İlk etapta aklıma gelen os kütüphanesi ile terminalden yapar gibi (pkill -f "python /home/.../anaPencere.py") şeklinde Ana pencereyi öldürüp tekrar başlatmak.("python /home/.../tanaPencere.py")
Ama bu pek mantıklı olmadı çünkü Ayarlar penceresi kilitleniyor ve kapatılınca kendisi üzerinden yeniden açılan anaPencere de ölüyor.

Başka bir fikir ise;
anaPencere.py dosyasını ayarlar.py dosyasından import etmek, ama bu sefer de yeni yapılan örnekleme den Ana pencereye nasıl ulaşacağım...

Neyse çok konuştum sanırım ama derdimi açıklayabildim sanırım(?).
Umarım ışık tutarsınız yoluma. :)


1
root.update()
root.deiconify()
بسم الله الرحمن الرحيم
|ACEMİLER İÇİN İLK DURAK|Çözüldü|Kod etiketi|

sem

Tkinter hakkında pek bilgim yok;

İlk olarak şu geldi aklıma; pkill uygulamak yerinene SIGUSR1 gönderseniz ve SIGUSR1 sinyalini ana pencere içinde yakalayarak tazeleme (refresh) işlemi uygulasanız işinizi görüyor mu?
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

berkayaslan

Farklı bir pencere dosyada değil.  Anapencere içinde def olarak fonksiyon tanımla.  Bu tanımladığın fonksiyon şöyle olabilir tabi çok kısa bu yqni fikir verme açısından. 

from tkinter import *

Renkgir = Entry(ayarlar)
#Daha önce açtığını varsaydığım ayarlar penceresine bir yazı boşluğu ekledik.
Renkgir.pack()

def kaydet():
    Anapen.tk_setPalette(Renkgir.get())

mainloop()


Tabi ben şuan tabletten yazıyorum.  Bu kodu python 3e göre yazdım.  Elbet yanlışları vardır.  Ama fikir verebilecek durumda bilgisayardan girince eğer çözülmemişse daha net bir şeyler yazarım.  Burada anlatmak istediğim:

Python içinde bir yerde halihazırdakli pencerenin özelliğini pythona başka şekilde gösterirsen python onu alır ve uygular. 




Haa eğer tüm bunlardan anlamadım dersen ya da ben ufak bir noktayı kaçırıyorsam:


Evet iyi bir yöntem olmaz hatta komik bile olur bence ama pencereyi kapatıp tekrar açman mümkün.  Tek yapman gereken ayarlar penceresini toplevel değilde tk()  olarak.  Açman.    Toplevel() in mantığı mevzubahis pencereyi başka bir pencereye bağlı kılmak.  Ama Tk()  bağımsızdır.  Yani ayarları Tk()  olarak açarsan pencere rahatlıkla kapanıp açılır.  Ama program için hoş durmaz.  Birde sanırım başka dosyada açtığın için os modülünü kullanmak zorunda kalıyorsun.  Ama aynı dosyada kullanırsan os modülüne gerek yok.  Anapen.destroy()  komutu pencereyi ya da içindeki frame'yi hatta içindeki labeli öldürmek için yeterli.  Yani birbiriyle bağımlı olayları farklı dosyalarda düzenlemen seni çook uğraştırır.  Hatta bazen içinden çıkamazsın.  Tabi bairkeç adımla yapılır ama böyle ilk uygulamalar için biraz zor gibi :) zaten ilerde çözersin durumu :) 



İf you wanna be the best, You must SMURF something. :)

empax

@sem0900, @berkayaslan;

SIGUSR1 hakkında bir fikrim yok ama anaPencere.py den sinyali nasıl yakalarım bilemiyorum.
Sanırım ne kadar da istemesem en iyi yöntem sınıfları tek dosyada toplamak. Ama şimdilik biraz daha araştıracağım, bu arada belki farklı çözüm yolları da gelir. :)

Teşekkürler.
بسم الله الرحمن الرحيم
|ACEMİLER İÇİN İLK DURAK|Çözüldü|Kod etiketi|

guopx

@empax
Eğer uygulamanın ve ayarların ayrı ayrı olması şart ise veritabanınızı gsettings'e taşıyarak iki uygulamanın gsettings aracılığıyla haberleşmesini sağlayabilirsiniz. Tabi bu durumda yazdığınız uygulama sadece linux ve gtk yüklü bir sistem üzerinde çalışacaktır. Eğer olur derseniz eve gidince bir örnek verebilirim sizin için.
Sevdiklerine sevdiğini söyle çok geç olmadan.

empax

@guopx, size zahmet olmazsa tabi ki örneği incelemek isterim. :)
بسم الله الرحمن الرحيم
|ACEMİLER İÇİN İLK DURAK|Çözüldü|Kod etiketi|

guopx

@empax
Kusura bakma dün giremedim foruma. Biraz bakındım ama gsettings'i kullanmak için şema kurulması gerektiğini ben tamamen unutmuşum. http://www.micahcarrick.com/gsettings-python-gnome-3.html Şimdi bir pencere için de /usr altına şema kurmaya gerek yok bence.
Şöyle yapabiliriz:
Veritabanı dosyasını değişiklikler için pyinotify ile izleyebilir ve dosya değiştiğinde pencere özelliklerini değişen dosyaden çekerek pencereyi güncelleştirebiliriz.
sudo apt-get install python-pyinotify
ile pyinotify yükle.
#!/usr/bin/env python
#-*-coding:utf-8-*-
import threading
from Tkinter import *
import os
import ConfigParser
import pyinotify

##### ayarların bulunduğu dosyayı yani veritabanını okur, yoksa ~/pencere_ayarlari/ayarlar.conf  oluşturur
class ConfigParse():
      def __init__(self):
          self.confDir =  os.path.join(os.getenv('HOME'), 'pencere_ayarlari/')
          self.confFile = os.path.join(self.confDir + "ayarlar.conf")
          self.config = ConfigParser.ConfigParser()

          if os.path.isfile(self.confFile):
             self.config.read(self.confFile)
          else:
              if not os.path.exists(self.confDir):
                  os.makedirs(self.confDir)
              self.config.add_section('bolum1')
              self.config.set('bolum1', 'ayar1', 'green')
              self.config.set('bolum1', 'ayar2', 'red')
              self.config.set('bolum1', 'ayar3', 'ornek metin')

              with open(self.confFile, 'wb') as self.confFile:
                    self.config.write(self.confFile)

gui = None

###### ayarların bulunduğu dosyayı sessizce izler, değiştiğinde pencereyi güncellemesini tetikler
class DosyaIzle(threading.Thread):
      def run(self):
          def degisimVarsa(ev):
              pencere.guncelle()
          wm = pyinotify.WatchManager()
          wm.add_watch(ConfigParse().confDir, pyinotify.IN_CLOSE_WRITE, degisimVarsa)
          notifier = pyinotify.Notifier(wm)
          notifier.loop()


##### Bu da penceremiz :)
class Pencere(object):
    def __init__(self):
        self.root = Tk()
        self.root.geometry("250x150")
        self.etiket = Label(self.root, text=ConfigParse().config.get('bolum1', 'ayar3'), fg=ConfigParse().config.get('bolum1', 'ayar1'),  bg=ConfigParse().config.get('bolum1', 'ayar2'))
        self.etiket.pack(expand=1, fill='both')
       
    def guncelle(self):
        self.etiket["text"] = ConfigParse().config.get('bolum1', 'ayar3')
        self.etiket["fg"] = ConfigParse().config.get('bolum1', 'ayar1')
        self.etiket["bg"] = ConfigParse().config.get('bolum1', 'ayar2')
        self.root.update()

DosyaIzle().start()
pencere = Pencere()
pencere.root.mainloop()
Bu bizim ana penceremizin kodları. Ayarlar yani veritabanı ev dizini altında pencere_ayarları adlı dizinin içinde ayarlar.conf adlı dosyada saklanıyor. Betiği ilk çalıştırdığında eğer yoksa bu dosya ve dizinler kendiliğinden oluşturulur. Bu dosyadan veri okumak ve bu dosyaya yazmak için ConfigParser modülünü kullandım ki basit ve kullanışlıdır :) Bu arada neden bir klasör oluşturup ayar dosyasını içine koyduk diye sorarsan pyinotify tek bir dosyayı izlerken bazen sorun çıkarabiliyor o yüzden biz de dosyanın içinde bulunduğu dizini izliyoruz.
Aslında ayarları ayarlar.conf dosyasını herhangi bir metin editörü ile açıp düzenleyerek de değiştirebilirsiniz ama bir ayar penceresi oluşturalım yine de :)
Bu da ayarların yapıldığı pencerenin kodları olsun:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import *
import tkColorChooser
import ConfigParser
import os



class Example(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)   
         
        self.parent = parent       
        self.initUI()
       
    def initUI(self):   
        self.pack(fill=BOTH, expand=1)
       
        self.btn1 = Button(self, text="Arkaplan rengi",
            command=self.btn1)
        self.btn1.place(x=30, y=30)
       
        self.frame1 = Frame(self, border=1,
            relief=SUNKEN, width=30, height=30)
        self.frame1.place(x=160, y=30)       

        self.btn2 = Button(self, text="Yazı rengi",
            command=self.btn2)
        self.btn2.place(x=30, y=60)
       
        self.frame2 = Frame(self, border=1,
            relief=SUNKEN, width=30, height=30)
        self.frame2.place(x=160, y=60)   

        self.yazi = Entry(self,bd =5)
        self.yazi.place(x=30, y= 95)
   
        self.kaydet_butonu = Button(self, text="Kaydet",
            command=self.kaydet)
        self.kaydet_butonu.place(x= 150, y=120)
   
    def btn1(self):
        (rgb, hx) = tkColorChooser.askcolor()
        self.arkaplan_rengi = hx
        self.frame1.config(bg=hx)
    def btn2(self):
        (rgb, hx) = tkColorChooser.askcolor()
        self.yazi_rengi = hx
        self.frame2.config(bg=hx)
    def kaydet(self):
        confDir =  os.path.join(os.getenv('HOME'), 'pencere_ayarlari/')
        confFile = os.path.join(confDir + "ayarlar.conf")
        config = ConfigParser.ConfigParser()
        config.add_section('bolum1')
        config.set('bolum1', 'ayar1', self.yazi_rengi)
        config.set('bolum1', 'ayar2', self.arkaplan_rengi)
        config.set('bolum1', 'ayar3', self.yazi.get())
        with open(confFile, 'wb') as confFile:
             config.write(confFile)

 
root = Tk()
ex = Example(root)
root.geometry("300x150+300+300")
root.mainloop() 

Mantığı basit :) ana pencere ayarlar.conf dosyasındaki değişiklikleri izlerken bu da ayarlar.conf dosyasına değişiklikleri yazıyor. Değişiklikler algılanınca da pencere güncellenmiş olur. Birçok eksiği var, özellikle benim threading bilgim çok iyi olmadığından pencere kapansa bile dosyayı izlemeye devam ediyor. Ayar penceresinde bütün değerleri ayarlamadan kaydedince hata veriyor. Pencereden önce ayarları çalıştırınca hata veriyor. Ben sadece fikir vermek için yazdım, düzenleyip kullanmak - kullanmamak sana kalmış :)
Sevdiklerine sevdiğini söyle çok geç olmadan.

sem

@empax, sinyaller konusuna SUDO'da değinmiştik bir terminal uygulaması da yazılmıştı o sayıda yanılmıyorsam. Aslında sinyaller hep kullandığımız araçlar;

kill -9 dediğimizde aslında burada kill komutu sinyal göndermek için kullanılan ismi kötü olan bir uygulama. Yoksa tek görevi sinyal göndermek. -9 ise gönderilen sinyalin ismi ve -9 yanılmıyorsam SIGKILL'e tekabul ediyordu. SIGKILL ise gerçekten ismindeki gibi, prosesi sonlandırmak için kullanılıuyor =).... Yani bir pid numarasına kill -9 pidno dediğimiz zaman uygulamayı sonlandıran aslında kill değil -9 ibaresi. Çünkü SIGKILL üzerine yazılamayan ve olağan davranışı uygulamayı sonlandıran bir sinyal. Fakat SIGUSR1 üzerine yazılabilen yani olağan davranışı değiştirilebilen bir sinyal. Yanılmıyorsam kodu 11 ya da 12 idi yani uygulamanıza kill -11 gibi de sinyal gönderebilirsiniz.

Benim bahsettiğim ise bu sinyalleri uygulama içerisinden gönderip, uygulama içerisinden yakalamak. Ama tkinter bilmediğim için böyle genel bir çözüm önerisine gittim aslında, yoksa böyle bir çözüme ihtiyaç olmamalı aslında düşününce. Python için şurada bahsedilmiş;

http://docs.python.org/2/library/signal.html
".NET çemberinden geçen lirisist etkisi bir 'Volcano', bir yüzüm Java bir yüzüm Badalamenti Don Tano"
----------------------------------------------------------------------------------------------------------------------
"Her yer ölüm yine, burası dünya
Derken ölüm bile bu nasıl dünya?
Benden ölüm dile, batıyor gün yine
Burası dünya?

empax

@guopx, @sem0900.

Öncelikle verdiğiniz detaylı bilgiler için her ikinize de çok teşekkürler.

Denemelere başlayalım bakalım neler yapabileceğim. :)
بسم الله الرحمن الرحيم
|ACEMİLER İÇİN İLK DURAK|Çözüldü|Kod etiketi|

berkayaslan

Şöyle bir şey aklıma düştü. Siz ayarlar.py dosyasında kodlarınızı fonksiyon olarak belirtirseniz ve anapencerede bu ayarlar.py dosyasını import ederken aynı zamanda bu pencereye bir 'UYGULA' butonu iliştiren bir fonksiyon hazırlarsanız. Uygula butonu anapencereyi güncellemekte sorun çekmez.. Açıkçası denemedim ama yakın zamanda deneyeceğim gibi..
İf you wanna be the best, You must SMURF something. :)

empax

Alıntı yapılan: berkayaslanŞöyle bir şey aklıma düştü. Siz ayarlar.py dosyasında kodlarınızı fonksiyon olarak belirtirseniz ve anapencerede bu ayarlar.py dosyasını import ederken aynı zamanda bu pencereye bir 'UYGULA' butonu iliştiren bir fonksiyon hazırlarsanız. Uygula butonu anapencereyi güncellemekte sorun çekmez.. Açıkçası denemedim ama yakın zamanda deneyeceğim gibi..
Bu aralar pek fırsat bulamadığımdan biraz askıda kaldı ilk fırsatta devam edeceğim. Dediğiniz yöntem ihtimaller arasındaydı ancak ana pencerede buton olmadığı hatta yer bile olmadığı için burada takıldım. :)
Bu yüzden farklı bir dosya üzerinden ana pencereyi etkileyecek Python dosyasına ihtiyacım oldu.
بسم الله الرحمن الرحيم
|ACEMİLER İÇİN İLK DURAK|Çözüldü|Kod etiketi|

enesergun

Eğer pencerenizi bir frame içinde tutuyorsanız o frame i destroy edip tekrardan o fonksiyonu çağırın.
Veya

http://stackoverflow.com/questions/1960725/refreshing-a-window-in-tkinter

bundan yararlanabilirsiniz.