Write desktop and web apps in pure Python

Overview

Flexx

Build Status Documentation Status

Want to stay up-to-date about (changes to) Flexx? Subscribe to the NEWS issue.

Introduction

Flexx is a pure Python toolkit for creating graphical user interfaces (GUI's), that uses web technology for its rendering. Apps are written purely in Python; The PScript transpiler generates the necessary JavaScript on the fly.

You can use Flexx to create (cross platform) desktop applications, web applications, and export an app to a standalone HTML document. It also works in the Jupyter notebook.

The docs are on Readthedocs. the code is on Github.

Example

Click the image below for an interactive example:

demo

There is a demo server at http://demo.flexx.app .

Motivation

The primary motivation for Flexx is the undeniable fact that the web (i.e. browser technology) has become an increasingly popular method for delivering applications to users, also for (interactive) scientific content.

The purpose of Flexx is to provide a single application framework to create desktop applications, web apps, and (hopefully someday) mobile apps. By making use of browser technology, the library itself can be relatively small and pure Python, making it widely available and easy to use.

A word of caution

Flexx is very versatile and can be used in different ways. It also makes it easy to mix Python that runs on the server and Python that runs in the browser. This is a powerful feature but this also makes it easy to create code that becomes difficult to maintain. You, the developer, must ensure that Python and PScript code are clearly separated.

Installation

Flexx requires Python 3.5+ and also works on pypy. Further, it depends on:

  • the Tornado library (pure Python).
  • the PScript library (a pure Python flexxui project).
  • the Webruntime library (a pure Python flexxui project).
  • the Dialite library (a pure Python flexxui project).

To install the latest release (and dependencies), use either of these commands:

  • pip install flexx
  • conda install flexx -c conda-forge

Or get the bleeding edge with:

  • pip install https://github.com/flexxui/flexx/archive/master.zip

Supported browsers

Flexx aims to support all modern browsers, including Firefox, Chrome and Edge. Internet Explorer version 10 and up should work, but some things may be flaky.

For running desktop apps, it is needed to have Firefox or NW.js installed.

License

Flexx makes use of the liberal 2-clause BSD license. See LICENSE for details.

Issues
  • Wrapper for 'Tabulator' weird behaviour

    Wrapper for 'Tabulator' weird behaviour

    Hi,

    I have a wrapped JS object (table: http://tabulator.info/) which has a function:

    class TabulatorTableJS(flx.Widget):
        
        # More code
    
        @flx.action
        def write_cell(self, row_number, column_index, value):
            row = self.table.getRows()[row_number]
            cell = row.getCell(column_index)
            cell.setValue(value, True)
    

    ... which works great. But when calling the function/action in a loop of let's say 100 repetitions, after 40-60 repetitions, flexx throws this: [E 12:28:48 flexx.app] JS: TypeError: cell.setValue is not a function - stack trace in browser console (hit F12).

    I have no idea why this is happening. It feels like some things are executed too fast on the Python side in order for the JS, but I'm just guessing here. Does anyone have an idea of what is going on or how to fix this?

    Thanks, Matic

    type: question 
    opened by matkuki 29
  • Memory leak in PyWidget

    Memory leak in PyWidget

    Looks like the PyWidget never gets garbage-collected. Causing all its attributes to stick around too. When these contain e.g. large datasets, this can cause severe memory leaks.

    This needs some research to see what is holding a ref, and if we can solve this using e.g. a weakref. See a self-contained test-example further down.


    original post

    Hi @almarklein,

    I have a flx.PyWidget that has flx.Widget that wraps a javascript widget as a member:

    class MyWrappedWidget(flx.Widget):
      ...
      def dispose(self):
        # clean up code
        print("clean-up-completed")
    
      @flx.action
      def manual_dispose(self):
        # clean up code
        print("manual-clean-up-completed")
    
    class MyPyWidget(flx.PyWidget):
      def init(self):
        with flx.VFix(flex=1) as self.frame:
          self.mywidget = MyWrappedWidget() # the wrapped widget defined above
    
      def dispose(self):
        # self.mywidget.dispose()
        self.mywidget.manual_dispose()
        print("MyPyWidget-clean-up")
    

    Now when the flx.PyWidget is disposed, the manual_dispose call seems to be made, but doesn't execute, the print is never made to the command line. I also tried calling the flx.Widget's dispose method directly, but it's also doesn't execute. The wrapped flx.Widget (MyWrappedWidget) can be quite large (100's of MBs), so when old ones should be deleted and new ones created, the memory just stacks up, it doesn't get released. That's how it seems to me, don't hold me to this, I may be wrong.

    Is there a way to force the child flx.Widget to get disposed?

    opened by matkuki 26
  • Adopt a Flux-like approach to let information flow through an application

    Adopt a Flux-like approach to let information flow through an application

    This is a proposal for some pretty profound changes to how building apps with Flexx works. Though Flexx is still marked alpha, there are people using Flexx already, and they'd need to make some serious changes if we go this route. We thus have to think carefully whether the proposed changes are worth it.

    Background

    We've found Flexx to be working pretty well, even for larger applications, though the complexity of an app increases too, and we've found that newcomers to our app have trouble understanding the data-flows etc. I feel that #359 is a symptom of this, and that there is a deeper cause.

    Flexx uses events. A lot. Everything is tied together using events. This is the case for both user input (mouse and key events) and property changes. The system works very nice (if I may say so myself), but a problem is that information flows all over the place, which makes it difficult to reason about the state of the application.

    Flux and friends

    At Facebook they had similar problems with their classic MCV approach; it scales badly because its hard to predict the state of an application based on stuff that happens in the app. Their core insight was that if information flows in one direction, an app becomes much more predictable. Here is a video that explains it very clearly (thanks @korijn) and a comic.

    At Facebook they came up with a pattern (and framework) that they call Flux. The same pattern has been used in different places, in different variants, e.g. Redux and Veux. The core principal is that information flows like this:

    Actions --> Dispatcher  --> One ore more stores --> Views
                    /\                                    |
                     - - - - - - - - - -  Actions - - - - -
    

    The store(s) represent the state of the application. The views listen to changes in the state and update the UI accordingly. Views (and other parts of an app) can create actions (kind of events) that are handled by the store and eventually give rise to changes in the state.

    An important concept is that any actions that are dispatched (e.g. from views) are only handled after the view is done processing stuff. That's why we can legitimate saying that data flows in one direction, even though we see an arrow going to the left. Also important is that updates to the store are atomic, "commiting mutations" in Veux-terminology. The store handles actions, and then either applies mutations, or it may e.g. call out to an API, schedule some work, and eventually (asynchronously) apply mutations. Or both. This page explains it in more detail.

    The state in the store is a higher-level representation of the application state; instead of having a label for which its text property represents the username, the app would have a "username" entry in the store, and a view would be responsible for showing it.

    Adopting this pattern in Flexx

    My initial feeling is that with this model, Flexx can look like this:

    Py                             |                  JS
                                   |
                            -------------------
         Server stuff <--   | Stores / models |  --> Views / widgets
             |              -------------------               |
             -- actions -->        |             <-- actions --
                                   |
    

    Where a store is a bit like our current app.Model, having properties that are synchronised between Python and JS. Properties are not set directly, but via actions that can come either from JS or Python. The views/widgets live completely in JS (they have no representation in Python).

    Advantages

    • Business logic is separated from UX.
    • Its easier to reason about how actions change state and how state affects the UI.
    • Js and Python can no longer have conflicting states, which can lead to hard-to-predict behavior.
    • Due to the above points, larger applications become much easier to maintain.
    • It becomes possible to set the state of an app, log actions, log the history of the state, etc. which can be awesome during developing and debugging.
    • The server is only concerned with stuff that matters (app state, and server specific tasks), and is unaware of all the properties of all the widgets as is the case now. This should make the server more lean for web apps.
    • If Widgets are JS-only, they are lighter, and we can instantiated them at runtime from JS. This also avoids restrictions such as discussed in #301.
    • In-line callbacks for widgets are now in JS, which can help writing in a more declarative style (e.g. more like Enaml, #359). Callbacks in widgets will typically also be smaller (emit a certain action).

    Disadvantages

    • Ppl will have to rewrite their apps
    • Simple apps become slightly more complex? Maybe not, if a store is optional. Widgets can always have internal state.

    I'll make another post to give an idea of how the code would look like. This is something that I need to work on some more, and which I want to compare against current examples and apps.

    tag: event type: discussion 
    opened by almarklein 23
  • Insert the path into the session when creating it

    Insert the path into the session when creating it

    It follows the same logic as setting the cookies: it is added to the object right after it has been constructed and makes sense only in the scope of web applications.

    type: enhancement tag: app PR: ready 
    opened by Konubinix 20
  • Use with Enaml

    Use with Enaml

    Is there any way this could be implemented as a toolkit for use with Enaml?

    Flexx does have a nice declarative way of defining the structure, however the data binding aspect is separated into different handlers, which (from experience) quickly gets tedious in larger applications. Enaml nicely keeps everything contained.

    Just wondering... I think flexx is pretty awesome 👍

    tag: event type: discussion 
    opened by frmdstryr 19
  • Improve SplitPanel to respect flex values and allow spacing

    Improve SplitPanel to respect flex values and allow spacing

    Original title: Can flex spacing be used with SplitPanel?

    If not, is there a way to set the spacing/ratio of split panels? Adding the flex parameter to widgets within a SplitPanel context does not have the desired effect.

    type: enhancement tag: ui 
    opened by JohnLunzer 18
  • Is flexx.ui Pythonic enough?

    Is flexx.ui Pythonic enough?

    @JohnLunzer wrote in #302:

    I understand that Flexx is in part an attempt to bridge Python and Javascript. I understand also that the GUI elements of Flexx originate from the phosphor JS package. If I could draw an analogy. The PyQt package makes little if any demands on the user to understand C++ (the native language of Qt).

    Do you have any goals of providing that same level of abstraction to Flexx in the future? I realize the implications of that could affect the "bridge" aspect of Flexx. With careful design I believe the UI component of Flexx could have an API which made no demands on the user to have knowledge of JS/HTML/CSS. I'm not saying that having knowledge of those languages is a bad thing, but along with the "bridge" component Flexx touts "Apps are written purely in Python". Based on my short experience with Flexx I feel like while that is technically true, a more honest statement would be "Apps are written purely in Python, with some knowledge of Javascript, HTML, and CSS."

    tag: ui type: discussion 
    opened by almarklein 17
  • Initial event for properties is only send to handlers of same object

    Initial event for properties is only send to handlers of same object

    
    from flexx import event
    
    class Foo1(event.HasEvents):
    
        @event.prop
        def bar(self, v=0):
            return v
    
        @event.connect('bar')
        def on_bar(self, *events):
            print('Foo1 saw bar change')
    
    class Foo2(event.HasEvents):
    
        def __init__(self):
            self.x = Foo1()
            super().__init__()
    
        @event.connect('x.bar')
        def on_bar(self, *events):
            print('Foo2 saw bar change')
    
    >>> f = Foo2()
    Foo1 saw bar change
    >>> f.x.bar = 3
    Foo1 saw bar change
    Foo2 saw bar change
    

    This was initially somewhat intended. Or at least a consequence of how the initialization worked, which at the time seemed acceptable. But I just ran into this and banged my head into the wall, so I now consider it a bug.

    The point is that each object sends initial events at the end of initialization. But x does that at a time when the handlers of f are not yet connected. Maybe it makes sense to have each object check all handlers and create initial events for itself when such a handler is attached to a property.

    type: bug tag: event 
    opened by almarklein 17
  • how to track event like lost focus?

    how to track event like lost focus?

    Hi, I am new to flexx and going through http://flexx.readthedocs.io for examples. Here in http://flexx.readthedocs.io/en/latest/ui/button.html has event for mouse_click (button), checked (radio/toggle button) etc. Whereas LineEdit has only one -submit(). I want to check the data when LineEdit loses focus. Is there a way to achieve this?

    e.g. I want LineEdit ui to hold only interges greater than 5000

    type: question tag: ui 
    opened by apdd2003 16
  • Proposal of changes to make Flexx scale better

    Proposal of changes to make Flexx scale better

    Here is a preliminary proposal of changes to make writing (complex) apps easier and make Flexx scale better. Everything is up for discussion, so don't hesitate to challenge it.

    For context and discussion see #364. I am using a PR for this proposal, so that others can easily react in-line with the text. See the "files changed" section for what I think the docs for the new Model class could look like. Below I give a summary with argumentation.


    Introduction

    The problems that I'd like to address with this proposal:

    • A) Hard to predict flow of information in general.
    • B) Need rather verbose code for simpler handlers and properties.
    • C) Confusion of user on how the current Model works. Py and JS is too "entangled".
    • D) Flickering effect of properties (in Python) due to eventual synchronicity.
    • E) Complex memory management (it was quite leaky until #380, also see #381).
    • F) Its not trivial to write apps with centralized storage.
    • G) No story for updating array data effectively (e.g. scientific purposes).
    • H)

    First off, in my view, the Elm architecture (Flux, Veux et al.) provides two main advantages/insights: having global state that can be observed/used in different parts of the application (helping with F); having a predictable flow of information, where certain user-interactions in the view can cause an "action" that starts a new flow of information (helping with A and D).

    It took me a while to come up with an approach to include these ideas in Flexx, while also keeping things simple. I've considered everything from tiny changes to a complete overhaul of the event system. The latter is not what I propose, though some changes are pretty profound and not backward compatible.

    Summary + argumentation

    action state reaction

    Components

    • Rename Model to Component, because it takes the role of both the M and V in MVC. The new component comes in two flavors:
    • The PyComponent has all its logic in Python. It is instantiated in Python and can even be associated with multiple clients (e..g. for shared data in a chat app).
    • The JSComponent has all its logic in JavaScript. It can be instantiated from Python though, in which case its state can be observed and actions can be invoked.
    • No more need for the nested classes.
    • The flow of information starts at actions, which mutate state, upon which there are reactions. Actions and reactions are really just methods on a Component class.
    • State (properties) are readonly (makes code predictable) and can only be mutated from actions.
    • Widgets should be more optional; it should be easy (and not feel like a hack) to use other means to realize the view of an app, e.g. using bootstrap.
    • All components have a root attribute that refers to the main application component. This can serve as a place to keep global state (a "store" in Veux/Flux terminology).

    Properties (state)

    • Properties can be defined on a single line (saves lines of code).
    • A standard (typed) set_foo() action can be created automatically, because its so common by foo = prop(settable=int).
    • Introduce a "computed property", similar to automagic reactions mentioned below.
    • Introduce an array_prop to manage state in an array. Elements can be heterogeneous (list) or typed arrays (ctypes arrays in Python). Mutations can append/insert/remove items, making syncing/tracking such state very efficient.
    • Perhaps introduce a dict_prop which can similarly be mutated partially.

    Actions

    • Calling an action runs the action async (i.e. later), unless its called from another action. This makes it that the flow of information "starts" at the action.
    • Actions can be called (i.e. invoked) from both Python and JS, as long as the args can be serialized. Think of button.set_text().
    • Flexx handles one action at a time, and all reactions caused by the mutations done by the action are handled before moving on to the next action.

    Reactions

    • Reactions are more or less what we call handlers now, using @connect(...).
    • Reactions react to mutations to make the app reflect the new state.
    • Reactions react to events, in most cases by invoking new actions.
    • This still works: @reaction(... connection strings ...)
    • We also allow just @reaction, and let Flexx figure out the dependencies automagically.
    • Inline reactions: Label(text=lambda:self.username) and Button(on_mouse_click=lambda ev: self.submit()). These will greatly help reduce code.

    Renaming / restructuring

    • Model ->PyComponent and JSComponent.
    • The events subpackage made sense since Flexx is now very event-centric. The proposed changes make it more state-centric, and the name bugs me. Perhaps I'll just move it all to flexx.app.
    • Maybe spin out pyscript and webruntime, so that we can just do flexx.PyComponent?

    More motivation / argumentation

    Similarity and differences w.r.t. Elm/Flux/Veux/Redux

    Redux adopts a very "functional" approach to dealing with state, where reducers (i.e. actions) receive the state as an input argument, and return a new state. I don't doubt that this helps predictability, but it means having to make a copy of the whole state at each transition. This breaks down if we want to do something with data. It also does not work well with the OO style that Flexx uses.

    A difference with Flux/Veux is that what they call "view", we call "reactions". One reason is that our reactions will often involve invoking actions on lower level components (e.g. widgets) rather than do DOM updates directly. So the scope of our reactions is somewhat broader, but the idea is very similar.

    In most of the aforementioned frameworks there is a concept of a global/centralized state object, though each framework has another means to have some kind of modularity. In Flexx each component has its own state, and its up to the user to design the relationships in a sensible way, e.g. defining a widget's state as "local state" and using a common component, or the root component as "application state".

    Debugging / testing

    The clear flow of information also makes is possible/easier to create fancy debugging tools. E.g. see the list of pending actions, clicking a button to process the first one, see what mutations it causes, and which reactions follow from it. Similarly, it might help with (unit) testing.

    Separation of Python and JS

    It's become clear to me that Flexx' power to bring Python (server side) code and JavaScript (client side) code close together is also its weakness; it is confusing for users.

    My initial take (written down originally in this PR) was to allow instantiating components in JS, in which case they exist/operate only in JS. That would make it easier to write apps that clearly separate JS code from Py code (i.e. views from application logic). I now think that this is not sufficient.

    By making a component either operate in JS or Python, the concerns of such a component are much more clear. The state that can still be observed from the other end, and the actions that can be invoked, provide an easy API to handle the Python-JS interactions.

    A point of discussion was whether js-components could be instantiated from Python. If not, we'd need a way to somehow bind a Python and JS entry point together, which would greatly reduce the ease and number of places where JS and Python can interact. IMO the possibility to instantiate and use a js-component from Python does not break the JS/Py separation too much, since its still fully implemented in Python.

    We'd need PyScript to support context managers and keyword args to allow instantiating components in JS in the same way as we do now.

    array_prop

    I'd like a better story to manage arrays as state, without having to resend the whole array on each change, and making it easy for a view to update its local representation without a hard reset. Thinking of WebGL in particular, but also e.g. a list view with a lot of items. On top of this, one could implement "data sources" e.g. to manage image data.

    To send mutations with data in the form of typed arrays we need a way to send binary messages. To keep things in order, this must happen over the same single websocket. So we should probably use a binary protocol instead.

    tag: app tag: event type: discussion PR: declined 
    opened by almarklein 16
  • add support for HTTPS protocol

    add support for HTTPS protocol

    Proof of concept for #303

    • Allows to pass arguments to tornado.HTTPServer constructor through app.create_server.
    • support for HTTPS protocol

    Enable SSL transport by calling :

    args = {}
    args['ssl_options'] = {'certfile' : 'path-to-crtfile', 'keyfile' : 'path-to-keyfile'}
    app.create_server(**args)
    
    app.serve(Example, 'Example')
    app.run()
    
    type: enhancement tag: app PR: ready 
    opened by pigay 16
  • JS: RangeError: Maximum call stack size exceeded

    JS: RangeError: Maximum call stack size exceeded

    Hello,

    The problem "JS: RangeError: Maximum call stack size exceeded" is often encountered in the project, which causes the project to click without continuing to respond.

    error

    Since I am not in-depth on the underlying code research, help analyze the reasons and solutions.

    Thank you.

    type: question 
    opened by chinaericgithub 10
  • Real projects using Flexx

    Real projects using Flexx

    Are there any projects that use Flexx that you could list here to see Flexx in action?

    Primarily, of course, I mean open source projects whose source code is listed on Github or Gitlab. But if anyone also knows of closed-source projects, it would be great if they were listed here as well.

    And I mean projects of any kind, so any projects that use Flexx as a GUI/webapp framework, but are from any category.

    I'd like to get a feel for how Flex has already been used, and more importantly, how different use cases have been implemented.

    So if anyone is running a public project using Flexx, feel free to link it here :)

    I mean projects that are not listed under "dependents" (https://github.com/flexxui/flexx/network/dependents?package_id=UGFja2FnZS01MjEyMzE2NA%3D%3D), but if there is a particularly worth seeing project that is already listed on the site, you are welcome to point it out here again.

    opened by C0D3D3V 8
  • Requests Blocked by CORS

    Requests Blocked by CORS

    It isn't 100% clear to me how to write a flexx app based around asyncio. I read through:

    1. #373
    2. #408
    3. #413 Was async ever integrated directly into flexx? I couldn't find the commit :P
    opened by i1Fury 4
  • Added a DynamicWidgetContainer

    Added a DynamicWidgetContainer

    Hi Almarklein,

    I've added a dynamic container for widgets. I'm using it for a few applications and I thought of sharing it as I see some questions regarding adding and removing widgets on the fly.

    Look at the examples, it will show you what it is capable of.

    Side note: The file flexx/event/_js.py was not working for me, there is some error in _clean_code_of_thread_stuff. It seem to block a lot of examples so you are probably on it. Just use the old version or the fixed one if you have one.

    Have fun ;)

    opened by ceprio 1
  • How do I set

    How do I set "data-xxx" attributes on widgets?

    I'd like to set a data attribute on widgets, as per https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes

    I've tried using create_element('div', {'data-my-prop': 'my value'}, ...) but something in Flexx seems to strip them out.

    Any clues?

    opened by TreyBoudreau 1
