Tkinter'da Label yada create_image() kullanımı


#1

Merhaba,
Tkinter’de bir arka plan resmi oluşturmak ve üzerinde belli koordinatlara bazı yazılar getirmek istiyorum. Daha sonra bu sayfayı yazdıracağım.

from tkinter import *

root = Tk()
root.geometry("595x682+100+0")

# --------- SCROOLBAR SETİ ----------
def update_layout():
    inside.update_idletasks()
    canv.configure(scrollregion=canv.bbox('all'))
    canv.yview('moveto', '1.0')
    size = inside.grid_size()


def on_configure(event):
    w, h = event.width, event.height
    natural = inside.winfo_reqwidth()
    canv.itemconfigure('inner', width=w if w > natural else natural)
    canv.configure(scrollregion=canv.bbox('all'))


canv = Canvas(root, bd=0, highlightthickness=0, bg="#eeeeee")
canv.pack(side=LEFT, expand=1, fill=BOTH, )

scrollbar = Scrollbar(root, orient='vertical', command=canv.yview)
scrollbar.pack(side=LEFT, fill='y')

inside = Frame(canv, bg="#fefeee")
inside.grid_columnconfigure(0, weight=1)

canv.create_window((0, 0), window=inside, anchor='nw', tags='inner')
canv.configure(yscrollcommand=scrollbar.set)
canv.bind('<Configure>', on_configure)


def right_click(event):
    print("coor: ", event.x, event.y)

root.bind("<ButtonPress-3>", right_click)

ft_img = PhotoImage(file='Fatura.gif') # A4 size - 595 x 842 pixel

canv.create_image(1, 1, image=ft_img, anchor="nw") # 1) <---!!!!
#Label(inside, image=ft_img).pack()             # 2) <---!!!!


sozluk = {}
item_no = 2
liste = ["İsim", "Adres", "VD", ""]
yazilar = ["Koç Tex", "Merter", "12345", "18.10.1998"]

yan = 100
for z in yazilar:
    canv.create_text(100, yan, fill="darkblue", font="Arial 11",
                                text=z, tags="token", anchor='nw')
    yan += 20
    item_no += 1

mainloop()

Arka planda A4 boyutlu kağıdın görüntüsünü kullandım. (A4 boyutu - 595 x 842 piksel). Üzerine gelecek yazılar için iki yöntem kullanabilirim.

Satır43: Label(inside, image = ft_img).pack ()

Label kullandığımda arka plan görüntüsünü alıyorum, ancak for döngüsü içindeki verileri gösteremiyorum. (Daha sonra sürüklenerek belli yerlere taşınacak yazılar)

Satır 42: canv.create_image(1, 1, image = ft_img, anchor = "nw")

Eğer create_image kullanırsam, yazılar istediğim şekilde görünüyot, ancak canvaspiksel durumunu kaybeder. Örneğin, sayfanın alt kenarındaki 675px, kaydırma çubuğunu aşağı kaydırdığımda yine 675 değerini veriyor. (Bunu, sayfanın herhangi bir yerinde sağ tıklayarak test edebilirsiniz)
Düşeyde root.geometry() içinde belirlediğim pixelden daha fazlasını alamıyorum. Bu nedenle, öğeleri gereken yerlere taşıyamıyorum.

Bir fatura tasarım programı yapmaya çalışıyorum. İstenen metni basılı kağıtların uygun yerlerine yazdırmak için. Yazıları taşımayı başardım, ancak bu problemi bir türlü halledemedim. Fikirlerinizi paylaşırsanız çok sevinirim.
Selamlar


#2

Bu probleminiz için pack değil de place pencere yöneticisini kullanmanız gerekiyor.


#4

