paint-brush
Python için Webflow Benzeri Bir UI Oluşturucu Nasıl Oluşturdumile@paulfreeman
Yeni tarih

Python için Webflow Benzeri Bir UI Oluşturucu Nasıl Oluşturdum

ile Paul10m2024/10/05
Read on Terminal Reader

Çok uzun; Okumak

Python için Sürükle ve Bırak kullanıcı arayüzü oluşturucusu oluşturma konusundaki düşünce sürecimi ve deneyimimi paylaşıyorum
featured image - Python için Webflow Benzeri Bir UI Oluşturucu Nasıl Oluşturdum
Paul HackerNoon profile picture
0-item
1-item


Son birkaç haftadır Python için bir Sürükle ve Bırak oluşturucu üzerinde çalışıyorum.


Bunu şu adreste kontrol edebilirsiniz: PyUIOluşturucu

Kaynak kodu: https://github.com/PaulleDemon/PyUIBuilder


İnşaatçı ne yapabilir?

Kısaca, Python için hızlı bir şekilde kullanıcı arayüzü oluşturmanıza ve Tkinter ve customtkinter dahil olmak üzere birden fazla kütüphane/çerçevede kullanıcı arayüzü kodu oluşturmanıza yardımcı olabilir. Daha fazla bilgi için şuraya bakabilirsiniz: özellikler bölümü


Ama sadece bir proje başlatmak istemiyorum, aynı zamanda deneyimimi sizinle paylaşmak istiyorum. Bu blogda, düşünce sürecimi ve uygulamayı nasıl oluşturduğuma dair üst düzey bir genel bakışı ele alacağım.

Fikir ortaya atılıyor.

Yaygın inanışın aksine, Python genellikle hızlı uygulamalar oluşturmak için kullanılır, özellikle veri bilimi, otomasyon, komut dosyası görevleri vb. alanlarda çalışan geliştiriciler arasında popülerdir. Birçok dahili araç ve GUI, özellikle bilimsel ve araştırma ortamlarında, basitliği ve Tkinter, PyQt ve diğerleri gibi çerçevelerin kullanılabilirliği nedeniyle Python ile oluşturulur.

fikir

Şimdi, web için çok sayıda Sürükle ve bırak oluşturucu vardı, ancak Python GUI'leri için çok azdı, özellikle de tkinter için. Birkaç tane gördüm, ancak sorun şu ki çok sınırlı sayıda widget'ları vardı veya Python'da kullanıcı arayüzü geliştiriyorsanız ideal olmayan XML formatında kod üretiyorlardı.


Yani, ilk başta sadece Tkinter için uygun bir sürükle ve bırak kullanıcı arayüzü oluşturucusu oluşturmak istedim.


İdeal bir GUI oluşturucu fikri üzerinde durmaya devam ettim (kasıtlı bir kelime oyunu değil). Canva'nın kullanıcı arayüzünden ilham aldım ve GUI'mi ideal hale getirecek birkaç özellik buldum.


  1. Tüm widget'lar eklenti gibi yapılmalıdır.
  2. Eklenti şeklinde 3. parti kullanıcı arayüzü bileşenlerini desteklemelidir.
  3. Resim, video vb. varlıkları yükleyebilmeli.
  4. Python'da kod üretmesi gerekiyor.

Bu yüzden Temmuz ayının sonuna doğru proje üzerinde çalışmaya başlamaya karar verdim

Fikir genişletiliyor

Başlangıçta tkbuilder olarak adlandırılıyordu, bu da Tkinter UI kütüphanesi için bir GUI oluşturucu olduğunu gösteriyordu.


Ancak, fark ettiyseniz aynı fikri birden fazla Python GUI framework'ünü ve kütüphanesini destekleyecek şekilde de genişletebilirim, çünkü her şey bir eklenti gibi yapılmış ve tam olarak yapmayı planladığım şey buydu.

İlk versiyon planlaması.

İlk sürüm için, kullanıcıları bunaltacak çok fazla özellik eklemek istemedim. Bunu, kullanan kişilerin geri bildirimlerine dayanarak oluşturmak istedim. Bu şekilde, insanların istemediği şeyleri oluşturmak için zaman kaybetmiyorum.


En başından beri bir arka uç veya herhangi bir kayıt formu olmamasına karar verdim. Bu şekilde hem benim için hem de onu kullanan kullanıcılar için geliştirme çok daha basit oluyor. Sadece insanların başlayabileceği basit bir ön uç istiyordum.

Dil seçimi JS, TS veya Python

bir dil seçmek

Evet, bu üzerinde epeyce düşündüğüm bir şeydi, Python için çoğu GUI oluşturucu Python kullanılarak oluşturulmuştu. Python için ilk tercihim PySide'dı.


