Package: tkxui
TkXUI Python LibraryThe TkXUI Python library allows you to create frameless, modern and fully customizable GUIs using the simplicity of the Tkinter API.The library also implements a JSON loader to define your GUIs (windows, buttons, labels, etc.) with JSON for a fast and reliable UI design.
It supports all kind of widgets (both ttk and tkinter widgets), styling and theming like in CSS with id-class system.InstallationIf you are familiar with installing Python packages, you can use
the following command:pipinstalltkxuiOtherwise, you can simply download the source code from github and paste thetkxuifolder in your project root directory.Creating a windowIn order to create your window, you have to import the tkxui library and implement aTkobject.
If you want a frameless window, passFRAMELESSto the Tk's display parameter, otherwise it will create a normal window. If you want a system-like window passNATIVEto the Tk's display parameter (default value).importtkxuiimporttkinter# Setting up the window with frameless attributeroot=tkxui.Tk(display=tkxui.FRAMELESS)# Setting window attributesroot.config(bg="#2A2A2A")root.geometry("500x300")root.title("My First TkXUI window !")# Set the resizer's background colorroot.resizer_bg("#2A2A2A")# Create a labellabel=tkinter.Label(root,bg="#2A2A2A",text="Hello TkXUI !",fg="white")label.pack(fill=tkinter.BOTH,expand=1)root.mainloop()This is what we get :You can choose not to have a default border to your frameless window by passingFalseto the Tk's defaultBorder parameter (In this case, you would have to create your own border, there is a section down below that explains how to do it).Loading JSONYou can define your GUI in a JSON file, like this :{"doctype":"ui-definition","main":{"tk.Frame":{"bg":"#2A2A2A","name":"frame1","pack_options":{"fill":"both","expand":"1"},"tk.Label":{"text":"Hello TkXUI !","bg":"#2A2A2A","fg":"white","name":"hello_label"},"ttk.Button":{"text":"Click me !!!","name":"clickme_button"}}},"border":{"tk.Label":{"text":"TkXUI Window","name":"window_title","pack_options":{"side":"left","padx":"(20, 0)"}}}}Here, we define what is in the window -main- (a label and a button) and what is in theborder(a label) in aui-definitionfile.Don't forget to add this line on top of your file :"doctype":"ui-definition".Each widget has a name so that we can access them in our code.Then, we need to load it on our window. To do that, we need to create aJSONLoaderobject that takes the window as parameter :importtkxuiimporttkinter# Setting up the window with frameless attributeroot=tkxui.Tk(display=tkxui.FRAMELESS)# Setting window attributesroot.config(bg="#2A2A2A")root.geometry("500x300")root.title("My First TkXUI window !")# Set the resizer's background colorroot.resizer_bg("#2A2A2A")# Load the JSON filejson_loader=tkxui.JSONLoader(root)# Create a JSONLoader objectjson_loader.generate("ui.json")# Load our JSON file and generate our UI.# We can access our widgets directly with their namesroot.clickme_button.config(command=lambda:root.hello_label.config(text="Button clicked!"))root.mainloop()Here is what we get :Creating custom widgetsYou can create your own widgets by defining them on your JSON file.
Here is an example on how to use this feature :{"doctype":"ui-definition","widget:MyCustomWidget":{"tk.Frame":{"bg":"#2A2A2A","name":"frame","pack_options":{"fill":"both","expand":"1"},"tk.Entry":{"name":"entry"},"tk.Button":{"text":"Submit","border":"0","name":"submit_button"}}},"main":{"@MyCustomWidget":{"name":"my_widget1"},"@MyCustomWidget":{"name":"my_widget2"}}}You can define your widget withwidget:<YourWidgetName>and you can use it by typing@plus the name of the widget wherever you want in the window's ui definition file.This is going to create the same widget twice but all subwidgets will have a different parent so that you can access them explicitly.For instance if you want to change the background color of the first custom widget's button you would call it using the name you gave for the custom widget instance (it means<window>.<widget name>.<subwidget>), e.g. :# Change the color of the first custom widget's buttonroot.my_widget1.submit_button.config(bg="green")Here is what we get :ThemesThe TkXUI library allows you apply themes and styles to your window.In order to do that, we need to create another JSON file that is going to contain the theme definition (like astyle.cssfile in CSS) :{"doctype":"theme","tk.Button":{"bg":"lightblue"},"tk.Entry":{"bg":"red"}}Don't forget to add"doctype":"theme"on top of your file. Here, we define that all buttons and entries, by default, have a background color oflightbluefor the buttons andredfor the entries.In order to apply this theme, we need to generate the file with ourJSONLoaderobject:importtkxui# Setting up the window with frameless attributeroot=tkxui.Tk(display=tkxui.FRAMELESS)# Setting window attributesroot.config(bg="#2A2A2A")root.geometry("500x300")root.title("My First TkXUI window !")# Set the resizer's background colorroot.resizer_bg("#2A2A2A")# Load the JSON filejson_loader=tkxui.JSONLoader(root)# Create a JSONLoader objectjson_loader.generate("ui.json")# Load our JSON file and generate our UI.json_loader.generate("theme.json")# Load our JSON file and apply the theme.Here is our ui definition file :{"doctype":"ui-definition","main":{"tk.Frame":{"bg":"#2A2A2A","name":"frame1","pack_options":{"fill":"both","expand":"1"},"tk.Entry":{"name":"entry1"},"tk.Button":{"text":"Click me !!!","border":"0","name":"clickme_button"}}}}And this is what we get with the theme applied :As you can see, even the widgets of the border are affected by the theme.Names and classesYou can also set attributes to a specific widget using its name or its class attribute.ui.json:{"doctype":"ui-definition","main":{"tk.Frame":{"bg":"#2A2A2A","name":"frame1","pack_options":{"fill":"both","expand":"1"},"tk.Entry":{"name":"entry1","class":"my_class"},"tk.Button":{"text":"Click me !!!","border":"0","name":"clickme_button","class":"my_class"}}}}theme.json:{"doctype":"theme",".my_class":{"bg":"blue","fg":"white"},"#frame1":{"bg":"green"}}This is the final result, once we generated both files :To change the window attributes, usewindowinstead of the widget's name.Customizing the borderThere are several options to customize the window's border.You can set a theme to the border in your JSON theme file using theborderkeyword and by specifying attributes for each border's subwidgets :{"doctype":"theme","border":{"border":{"bg":"green"},"maximize":{"fg":"white","hoverfg":"white","hoverbg":"darkgreen","bg":"green"},"minimize":{"fg":"white","hoverfg":"white","hoverbg":"darkgreen","bg":"green"},"close":{"fg":"white","hoverfg":"white","hoverbg":"red","bg":"green"}}}You can also set those attributes using theconfig_borderborder method of yourTkobject by passing a dictionnary as parameter.
This is what we get:The last way to customize the window's border is to create your own border.Here is an example of a custom window's border with only one close button and a title:{"doctype":"ui-definition","main":{"tk.Frame":{"bg":"#2A2A2A","name":"border","pack_options":{"fill":"x","side":"top"},"tk.Label":{"name":"window_title","pack_options":{"side":"left","padx":"(10, 0)"},"bg":"#2A2A2A","fg":"white","text":"My custom border"},"tk.Button":{"name":"close","pack_options":{"side":"right"},"bg":"red","border":"0","fg":"white","text":"X","font":"Consolas, 15"}}}}Because we create our own window, we may not display the default window's border. It is very easy, just setdefaultBordertoFalsewhen you create yourTkobject :root=tkxui.Tk(display=tkxui.FRAMELESS,defaultBorder=False)Then, we need to make the window draggable, simply create aFramelessDragBehaviourobject on top of our window and our draggable widget, the border frame :root=tkxui.Tk(display=tkxui.FRAMELESS,defaultBorder=False)# Create the windowjson_loader=tkxui.JSONLoader(root)# Create the JSON file loaderjson_loader.generate("ui.json")# Now we have access to our border widgetcustom_border_draggable_behaviour=tkxui.FramelessDragBehaviour(root,root.border)# Now the window is draggable with the border frameFinally, you need to make sure the close button can close the window, simply add a command to it :root.close.config(command=lambda:root.destroy())Everything is now ready :Border EventsBy default a frameless window is reproducing Windows border events (for instance, when you drag a window to the top it will go fullscreen). You can disable that option by calling thedisable_winbehavioursmethod on your window's object :root.disable_winbehaviours()To get back to default border, simply do this :root.enable_winbehaviours()