paint-brush
Tu je návod, ako som vytvoril Webflow ako UI Builder pre Pythonpodľa@paulfreeman
Nová história

Tu je návod, ako som vytvoril Webflow ako UI Builder pre Python

podľa Paul10m2024/10/05
Read on Terminal Reader

Príliš dlho; Čítať

Zdieľam svoj myšlienkový proces a skúsenosti s vytváraním tvorcu používateľského rozhrania Drag and Drop pre python
featured image - Tu je návod, ako som vytvoril Webflow ako UI Builder pre Python
Paul HackerNoon profile picture
0-item
1-item


Posledných pár týždňov som pracoval na zostavovacom nástroji Drag and Drop pre Python.


Môžete si to overiť na PyUIBuilder

Zdrojový kód: https://github.com/PaulleDemon/PyUIBuilder


Čo môže urobiť stavebník?

Stručne povedané, môže vám pomôcť rýchlo vytvoriť používateľské rozhranie pre Python a generovať kód používateľského rozhrania vo viacerých knižniciach/rámcoch, vrátane Tkinter a customtkinter. viac si môžete prečítať na sekcia funkcií


Ale nechcem len rozbehnúť projekt, rád by som sa s vami podelil aj o svoje skúsenosti. V tomto blogu sa budem venovať môjmu myšlienkovému procesu a prehľadu na vysokej úrovni o tom, ako som vytvoril aplikáciu.

Prichádzať s nápadom.

Na rozdiel od všeobecného presvedčenia sa Python často používa na vytváranie rýchlych aplikácií, je obzvlášť populárny medzi vývojármi pracujúcimi v oblasti vedy o údajoch, automatizácie, skriptovacích úloh atď. Mnoho interných nástrojov a GUI, najmä vo vedeckých a výskumných prostrediach, je vytvorených s Pythonom kvôli jeho jednoduchosť a dostupnosť rámcov ako Tkinter, PyQt a ďalšie.

nápad

Teraz bolo veľa tvorcov drag and drop pre web, ale veľmi málo pre Python GUI, najmä pre tkinter. Videl som niekoľko, ale problém bol v tom, že mali veľmi obmedzený počet widgetov alebo by generovali kód vo formáte XML, čo nie je ideálne, ak vyvíjate používateľské rozhranie v Pythone.


Najprv som chcel vytvoriť správny nástroj na vytváranie používateľského rozhrania drag and drop len pre Tkinter.


Stále som sa zaoberal myšlienkou ideálneho tvorcu GUI (žiadna hračka). Inšpiroval som sa používateľským rozhraním Canva a prišiel som s niekoľkými funkciami, vďaka ktorým by bolo moje GUI ideálne.


  1. Všetky widgety by mali byť vytvorené ako pluginy.
  2. Mali by podporovať widgety používateľského rozhrania tretích strán vo forme doplnkov.
  3. Mal by byť schopný nahrávať položky, ako sú obrázky, videá atď.
  4. Mal by generovať kód v Pythone.

Takže koncom júla som sa rozhodol začať pracovať na projekte

Rozširovanie myšlienky

Na začiatku sa nazýval tkbuilder, čo naznačuje, že je to tvorca GUI pre knižnicu Tkinter UI.


Ale ak ste si všimli, môžem tiež rozšíriť rovnakú myšlienku na podporu viacerých rámcov a knižníc Python GUI, pretože všetko je vytvorené ako plugin a presne to som plánoval urobiť.

Plánovanie počiatočnej verzie.

Pre počiatočnú verziu som nechcel pridávať príliš veľa funkcií, ktoré by používateľov zahltili. Chcel som ho postaviť na základe spätnej väzby od ľudí, ktorí ho používajú. Takto nestrácam čas budovaním vecí, ktoré ľudia nechcú.


Od samého začiatku som sa rozhodol, že nebudem mať backend ani žiaden alebo registračný formulár. Takto je to pre mňa oveľa jednoduchšie na vývoj a pre používateľov, ktorí ho používajú. Chcel som len jednoduchý frontend, s ktorým môžu ľudia začať.

Výber jazyka JS, TS alebo Python

výber jazyka

