Posledných pár týždňov som pracoval na zostavovacom nástroji Drag and Drop pre Python.
Môžete si to overiť na
Zdrojový kód:
Č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
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.
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.
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.
Takže koncom júla som sa rozhodol začať pracovať na projekte
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ť.
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ť.
Á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
Rýchlo som si však uvedomil obmedzenia používania pythonu na zostavenie pôvodnej verzie.
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.
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.
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.
Veľa času sa venovalo úvahám o základnej abstrakcii, ktorú je možné rozšíriť na mieru, aby vyhovovala potrebám.
Chcel som mať plátno, ktoré sa dá zväčšovať a posúvať podobne ako Figma.
Základná miniaplikácia, z ktorej sa môžu rozširovať všetky ostatné miniaplikácie.
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.
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 🙄
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.
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
Skúsil som experimentovať s Fabric.Js a pokúsil som sa implementovať celú vec do fabric.js, ako to vidíte
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.
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
Keď som začínal, skúmal som niekoľko knižníc ako napr
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.
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. } ]
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:
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.
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.
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
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
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ý
#buildinpublic
Oh! nezabudnite sledovať aktualizácie
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 :)