paint-brush
Hier is hoe ek 'n webvloei soos UI-bouer vir Python gebou hetdeur@paulfreeman
Nuwe geskiedenis

Hier is hoe ek 'n webvloei soos UI-bouer vir Python gebou het

deur Paul10m2024/10/05
Read on Terminal Reader

Te lank; Om te lees

Deel my denkproses en ervaring met die bou van 'n Drag and Drop UI-bouer vir python
featured image - Hier is hoe ek 'n webvloei soos UI-bouer vir Python gebou het
Paul HackerNoon profile picture
0-item
1-item


Ek het die laaste paar weke gewerk aan 'n Drag and Drop-bouer vir Python.


Jy kan dit nagaan by PyUIBuilder

Bronkode: https://github.com/PaulleDemon/PyUIBuilder


Wat kan die bouer doen?

Kortliks, dit kan jou help om vinnig UI vir Python te bou en UI-kode te genereer in verskeie biblioteke/raamwerke, insluitend Tkinter en customtkinter. jy kan meer lees op die kenmerke afdeling


Maar ek wil nie net 'n projek loods nie, ek wil ook graag my ervaring met jou deel. In hierdie blog gaan ek oor my denkproses en 'n hoëvlakoorsig oor hoe ek die toepassing gebou het.

Kom met die idee.

In teenstelling met die algemene opvatting, word Python dikwels gebruik om vinnige toepassings te bou, dit is veral gewild onder ontwikkelaars wat in datawetenskap, outomatisering, skriftake, ens. eenvoud en die beskikbaarheid van raamwerke soos Tkinter, PyQt, en ander.

idee

Nou was daar baie sleep-en-losbouers vir die web, maar baie min vir Python GUI's, veral vir tkinter. Ek het 'n paar gesien, maar die probleem was dat hulle 'n baie beperkte aantal widgets was of kode in XML-formaat sou genereer, wat nie ideaal is as jy UI in Python ontwikkel nie.


So, aanvanklik wou ek net 'n behoorlike sleep-en-los-UI-bouer bou net vir Tkinter.


Ek het aanhou peuter rondom die idee van 'n ideale GUI-bouer (geen woordspeling bedoel nie). Ek is geïnspireer deur Canva se UI, en het met min kenmerke vorendag gekom wat my GUI 'n ideale een sou maak.


  1. Alle legstukke moet soos inproppe gemaak word.
  2. Moet derdeparty-UI-legstukke ondersteun in die vorm van inproppe.
  3. Moet bates soos beelde, video's ens kan oplaai.
  4. Dit moet kode in Python genereer.

So omstreeks einde Julie het ek besluit om aan die projek te begin werk

Brei uit op die idee

In die begin is dit tkbuilder genoem, wat aandui dat dit 'n GUI-bouer vir Tkinter UI-biblioteek is.


Maar as jy agtergekom het, kan ek ook op dieselfde idee uitbrei om verskeie Python GUI-raamwerke en -biblioteke te ondersteun, aangesien alles soos 'n inprop gemaak is en dit is presies wat ek beplan het om te doen.

Aanvanklike weergawe beplanning.

Vir die aanvanklike weergawe wou ek nie te veel funksies byvoeg wat gebruikers sou oorweldig nie. Ek wou dit bou op grond van terugvoer van mense wat dit gebruik. Op hierdie manier mors ek nie tyd om dinge te bou wat mense nie wil hê nie.


Van die begin af het ek besluit om nie 'n backend of enige of 'n aanmeldvorm te hê nie. Op hierdie manier is dit baie makliker vir my om te ontwikkel en vir die gebruikers wat dit gebruik. Ek wou net 'n eenvoudige frontend hê waarmee mense kan begin.

Kies taal JS, TS of Python

taal kies

Ja, dit was iets waaroor ek soms gedink het, die meeste GUI-bouers vir Python daar buite is met Python gebou. My eerste keuse vir Python was PySide.