Áno, bolo to niečo, nad čím som niekedy dosť často premýšľal, väčšina tvorcov GUI pre Python bola postavená pomocou Pythonu. Moja prvá voľba pre Python bola PySide.


Najkomplexnejšia aplikácia založená na GUI, ktorú som vytvoril pomocou PyQt/Pyside, bola a editor založený na uzloch pár rokov dozadu.


Rýchlo som si však uvedomil obmedzenia používania pythonu na zostavenie pôvodnej verzie.


  • Knižnice používateľského rozhrania Pythonu nemajú veľa miniaplikácií tretích strán, ktoré by mi pomohli rýchlo vytvoriť počiatočnú verziu.
  • Nie je ľahké distribuovať aplikáciu Python ako exe súbory, kde ako pomocou JS ju môžeme distribuovať vo forme elektrónovej aplikácie.
  • Väčšina ľudí radšej používa web namiesto sťahovania spustiteľného súboru z neznámej webovej stránky.


Strojopis bol tiež možnosťou, ale pri strojopise som vždy cítil, že je príliš podrobný


Toto boli jediné veci, ktoré som si okamžite všimol, takže mojou prvou voľbou sa stalo použitie JS.


PS: Neskôr som ľutoval, že som nezačal s TS, ale to bude inokedy.

Rámec alebo žiadny rámec.

Knižnica podobná frameworku, s ktorou mi najviac vyhovuje, je React.js, ale vytvorenie abstrakcie by si vyžadovalo použitie tried, čo sa od zavedenia hákov neodporúča.


Problém nepoužívania frameworku bol v tom, že som si musel všetko zostaviť sám a nemal by som prístup k rozsiahlym knižniciam komponentov, ktoré mi reakcia ponúka.


Obidve mali kompromisy, ale stále sa dajú použiť triedy React, takže sa to pre mňa stalo jasnou voľbou.

Hrboľatý štart

Začal som stavbou samotnej základne a bočnej lišty začiatkom augusta a pre nedostatok financií som musel prestať, tak som sa pustil do práce klienta, ktorý bohužiaľ nezaplatil konečnú sumu. Skúšal som crowdfunding, ale ani tam som nemal šťastie.


A tak som sa v mesiaci september s troškou financií, ktoré mi ostali, rozhodol ísť do tohto projektu naplno. Okolo 9. septembra som znovu spustil prácu.

Plánovanie dopredu...

plánovanie dopredu

Veľa času sa venovalo úvahám o základnej abstrakcii, ktorú je možné rozšíriť na mieru, aby vyhovovala potrebám.


  1. Chcel som mať plátno, ktoré sa dá zväčšovať a posúvať podobne ako Figma.

  2. Základná miniaplikácia, z ktorej sa môžu rozširovať všetky ostatné miniaplikácie.

  3. Funkcia drag and drop na pretiahnutie prvkov používateľského rozhrania na plátno.


Ak chcete stavať pomocou Reactu, musíte myslieť a budovať ho určitým spôsobom, napriek sporom o tom, či je to knižnica alebo rámec, vždy to vyzerá skôr ako Framework než knižnica.

Dizajn používateľského rozhrania

Vždy sa mi páčilo, ako Canva postavila svoj bočný panel, chcel som mať niečo podobné pre môjho drag and drop buildera.

Čo som mal na srdci, som nakreslil na papier. Nie je to najlepší umelec na svete 🙄

Dizajn používateľského rozhrania

Môj myšlienkový proces týkajúci sa interakcie plátna a widgetu.

plánovanie dopredu...

Takže, kto by mal mať na starosti ťahanie, zmenu veľkosti, výber. Plátno alebo základná miniaplikácia. Ako sa bude zaobchádzať s miniaplikáciami vo vnútri miniaplikácie?


Bude základná miniaplikácia poznať svoje deti alebo bude spravovaná pomocou jedinej dátovej štruktúry samotným plátnom. Ako urobím deti vo vnútri detí?


Ako bude fungovať presúvanie myšou na plátne a iných miniaplikáciách?


Ako sa budú spravovať rozloženia?


Toto boli niektoré z otázok, ktoré som si začal klásť pred výstavbou celej veci.


