paint-brush
Lūk, kā es izveidoju tīmekļa plūsmas līdzīgu lietotāja interfeisa veidotāju Pythonautors@paulfreeman
417 lasījumi
417 lasījumi

Lūk, kā es izveidoju tīmekļa plūsmas līdzīgu lietotāja interfeisa veidotāju Python

autors Paul10m2024/10/05
Read on Terminal Reader

Pārāk ilgi; Lasīt

Dalos ar savu domu procesu un pieredzi, veidojot vilkšanas un nomešanas lietotāja interfeisa veidotāju python
featured image - Lūk, kā es izveidoju tīmekļa plūsmas līdzīgu lietotāja interfeisa veidotāju Python
Paul HackerNoon profile picture
0-item
1-item


Pēdējo nedēļu laikā esmu strādājis pie Python vilkšanas un nomešanas veidotāja.


Jūs varat to pārbaudīt vietnē PyUIBuilder

Avota kods: https://github.com/PaulleDemon/PyUIBuilder


Ko celtnieks var darīt?

Īsāk sakot, tas var palīdzēt ātri izveidot Python lietotāja saskarni un ģenerēt lietotāja interfeisa kodu vairākās bibliotēkās/ietvaros, tostarp Tkinter un customtkinter. jūs varat lasīt vairāk par funkciju sadaļa


Bet es nevēlos tikai uzsākt projektu, es arī vēlētos dalīties ar jums savā pieredzē. Šajā emuārā es apskatīšu savu domu procesu un augsta līmeņa pārskatu par to, kā es izveidoju lietotni.

Nāk klajā ar ideju.

Pretēji izplatītajam uzskatam, Python bieži tiek izmantots, lai izveidotu ātras lietojumprogrammas, un tas ir īpaši populārs izstrādātāju vidū, kas strādā datu zinātnē, automatizācijā, skriptēšanas uzdevumos utt. Daudzi iekšējie rīki un GUI, īpaši zinātnes un pētniecības iestatījumos, tiek veidoti ar Python, jo tas ir vienkāršība un tādu ietvaru kā Tkinter, PyQt un citu pieejamība.

ideja

Tagad tīmeklim bija daudz vilkšanas un nomešanas veidotāju, bet ļoti maz Python GUI, īpaši tkinter. Es redzēju dažus, bet problēma bija tā, ka tie bija ļoti ierobežots logrīku skaits vai tie ģenerēja kodu XML formātā, kas nav ideāli, ja izstrādājat lietotāja saskarni Python.


Tāpēc sākumā es tikai gribēju izveidot atbilstošu vilkšanas un nomešanas lietotāja interfeisa veidotāju tikai Tkinter.


Es turpināju izdomāt ideālu GUI veidotāju (nav paredzēts vārdu spēle). Mani iedvesmoja Canva lietotāja saskarne, un es atklāju dažas funkcijas, kas padarītu manu GUI ideālu.


  1. Visi logrīki ir jāizveido kā spraudņi.
  2. Jāatbalsta trešās puses lietotāja interfeisa logrīki spraudņu veidā.
  3. Jābūt iespējai augšupielādēt tādus līdzekļus kā attēlus, video utt.
  4. Tam vajadzētu ģenerēt kodu Python.

Tāpēc aptuveni jūlija beigās es nolēmu sākt strādāt pie projekta

Idejas paplašināšana

Sākumā to sauca par tkbuilder, norādot, ka tas ir GUI veidotājs Tkinter UI bibliotēkai.


Bet, ja pamanījāt, es varu arī paplašināt to pašu ideju, lai atbalstītu vairākus Python GUI ietvarus un bibliotēkas, jo viss ir izveidots kā spraudnis, un tieši to es plānoju darīt.

Sākotnējās versijas plānošana.

Sākotnējai versijai es nevēlējos pievienot pārāk daudz funkciju, kas nomāktu lietotājus. Es gribēju to izveidot, pamatojoties uz atsauksmēm no cilvēkiem, kuri to izmanto. Tādā veidā es netērēju laiku, veidojot lietas, kuras cilvēki nevēlas.


No paša sākuma es nolēmu, ka man nav aizmugursistēmas vai nevienas vai pierakstīšanās veidlapas. Tādā veidā man ir daudz vienkāršāk izstrādāt un lietotājiem, kas to izmanto. Es tikai gribēju vienkāršu priekšpusi, ar kuru cilvēki var sākt darbu.