PyQt/Pyside kullanarak oluşturduğum en karmaşık GUI tabanlı uygulama şuydu: düğüm tabanlı düzenleyici Birkaç yıl önce.


Ancak ilk versiyonu derlemek için Python kullanmanın sınırlamalarını kısa sürede fark ettim.


  • Python UI kütüphaneleri, ilk sürümü hızlı bir şekilde oluşturmama yardımcı olacak pek çok üçüncü taraf bileşenine sahip değil.
  • Python uygulamalarını exe dosyaları olarak dağıtmak kolay değil, oysa JS kullanarak onu bir electron uygulaması şeklinde dağıtabiliriz.
  • Çoğu kişi bilmediği bir web sitesinden çalıştırılabilir bir dosya indirmek yerine web'i kullanmayı tercih ediyor.


Typescript de bir seçenekti, ancak Typescript'i her zaman çok ayrıntılı buldum


Bunlar ilk dikkatimi çeken şeylerdi, dolayısıyla ilk tercihim JS kullanmak oldu.


Not: Daha sonra TS ile başlamadığıma pişman oldum ama bu başka bir yazının konusu.

Çerçeveli veya çerçevesiz.

En rahat ettiğim framework benzeri kütüphane React.js'dir, ancak bir soyutlama oluşturmak sınıfların kullanılmasını gerektirir ve kancaların tanıtılmasından bu yana bu önerilmemektedir.


Bir çerçeve kullanmamanın sorunu, her şeyi kendim inşa etmek zorunda kalmam ve React'in sunduğu geniş bileşen kütüphanelerine erişimimin olmamasıydı.


Her ikisinin de artıları ve eksileri vardı, ama React sınıfları hala kullanılabiliyordu, bu yüzden benim için bariz bir tercih oldu.

Engebeli başlangıç

Ağustos ayının başında temel ve kenar çubuğunu inşa ederek başladım ve fon eksikliğinden dolayı durmak zorunda kaldım, bu yüzden ne yazık ki son tutarı ödemeyen bir müşterinin işini üstlendim. Kitle fonlaması denedim ama orada da şanslı değildim.


Bu yüzden, Eylül ayında elimde kalan az miktardaki parayla bu projeye tümüyle girişmeye karar verdim. 9 Eylül civarında işe yeniden başladım.

Önceden planlama...

önceden planlama

Zamanın büyük bir kısmı, ihtiyaçları karşılayacak şekilde ölçeklendirilebilecek temel soyutlamayı düşünmeye harcandı.


  1. Figma'ya benzer şekilde yakınlaştırılıp kaydırılabilen bir Canvas istiyordum.

  2. Diğer tüm bileşenlerin genişletilebileceği temel bir bileşen.

  3. Kullanıcı arayüzü öğelerini tuvale sürükleyip bırakmanızı sağlayan Sürükle ve Bırak özelliği.


React ile bir yapı inşa etmek için, onu belirli bir şekilde düşünmeniz ve inşa etmeniz gerekir, bunun bir kütüphane mi yoksa bir framework mü olduğu konusundaki tartışmalara rağmen, her zaman bir kütüphaneden çok bir Framework'e benziyor.

UI tasarımı

Canva'nın kenar çubuğunu nasıl oluşturduğunu her zaman beğenmişimdir, sürükle ve bırak oluşturucum için de benzer bir şeye sahip olmak istemiştim.

Aklımdakileri bir kağıda çizdim. En iyi sanatçı değilim 🙄

UI tasarımı

Tuval ve widget etkileşimine ilişkin düşünce sürecim.

önceden planlama...

Peki, sürükleme, yeniden boyutlandırma, seçme işlerinden kim sorumlu olmalı? Tuval mi yoksa temel widget mı? Widget içindeki widget'lar nasıl işlenecek?


Temel widget çocuklarını bilecek mi yoksa tuvalin kendisi tarafından tek bir veri yapısıyla mı yönetilecek? Çocukları çocukların içinde nasıl işleyeceğim?


Tuval ve diğer widget'ların içinde sürükle ve bırak nasıl çalışacak?


Düzenler nasıl yönetilecek?


Bunlar, her şeyi inşa etmeden önce sormaya başladığım sorulardan bazılarıydı.


Artık kullanıcı arayüzü daha basit görünse de, tabanın oluşturulmasına çok fazla emek verildiği için kullanıcılar için çok daha basit görünüyor.

HTML Canvas tabanlı yaklaşım veya Canvas dışı yaklaşım.

Tuval tabanlı yaklaşım

Artık HTML'de varsayılan bir Canvas öğesi var, bu öğe çizim, resim ekleme ve benzeri birçok şey yapmanıza olanak sağlıyor, artık programım için kullanabileceğim ideal bir öğe gibi görünüyor.