Aj keď teraz používateľské rozhranie vyzerá jednoduchšie, pri budovaní základne sa veľa myslelo, takže pre používateľov to vyzerá oveľa jednoduchšie.

HTML prístup založený na plátne alebo prístup bez plátna.

Prístup založený na plátne

Teraz má html predvolený prvok Canvas, ktorý vám umožňuje robiť veľa vecí, ako je kreslenie, pridávanie obrázkov a podobne, teraz to vyzeralo ako ideálny prvok na použitie pre môj program.


Tak som začal zisťovať, či existuje a existuje implementácia drag and drop, zmena veľkosti, zoom a pan. našiel som FabricJs , zdalo sa mi to ako fantastická knižnica pre môj prípad použitia.


Skúsil som experimentovať s Fabric.Js a pokúsil som sa implementovať celú vec do fabric.js, ako to vidíte implementáciu , ale na plátne bolo niečo, čo som nepredvídal.


  1. Pri vytváraní plátna som začal experimentovať s prístupom založeným na háčikoch, ale funkcia nakladania s fabric.js bola asynchrónna, takže by sa s háčikmi nehralo dobre.
  2. Plátno nemôže mať podradené prvky, ako napríklad Div alebo iné prvky, ktoré by trochu sťažili vytváranie správcov rozloženia
  3. Ladenie čohokoľvek na plátne je dosť ťažké, pretože vnútorné prvky plátna sa nezobrazujú v prvku kontroly nástrojov pre vývojárov


Prístup, ktorý nie je založený na plátne


Teraz po experimentovaní sa prístup bez plátna zdal lepší, pretože mám poskytnutý prístup k predvolenému správcovi rozloženia a navyše bolo k dispozícii veľa vopred vytvorených komponentov používateľského rozhrania, ktoré by pri škálovaní urobili túto ideálnu voľbu.


Mal som v pláne simulovať plátno pomocou dvoch rôznych div, jeden vnútorný div a vonkajší kontajner div.


Teraz bolo vytváranie zoomu a panorámu pomerne jednoduché na implementáciu, pretože CSS už malo transformáciu, škálovanie a preklad.


Po prvé, aby som to implementoval, musel som mať kontajner, ktorý obsahuje plátno. Teraz je toto plátno neviditeľným prvkom (bez skrytého pretečenia), toto je miesto, kde sa vypustia všetky prvky a použije sa mierka a preklad.

Kontajner

Pre priblíženie som musel mierku zväčšiť a pre oddialenie ju zmenšiť.

Skúste tento jednoduchý príklad. (tlačidlo + na priblíženie a - na oddialenie)


Podobne fungovalo aj ryžovanie

Drag and drop

drag and drop

Keď som začínal, skúmal som niekoľko knižníc ako napr Reagovať-krásne-Dnd , Reagovat Dnd-kit a Reagovat Swappy .


Po preskúmaní som zistil, že React-beautiful-dnd už nie je udržiavaný a začal som s React dnd-kit. Keď som začal budovať, zistil som, že dokumentácia k dnd-kitu je dosť obmedzená na to, čo som staval, navyše čoskoro vychádza nové vydanie s veľkými zmenami v knižnici, a tak som sa rozhodol prestať reagovať-dnd-kit až na hlavné vydanie.


Prepísal som časti, v ktorých som použil súpravu DND, pomocou rozhrania Drag and Drop API od HTML. Jediným obmedzením natívneho rozhrania Drag and drop API bolo, že ho stále nepodporujú niektoré dotykové zariadenia, čo mi nevadilo, pretože som staval pre nedotykové zariadenia.

Jediný zdroj pravdy

Čeliť pravde

pri vytváraní aplikácie, ako je táto, môže byť ľahké stratiť prehľad o všetkých premenných a zmenách. Takže nemôžem mať viacero premenných, ktoré sledujú tú istú informáciu.


Informácie/stav každého miniaplikácie by mal mať buď plátno, alebo samotný widget, ktorý potom na požiadanie odovzdá informácie.


Alebo možno použiť knižnicu riadenia štátu ako redux