Valodas izvēle JS, TS vai Python

izvēloties valodu

Jā, tas bija kaut kas, par ko es bieži domāju, lielākā daļa Python GUI veidotāju tika veidoti, izmantojot Python. Mana pirmā Python izvēle bija PySide.


Sarežģītākā GUI lietotne, ko izveidoju, izmantojot PyQt/Pyside, bija a uz mezglu balstīts redaktors dažus gadus atpakaļ.


Bet es ātri sapratu ierobežojumus, kas saistīti ar python izmantošanu, lai izveidotu sākotnējo versiju.


  • Python UI bibliotēkās nav daudz trešās puses logrīku, kas palīdzētu ātri izveidot sākotnējo versiju.
  • Nav viegli izplatīt Python lietotni kā exe failus, jo, izmantojot JS, mēs to varam izplatīt elektronu lietotnes veidā.
  • Lielākā daļa cilvēku izvēlas izmantot tīmekli, nevis lejupielādēt izpildāmo failu no nepazīstamas vietnes.


Arī mašīnraksts bija iespēja, taču ar Typescript man vienmēr šķita, ka tas ir pārāk daudznozīmīgs


Šīs bija vienīgās lietas, ko es uzreiz pamanīju, tāpēc mana pirmā izvēle kļuva par JS izmantošanu.


PS: Es vēlāk nožēloju, ka nesāku ar TS, bet tas būs stāsts citai reizei.

Ietvars vai bez ietvara.

Man visērtāk ir ietvariem līdzīga bibliotēka React.js, taču, lai izveidotu abstrakcijas, būtu jāizmanto klases, kas nav ieteicamas kopš āķu ieviešanas.


Sistēmas neizmantošanas problēma bija tāda, ka man viss bija jāveido pašam un man nebija piekļuves plašajām komponentu bibliotēkām, ko piedāvā React.


Abiem bija kompromisi, taču React klases joprojām var izmantot, tāpēc man tā kļuva acīmredzama izvēle.

Bedrains sākums

Sāku ar pašas pamatnes un sānjoslas izbūvi augusta sākumā un nācās pārtraukt līdzekļu trūkuma dēļ, tāpēc ķēros pie klienta, kurš diemžēl nesamaksāja galīgo summu. Es mēģināju pūļa finansējumu, bet arī tur nepaveicās.


Tāpēc septembra mēnesī ar mazajiem līdzekļiem, kas man bija atlikuši, es nolēmu pilnībā iesaistīties šajā projektā. Apmēram 9. septembrī es atsāku darbu.

Plānošana uz priekšu...

plānošana uz priekšu

Daudz laika tika domāts par bāzes abstrakciju, ko var paplašināt līdz mērogam, lai apmierinātu vajadzības.


  1. Vēlējos Canvas, kuru var tuvināt un panoramēt līdzīgi kā Figma.

  2. Pamata logrīks, no kura var izvērsties visi pārējie logrīki.

  3. Vilkšanas un nomešanas funkcija, lai vilktu un nomestu lietotāja interfeisa elementus audeklā.


Lai izveidotu ar React, jums tas ir jādomā un jāveido noteiktā veidā, neskatoties uz strīdiem par to, vai tā ir bibliotēka vai ietvars, tas vienmēr šķiet vairāk kā ietvars, nevis bibliotēka.

UI dizains

Man vienmēr ir paticis, kā Canva izveidoja sānjoslu, es gribēju, lai manam vilkšanas un nomešanas veidotājam būtu kaut kas līdzīgs.

Es uz papīra uzzīmēju to, kas man bija prātā. Nav labākais mākslinieks pasaulē 🙄

UI dizains

Mans domu gājiens par audekla un logrīka mijiedarbību.

plāno uz priekšu...

Tātad, kuram vajadzētu būt atbildīgam par vilkšanu, izmēru maiņu un atlasi. Audekls vai pamata logrīks. Kā tiks apstrādāti logrīki, kas atrodas logrīkā?


Vai bāzes logrīks pazīst viņu bērnus, vai arī to pārvaldīs pats audekls, izmantojot vienu datu struktūru. Kā es atveidos bērnus bērnos?


Kā vilkšana un nomešana darbosies audeklā un citos logrīkos?


Kā tiks pārvaldīti izkārtojumi?


Šie bija daži no jautājumiem, kurus es sāku uzdot pirms visas lietas izveides.


