Ek het die laaste paar weke gewerk aan 'n Drag and Drop-bouer vir Python.
Jy kan dit nagaan by
Bronkode:
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
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.
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.
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.
So omstreeks einde Julie het ek besluit om aan die projek te begin werk
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.
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.
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
Maar ek het vinnig die beperkings van die gebruik van python besef om die aanvanklike weergawe te bou.
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.
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.
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.
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.
Wou 'n doek hê wat soortgelyk aan Figma ingezoem en gepan kan word.
'n Basislegstuk waarvandaan al die ander legstukke kan strek.
'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.
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 🙄
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.
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
Ek het probeer eksperimenteer met Fabric.Js en probeer om die hele ding in fabric.js te implementeer soos jy dit kan sien
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.
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
Toe ek begin het, het ek navorsing gedoen oor 'n paar biblioteke soos
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.
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. } ]
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:
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.
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.
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
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.
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
#bouinpubliek
O! moenie vergeet om saam te volg vir opdaterings nie
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 :)