Malesef place() yi doğru şekilde kullanamadım. Bu birazda kodları derleme yapmamdan kaynaklanıyor sanırım. Ancak geldiğim aşamada bir tek sorun kaldı. Yazıları ekranın istediğim yerine taşıyabilirotum. Gerekli kayıt işlemleri de gerçekleşiyor. Fakat root.geometry() dışında kalan kısma hükmedemiyorum. scrollbar’ı kaydırdığım anda yazılar taşınamaz oluyor. Altta kalan kısımların pixel değerlerine ulaşamıyorum. Sayfanın dibi 650 ise scrool edip dibe de insem (sağ klik ile ) 650 değer veriyor.

Kodların bütünü aşağıda ve arkaplan resmi olarak kullandığım örnek sayfa da ekte. Muhtemel görüş ve önerileriniz için şimdiden teşekkür ederim.

from tkinter import *
from PIL import Image, ImageGrab, ImageDraw, ImageFont
import os

def update_layout():
    Example.icerik.update_idletasks()
    Example.canvas.configure(scrollregion=Example.canvas.bbox('all'))
    Example.canvas.yview('moveto', '1.0')
    size = Example.icerik.grid_size()

def on_configure(event):
    w, h = event.width, event.height
    natural = Example.icerik.winfo_reqwidth()
    Example.canvas.itemconfigure('inner', width=w if w > natural else natural)
    Example.canvas.configure(scrollregion=Example.canvas.bbox('all'))


root = Tk()
root.geometry("595x642+100+0")

class Example(Frame):

    canvas = Canvas(root, width=595, height=842, background="white")
    canvas.pack(fill="both", expand=True)

    icerik = Frame(canvas, bg="#eeeeee")
    icerik.grid_columnconfigure(0, weight=1)

    scrollbar = Scrollbar(canvas, command=canvas.yview)
    scrollbar.pack(side=RIGHT, fill='y')

    canvas.configure(yscrollcommand=scrollbar.set)
    canvas.bind('<Configure>', on_configure)

    # A4 595 x 842 pixel - Arka plan resmin ebatı
    w = 595
    h = 842
    img_pil = Image.new("RGB", (w, h), "white")
    cv_pil = ImageDraw.Draw(img_pil)

    def __init__(self, coor, tex):
        Frame.__init__(self,)
        print(coor, tex)
        self.coor = coor
        self.tex = tex

        # Bu veriler sürüklenen bir öğeyi
        # takip etmek için kullanılır
        self._drag_data = {"x": 0, "y": 0, "item": None}

        self.create_token()

        # "token" etiketiyle herhangi bir nesnenin üzerine tıklamak,
        # sürüklemek ve yayınlamak için bağlayıcılar ekleyin
        self.canvas.tag_bind("token", "<ButtonPress-1>", self.on_token_press)
        self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
        self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)


        self.canvas.bind("<ButtonPress-3>", self.onbuton_press)

    def onbuton_press(self, event):
        print("OnButon: ", event.x, event.y)

    def create_token(self):
        # Verilen renkte verilen koordinatta bir belirteç oluşturun
        (x,y) = self.coor
        self.canvas.create_text(x, y, fill="darkblue", font="Arial 11",
                                text=self.tex, tags="token", anchor='nw') # anchor=nw koordinatı yazının sol üstü yapar
        print("CreateToken: ", self.tex)

    def on_token_press(self, event):
        # Bir nesnenin sürüklenmesi başlıyor
        # öğeyi ve yerini kaydet
        print("--------- ", self.canvas.find_closest(event.x, event.y)[0])

        if not self.canvas.find_closest(event.x, event.y)[0] == 1:
            self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
            self._drag_data["x"] = event.x
            self._drag_data["y"] = event.y

        print("ITEM: ", self._drag_data)

    def on_token_release(self, event):
        # Bir nesnenin sürüklenmesi bitiyor
        # sürükleme bilgilerini sıfırla -----  NEDEN!?
        self.it_no = self._drag_data["item"]
        self.yeni_coor = (self._drag_data["x"], self._drag_data["y"])

        sozluk["I{}".format(self.it_no)].coor = self.yeni_coor

        print(sozluk["I{}".format(self.it_no)].coor)

        print(self._drag_data["x"], self._drag_data["y"], self._drag_data["item"])

        self._drag_data["item"] = None
        self._drag_data["x"] = 0
        self._drag_data["y"] = 0

    def on_token_motion(self, event):

        # Bir nesnenin sürüklenmesi
        # farenin ne kadar hareket ettiğini hesaplayın
        delta_x = event.x - self._drag_data["x"]
        delta_y = event.y - self._drag_data["y"]

        # nesneyi uygun miktarda taşı
        self.canvas.move(self._drag_data["item"], delta_x, delta_y)

        # yeni pozisyonu kaydet
        self._drag_data["x"] = event.x
        self._drag_data["y"] = event.y