Owner
flexxui
Repositories related to the Flexx UI toolkit
flexxui
A desktop application developed in Python with PyQt5 to predict demand and help monitor and schedule brewing processes for Barnaby's Brewhouse.

brewhouse-management A desktop application developed in Python with PyQt5 to predict demand and help monitor and schedule brewing processes for Barnab

Isaac Cheng 2 Mar 29, 2022
Learn to build a Python Desktop GUI app using pywebview, Python, JavaScript, HTML, & CSS.

Python Desktop App Learn how to make a desktop GUI application using Python, JavaScript, HTML, & CSS all thanks to pywebview. pywebview is essentially

Coding For Entrepreneurs 42 May 29, 2022
Make desktop applications using HTML and CSS with python

Neutron Make desktop applications using HTML and CSS with python What is Neutron Neutron will allow developers to design modern applications in python

Ian Baldelli 223 Jun 4, 2022
A simple Python Module for sending cross-platform desktop notifications on Windows, macOS and Linux

notify.py Cross platform desktop notifications for Python scripts and applications. Docs You can read the docs on this Git's Wiki, or here Supported P

Mustafa 149 May 31, 2022
Desktop application for Windows/macOS users to rotate through custom, preset, and searched-for collections of backgrounds with scheduling and additional settings

Background Revolution (In Development, Alpha Release) What? This will be an application for users to customize their windows backgrounds by uploading