Yani, sürükle ve bırak, yeniden boyutlandırma, yakınlaştırma ve kaydırma gibi mevcut bir uygulama varsa kontrol etmeye başladım. FabricJs , bu benim kullanım durumum için harika bir kütüphane gibi göründü.


Fabric.Js ile denemeler yaptım ve her şeyi fabric.js'de uygulamaya çalıştım, bunu görebilirsiniz uygulama Ama tuvalde öngöremediğim bir şey vardı.


  1. Canvas'ı oluştururken kanca tabanlı yaklaşımı denemeye başladım, ancak fabric.js'nin dispose fonksiyonu asenkrondu, bu yüzden Kancalarla iyi çalışmıyordu.
  2. Canvas, Div veya diğer öğeler gibi alt öğelere sahip olamaz, bu da düzen yöneticilerinin oluşturulmasını biraz daha zorlaştırır
  3. Tuval üzerindeki herhangi bir şeyi hata ayıklamak oldukça zordur çünkü tuvalin iç öğeleri geliştirici araçlarının inceleme öğesinde görünmez


Tuval tabanlı olmayan yaklaşım


Şimdi deneyip gördükten sonra, varsayılan düzen yöneticisine erişimim olduğu ve ölçekleme sırasında bu ideal seçeneği oluşturacak birçok önceden oluşturulmuş kullanıcı arayüzü bileşeni bulunduğu için, tuval dışı yaklaşımın daha iyi göründüğünü fark ettim.


Canvas'ı iki farklı div kullanarak simüle etmeyi planladım, bir iç div ve dış kapsayıcı div.


Artık yakınlaştırma ve uzaklaştırma oluşturmak oldukça kolaydı çünkü CSS'de zaten dönüştürme, ölçekleme ve çevirme vardı.


İlk olarak, bunu uygulamak için, bir tuval tutan bir konteynere sahip olmam gerekiyordu. Şimdi bu tuval görünmez bir öğedir (gizli taşma olmadan), tüm öğelerin bırakıldığı yer burasıdır ve ölçekleme ve çeviri uygulanır.

Konteyner

Yakınlaştırmak için ölçeği artırmam, uzaklaştırmak için ise azaltmam gerekti.

Bu basit örneği deneyin. ( + tuşu yakınlaştırmak için, - tuşu uzaklaştırmak için)


Panlama da benzer şekilde çalıştı

Sürükle ve bırak

sürükle ve bırak

Başlarken birkaç kütüphanede araştırma yapmıştım, örneğin: Tepki-güzel-Dnd , React Dnd-kit Ve Tepki Verme Takas .


Araştırdıktan sonra react-beautiful-dnd'nin artık sürdürülmediğini gördüm ve React dnd-kit ile başladım. Başlamış bir yapı olarak, dnd-kit'in dokümantasyonunun yaptığım şey için oldukça sınırlı olduğunu gördüm. Ayrıca, kütüphanede büyük değişiklikler içeren yeni bir sürüm yakında çıkacaktı, bu yüzden react-dnd-kit'i büyük sürüme kadar bırakmaya karar verdim.


DND-kit'i HTML'nin Sürükle ve Bırak API'siyle kullandığım kısımları yeniden yazdım. Yerel Sürükle ve Bırak API'siyle ilgili tek sınırlama, bazı dokunmatik cihazlar tarafından hala desteklenmemesiydi, bu benim için önemli değildi çünkü dokunmatik olmayan cihazlar için oluşturuyordum.

Tek bir hakikat kaynağı

Gerçekle yüzleş

böyle bir uygulama oluştururken, tüm değişkenleri ve değişiklikleri takip etmek kolaylaşabilir. Bu yüzden, aynı bilgi parçasını takip eden birden fazla değişkenim olamaz.


Her widget'ın bilgisi/durumu ya tuvalde ya da widget'ın kendisinde tutulmalı, böylece istek üzerine bilgi iletilmelidir.


Ya da redux gibi bir durum yönetim kütüphanesi kullanabilirsiniz


Farklı yaklaşımları denedikten sonra, widget'larla ilgili tüm bilgilerin Canvas bileşeni tarafından yönetilmesini seçtim.