Die mees komplekse GUI-gebaseerde toepassing wat ek met PyQt/Pyside gebou het, was a node-gebaseerde redakteur paar jaar terug.


Maar ek het vinnig die beperkings van die gebruik van python besef om die aanvanklike weergawe te bou.


  • Python UI-biblioteke het nie baie widgets van derdepartye om my te help om die aanvanklike weergawe vinnig te bou nie.
  • Dit is nie maklik om Python-toepassing as exe-lêers te versprei nie, waar ons dit as die gebruik van JS in die vorm van 'n elektrontoepassing kan versprei.
  • Die meeste mense verkies om web te gebruik in plaas daarvan om 'n uitvoerbare weergawe van 'n onbekende webwerf af te laai.


Tikskrif was ook 'n opsie, maar met Tikskrif het ek altyd gevoel dit was te breedsprakig


Dit was die enigste dinge wat ek dadelik opgemerk het, so my eerste keuse het begin om JS te gebruik.


NS: Ek was later spyt dat ek nie met TS begin het nie, maar dit sal 'n storie vir 'n ander keer wees.

Raamwerk of geen raamwerk nie.

Die raamwerk-agtige biblioteek waarmee ek die gemaklikste is, is React.js, maar die skep van 'n abstraksie sal die gebruik van klasse vereis, wat nie aanbeveel word sedert die bekendstelling van hake nie.


Die probleem om nie 'n raamwerk te gebruik nie, was dat ek alles self moes bou en nie toegang sou hê tot die groot komponentbiblioteke wat React bied nie.


Albei het afwykings gehad, maar React-klasse kan steeds gebruik word, so dit het vir my 'n duidelike keuse geword.

Hommelrige begin

Ek het begin met die bou van die einste basis en sybalk in die begin van Augustus, en moes ophou weens 'n gebrek aan fondse, so ek het 'n kliënt se werk opgeneem, wat ongelukkig nie die finale bedrag opbetaal het nie. Ek het skarefinansiering probeer, maar was ook nie gelukkig daar nie.


So, in die maand September met die bietjie fondse wat ek oor het, het ek besluit om alles in te gaan op hierdie projek. Omstreeks 9 September het ek die werk weer begin.

Beplan vooruit...

vooruit beplan

Baie van die tyd het gegaan om te dink aan die basis-abstraksie, wat na skaal uitgebrei kan word om aan die behoeftes te voldoen.


  1. Wou 'n doek hê wat soortgelyk aan Figma ingezoem en gepan kan word.

  2. 'n Basislegstuk waarvandaan al die ander legstukke kan strek.

  3. 'n Sleep-en-los-kenmerk om UI-elemente na doek te sleep en te laat val.


Om met React te bou, moet jy dit op 'n sekere manier dink en bou, ten spyte van argumente oor of dit 'n biblioteek of 'n raamwerk is, voel dit altyd meer soos Framework as 'n biblioteek.

UI ontwerp

Ek het altyd gehou van hoe Canva hul sidebar gebou het, ek wou iets soortgelyks hê vir my sleep-en-losbouer.

Ek het dit wat in my gedagtes was op 'n stuk papier opgeteken. Nie die beste kunstenaar daar buite nie 🙄

UI ontwerp

My denkproses rakende die doek en widget interaksie.

beplan vooruit...

Dus, wie moet in beheer wees van sleep, grootte verander, kies. Die doek of die basislegstuk. Hoe sal die legstukke binne die legstuk hanteer word?


Sal die basislegstuk hul kinders ken of gaan dit met 'n enkele datastruktuur deur die doek self bestuur word. Hoe sal ek kinders binne-in kinders weergee?


Hoe sal die sleep-en-los binne die doek en ander legstukke werk?


Hoe gaan uitlegte bestuur word?


Dit was van die vrae wat ek begin vra het voordat ek die hele ding gebou het.


Alhoewel die UI nou eenvoudiger lyk, is baie gedink aan die bou van die basis, so dit lyk baie eenvoudiger vir gebruikers.