Daniel Agapov 1 Nov 2, 2021
🧮A simple calculator written in python allows you to make simple calculations, write charts, calculate the dates, and exchange currency.

Calculator ?? A simple calculator written in python allows you to make simple calculations, write charts, calculate the dates, and exchange currency.

Jan Kupczyk 1 Jan 15, 2022
A Virtual Desktop Assistant Written in Python

DesktopAssitant A Virtual Desktop Assistant Written in Python. It's generally a basic virtual assistant The basic purpose of this is to make work easi

Technerd brainiac 580 Jun 9, 2022
A Virtual Desktop Assistant Written in Python

DesktopAssitant A Virtual Desktop Assistant Written in Python. It's generally a basic virtual assistant The basic purpose of this is to make work easi

Technerd Brainiac 580 Jun 9, 2022
A simple desktop news application written using python created using PyQt5

News-Application---Python This is a news application created using PyQt5. News is fetched through API from newsapi.org. Available top headlines from c

Sritiman Adak 1 Nov 14, 2021
Create custom desktop notificatons using python

Create custom desktop notificatons using python In this video i am going to use a module called plyer

Niranjan 2 Dec 15, 2021
A library for building modern declarative desktop applications in WX.

re-wx is a library for building modern declarative desktop applications. It's built as a management layer on top of WXPython, which means you get all the goodness of a mature, native, cross-platform UI kit, wrapped up in a modern, React inspired API.