Veri yapısı aşağı yukarı şöyle görünüyor.

 [ { id: "", // id of the widget widgetType: WidgetClass, // base widget children: [], // children will also have the same datastructure as the parent parent: "", // id of the parent of the current widget initialData: {} // information about the widget's data that's about to be rendered eg: backgroundColor, foregroundColor etc. } ]

React Context yöneticileri

Şimdi varlıkların widget'ların araç çubuğuyla erişilebilen kenar çubuğuna yüklenmesini istedim. Ancak her seferinde yan sekmeleri değiştirdiğimde, yeniden işleme yüklenen varlıkların kaybolmasına neden oldu.


Redux'un en büyük kısıtlamalarından biri yalnızca serileştirilebilir verileri depolayabilmenizdir. Görüntü, video, diğer varlıklar gibi serileştirilemeyen veriler redux'ta depolanamaz. Bu, ortak verileri farklı bileşenler arasında geçirmeyi zorlaştırır.


Bunun üstesinden gelmenin bir yolu React Context kullanmaktır. Kısaca, React Context, her seviyede manuel olarak props iletmek zorunda kalmadan bileşen ağacından veri geçirmenin bir yolunu sağlar.


Verileri farklı bileşenlerde tutmak için yapmam gereken tek şey, bunları bir React bağlam sağlayıcısının etrafına sarmaktı.


İki şey için kendi bağlam sağlayıcılarımı oluşturdum:

  1. Sürükle ve bırak - Kenar çubuğundan sürükle ve bırak özelliğini etkinleştirme + alt öğeler arasında sürükle ve bırak özelliğini etkinleştirme.
  2. Dosya yükleme - Yüklenen dosyaların her widget için araç çubuğunda erişilebilir olmasını sağlamak.


İşte Sürükle ve bırak için React bağlamını nasıl kullandığıma dair basit bir örnek.

 import React, { createContext, useContext, useState } from 'react' const DragWidgetContext = createContext() export const useDragWidgetContext = () => useContext(DragWidgetContext) // Provider component to wrap around parts that need drag-and-drop functionality export const DragWidgetProvider = ({ children }) => { const [draggedElement, setDraggedElement] = useState(null) const onDragStart = (element) => { setDraggedElement(element) } const onDragEnd = () => { setDraggedElement(null) } return ( <DragWidgetContext.Provider value={{ draggedElement, onDragStart, onDragEnd }}> {children} </DragWidgetContext.Provider> ) }


Evet! işte bu kadar. Şimdi yapmam gereken tek şey, onu içeriğe ihtiyaç duyduğum bileşenin etrafına sarmaktı, benim durumumda bu Canvas ve kenar çubuğu üzerindeydi.

Kod oluşturma

Sorumluluk

Her widget'ın farklı davranması ve kendine özgü nitelikleri olması nedeniyle, widget'ların kendi kodlarını üretmekten sorumlu olmaları gerektiğine ve bir kod motorunun yalnızca değişken adı çakışmalarını ve kodu bir araya getirmeyi ele alacağına karar verdim.


Bu sayede birçok hazır widget'ı ve bazı 3. parti UI eklentilerini destekleyecek şekilde kolayca genişletebildim.

Canlı yayına geçiliyor

Bir arka ucum veya kaydım yoktu ve statik sayfalar için ücretsiz barındırma sağlayan birçok şirket vardı. İlk önce Vercel'i seçmeye karar verdim, ancak çok fazla istek olduğunda Vercel'in ücretsiz lastiğinin düştüğünü sık sık gördüm.


İşte o zaman öğrendim ki Cloudflares sayfaları teklif. Ücretsiz lastikleri neredeyse her şeyi sınırsızdı. Bu yüzden, cloudflare'i kullanmak benim birincil tercihim oldu.


Tek olumsuz yanı yapım sürelerinin oldukça yavaş olması ve çok fazla dokümantasyon eksikliğiydi.


Yapım aşamasının en can sıkıcı kısmı yapı başarısızlığıydı. Vercel'de çalıştı ama Cloudflare sayfalarında çalışmadı??? Günlükler de o kadar net değildi. Ayrıca ücretsiz lastiklerimiz var ve ayda sadece 500 yapı var, bu yüzden çok fazla şey israf etmek istemedim.


Saatlerce denedim sonra sürekli entegrasyonu boş dizeye ayarlamaya karar verdim

 CI='' npm install


Ve sonunda yayına girdi.
Canlı

Aylar boyunca nasıl ilerlediğini görmek ister misin?

Tüm bunları halka açık bir şekilde inşa ediyorum. Eğer bunun basit bir kenar çubuğundan tam teşekküllü bir Sürükle ve bırak oluşturucuya nasıl ilerlediğini görmek istiyorsanız, tümünü kontrol edebilirsiniz zaman çizelgesi burada .


#kamuoyundainşaat


Ah! Güncellemeler için takip etmeyi unutmayın

Yıldız repo ⭐️


Eğer bu tarz içerikleri beğendiyseniz, daha detaylı olarak planlama ve yapım aşamalarını anlattığım daha fazla blog yazısı yazacağım. Takip etmek için substack bültenime abone olabilirsiniz :)