HTML-doek-gebaseerde benadering of nie-doek-benadering.

Canvas-gebaseerde benadering

Nou het html 'n standaard Canvas element, wat jou toelaat om baie dinge te doen soos teken, prente byvoeg en goed, nou het dit gelyk na 'n ideale element om vir my program te gebruik.


So, ek het begin afreken of daar 'n bestaande implementering was van 'n sleep-en-los, verander grootte, zoom en pan. Ek het gevind StofJs , Dit het gelyk soos 'n fantastiese biblioteek vir my gebruik geval.


Ek het probeer eksperimenteer met Fabric.Js en probeer om die hele ding in fabric.js te implementeer soos jy dit kan sien implementering , maar daar was iets omtrent doek wat ek nie voorsien het nie.


  1. Ek het begin eksperimenteer met hake-gebaseerde benadering toe ek die doek gebou het, maar fabric.js dispose-funksie was asinkroniseer, so dit sou nie goed met Hooks speel nie.
  2. Canvas kan nie kinderelemente soos Div of ander elemente hê nie wat dit 'n bietjie moeiliker sal maak om uitlegbestuurders te bou
  3. Dit is nogal moeilik om enigiets op doek te ontfout, aangesien die innerlike elemente van doek nie in die ontwikkelaarnutsgoed-inspeksie-element verskyn nie


Nie-doek-gebaseerde benadering


Nou nadat ek geëksperimenteer het, het die nie-doek-benadering beter gelyk, aangesien ek toegang het tot die standaarduitlegbestuurder wat voorsien word, en daar was baie voorafgeboude komponente van die gebruikerskoppelvlak beskikbaar wat hierdie ideale keuse sou maak tydens skaal.


Ek het beplan om doek te simuleer deur twee verskillende div's een binneste div en buitenste houer div te gebruik.


Die skep van zoom en pan was redelik maklik om te implementeer, aangesien CSS reeds transformeer, skaal en vertaal het.


Eerstens, om dit te implementeer, moes ek 'n houer hê wat 'n doek bevat. Nou is hierdie doek onsigbare element (sonder oorloop verborge), dit is waar al die elemente laat val word, en skaal en vertaling toegepas word.

Houer

Vir inzoem moes ek die skaal verhoog en om uit te zoem, verminder dit.

Probeer hierdie eenvoudige voorbeeld. ( + sleutel om te zoem en - om uit te zoem)


Panning het soortgelyk gewerk

Sleep en los

sleep en los

Toe ek begin het, het ek navorsing gedoen oor 'n paar biblioteke soos Reageer-mooi-Dnd , Reageer Dnd-kit en Reageer Swappie .


Na navorsing het ek gesien dat react-beautiful-dnd nie meer onderhou word nie en het met React dnd-kit begin. As 'n begin met die bou, het ek gevind dat die dnd-kit se dokumentasie redelik beperk is vir wat ek besig was om te bou, Plus, 'n nuwe weergawe met groot veranderinge aan biblioteek kom binnekort uit, so ek het besluit om react-dnd-kit te laat vaar tot die groot vrystelling.


Ek het die dele van waar ek DND-kit gebruik het met HTML se Drag and Drop API herskryf. Enigste beperking met die inheemse Sleep-en-los-API was dat dit steeds nie deur sommige aanraaktoestelle ondersteun word nie, wat nie vir my saak gemaak het nie, want ek het vir nie-aanraaktoestelle gebou.

Enkele bron van waarheid

Staar die waarheid in die oë

wanneer 'n toepassing soos hierdie gebou word, kan dit maklik raak om tred te verloor met al die veranderlikes en veranderinge. So, ek kan nie veelvuldige veranderlikes hê wat dieselfde stukkie inligting dophou nie.


Die inligting/status van elke legstuk moet óf deur die doek óf deur die legstuk s'n gehou word, wat dan die inligting op versoek deurgee.