Po vyskúšaní rôznych prístupov som sa rozhodol mať všetky informácie o widgetoch spravovaných komponentom Canvas.


Štruktúra údajov vyzerá asi takto.

 [ { 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. } ]

Reagovať Kontextoví manažéri

Teraz som chcel, aby boli aktíva nahrané na bočnom paneli prístupné pomocou panela nástrojov miniaplikácií. Ale zakaždým, keď zmením bočné karty, opätovné vykreslenie spôsobilo zmiznutie nahraných prvkov.


Jedným z najväčších obmedzení Reduxu je, že môžete ukladať iba serializovateľné údaje. Neserializovateľné údaje, ako je obrázok, video alebo iné aktíva, nemožno uložiť na redux. To by sťažilo prenos spoločných údajov okolo rôznych komponentov.


Jedným zo spôsobov, ako to prekonať, je použiť React Context. Stručne povedané, React Context poskytuje spôsob, ako preniesť údaje cez strom komponentov bez toho, aby ste museli manuálne odovzdávať rekvizity na každej úrovni.


Všetko, čo by som musel urobiť, aby som mal údaje v rôznych komponentoch, bolo zabaliť ich okolo poskytovateľa kontextu React.


Vytvoril som si vlastných poskytovateľov kontextu pre dve veci:

  1. Drag and drop – Povolenie pretiahnutia z bočného panela + pretiahnutie v rámci podradených prvkov.
  2. Nahranie súboru – Na sprístupnenie odovzdaných súborov na paneli nástrojov pre každú miniaplikáciu.


Tu je jednoduchý príklad toho, ako som použil kontext React pre Drag and drop.

 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> ) }


Áno! to je všetko. Všetko, čo som teraz musel urobiť, bolo omotať ho okolo komponentu, kde som potreboval kontext, čo bol v mojom prípade cez Canvas a bočný panel.

Generovanie kódu

Zodpovednosť

Keďže každý widget sa správa inak a má svoje vlastné atribúty, rozhodol som sa, že widgety musia byť zodpovedné za generovanie vlastného kódu a kódový nástroj bude riešiť iba konflikty názvov premenných a zostavenie kódu.


Týmto spôsobom som mohol ľahko rozšíriť podporu mnohých vopred vytvorených miniaplikácií, ako aj niektorých doplnkov používateľského rozhrania tretích strán.

Prebieha naživo

Nemal som backend ani registráciu a existovalo veľa spoločností poskytujúcich bezplatný hosting pre statické stránky. Najprv som sa rozhodol, že pôjdem s Vercelom, ale často som videl, ako pneumatika bez Vercelu klesla, ak bolo príliš veľa požiadaviek.


Vtedy som sa dozvedel o Stránky Cloudflares ponuka. Ich bezplatná pneumatika mala takmer všetko neobmedzené. Takže použitie cloudflare sa stalo mojou primárnou voľbou.


Jedinou nevýhodou bolo, že časy výstavby boli dosť pomalé a chýbalo im dosť dokumentácie.


Najnepríjemnejšou časťou kroku zostavenia bolo zlyhanie zostavenia, fungovalo to na Vercel, ale nie na stránkach cloudflare??? Záznamy tiež neboli také jasné. a máme pneumatiky zadarmo, máme len 500 stavieb za mesiac, takže som ich nechcel zbytočne míňať


Snažil som sa hodiny, potom som sa rozhodol nastaviť nepretržitú integráciu na prázdny reťazec

 CI='' npm install


A konečne to išlo naživo.
Naživo

Chcete vidieť, ako sa to v priebehu mesiacov vyvíjalo?

Celú túto vec som budoval verejne. Zaujíma vás, ako sa to zmenilo z jednoduchého bočného panela na plne rozvinutý tvorca drag n drop, môžete si pozrieť celý časová os tu .


#buildinpublic


Oh! nezabudnite sledovať aktualizácie

Hviezdne repo ⭐️


Ak sa vám páčil tento typ obsahu, budem písať ďalšie blogy, ktoré budú podrobnejšie o tom, ako plánujem a staviam veci, a aby ste ich mohli sledovať, môžete sa prihlásiť na odber môjho newslettera :)