def yazdir():
    for i in range(2, 6):
        (x, y) = sozluk["I{}".format(i)].coor
        fnt = ImageFont.truetype('arial.ttf', 12)
        Example.cv_pil.text((x, y), text=sozluk["I{}".format(i)].tex, font=fnt, fill="black")

    filename = "Fatura_png.png"
    Example.img_pil.save(filename)
    newfilename = 'Fatura_pdf.pdf'

    im = Image.open(filename)
    im.save(newfilename, "PDF", quality=100)

    #os.startfile("grab.pdf", "print")
    print("İçeriği Fatura_png.png ve Fatura_pdf.pdf isimleriyle kaydedildi.\nYazıcı çıktısı durduruldu")


if __name__ == "__main__":

    ft_img = PhotoImage(file='Fatura.gif')

    Example.canvas.create_image(1, 1, image=ft_img, anchor="nw")

    # bir kaç hareketli nesne oluşturmak
    sozluk = {}
    item_no = 2
    yazilar = ["153,00 TL", "Merter", "12345", "18.10.1998"]

    satir = 100
    for z in yazilar:
        sozluk["I{}".format(item_no)] = Example((100, satir), z)
        satir += 20
        item_no += 1

    #Example((300, 600), "SON")

    yazdir_buton = Button(root, text="yazdir", command=yazdir)
    yazdir_buton.pack()

    print("SÖZLÜK", sozluk.keys())
    print(len(yazilar))
    root.mainloop()

#5

Kodunuzu çalıştıramadım. Gerekli resim dosyalarını da paylaşabilir misiniz?


#6

En son mesajda Fatura yazılı bir resim dosyası eklemiştim. Arka planda kullanılan resim o. Fatura.gif
Diğerleri programın çıktısı olan png ve pdf ler. Gif indirilebilir değilse tekrar deneyeyim göndermeyi


#7

Görmemişim, kusura bakmayın.

Hatanın kaynağını buldum sanırım. Siz kaydırma çubuğunu indirince aldığınız y koordinatı bilgisi değişiyor. Mesela 100 alıyorsunuz diyelim. Eğer kaydırma çubuğunu 50 piksel aşağı indirirseniz bu değer 50 oluyor. Yani size gelen x ve y koordinatları pencerede gördüğünüz alan üzerinden size geliyor. Yani bir şekilde kaydırılan miktarı bu koordinatlara eklemek lazım. Sanırım bunun için halihazırda bir metod var. Şurası size yardımcı olabilir: https://stackoverflow.com/a/11310847/1583714


#8

Rica ederim.,
Verdiğiniz linki inceleyeceğim. Peki sizce arkaplan resmi için label mi, create_image mi kullanmak doğru olur? Label kullandığımda piksel sorunu olmuyor (ilk kod grubunda # ile yorum satırına dönüştürdüğüm kısım) ancak taşınacak yazılar bir şekilde arka planda kalıyor.
Hangisinin üstünde çalışmalı?


#9

Resim için tamamen resim göstermeye yönelik bir pencere aracı kullanmak daha doğru olur düşüncesindeyim. Mesela şuna bakabilirsiniz: http://effbot.org/tkinterbook/photoimage.htm