Of gebruik dalk staatsbestuursbiblioteek soos redux


Ek het gekies om al die inligting oor die legstukke deur die Canvas-komponent te laat bestuur nadat ek verskillende benaderings geëksperimenteer het.


Die datastruktuur lyk iets soos hierdie.

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

Reageer Konteksbestuurders

Nou wou ek hê dat die bates wat in die sybalk opgelaai is, toeganklik was deur die nutsbalk van die widgets. Maar elke keer as ek die kantoortjies verander, het die herweergawe veroorsaak dat die opgelaaide bates verdwyn het.


Een van die grootste beperkings met Redux is dat u slegs serialiseerbare data kan stoor. Nie-serialiseerbare data soos beeld, video, ander bates kan nie op redux gestoor word nie. Dit sal dit moeiliker maak om algemene data om verskillende komponente deur te gee.


Een manier om dit te oorkom, is om React Context te gebruik. Kortliks, React Context bied 'n manier om data deur die komponentboom te stuur sonder om rekwisiete met die hand op elke vlak deur te gee.


Al wat ek hoef te doen om die data in verskillende komponente te hê, was om dit om 'n React-konteksverskaffer te draai.


Ek het my eie konteksverskaffers vir twee dinge geskep:

  1. Sleep en los - Aktiveer sleep en los vanaf sybalk + sleep en los binne kinderelemente.
  2. Lêeroplaai - Om die opgelaaide lêers toeganklik te maak op die nutsbalk vir elke legstuk.


Hier is 'n eenvoudige voorbeeld van hoe ek React-konteks gebruik het vir 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> ) }


Ja! dit is dit. Al wat ek nou moes doen, was om dit om die komponent te draai waar ek die konteks nodig het, wat in my geval oor Canvas en sidebar was.

Genereer kode

Verantwoordelikheid

Aangesien elke widget anders optree en hul eie eienskappe het, het ek besluit dat widgets verantwoordelik moet wees vir die generering van hul eie kode en 'n kode-enjin sal slegs veranderlike naamkonflik hanteer en die kode saamstel.


Op hierdie manier kon ek maklik uitbrei om baie voorafgeboude widgets sowel as sommige UI-inproppe van derdepartye te ondersteun.

Gaan regstreeks

Ek het nie 'n backend of 'n aanmelding gehad nie en daar was baie maatskappye wat gratis hosting vir statiese bladsye verskaf het. Ek het eers besluit om met Vercel te gaan, maar ek het dikwels gesien hoe Vercel-vrye band afgaan as daar te veel versoeke was.


Dis toe dat ek uitgevind het Cloudflares-bladsye offer. Hul gratis band het feitlik alles onbeperk gehad. Dus, die gebruik van cloudflare het my primêre keuse geword.


Die enigste nadele was die boutye was redelik stadig en het 'n tekort aan dokumentasie gehad.


Die mees irriterende deel van die boustap was die boufout, dit het op Vercel gewerk, maar nie op cloudflare-bladsye nie??? Die logs was ook nie so duidelik nie. en ons het gratis bande het net 500 bouwerk per maand, so ek wou nie te veel mors nie


Ek het ure lank probeer, toe besluit ek om deurlopende integrasie op leë string te stel

 CI='' npm install


En dit het uiteindelik regstreeks gegaan.
Leef

Wil jy sien hoe dit deur die maande gevorder het?

Ek het hierdie hele ding in die openbaar gebou. As jy belangstel om te sien hoe dit van 'n eenvoudige sybalk na 'n volledig geblaasde Drag n drop-bouer gevorder het, kan jy die hele tydlyn hier .


#bouinpubliek


O! moenie vergeet om saam te volg vir opdaterings nie

Sterrepo ⭐️


As jy van hierdie tipe inhoud gehou het, sal ek meer blogs skryf wat in meer dieptes gaan oor hoe ek goed beplan en bou, om saam te volg kan jy inteken op my substack-nuusbrief :)