Lai gan tagad lietotāja interfeiss izskatās vienkāršāks, bāzes izveidei tika pievērsta liela uzmanība, tāpēc lietotājiem tā šķiet daudz vienkāršāka.

Uz HTML kanvas balstīta pieeja vai pieeja bez kanvas.

Audekls balstīta pieeja

Tagad html ir noklusējuma Canvas elements, kas ļauj veikt daudzas lietas, piemēram, zīmēt, pievienot attēlu un citas lietas, tagad tas izskatījās kā ideāls elements manai programmai.


Tāpēc es sāku pārbaudīt, vai ir un pastāvēja vilkšanas un nomešanas, izmēru maiņas, tālummaiņas un panoramēšanas ieviešana. es atradu Audumi , šī šķita fantastiska bibliotēka manam lietošanas gadījumam.


Es mēģināju eksperimentēt ar Fabric.Js un mēģināju ieviest visu failu fabric.js, kā jūs to redzat īstenošana , bet audeklā bija kaut kas tāds, ko es neparedzēju.


  1. Veidojot audeklu, es sāku eksperimentēt ar uz āķiem balstītu pieeju, taču fabric.js dispose funkcija bija asinhrona, tāpēc ar Hooks tā nederēja labi.
  2. Audekls nedrīkst saturēt pakārtotus elementus, piemēram, Div vai citus elementus, kas nedaudz apgrūtinātu izkārtojuma pārvaldnieku izveidi.
  3. Jebkāda atkļūdošana uz audekla ir diezgan sarežģīta, jo kanvas iekšējie elementi neparādās izstrādātāja rīku pārbaudes elementā.


Uz audekls nebalstīta pieeja


Tagad pēc eksperimentēšanas šķita labāka pieeja bez kanvas, jo man ir pieejams noklusējuma izkārtojuma pārvaldnieks, kā arī bija pieejami daudzi lietotāja interfeisa komponenti, kas padarītu šo ideālo izvēli mērogošanas laikā.


Es plānoju simulēt audeklu, izmantojot divus dažādus div vienu iekšējo div un ārējo konteineru div.


Tagad tālummaiņas un panoramēšanas izveide bija diezgan viegli īstenojama, jo CSS jau bija pārveidošana, mērogošana un tulkošana.


Pirmkārt, lai to īstenotu, man bija jābūt konteineram, kurā ir audekls. Tagad šis audekls ir neredzams elements (bez pārplūdes paslēpta), šeit tiek izmesti visi elementi un tiek piemērota mērogošana un tulkošana.

Konteiners

Lai tuvinātu, man bija jāpalielina skala, bet tālināšanai tas jāsamazina.

Izmēģiniet šo vienkāršo piemēru. ( + taustiņš, lai tuvinātu, un - , lai tālinātu)


Panoramēšana darbojās līdzīgi

Velciet un nometiet

velciet un nometiet

Sākot darbu, es biju pētījis dažas bibliotēkas, piemēram, Reaģēt-skaisti-Dnd , Reaģēt Dnd-kit un Reaģēt Swappy .


Pēc izpētes es redzēju, ka react-beautiful-dnd vairs netiek uzturēts, un sāku ar React dnd-kit. Sākot būvēt, es atklāju, ka dnd-kit dokumentācija par to, ko es veidoju, ir diezgan ierobežota, turklāt drīzumā iznāks jauns laidiens ar lielām izmaiņām bibliotēkā, tāpēc es nolēmu atteikties no react-dnd-kit līdz lielajam laidienam.


Es pārrakstīju daļas, kur izmantoju DND komplektu, izmantojot HTML vilkšanas un nomešanas API. Vienīgais ierobežojums ar vietējo vilkšanas un nomešanas API bija tāds, ka to joprojām neatbalsta dažas skārienierīces, kas man nebija svarīgi, jo es veidoju ierīcēm bez pieskāriena.

Viens patiesības avots

Saskarieties ar patiesību

veidojot šādu lietotni, var viegli zaudēt visu mainīgo un izmaiņu izsekojamību. Tāpēc man nevar būt vairāki mainīgie, kas sekotu vienai un tai pašai informācijai.


Katra logrīka informācijai/stāvoklim jābūt vai nu audeklā, vai pašā logrīkā, kas pēc pieprasījuma nodod informāciju.


Vai varbūt izmantojiet valsts pārvaldības bibliotēku, piemēram, redux