Chris 105 Jun 4, 2022
MATE Layouts is a small panel layout switching application for the MATE Desktop.

a small panel layout switching application for the MATE Desktop

Wilbur Wetterquarz 4 Mar 15, 2022
A desktop application for JupyterLab, based on Electron.

A desktop application for JupyterLab, based on Electron.

JupyterLab 1.8k Jun 1, 2022
Cross-platform BrowserViews for the desktop.

Webview We use wxPython Phoenix to provide webviews. It's cross platform between Windows and macOS primarily, Linux versions require extra setup. Appl

null 1 Feb 12, 2022
A little Python library for making simple Electron-like HTML/JS GUI apps

Eel Eel is a little Python library for making simple Electron-like offline HTML/JS GUI apps, with full access to Python capabilities and libraries. Ee

Chris Knott 5k Jun 2, 2022
AppQuickLauncher is a tool that can quickly launch apps by clicking the app tray icon.

AppQuickLauncher AppQuickLauncher is a tool that can quickly launch apps by clicking the app tray icon. On Windows 7 or Windows 10, we can add a folde

yin kaisheng 2 Jun 4, 2022
Use CSS styling in Tkinter apps

cssTk To-Do Support Upto CSS 4.15 Set Up Docs Features * Corner Radius Gradient BG Blur Animations Usage Scenarios Allows easy import of GTK 3 and GTK

RUG 4 Jan 23, 2022
A Windows Dock Widget Written In Pure Python

VEПUS A Windows Dock Widget Written In Pure Python What is Venus? Venus is a Dock Widget for your desktops interface. It adds a couple of really cool

Secrets 17 May 2, 2022