Es izvēlējos visu informāciju par logrīkiem, ko pārvalda komponents Canvas, pēc dažādu pieeju eksperimentēšanas.


Datu struktūra izskatās apmēram šādi.

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

Reaģēt konteksta pārvaldnieki

Tagad es gribēju, lai sānjoslā augšupielādētie līdzekļi būtu pieejami, izmantojot logrīku rīkjoslu. Taču katru reizi, kad pārslēdzu sānu cilnes, atkārtotas renderēšanas rezultātā augšupielādētie līdzekļi pazuda.


Viens no lielākajiem Redux ierobežojumiem ir tas, ka varat uzglabāt tikai serializējamus datus. Neserializējamus datus, piemēram, attēlus, video, citus līdzekļus, nevar glabāt redux. Tas apgrūtinātu kopīgu datu nodošanu dažādiem komponentiem.


Viens no veidiem, kā to pārvarēt, ir izmantot React Context. Īsāk sakot, React Context nodrošina veidu, kā nosūtīt datus caur komponentu koku, bez nepieciešamības manuāli nodot rekvizītus katrā līmenī.


Viss, kas man būtu jādara, lai dati būtu dažādos komponentos, bija tie jāaptver React konteksta nodrošinātājam.


Es izveidoju savus konteksta nodrošinātājus divām lietām:

  1. Vilkšana un nomešana — vilkšanas un nomešanas iespējošana no sānjoslas + vilkšana un nomešana ar pakārtotiem elementiem.
  2. Failu augšupielāde — lai augšupielādētie faili būtu pieejami katra logrīka rīkjoslā.


Šeit ir vienkāršs piemērs tam, kā es izmantoju React kontekstu vilkšanai un nomešanai.

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


Jā! tas arī viss. Viss, kas man tagad bija jādara, bija apvilkt to ap komponentu, kur man bija nepieciešams konteksts, kas manā gadījumā bija virs Canvas un sānjoslas.

Koda ģenerēšana

Atbildība

Tā kā katrs logrīks darbojas atšķirīgi un tam ir savi atribūti, es nolēmu, ka logrīkiem ir jābūt atbildīgiem par sava koda ģenerēšanu un koda dzinējs apstrādās tikai mainīgo nosaukumu konfliktus un koda apvienošanu.


Tādā veidā es varēju viegli paplašināt, lai atbalstītu daudzus iepriekš izveidotos logrīkus, kā arī dažus trešās puses lietotāja interfeisa spraudņus.

Notiek tiešraide

Man nebija aizmugursistēmas vai reģistrēšanās, un bija daudz uzņēmumu, kas nodrošina bezmaksas mitināšanu statiskām lapām. Vispirms biju nolēmis izmantot Vercel, taču bieži vien esmu redzējis, ka Vercel bezmaksas riepa nolaižas, ja bija pārāk daudz pieprasījumu.


Toreiz es uzzināju par Cloudflares lapas piedāvājums. Viņu brīvajā riepā bija gandrīz viss neierobežots. Tāpēc cloudflare izmantošana kļuva par manu primāro izvēli.


Vienīgie mīnusi bija diezgan lēni būvniecības laiki, un tam trūka diezgan daudz dokumentācijas.


Viskaitinošākā būvēšanas soļa daļa bija būvēšanas kļūme, Vercelā tas strādāja, bet ne cloudflare lapās??? Arī baļķi nebija tik skaidri. un mums ir bezmaksas riepas ir tikai 500 būves mēnesī, tāpēc es negribēju iztērēt pārāk daudz


Es mēģināju stundas, tad es nolēmu iestatīt nepārtrauktu integrāciju uz tukšu virkni

 CI='' npm install


Un tas beidzot tika nodots tiešraidē.
Tiešraidē

Vai vēlaties redzēt, kā tas ir progresējis pa mēnešiem?

Es visu šo lietu veidoju publiski. Man ir interese redzēt, kā tas pāriet no vienkāršas sānjoslas uz pilnībā izpūstu vilkšanas un nomešanas veidotāju, kurā varat pārbaudīt visu laika skala šeit .


#buildinpublic


Ak! neaizmirstiet sekot līdzi atjauninājumiem

Zvaigžņu repo ⭐️


Ja jums patika šāda veida saturs, es rakstīšu vairāk emuārus, kuros sīkāk izklāstīšu, kā es plānoju un veidoju materiālus. Lai sekotu līdzi, varat abonēt manu apakškopas biļetenu :)